CMakeSetupDialog.cxx 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039
  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), 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. QMenu* FileMenu = this->menuBar()->addMenu(tr("&File"));
  75. this->ReloadCacheAction = FileMenu->addAction(tr("&Reload Cache"));
  76. QObject::connect(this->ReloadCacheAction, SIGNAL(triggered(bool)),
  77. this, SLOT(doReloadCache()));
  78. this->DeleteCacheAction = FileMenu->addAction(tr("&Delete Cache"));
  79. QObject::connect(this->DeleteCacheAction, SIGNAL(triggered(bool)),
  80. this, SLOT(doDeleteCache()));
  81. this->ExitAction = FileMenu->addAction(tr("E&xit"));
  82. QObject::connect(this->ExitAction, SIGNAL(triggered(bool)),
  83. this, SLOT(close()));
  84. QMenu* ToolsMenu = this->menuBar()->addMenu(tr("&Tools"));
  85. this->ConfigureAction = ToolsMenu->addAction(tr("&Configure"));
  86. // prevent merging with Preferences menu item on Mac OS X
  87. this->ConfigureAction->setMenuRole(QAction::NoRole);
  88. QObject::connect(this->ConfigureAction, SIGNAL(triggered(bool)),
  89. this, SLOT(doConfigure()));
  90. this->GenerateAction = ToolsMenu->addAction(tr("&Generate"));
  91. QObject::connect(this->GenerateAction, SIGNAL(triggered(bool)),
  92. this, SLOT(doGenerate()));
  93. QAction* showChangesAction = ToolsMenu->addAction(tr("&Show My Changes"));
  94. QObject::connect(showChangesAction, SIGNAL(triggered(bool)),
  95. this, SLOT(showUserChanges()));
  96. #if defined(Q_WS_MAC)
  97. this->InstallForCommandLineAction
  98. = ToolsMenu->addAction(tr("&Install For Command Line Use"));
  99. QObject::connect(this->InstallForCommandLineAction, SIGNAL(triggered(bool)),
  100. this, SLOT(doInstallForCommandLine()));
  101. #endif
  102. QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options"));
  103. this->SuppressDevWarningsAction = OptionsMenu->addAction(tr("&Suppress dev Warnings (-Wno-dev)"));
  104. this->SuppressDevWarningsAction->setCheckable(true);
  105. QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output"));
  106. debugAction->setCheckable(true);
  107. QObject::connect(debugAction, SIGNAL(toggled(bool)),
  108. this, SLOT(setDebugOutput(bool)));
  109. OptionsMenu->addSeparator();
  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->groupedCheck, SIGNAL(toggled(bool)),
  184. this, SLOT(setGroupedView(bool)));
  185. QObject::connect(this->advancedCheck, SIGNAL(toggled(bool)),
  186. this, SLOT(setAdvancedView(bool)));
  187. QObject::connect(this->Search, SIGNAL(textChanged(QString)),
  188. this, SLOT(setSearchFilter(QString)));
  189. QObject::connect(this->CMakeThread->cmakeInstance(),
  190. SIGNAL(generatorChanged(QString)),
  191. this, SLOT(updateGeneratorLabel(QString)));
  192. this->updateGeneratorLabel(QString());
  193. QObject::connect(this->CacheValues->cacheModel(),
  194. SIGNAL(dataChanged(QModelIndex,QModelIndex)),
  195. this, SLOT(setCacheModified()));
  196. QObject::connect(this->CacheValues->selectionModel(),
  197. SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
  198. this, SLOT(selectionChanged()));
  199. QObject::connect(this->RemoveEntry, SIGNAL(clicked(bool)),
  200. this, SLOT(removeSelectedCacheEntries()));
  201. QObject::connect(this->AddEntry, SIGNAL(clicked(bool)),
  202. this, SLOT(addCacheEntry()));
  203. QObject::connect(this->SuppressDevWarningsAction, SIGNAL(triggered(bool)),
  204. this->CMakeThread->cmakeInstance(), SLOT(setSuppressDevWarnings(bool)));
  205. if(!this->SourceDirectory->text().isEmpty() ||
  206. !this->BinaryDirectory->lineEdit()->text().isEmpty())
  207. {
  208. this->onSourceDirectoryChanged(this->SourceDirectory->text());
  209. this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
  210. }
  211. else
  212. {
  213. this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
  214. }
  215. }
  216. CMakeSetupDialog::~CMakeSetupDialog()
  217. {
  218. QSettings settings;
  219. settings.beginGroup("Settings/StartPath");
  220. settings.setValue("Height", this->height());
  221. settings.setValue("Width", this->width());
  222. settings.setValue("SplitterSizes", this->Splitter->saveState());
  223. // wait for thread to stop
  224. this->CMakeThread->quit();
  225. this->CMakeThread->wait(2000);
  226. }
  227. void CMakeSetupDialog::doConfigure()
  228. {
  229. if(this->CurrentState == Configuring)
  230. {
  231. // stop configure
  232. doInterrupt();
  233. return;
  234. }
  235. // make sure build directory exists
  236. QString bindir = this->CMakeThread->cmakeInstance()->binaryDirectory();
  237. QDir dir(bindir);
  238. if(!dir.exists())
  239. {
  240. QString msg = tr("Build directory does not exist, "
  241. "should I create it?")
  242. + "\n\n"
  243. + tr("Directory: ");
  244. msg += bindir;
  245. QString title = tr("Create Directory");
  246. QMessageBox::StandardButton btn;
  247. btn = QMessageBox::information(this, title, msg,
  248. QMessageBox::Yes | QMessageBox::No);
  249. if(btn == QMessageBox::No)
  250. {
  251. return;
  252. }
  253. if(!dir.mkpath("."))
  254. {
  255. QMessageBox::information(this, tr("Create Directory Failed"),
  256. QString(tr("Failed to create directory %1")).arg(dir.path()),
  257. QMessageBox::Ok);
  258. return;
  259. }
  260. }
  261. // if no generator, prompt for it and other setup stuff
  262. if(this->CMakeThread->cmakeInstance()->generator().isEmpty())
  263. {
  264. if(!this->setupFirstConfigure())
  265. {
  266. return;
  267. }
  268. }
  269. // remember path
  270. this->addBinaryPath(dir.absolutePath());
  271. this->enterState(Configuring);
  272. this->CacheValues->selectionModel()->clear();
  273. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  274. "setProperties", Qt::QueuedConnection,
  275. Q_ARG(QCMakePropertyList,
  276. this->CacheValues->cacheModel()->properties()));
  277. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  278. "configure", Qt::QueuedConnection);
  279. }
  280. void CMakeSetupDialog::finishConfigure(int err)
  281. {
  282. if(0 == err && !this->CacheValues->cacheModel()->newPropertyCount())
  283. {
  284. this->enterState(ReadyGenerate);
  285. }
  286. else
  287. {
  288. this->enterState(ReadyConfigure);
  289. this->CacheValues->scrollToTop();
  290. }
  291. if(err != 0)
  292. {
  293. QMessageBox::critical(this, tr("Error"),
  294. tr("Error in configuration process, project files may be invalid"),
  295. QMessageBox::Ok);
  296. }
  297. }
  298. void CMakeSetupDialog::finishGenerate(int err)
  299. {
  300. this->enterState(ReadyConfigure);
  301. if(err != 0)
  302. {
  303. QMessageBox::critical(this, tr("Error"),
  304. tr("Error in generation process, project files may be invalid"),
  305. QMessageBox::Ok);
  306. }
  307. }
  308. void CMakeSetupDialog::doInstallForCommandLine()
  309. {
  310. QMacInstallDialog setupdialog(0);
  311. setupdialog.exec();
  312. }
  313. void CMakeSetupDialog::doGenerate()
  314. {
  315. if(this->CurrentState == Generating)
  316. {
  317. // stop generate
  318. doInterrupt();
  319. return;
  320. }
  321. this->enterState(Generating);
  322. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  323. "generate", Qt::QueuedConnection);
  324. }
  325. void CMakeSetupDialog::closeEvent(QCloseEvent* e)
  326. {
  327. // prompt for close if there are unsaved changes, and we're not busy
  328. if(this->CacheModified)
  329. {
  330. QString msg = tr("You have changed options but not rebuilt, "
  331. "are you sure you want to exit?");
  332. QString title = tr("Confirm Exit");
  333. QMessageBox::StandardButton btn;
  334. btn = QMessageBox::critical(this, title, msg,
  335. QMessageBox::Yes | QMessageBox::No);
  336. if(btn == QMessageBox::No)
  337. {
  338. e->ignore();
  339. }
  340. }
  341. // don't close if we're busy, unless the user really wants to
  342. if(this->CurrentState == Configuring)
  343. {
  344. QString msg = "You are in the middle of a Configure.\n"
  345. "If you Exit now the configure information will be lost.\n"
  346. "Are you sure you want to Exit?";
  347. QString title = tr("Confirm Exit");
  348. QMessageBox::StandardButton btn;
  349. btn = QMessageBox::critical(this, title, msg,
  350. QMessageBox::Yes | QMessageBox::No);
  351. if(btn == QMessageBox::No)
  352. {
  353. e->ignore();
  354. }
  355. else
  356. {
  357. this->doInterrupt();
  358. }
  359. }
  360. // let the generate finish
  361. if(this->CurrentState == Generating)
  362. {
  363. e->ignore();
  364. }
  365. }
  366. void CMakeSetupDialog::doHelp()
  367. {
  368. QString msg = tr("CMake is used to configure and generate build files for "
  369. "software projects. The basic steps for configuring a project are as "
  370. "follows:\r\n\r\n1. Select the source directory for the project. This should "
  371. "contain the CMakeLists.txt files for the project.\r\n\r\n2. Select the build "
  372. "directory for the project. This is the directory where the project will be "
  373. "built. It can be the same or a different directory than the source "
  374. "directory. For easy clean up, a separate build directory is recommended. "
  375. "CMake will create the directory if it does not exist.\r\n\r\n3. Once the "
  376. "source and binary directories are selected, it is time to press the "
  377. "Configure button. This will cause CMake to read all of the input files and "
  378. "discover all the variables used by the project. The first time a variable "
  379. "is displayed it will be in Red. Users should inspect red variables making "
  380. "sure the values are correct. For some projects the Configure process can "
  381. "be iterative, so continue to press the Configure button until there are no "
  382. "longer red entries.\r\n\r\n4. Once there are no longer red entries, you "
  383. "should click the Generate button. This will write the build files to the build "
  384. "directory.");
  385. QDialog dialog;
  386. QFontMetrics met(this->font());
  387. int msgWidth = met.width(msg);
  388. dialog.setMinimumSize(msgWidth/15,20);
  389. dialog.setWindowTitle(tr("Help"));
  390. QVBoxLayout* l = new QVBoxLayout(&dialog);
  391. QLabel* lab = new QLabel(&dialog);
  392. lab->setText(msg);
  393. lab->setWordWrap(true);
  394. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
  395. Qt::Horizontal, &dialog);
  396. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  397. l->addWidget(lab);
  398. l->addWidget(btns);
  399. dialog.exec();
  400. }
  401. void CMakeSetupDialog::doInterrupt()
  402. {
  403. this->enterState(Interrupting);
  404. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  405. "interrupt", Qt::QueuedConnection);
  406. }
  407. void CMakeSetupDialog::doSourceBrowse()
  408. {
  409. QString dir = QFileDialog::getExistingDirectory(this,
  410. tr("Enter Path to Source"), this->SourceDirectory->text());
  411. if(!dir.isEmpty())
  412. {
  413. this->setSourceDirectory(dir);
  414. }
  415. }
  416. void CMakeSetupDialog::updateSourceDirectory(const QString& dir)
  417. {
  418. if(this->SourceDirectory->text() != dir)
  419. {
  420. this->SourceDirectory->blockSignals(true);
  421. this->SourceDirectory->setText(dir);
  422. this->SourceDirectory->blockSignals(false);
  423. }
  424. }
  425. void CMakeSetupDialog::updateBinaryDirectory(const QString& dir)
  426. {
  427. if(this->BinaryDirectory->currentText() != dir)
  428. {
  429. this->BinaryDirectory->blockSignals(true);
  430. this->BinaryDirectory->setEditText(dir);
  431. this->BinaryDirectory->blockSignals(false);
  432. }
  433. }
  434. void CMakeSetupDialog::doBinaryBrowse()
  435. {
  436. QString dir = QFileDialog::getExistingDirectory(this,
  437. tr("Enter Path to Build"), this->BinaryDirectory->currentText());
  438. if(!dir.isEmpty() && dir != this->BinaryDirectory->currentText())
  439. {
  440. this->setBinaryDirectory(dir);
  441. }
  442. }
  443. void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
  444. {
  445. this->BinaryDirectory->setEditText(dir);
  446. }
  447. void CMakeSetupDialog::onSourceDirectoryChanged(const QString& dir)
  448. {
  449. this->Output->clear();
  450. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  451. "setSourceDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
  452. }
  453. void CMakeSetupDialog::onBinaryDirectoryChanged(const QString& dir)
  454. {
  455. QString title = QString(tr("CMake %1 - %2"));
  456. title = title.arg(cmVersion::GetCMakeVersion());
  457. title = title.arg(dir);
  458. this->setWindowTitle(title);
  459. this->CacheModified = false;
  460. this->CacheValues->cacheModel()->clear();
  461. qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())->clearChanges();
  462. this->Output->clear();
  463. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  464. "setBinaryDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
  465. }
  466. void CMakeSetupDialog::setSourceDirectory(const QString& dir)
  467. {
  468. this->SourceDirectory->setText(dir);
  469. }
  470. void CMakeSetupDialog::showProgress(const QString& /*msg*/, float percent)
  471. {
  472. this->ProgressBar->setValue(qRound(percent * 100));
  473. }
  474. void CMakeSetupDialog::error(const QString& msg)
  475. {
  476. this->Output->setCurrentCharFormat(this->ErrorFormat);
  477. this->Output->append(msg);
  478. }
  479. void CMakeSetupDialog::message(const QString& msg)
  480. {
  481. this->Output->setCurrentCharFormat(this->MessageFormat);
  482. this->Output->append(msg);
  483. }
  484. void CMakeSetupDialog::setEnabledState(bool enabled)
  485. {
  486. // disable parts of the GUI during configure/generate
  487. this->CacheValues->cacheModel()->setEditEnabled(enabled);
  488. this->SourceDirectory->setEnabled(enabled);
  489. this->BrowseSourceDirectoryButton->setEnabled(enabled);
  490. this->BinaryDirectory->setEnabled(enabled);
  491. this->BrowseBinaryDirectoryButton->setEnabled(enabled);
  492. this->ReloadCacheAction->setEnabled(enabled);
  493. this->DeleteCacheAction->setEnabled(enabled);
  494. this->ExitAction->setEnabled(enabled);
  495. this->ConfigureAction->setEnabled(enabled);
  496. this->AddEntry->setEnabled(enabled);
  497. this->RemoveEntry->setEnabled(false); // let selection re-enable it
  498. }
  499. bool CMakeSetupDialog::setupFirstConfigure()
  500. {
  501. FirstConfigure dialog;
  502. // initialize dialog and restore saved settings
  503. // add generators
  504. dialog.setGenerators(this->CMakeThread->cmakeInstance()->availableGenerators());
  505. // restore from settings
  506. dialog.loadFromSettings();
  507. if(dialog.exec() == QDialog::Accepted)
  508. {
  509. dialog.saveToSettings();
  510. this->CMakeThread->cmakeInstance()->setGenerator(dialog.getGenerator());
  511. QCMakeCacheModel* m = this->CacheValues->cacheModel();
  512. if(dialog.compilerSetup())
  513. {
  514. QString fortranCompiler = dialog.getFortranCompiler();
  515. if(!fortranCompiler.isEmpty())
  516. {
  517. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
  518. "Fortran compiler.", fortranCompiler, false);
  519. }
  520. QString cxxCompiler = dialog.getCXXCompiler();
  521. if(!cxxCompiler.isEmpty())
  522. {
  523. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
  524. "CXX compiler.", cxxCompiler, false);
  525. }
  526. QString cCompiler = dialog.getCCompiler();
  527. if(!cCompiler.isEmpty())
  528. {
  529. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
  530. "C compiler.", cCompiler, false);
  531. }
  532. }
  533. else if(dialog.crossCompilerSetup())
  534. {
  535. QString fortranCompiler = dialog.getFortranCompiler();
  536. if(!fortranCompiler.isEmpty())
  537. {
  538. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
  539. "Fortran compiler.", fortranCompiler, false);
  540. }
  541. QString mode = dialog.getCrossIncludeMode();
  542. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE",
  543. "CMake Find Include Mode", mode, false);
  544. mode = dialog.getCrossLibraryMode();
  545. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY",
  546. "CMake Find Library Mode", mode, false);
  547. mode = dialog.getCrossProgramMode();
  548. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM",
  549. "CMake Find Program Mode", mode, false);
  550. QString rootPath = dialog.getCrossRoot();
  551. m->insertProperty(QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH",
  552. "CMake Find Root Path", rootPath, false);
  553. QString systemName = dialog.getSystemName();
  554. m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME",
  555. "CMake System Name", systemName, false);
  556. QString cxxCompiler = dialog.getCXXCompiler();
  557. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
  558. "CXX compiler.", cxxCompiler, false);
  559. QString cCompiler = dialog.getCCompiler();
  560. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
  561. "C compiler.", cCompiler, false);
  562. }
  563. else if(dialog.crossCompilerToolChainFile())
  564. {
  565. QString toolchainFile = dialog.getCrossCompilerToolChainFile();
  566. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE",
  567. "Cross Compile ToolChain File", toolchainFile, false);
  568. }
  569. return true;
  570. }
  571. return false;
  572. }
  573. void CMakeSetupDialog::updateGeneratorLabel(const QString& gen)
  574. {
  575. QString str = tr("Current Generator: ");
  576. if(gen.isEmpty())
  577. {
  578. str += tr("None");
  579. }
  580. else
  581. {
  582. str += gen;
  583. }
  584. this->Generator->setText(str);
  585. }
  586. void CMakeSetupDialog::doReloadCache()
  587. {
  588. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  589. "reloadCache", Qt::QueuedConnection);
  590. }
  591. void CMakeSetupDialog::doDeleteCache()
  592. {
  593. QString title = tr("Delete Cache");
  594. QString msg = "Are you sure you want to delete the cache?";
  595. QMessageBox::StandardButton btn;
  596. btn = QMessageBox::information(this, title, msg,
  597. QMessageBox::Yes | QMessageBox::No);
  598. if(btn == QMessageBox::No)
  599. {
  600. return;
  601. }
  602. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  603. "deleteCache", Qt::QueuedConnection);
  604. }
  605. void CMakeSetupDialog::doAbout()
  606. {
  607. QString msg = "CMake %1\n"
  608. "Using Qt %2\n"
  609. "www.cmake.org";
  610. msg = msg.arg(cmVersion::GetCMakeVersion());
  611. msg = msg.arg(qVersion());
  612. QDialog dialog;
  613. dialog.setWindowTitle(tr("About"));
  614. QVBoxLayout* l = new QVBoxLayout(&dialog);
  615. QLabel* lab = new QLabel(&dialog);
  616. l->addWidget(lab);
  617. lab->setText(msg);
  618. lab->setWordWrap(true);
  619. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
  620. Qt::Horizontal, &dialog);
  621. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  622. l->addWidget(btns);
  623. dialog.exec();
  624. }
  625. void CMakeSetupDialog::setExitAfterGenerate(bool b)
  626. {
  627. this->ExitAfterGenerate = b;
  628. }
  629. void CMakeSetupDialog::addBinaryPath(const QString& path)
  630. {
  631. QString cleanpath = QDir::cleanPath(path);
  632. // update UI
  633. this->BinaryDirectory->blockSignals(true);
  634. int idx = this->BinaryDirectory->findText(cleanpath);
  635. if(idx != -1)
  636. {
  637. this->BinaryDirectory->removeItem(idx);
  638. }
  639. this->BinaryDirectory->insertItem(0, cleanpath);
  640. this->BinaryDirectory->setCurrentIndex(0);
  641. this->BinaryDirectory->blockSignals(false);
  642. // save to registry
  643. QStringList buildPaths = this->loadBuildPaths();
  644. buildPaths.removeAll(cleanpath);
  645. buildPaths.prepend(cleanpath);
  646. this->saveBuildPaths(buildPaths);
  647. }
  648. void CMakeSetupDialog::dragEnterEvent(QDragEnterEvent* e)
  649. {
  650. if(!(this->CurrentState == ReadyConfigure ||
  651. this->CurrentState == ReadyGenerate))
  652. {
  653. e->ignore();
  654. return;
  655. }
  656. const QMimeData* dat = e->mimeData();
  657. QList<QUrl> urls = dat->urls();
  658. QString file = urls.count() ? urls[0].toLocalFile() : QString();
  659. if(!file.isEmpty() &&
  660. (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive) ||
  661. file.endsWith("CMakeLists.txt", Qt::CaseInsensitive) ) )
  662. {
  663. e->accept();
  664. }
  665. else
  666. {
  667. e->ignore();
  668. }
  669. }
  670. void CMakeSetupDialog::dropEvent(QDropEvent* e)
  671. {
  672. if(!(this->CurrentState == ReadyConfigure ||
  673. this->CurrentState == ReadyGenerate))
  674. {
  675. return;
  676. }
  677. const QMimeData* dat = e->mimeData();
  678. QList<QUrl> urls = dat->urls();
  679. QString file = urls.count() ? urls[0].toLocalFile() : QString();
  680. if(file.endsWith("CMakeCache.txt", Qt::CaseInsensitive))
  681. {
  682. QFileInfo info(file);
  683. if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
  684. {
  685. this->setBinaryDirectory(info.absolutePath());
  686. }
  687. }
  688. else if(file.endsWith("CMakeLists.txt", Qt::CaseInsensitive))
  689. {
  690. QFileInfo info(file);
  691. if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
  692. {
  693. this->setSourceDirectory(info.absolutePath());
  694. this->setBinaryDirectory(info.absolutePath());
  695. }
  696. }
  697. }
  698. QStringList CMakeSetupDialog::loadBuildPaths()
  699. {
  700. QSettings settings;
  701. settings.beginGroup("Settings/StartPath");
  702. QStringList buildPaths;
  703. for(int i=0; i<10; i++)
  704. {
  705. QString p = settings.value(QString("WhereBuild%1").arg(i)).toString();
  706. if(!p.isEmpty())
  707. {
  708. buildPaths.append(p);
  709. }
  710. }
  711. return buildPaths;
  712. }
  713. void CMakeSetupDialog::saveBuildPaths(const QStringList& paths)
  714. {
  715. QSettings settings;
  716. settings.beginGroup("Settings/StartPath");
  717. int num = paths.count();
  718. if(num > 10)
  719. {
  720. num = 10;
  721. }
  722. for(int i=0; i<num; i++)
  723. {
  724. settings.setValue(QString("WhereBuild%1").arg(i), paths[i]);
  725. }
  726. }
  727. void CMakeSetupDialog::setCacheModified()
  728. {
  729. this->CacheModified = true;
  730. this->enterState(ReadyConfigure);
  731. }
  732. void CMakeSetupDialog::removeSelectedCacheEntries()
  733. {
  734. QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
  735. QList<QPersistentModelIndex> pidxs;
  736. foreach(QModelIndex i, idxs)
  737. {
  738. pidxs.append(i);
  739. }
  740. foreach(QPersistentModelIndex pi, pidxs)
  741. {
  742. this->CacheValues->model()->removeRow(pi.row(), pi.parent());
  743. }
  744. }
  745. void CMakeSetupDialog::selectionChanged()
  746. {
  747. QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
  748. if(idxs.count() &&
  749. (this->CurrentState == ReadyConfigure ||
  750. this->CurrentState == ReadyGenerate) )
  751. {
  752. this->RemoveEntry->setEnabled(true);
  753. }
  754. else
  755. {
  756. this->RemoveEntry->setEnabled(false);
  757. }
  758. }
  759. void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
  760. {
  761. if(s == this->CurrentState)
  762. {
  763. return;
  764. }
  765. this->CurrentState = s;
  766. if(s == Interrupting)
  767. {
  768. this->ConfigureButton->setEnabled(false);
  769. this->GenerateButton->setEnabled(false);
  770. }
  771. else if(s == Configuring)
  772. {
  773. this->Output->clear();
  774. this->setEnabledState(false);
  775. this->GenerateButton->setEnabled(false);
  776. this->GenerateAction->setEnabled(false);
  777. this->ConfigureButton->setText(tr("&Stop"));
  778. }
  779. else if(s == Generating)
  780. {
  781. this->CacheModified = false;
  782. this->setEnabledState(false);
  783. this->ConfigureButton->setEnabled(false);
  784. this->GenerateAction->setEnabled(false);
  785. this->GenerateButton->setText(tr("&Stop"));
  786. }
  787. else if(s == ReadyConfigure)
  788. {
  789. this->ProgressBar->reset();
  790. this->setEnabledState(true);
  791. this->GenerateButton->setEnabled(false);
  792. this->GenerateAction->setEnabled(false);
  793. this->ConfigureButton->setEnabled(true);
  794. this->ConfigureButton->setText(tr("&Configure"));
  795. this->GenerateButton->setText(tr("&Generate"));
  796. }
  797. else if(s == ReadyGenerate)
  798. {
  799. this->ProgressBar->reset();
  800. this->setEnabledState(true);
  801. this->GenerateButton->setEnabled(true);
  802. this->GenerateAction->setEnabled(true);
  803. this->ConfigureButton->setEnabled(true);
  804. this->ConfigureButton->setText(tr("&Configure"));
  805. this->GenerateButton->setText(tr("&Generate"));
  806. }
  807. }
  808. void CMakeSetupDialog::addCacheEntry()
  809. {
  810. QDialog dialog(this);
  811. dialog.resize(400, 200);
  812. dialog.setWindowTitle(tr("Add Cache Entry"));
  813. QVBoxLayout* l = new QVBoxLayout(&dialog);
  814. AddCacheEntry* w = new AddCacheEntry(&dialog);
  815. QDialogButtonBox* btns = new QDialogButtonBox(
  816. QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
  817. Qt::Horizontal, &dialog);
  818. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  819. QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(reject()));
  820. l->addWidget(w);
  821. l->addStretch();
  822. l->addWidget(btns);
  823. if(QDialog::Accepted == dialog.exec())
  824. {
  825. QCMakeCacheModel* m = this->CacheValues->cacheModel();
  826. m->insertProperty(w->type(), w->name(), w->description(), w->value(), false);
  827. }
  828. }
  829. void CMakeSetupDialog::startSearch()
  830. {
  831. this->Search->setFocus(Qt::OtherFocusReason);
  832. this->Search->selectAll();
  833. }
  834. void CMakeSetupDialog::setDebugOutput(bool flag)
  835. {
  836. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  837. "setDebugOutput", Qt::QueuedConnection, Q_ARG(bool, flag));
  838. }
  839. void CMakeSetupDialog::setGroupedView(bool v)
  840. {
  841. this->CacheValues->cacheModel()->setViewType(v ? QCMakeCacheModel::GroupView : QCMakeCacheModel::FlatView);
  842. this->CacheValues->setRootIsDecorated(v);
  843. QSettings settings;
  844. settings.beginGroup("Settings/StartPath");
  845. settings.setValue("GroupView", v);
  846. }
  847. void CMakeSetupDialog::setAdvancedView(bool v)
  848. {
  849. this->CacheValues->setShowAdvanced(v);
  850. }
  851. void CMakeSetupDialog::showUserChanges()
  852. {
  853. QSet<QCMakeProperty> changes =
  854. qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())->changes();
  855. QDialog dialog(this);
  856. dialog.setWindowTitle(tr("My Changes"));
  857. dialog.resize(600, 400);
  858. QVBoxLayout* l = new QVBoxLayout(&dialog);
  859. QTextEdit* textedit = new QTextEdit(&dialog);
  860. textedit->setReadOnly(true);
  861. l->addWidget(textedit);
  862. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Close,
  863. Qt::Horizontal, &dialog);
  864. QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(accept()));
  865. l->addWidget(btns);
  866. QString command;
  867. QString cache;
  868. foreach(QCMakeProperty prop, changes)
  869. {
  870. QString type;
  871. switch(prop.Type)
  872. {
  873. case QCMakeProperty::BOOL:
  874. type = "BOOL";
  875. break;
  876. case QCMakeProperty::PATH:
  877. type = "PATH";
  878. break;
  879. case QCMakeProperty::FILEPATH:
  880. type = "FILEPATH";
  881. break;
  882. case QCMakeProperty::STRING:
  883. type = "STRING";
  884. break;
  885. }
  886. QString value;
  887. if(prop.Type == QCMakeProperty::BOOL)
  888. {
  889. value = prop.Value.toBool() ? "1" : "0";
  890. }
  891. else
  892. {
  893. value = prop.Value.toString();
  894. }
  895. QString line("%1:%2=");
  896. line = line.arg(prop.Key);
  897. line = line.arg(type);
  898. command += QString("-D%1\"%2\" ").arg(line).arg(value);
  899. cache += QString("%1%2\n").arg(line).arg(value);
  900. }
  901. textedit->append(tr("Commandline options:"));
  902. textedit->append(command);
  903. textedit->append("\n");
  904. textedit->append(tr("Cache file:"));
  905. textedit->append(cache);
  906. dialog.exec();
  907. }
  908. void CMakeSetupDialog::setSearchFilter(const QString& str)
  909. {
  910. this->CacheValues->selectionModel()->clear();
  911. this->CacheValues->setSearchFilter(str);
  912. }