CMakeSetupDialog.cxx 27 KB

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