1
0

CMakeSetupDialog.cxx 34 KB

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