CMakeSetupDialog.cxx 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "CMakeSetupDialog.h"
  14. #include <QFileDialog>
  15. #include <QProgressBar>
  16. #include <QMessageBox>
  17. #include <QStatusBar>
  18. #include <QToolButton>
  19. #include <QDialogButtonBox>
  20. #include <QCloseEvent>
  21. #include <QCoreApplication>
  22. #include <QSettings>
  23. #include <QMenu>
  24. #include <QMenuBar>
  25. #include <QDragEnterEvent>
  26. #include <QMimeData>
  27. #include <QUrl>
  28. #include <QShortcut>
  29. #include <QMacInstallDialog.h>
  30. #include "QCMake.h"
  31. #include "QCMakeCacheView.h"
  32. #include "AddCacheEntry.h"
  33. #include "CMakeFirstConfigure.h"
  34. QCMakeThread::QCMakeThread(QObject* p)
  35. : QThread(p), CMakeInstance(NULL)
  36. {
  37. }
  38. QCMake* QCMakeThread::cmakeInstance() const
  39. {
  40. return this->CMakeInstance;
  41. }
  42. void QCMakeThread::run()
  43. {
  44. this->CMakeInstance = new QCMake;
  45. // emit that this cmake thread is ready for use
  46. emit this->cmakeInitialized();
  47. this->exec();
  48. delete this->CMakeInstance;
  49. this->CMakeInstance = NULL;
  50. }
  51. CMakeSetupDialog::CMakeSetupDialog()
  52. : ExitAfterGenerate(true), CacheModified(false), CurrentState(Interrupting)
  53. {
  54. // create the GUI
  55. QSettings settings;
  56. settings.beginGroup("Settings/StartPath");
  57. int h = settings.value("Height", 500).toInt();
  58. int w = settings.value("Width", 700).toInt();
  59. this->resize(w, h);
  60. QWidget* cont = new QWidget(this);
  61. this->setupUi(cont);
  62. this->Splitter->setStretchFactor(0, 3);
  63. this->Splitter->setStretchFactor(1, 1);
  64. this->setCentralWidget(cont);
  65. this->ProgressBar->reset();
  66. this->RemoveEntry->setEnabled(false);
  67. this->AddEntry->setEnabled(false);
  68. bool groupView = settings.value("GroupView", false).toBool();
  69. this->CacheValues->cacheModel()->setViewType(groupView ?
  70. QCMakeCacheModel::GroupView : QCMakeCacheModel::FlatView);
  71. this->CacheValues->setRootIsDecorated(groupView);
  72. QMenu* FileMenu = this->menuBar()->addMenu(tr("&File"));
  73. this->ReloadCacheAction = FileMenu->addAction(tr("&Reload Cache"));
  74. QObject::connect(this->ReloadCacheAction, SIGNAL(triggered(bool)),
  75. this, SLOT(doReloadCache()));
  76. this->DeleteCacheAction = FileMenu->addAction(tr("&Delete Cache"));
  77. QObject::connect(this->DeleteCacheAction, SIGNAL(triggered(bool)),
  78. this, SLOT(doDeleteCache()));
  79. this->ExitAction = FileMenu->addAction(tr("E&xit"));
  80. QObject::connect(this->ExitAction, SIGNAL(triggered(bool)),
  81. this, SLOT(close()));
  82. QMenu* ToolsMenu = this->menuBar()->addMenu(tr("&Tools"));
  83. this->ConfigureAction = ToolsMenu->addAction(tr("&Configure"));
  84. // prevent merging with Preferences menu item on Mac OS X
  85. this->ConfigureAction->setMenuRole(QAction::NoRole);
  86. QObject::connect(this->ConfigureAction, SIGNAL(triggered(bool)),
  87. this, SLOT(doConfigure()));
  88. this->GenerateAction = ToolsMenu->addAction(tr("&Generate"));
  89. QObject::connect(this->GenerateAction, SIGNAL(triggered(bool)),
  90. this, SLOT(doGenerate()));
  91. #if defined(Q_WS_MAC)
  92. this->InstallForCommandLineAction
  93. = ToolsMenu->addAction(tr("&Install For Command Line Use"));
  94. QObject::connect(this->InstallForCommandLineAction, SIGNAL(triggered(bool)),
  95. this, SLOT(doInstallForCommandLine()));
  96. #endif
  97. QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options"));
  98. this->SuppressDevWarningsAction = OptionsMenu->addAction(tr("&Suppress dev Warnings (-Wno-dev)"));
  99. this->SuppressDevWarningsAction->setCheckable(true);
  100. QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output"));
  101. debugAction->setCheckable(true);
  102. QObject::connect(debugAction, SIGNAL(toggled(bool)),
  103. this, SLOT(setDebugOutput(bool)));
  104. OptionsMenu->addSeparator();
  105. QAction* groupAction = OptionsMenu->addAction(tr("&Group Entries"));
  106. groupAction->setCheckable(true);
  107. groupAction->setChecked(this->CacheValues->cacheModel()->viewType() == QCMakeCacheModel::GroupView);
  108. QObject::connect(groupAction, SIGNAL(toggled(bool)),
  109. this, SLOT(toggleGroupView(bool)));
  110. QAction* expandAction = OptionsMenu->addAction(tr("&Expand Grouped Entries"));
  111. QObject::connect(expandAction, SIGNAL(triggered(bool)),
  112. this->CacheValues, SLOT(expandAll()));
  113. QAction* collapseAction = OptionsMenu->addAction(tr("&Collapse Grouped Entries"));
  114. QObject::connect(collapseAction, SIGNAL(triggered(bool)),
  115. this->CacheValues, SLOT(collapseAll()));
  116. QMenu* HelpMenu = this->menuBar()->addMenu(tr("&Help"));
  117. QAction* a = HelpMenu->addAction(tr("About"));
  118. QObject::connect(a, SIGNAL(triggered(bool)),
  119. this, SLOT(doAbout()));
  120. a = HelpMenu->addAction(tr("Help"));
  121. QObject::connect(a, SIGNAL(triggered(bool)),
  122. this, SLOT(doHelp()));
  123. QShortcut* filterShortcut = new QShortcut(QKeySequence::Find, this);
  124. QObject::connect(filterShortcut, SIGNAL(activated()),
  125. this, SLOT(startSearch()));
  126. this->setAcceptDrops(true);
  127. // get the saved binary directories
  128. QStringList buildPaths = this->loadBuildPaths();
  129. this->BinaryDirectory->addItems(buildPaths);
  130. this->BinaryDirectory->setCompleter(new QCMakeFileCompleter(this, true));
  131. this->SourceDirectory->setCompleter(new QCMakeFileCompleter(this, true));
  132. // fixed pitch font in output window
  133. QFont outputFont("Courier");
  134. this->Output->setFont(outputFont);
  135. this->ErrorFormat.setForeground(QBrush(Qt::red));
  136. // start the cmake worker thread
  137. this->CMakeThread = new QCMakeThread(this);
  138. QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()),
  139. this, SLOT(initialize()), Qt::QueuedConnection);
  140. this->CMakeThread->start();
  141. this->enterState(ReadyConfigure);
  142. }
  143. void CMakeSetupDialog::initialize()
  144. {
  145. // now the cmake worker thread is running, lets make our connections to it
  146. QObject::connect(this->CMakeThread->cmakeInstance(),
  147. SIGNAL(propertiesChanged(const QCMakePropertyList&)),
  148. this->CacheValues->cacheModel(),
  149. SLOT(setProperties(const QCMakePropertyList&)));
  150. QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)),
  151. this, SLOT(doConfigure()));
  152. QObject::connect(this->CMakeThread->cmakeInstance(),
  153. SIGNAL(configureDone(int)),
  154. this, SLOT(finishConfigure(int)));
  155. QObject::connect(this->CMakeThread->cmakeInstance(),
  156. SIGNAL(generateDone(int)),
  157. this, SLOT(finishGenerate(int)));
  158. QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)),
  159. this, SLOT(doGenerate()));
  160. QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)),
  161. this, SLOT(doSourceBrowse()));
  162. QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)),
  163. this, SLOT(doBinaryBrowse()));
  164. QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)),
  165. this, SLOT(onBinaryDirectoryChanged(QString)));
  166. QObject::connect(this->SourceDirectory, SIGNAL(textChanged(QString)),
  167. this, SLOT(onSourceDirectoryChanged(QString)));
  168. QObject::connect(this->CMakeThread->cmakeInstance(),
  169. SIGNAL(sourceDirChanged(QString)),
  170. this, SLOT(updateSourceDirectory(QString)));
  171. QObject::connect(this->CMakeThread->cmakeInstance(),
  172. SIGNAL(binaryDirChanged(QString)),
  173. this, SLOT(updateBinaryDirectory(QString)));
  174. QObject::connect(this->CMakeThread->cmakeInstance(),
  175. SIGNAL(progressChanged(QString, float)),
  176. this, SLOT(showProgress(QString,float)));
  177. QObject::connect(this->CMakeThread->cmakeInstance(),
  178. SIGNAL(errorMessage(QString)),
  179. this, SLOT(error(QString)));
  180. QObject::connect(this->CMakeThread->cmakeInstance(),
  181. SIGNAL(outputMessage(QString)),
  182. this, SLOT(message(QString)));
  183. QObject::connect(this->Advanced, SIGNAL(clicked(bool)),
  184. this->CacheValues, SLOT(setShowAdvanced(bool)));
  185. QObject::connect(this->Search, SIGNAL(textChanged(QString)),
  186. this->CacheValues, SLOT(setSearchFilter(QString)));
  187. QObject::connect(this->CMakeThread->cmakeInstance(),
  188. SIGNAL(generatorChanged(QString)),
  189. this, SLOT(updateGeneratorLabel(QString)));
  190. this->updateGeneratorLabel(QString());
  191. QObject::connect(this->CacheValues->cacheModel(),
  192. SIGNAL(dataChanged(QModelIndex,QModelIndex)),
  193. this, SLOT(setCacheModified()));
  194. QObject::connect(this->CacheValues->selectionModel(),
  195. SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
  196. this, SLOT(selectionChanged()));
  197. QObject::connect(this->RemoveEntry, SIGNAL(clicked(bool)),
  198. this, SLOT(removeSelectedCacheEntries()));
  199. QObject::connect(this->AddEntry, SIGNAL(clicked(bool)),
  200. this, SLOT(addCacheEntry()));
  201. QObject::connect(this->SuppressDevWarningsAction, SIGNAL(triggered(bool)),
  202. this->CMakeThread->cmakeInstance(), SLOT(setSuppressDevWarnings(bool)));
  203. if(!this->SourceDirectory->text().isEmpty() ||
  204. !this->BinaryDirectory->lineEdit()->text().isEmpty())
  205. {
  206. this->onSourceDirectoryChanged(this->SourceDirectory->text());
  207. this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
  208. }
  209. else
  210. {
  211. this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
  212. }
  213. }
  214. CMakeSetupDialog::~CMakeSetupDialog()
  215. {
  216. QSettings settings;
  217. settings.beginGroup("Settings/StartPath");
  218. settings.setValue("Height", this->height());
  219. settings.setValue("Width", this->width());
  220. // wait for thread to stop
  221. this->CMakeThread->quit();
  222. this->CMakeThread->wait(2000);
  223. }
  224. void CMakeSetupDialog::doConfigure()
  225. {
  226. if(this->CurrentState == Configuring)
  227. {
  228. // stop configure
  229. doInterrupt();
  230. return;
  231. }
  232. // make sure build directory exists
  233. QString bindir = this->CMakeThread->cmakeInstance()->binaryDirectory();
  234. QDir dir(bindir);
  235. if(!dir.exists())
  236. {
  237. QString message = tr("Build directory does not exist, "
  238. "should I create it?")
  239. + "\n\n"
  240. + tr("Directory: ");
  241. message += bindir;
  242. QString title = tr("Create Directory");
  243. QMessageBox::StandardButton btn;
  244. btn = QMessageBox::information(this, title, message,
  245. QMessageBox::Yes | QMessageBox::No);
  246. if(btn == QMessageBox::No)
  247. {
  248. return;
  249. }
  250. dir.mkpath(".");
  251. }
  252. // if no generator, prompt for it and other setup stuff
  253. if(this->CMakeThread->cmakeInstance()->generator().isEmpty())
  254. {
  255. if(!this->setupFirstConfigure())
  256. {
  257. return;
  258. }
  259. }
  260. // remember path
  261. this->addBinaryPath(dir.absolutePath());
  262. this->enterState(Configuring);
  263. this->CacheValues->selectionModel()->clear();
  264. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  265. "setProperties", Qt::QueuedConnection,
  266. Q_ARG(QCMakePropertyList,
  267. this->CacheValues->cacheModel()->properties()));
  268. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  269. "configure", Qt::QueuedConnection);
  270. }
  271. void CMakeSetupDialog::finishConfigure(int err)
  272. {
  273. if(0 == err && !this->CacheValues->cacheModel()->newPropertyCount())
  274. {
  275. this->enterState(ReadyGenerate);
  276. }
  277. else
  278. {
  279. this->enterState(ReadyConfigure);
  280. this->CacheValues->scrollToTop();
  281. }
  282. if(err != 0)
  283. {
  284. QMessageBox::critical(this, tr("Error"),
  285. tr("Error in configuration process, project files may be invalid"),
  286. QMessageBox::Ok);
  287. }
  288. }
  289. void CMakeSetupDialog::finishGenerate(int err)
  290. {
  291. this->enterState(ReadyGenerate);
  292. if(err != 0)
  293. {
  294. QMessageBox::critical(this, tr("Error"),
  295. tr("Error in generation process, project files may be invalid"),
  296. QMessageBox::Ok);
  297. }
  298. }
  299. void CMakeSetupDialog::doInstallForCommandLine()
  300. {
  301. QMacInstallDialog setupdialog(0);
  302. setupdialog.exec();
  303. }
  304. void CMakeSetupDialog::doGenerate()
  305. {
  306. if(this->CurrentState == Generating)
  307. {
  308. // stop generate
  309. doInterrupt();
  310. return;
  311. }
  312. this->enterState(Generating);
  313. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  314. "generate", Qt::QueuedConnection);
  315. }
  316. void CMakeSetupDialog::closeEvent(QCloseEvent* e)
  317. {
  318. // prompt for close if there are unsaved changes, and we're not busy
  319. if(this->CacheModified)
  320. {
  321. QString message = tr("You have changed options but not rebuilt, "
  322. "are you sure you want to exit?");
  323. QString title = tr("Confirm Exit");
  324. QMessageBox::StandardButton btn;
  325. btn = QMessageBox::critical(this, title, message,
  326. QMessageBox::Yes | QMessageBox::No);
  327. if(btn == QMessageBox::No)
  328. {
  329. e->ignore();
  330. }
  331. }
  332. // don't close if we're busy, unless the user really wants to
  333. if(this->CurrentState == Configuring)
  334. {
  335. QString message = "You are in the middle of a Configure.\n"
  336. "If you Exit now the configure information will be lost.\n"
  337. "Are you sure you want to Exit?";
  338. QString title = tr("Confirm Exit");
  339. QMessageBox::StandardButton btn;
  340. btn = QMessageBox::critical(this, title, message,
  341. QMessageBox::Yes | QMessageBox::No);
  342. if(btn == QMessageBox::No)
  343. {
  344. e->ignore();
  345. }
  346. else
  347. {
  348. this->doInterrupt();
  349. }
  350. }
  351. // let the generate finish
  352. if(this->CurrentState == Generating)
  353. {
  354. e->ignore();
  355. }
  356. }
  357. void CMakeSetupDialog::doHelp()
  358. {
  359. QString msg = tr("CMake is used to configure and generate build files for "
  360. "software projects. The basic steps for configuring a project are as "
  361. "follows:\r\n\r\n1. Select the source directory for the project. This should "
  362. "contain the CMakeLists.txt files for the project.\r\n\r\n2. Select the build "
  363. "directory for the project. This is the directory where the project will be "
  364. "built. It can be the same or a different directory than the source "
  365. "directory. For easy clean up, a separate build directory is recommended. "
  366. "CMake will create the directory if it does not exist.\r\n\r\n3. Once the "
  367. "source and binary directories are selected, it is time to press the "
  368. "Configure button. This will cause CMake to read all of the input files and "
  369. "discover all the variables used by the project. The first time a variable "
  370. "is displayed it will be in Red. Users should inspect red variables making "
  371. "sure the values are correct. For some projects the Configure process can "
  372. "be iterative, so continue to press the Configure button until there are no "
  373. "longer red entries.\r\n\r\n4. Once there are no longer red entries, you "
  374. "should click the Generate button. This will write the build files to the build "
  375. "directory.");
  376. QDialog dialog;
  377. QFontMetrics met(this->font());
  378. int msgWidth = met.width(msg);
  379. dialog.setMinimumSize(msgWidth/15,20);
  380. dialog.setWindowTitle(tr("Help"));
  381. QVBoxLayout* l = new QVBoxLayout(&dialog);
  382. QLabel* lab = new QLabel(&dialog);
  383. lab->setText(msg);
  384. lab->setWordWrap(true);
  385. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
  386. Qt::Horizontal, &dialog);
  387. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  388. l->addWidget(lab);
  389. l->addWidget(btns);
  390. dialog.exec();
  391. }
  392. void CMakeSetupDialog::doInterrupt()
  393. {
  394. this->enterState(Interrupting);
  395. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  396. "interrupt", Qt::QueuedConnection);
  397. }
  398. void CMakeSetupDialog::doSourceBrowse()
  399. {
  400. QString dir = QFileDialog::getExistingDirectory(this,
  401. tr("Enter Path to Source"), this->SourceDirectory->text());
  402. if(!dir.isEmpty())
  403. {
  404. this->setSourceDirectory(dir);
  405. }
  406. }
  407. void CMakeSetupDialog::updateSourceDirectory(const QString& dir)
  408. {
  409. if(this->SourceDirectory->text() != dir)
  410. {
  411. this->SourceDirectory->blockSignals(true);
  412. this->SourceDirectory->setText(dir);
  413. this->SourceDirectory->blockSignals(false);
  414. }
  415. }
  416. void CMakeSetupDialog::updateBinaryDirectory(const QString& dir)
  417. {
  418. if(this->BinaryDirectory->currentText() != dir)
  419. {
  420. this->BinaryDirectory->blockSignals(true);
  421. this->BinaryDirectory->setEditText(dir);
  422. this->BinaryDirectory->blockSignals(false);
  423. }
  424. }
  425. void CMakeSetupDialog::doBinaryBrowse()
  426. {
  427. QString dir = QFileDialog::getExistingDirectory(this,
  428. tr("Enter Path to Build"), this->BinaryDirectory->currentText());
  429. if(!dir.isEmpty() && dir != this->BinaryDirectory->currentText())
  430. {
  431. this->setBinaryDirectory(dir);
  432. }
  433. }
  434. void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
  435. {
  436. this->BinaryDirectory->setEditText(dir);
  437. }
  438. void CMakeSetupDialog::onSourceDirectoryChanged(const QString& dir)
  439. {
  440. this->Output->clear();
  441. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  442. "setSourceDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
  443. }
  444. void CMakeSetupDialog::onBinaryDirectoryChanged(const QString& dir)
  445. {
  446. this->CacheModified = false;
  447. this->CacheValues->cacheModel()->clear();
  448. this->Output->clear();
  449. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  450. "setBinaryDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
  451. }
  452. void CMakeSetupDialog::setSourceDirectory(const QString& dir)
  453. {
  454. this->SourceDirectory->setText(dir);
  455. }
  456. void CMakeSetupDialog::showProgress(const QString& /*msg*/, float percent)
  457. {
  458. this->ProgressBar->setValue(qRound(percent * 100));
  459. }
  460. void CMakeSetupDialog::error(const QString& message)
  461. {
  462. this->Output->setCurrentCharFormat(this->ErrorFormat);
  463. this->Output->append(message);
  464. }
  465. void CMakeSetupDialog::message(const QString& message)
  466. {
  467. this->Output->setCurrentCharFormat(this->MessageFormat);
  468. this->Output->append(message);
  469. }
  470. void CMakeSetupDialog::setEnabledState(bool enabled)
  471. {
  472. // disable parts of the GUI during configure/generate
  473. this->CacheValues->cacheModel()->setEditEnabled(enabled);
  474. this->SourceDirectory->setEnabled(enabled);
  475. this->BrowseSourceDirectoryButton->setEnabled(enabled);
  476. this->BinaryDirectory->setEnabled(enabled);
  477. this->BrowseBinaryDirectoryButton->setEnabled(enabled);
  478. this->ReloadCacheAction->setEnabled(enabled);
  479. this->DeleteCacheAction->setEnabled(enabled);
  480. this->ExitAction->setEnabled(enabled);
  481. this->ConfigureAction->setEnabled(enabled);
  482. this->AddEntry->setEnabled(enabled);
  483. this->RemoveEntry->setEnabled(false); // let selection re-enable it
  484. }
  485. bool CMakeSetupDialog::setupFirstConfigure()
  486. {
  487. CMakeFirstConfigure dialog;
  488. // initialize dialog and restore saved settings
  489. // add generators
  490. dialog.setGenerators(this->CMakeThread->cmakeInstance()->availableGenerators());
  491. // restore from settings
  492. dialog.loadFromSettings();
  493. if(dialog.exec() == QDialog::Accepted)
  494. {
  495. dialog.saveToSettings();
  496. this->CMakeThread->cmakeInstance()->setGenerator(dialog.getGenerator());
  497. QCMakeCacheModel* m = this->CacheValues->cacheModel();
  498. if(dialog.compilerSetup())
  499. {
  500. QString fortranCompiler = dialog.getFortranCompiler();
  501. if(!fortranCompiler.isEmpty())
  502. {
  503. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
  504. "Fortran compiler.", fortranCompiler, false);
  505. }
  506. QString cxxCompiler = dialog.getCXXCompiler();
  507. if(!cxxCompiler.isEmpty())
  508. {
  509. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
  510. "CXX compiler.", cxxCompiler, false);
  511. }
  512. QString cCompiler = dialog.getCCompiler();
  513. if(!cCompiler.isEmpty())
  514. {
  515. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
  516. "C compiler.", cCompiler, false);
  517. }
  518. }
  519. else if(dialog.crossCompilerSetup())
  520. {
  521. QString toolchainFile = dialog.crossCompilerToolChainFile();
  522. if(!toolchainFile.isEmpty())
  523. {
  524. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE",
  525. "Cross Compile ToolChain File", toolchainFile, false);
  526. }
  527. else
  528. {
  529. QString fortranCompiler = dialog.getFortranCompiler();
  530. if(!fortranCompiler.isEmpty())
  531. {
  532. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
  533. "Fortran compiler.", fortranCompiler, false);
  534. }
  535. QString mode = dialog.getCrossIncludeMode();
  536. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE",
  537. "CMake Find Include Mode", mode, false);
  538. mode = dialog.getCrossLibraryMode();
  539. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY",
  540. "CMake Find Library Mode", mode, false);
  541. mode = dialog.getCrossProgramMode();
  542. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM",
  543. "CMake Find Program Mode", mode, false);
  544. QString rootPath = dialog.getCrossRoot();
  545. m->insertProperty(QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH",
  546. "CMake Find Root Path", rootPath, false);
  547. QString systemName = dialog.getSystemName();
  548. m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME",
  549. "CMake System Name", systemName, false);
  550. QString cxxCompiler = dialog.getCXXCompiler();
  551. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
  552. "CXX compiler.", cxxCompiler, false);
  553. QString cCompiler = dialog.getCCompiler();
  554. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
  555. "C compiler.", cCompiler, false);
  556. }
  557. }
  558. return true;
  559. }
  560. return false;
  561. }
  562. void CMakeSetupDialog::updateGeneratorLabel(const QString& gen)
  563. {
  564. QString str = tr("Current Generator: ");
  565. if(gen.isEmpty())
  566. {
  567. str += tr("None");
  568. }
  569. else
  570. {
  571. str += gen;
  572. }
  573. this->Generator->setText(str);
  574. }
  575. void CMakeSetupDialog::doReloadCache()
  576. {
  577. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  578. "reloadCache", Qt::QueuedConnection);
  579. }
  580. void CMakeSetupDialog::doDeleteCache()
  581. {
  582. QString title = tr("Delete Cache");
  583. QString message = "Are you sure you want to delete the cache?";
  584. QMessageBox::StandardButton btn;
  585. btn = QMessageBox::information(this, title, message,
  586. QMessageBox::Yes | QMessageBox::No);
  587. if(btn == QMessageBox::No)
  588. {
  589. return;
  590. }
  591. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  592. "deleteCache", Qt::QueuedConnection);
  593. }
  594. void CMakeSetupDialog::doAbout()
  595. {
  596. QString msg = "CMake\nwww.cmake.org";
  597. QDialog dialog;
  598. dialog.setWindowTitle(tr("About"));
  599. QVBoxLayout* l = new QVBoxLayout(&dialog);
  600. QLabel* lab = new QLabel(&dialog);
  601. l->addWidget(lab);
  602. lab->setText(msg);
  603. lab->setWordWrap(true);
  604. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
  605. Qt::Horizontal, &dialog);
  606. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  607. l->addWidget(btns);
  608. dialog.exec();
  609. }
  610. void CMakeSetupDialog::setExitAfterGenerate(bool b)
  611. {
  612. this->ExitAfterGenerate = b;
  613. }
  614. void CMakeSetupDialog::addBinaryPath(const QString& path)
  615. {
  616. QString cleanpath = QDir::cleanPath(path);
  617. // update UI
  618. this->BinaryDirectory->blockSignals(true);
  619. int idx = this->BinaryDirectory->findText(cleanpath);
  620. if(idx != -1)
  621. {
  622. this->BinaryDirectory->removeItem(idx);
  623. }
  624. this->BinaryDirectory->insertItem(0, cleanpath);
  625. this->BinaryDirectory->setCurrentIndex(0);
  626. this->BinaryDirectory->blockSignals(false);
  627. // save to registry
  628. QStringList buildPaths = this->loadBuildPaths();
  629. buildPaths.removeAll(cleanpath);
  630. buildPaths.prepend(cleanpath);
  631. this->saveBuildPaths(buildPaths);
  632. }
  633. void CMakeSetupDialog::dragEnterEvent(QDragEnterEvent* e)
  634. {
  635. if(!(this->CurrentState == ReadyConfigure ||
  636. this->CurrentState == ReadyGenerate))
  637. {
  638. e->ignore();
  639. return;
  640. }
  641. const QMimeData* dat = e->mimeData();
  642. QList<QUrl> urls = dat->urls();
  643. QString file = urls.count() ? urls[0].toLocalFile() : QString();
  644. if(!file.isEmpty() &&
  645. (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive) ||
  646. file.endsWith("CMakeLists.txt", Qt::CaseInsensitive) ) )
  647. {
  648. e->accept();
  649. }
  650. else
  651. {
  652. e->ignore();
  653. }
  654. }
  655. void CMakeSetupDialog::dropEvent(QDropEvent* e)
  656. {
  657. if(!(this->CurrentState == ReadyConfigure ||
  658. this->CurrentState == ReadyGenerate))
  659. {
  660. return;
  661. }
  662. const QMimeData* dat = e->mimeData();
  663. QList<QUrl> urls = dat->urls();
  664. QString file = urls.count() ? urls[0].toLocalFile() : QString();
  665. if(file.endsWith("CMakeCache.txt", Qt::CaseInsensitive))
  666. {
  667. QFileInfo info(file);
  668. if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
  669. {
  670. this->setBinaryDirectory(info.absolutePath());
  671. }
  672. }
  673. else if(file.endsWith("CMakeLists.txt", Qt::CaseInsensitive))
  674. {
  675. QFileInfo info(file);
  676. if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
  677. {
  678. this->setSourceDirectory(info.absolutePath());
  679. this->setBinaryDirectory(info.absolutePath());
  680. }
  681. }
  682. }
  683. QStringList CMakeSetupDialog::loadBuildPaths()
  684. {
  685. QSettings settings;
  686. settings.beginGroup("Settings/StartPath");
  687. QStringList buildPaths;
  688. for(int i=0; i<10; i++)
  689. {
  690. QString p = settings.value(QString("WhereBuild%1").arg(i)).toString();
  691. if(!p.isEmpty())
  692. {
  693. buildPaths.append(p);
  694. }
  695. }
  696. return buildPaths;
  697. }
  698. void CMakeSetupDialog::saveBuildPaths(const QStringList& paths)
  699. {
  700. QSettings settings;
  701. settings.beginGroup("Settings/StartPath");
  702. int num = paths.count();
  703. if(num > 10)
  704. {
  705. num = 10;
  706. }
  707. for(int i=0; i<num; i++)
  708. {
  709. settings.setValue(QString("WhereBuild%1").arg(i), paths[i]);
  710. }
  711. }
  712. void CMakeSetupDialog::setCacheModified()
  713. {
  714. this->CacheModified = true;
  715. this->enterState(ReadyConfigure);
  716. }
  717. void CMakeSetupDialog::removeSelectedCacheEntries()
  718. {
  719. QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
  720. QList<QPersistentModelIndex> pidxs;
  721. foreach(QModelIndex i, idxs)
  722. {
  723. pidxs.append(i);
  724. }
  725. foreach(QPersistentModelIndex pi, pidxs)
  726. {
  727. this->CacheValues->model()->removeRow(pi.row(), pi.parent());
  728. }
  729. }
  730. void CMakeSetupDialog::selectionChanged()
  731. {
  732. QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
  733. if(idxs.count() &&
  734. (this->CurrentState == ReadyConfigure ||
  735. this->CurrentState == ReadyGenerate) )
  736. {
  737. this->RemoveEntry->setEnabled(true);
  738. }
  739. else
  740. {
  741. this->RemoveEntry->setEnabled(false);
  742. }
  743. }
  744. void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
  745. {
  746. if(s == this->CurrentState)
  747. {
  748. return;
  749. }
  750. this->CurrentState = s;
  751. if(s == Interrupting)
  752. {
  753. this->ConfigureButton->setEnabled(false);
  754. this->GenerateButton->setEnabled(false);
  755. }
  756. else if(s == Configuring)
  757. {
  758. this->Output->clear();
  759. this->setEnabledState(false);
  760. this->GenerateButton->setEnabled(false);
  761. this->GenerateAction->setEnabled(false);
  762. this->ConfigureButton->setText(tr("&Stop"));
  763. }
  764. else if(s == Generating)
  765. {
  766. this->CacheModified = false;
  767. this->setEnabledState(false);
  768. this->ConfigureButton->setEnabled(false);
  769. this->GenerateAction->setEnabled(false);
  770. this->GenerateButton->setText(tr("&Stop"));
  771. }
  772. else if(s == ReadyConfigure)
  773. {
  774. this->ProgressBar->reset();
  775. this->setEnabledState(true);
  776. this->GenerateButton->setEnabled(false);
  777. this->GenerateAction->setEnabled(false);
  778. this->ConfigureButton->setEnabled(true);
  779. this->ConfigureButton->setText(tr("&Configure"));
  780. this->GenerateButton->setText(tr("&Generate"));
  781. }
  782. else if(s == ReadyGenerate)
  783. {
  784. this->ProgressBar->reset();
  785. this->setEnabledState(true);
  786. this->GenerateButton->setEnabled(true);
  787. this->GenerateAction->setEnabled(true);
  788. this->ConfigureButton->setEnabled(true);
  789. this->ConfigureButton->setText(tr("&Configure"));
  790. this->GenerateButton->setText(tr("&Generate"));
  791. }
  792. }
  793. void CMakeSetupDialog::addCacheEntry()
  794. {
  795. QDialog dialog(this);
  796. dialog.resize(400, 200);
  797. dialog.setWindowTitle(tr("Add Cache Entry"));
  798. QVBoxLayout* l = new QVBoxLayout(&dialog);
  799. AddCacheEntry* w = new AddCacheEntry(&dialog);
  800. QDialogButtonBox* btns = new QDialogButtonBox(
  801. QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
  802. Qt::Horizontal, &dialog);
  803. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  804. QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(reject()));
  805. l->addWidget(w);
  806. l->addStretch();
  807. l->addWidget(btns);
  808. if(QDialog::Accepted == dialog.exec())
  809. {
  810. QCMakeCacheModel* m = this->CacheValues->cacheModel();
  811. m->insertProperty(w->type(), w->name(), w->description(), w->value(), false);
  812. }
  813. }
  814. void CMakeSetupDialog::startSearch()
  815. {
  816. this->Search->setFocus(Qt::OtherFocusReason);
  817. this->Search->selectAll();
  818. }
  819. void CMakeSetupDialog::setDebugOutput(bool flag)
  820. {
  821. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  822. "setDebugOutput", Qt::QueuedConnection, Q_ARG(bool, flag));
  823. }
  824. void CMakeSetupDialog::toggleGroupView(bool f)
  825. {
  826. this->CacheValues->cacheModel()->setViewType(f ? QCMakeCacheModel::GroupView : QCMakeCacheModel::FlatView);
  827. this->CacheValues->setRootIsDecorated(f);
  828. QSettings settings;
  829. settings.beginGroup("Settings/StartPath");
  830. settings.setValue("GroupView", this->CacheValues->cacheModel()->viewType() == QCMakeCacheModel::GroupView);
  831. }