CMakeSetupDialog.cxx 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "CMakeSetupDialog.h"
  14. #include <QFileDialog>
  15. #include <QProgressBar>
  16. #include <QMessageBox>
  17. #include <QStatusBar>
  18. #include <QToolButton>
  19. #include <QDialogButtonBox>
  20. #include <QCloseEvent>
  21. #include <QCoreApplication>
  22. #include <QSettings>
  23. #include <QMenu>
  24. #include <QMenuBar>
  25. #include <QDragEnterEvent>
  26. #include <QMimeData>
  27. #include <QUrl>
  28. #include <QShortcut>
  29. #include <QMacInstallDialog.h>
  30. #include "QCMake.h"
  31. #include "QCMakeCacheView.h"
  32. #include "AddCacheEntry.h"
  33. #include "CMakeFirstConfigure.h"
  34. QCMakeThread::QCMakeThread(QObject* p)
  35. : QThread(p), CMakeInstance(NULL)
  36. {
  37. }
  38. QCMake* QCMakeThread::cmakeInstance() const
  39. {
  40. return this->CMakeInstance;
  41. }
  42. void QCMakeThread::run()
  43. {
  44. this->CMakeInstance = new QCMake;
  45. // emit that this cmake thread is ready for use
  46. emit this->cmakeInitialized();
  47. this->exec();
  48. delete this->CMakeInstance;
  49. this->CMakeInstance = NULL;
  50. }
  51. CMakeSetupDialog::CMakeSetupDialog()
  52. : ExitAfterGenerate(true), CacheModified(false), CurrentState(Interrupting)
  53. {
  54. // create the GUI
  55. QSettings settings;
  56. settings.beginGroup("Settings/StartPath");
  57. int h = settings.value("Height", 500).toInt();
  58. int w = settings.value("Width", 700).toInt();
  59. this->resize(w, h);
  60. QWidget* cont = new QWidget(this);
  61. this->setupUi(cont);
  62. this->Splitter->setStretchFactor(0, 3);
  63. this->Splitter->setStretchFactor(1, 1);
  64. this->setCentralWidget(cont);
  65. this->ProgressBar->reset();
  66. this->RemoveEntry->setEnabled(false);
  67. this->AddEntry->setEnabled(false);
  68. 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. this->SuppressDevWarningsAction = OptionsMenu->addAction(tr("&Suppress dev Warnings (-Wno-dev)"));
  95. this->SuppressDevWarningsAction->setCheckable(true);
  96. QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output"));
  97. debugAction->setCheckable(true);
  98. QObject::connect(debugAction, SIGNAL(toggled(bool)),
  99. this, SLOT(setDebugOutput(bool)));
  100. QAction* expandAction = OptionsMenu->addAction(tr("&Expand Variables Tree"));
  101. QObject::connect(expandAction, SIGNAL(triggered(bool)),
  102. this->CacheValues, SLOT(expandAll()));
  103. QAction* collapseAction = OptionsMenu->addAction(tr("&Collapse Variables Tree"));
  104. QObject::connect(collapseAction, SIGNAL(triggered(bool)),
  105. this->CacheValues, SLOT(collapseAll()));
  106. QMenu* HelpMenu = this->menuBar()->addMenu(tr("&Help"));
  107. QAction* a = HelpMenu->addAction(tr("About"));
  108. QObject::connect(a, SIGNAL(triggered(bool)),
  109. this, SLOT(doAbout()));
  110. a = HelpMenu->addAction(tr("Help"));
  111. QObject::connect(a, SIGNAL(triggered(bool)),
  112. this, SLOT(doHelp()));
  113. QShortcut* filterShortcut = new QShortcut(QKeySequence::Find, this);
  114. QObject::connect(filterShortcut, SIGNAL(activated()),
  115. this, SLOT(startSearch()));
  116. this->setAcceptDrops(true);
  117. // get the saved binary directories
  118. QStringList buildPaths = this->loadBuildPaths();
  119. this->BinaryDirectory->addItems(buildPaths);
  120. this->BinaryDirectory->setCompleter(new QCMakeFileCompleter(this, true));
  121. this->SourceDirectory->setCompleter(new QCMakeFileCompleter(this, true));
  122. // fixed pitch font in output window
  123. QFont outputFont("Courier");
  124. this->Output->setFont(outputFont);
  125. this->ErrorFormat.setForeground(QBrush(Qt::red));
  126. // start the cmake worker thread
  127. this->CMakeThread = new QCMakeThread(this);
  128. QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()),
  129. this, SLOT(initialize()), Qt::QueuedConnection);
  130. this->CMakeThread->start();
  131. this->enterState(ReadyConfigure);
  132. }
  133. void CMakeSetupDialog::initialize()
  134. {
  135. // now the cmake worker thread is running, lets make our connections to it
  136. QObject::connect(this->CMakeThread->cmakeInstance(),
  137. SIGNAL(propertiesChanged(const QCMakePropertyList&)),
  138. this->CacheValues->cacheModel(),
  139. SLOT(setProperties(const QCMakePropertyList&)));
  140. QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)),
  141. this, SLOT(doConfigure()));
  142. QObject::connect(this->CMakeThread->cmakeInstance(),
  143. SIGNAL(configureDone(int)),
  144. this, SLOT(finishConfigure(int)));
  145. QObject::connect(this->CMakeThread->cmakeInstance(),
  146. SIGNAL(generateDone(int)),
  147. this, SLOT(finishGenerate(int)));
  148. QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)),
  149. this, SLOT(doGenerate()));
  150. QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)),
  151. this, SLOT(doSourceBrowse()));
  152. QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)),
  153. this, SLOT(doBinaryBrowse()));
  154. QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)),
  155. this, SLOT(onBinaryDirectoryChanged(QString)));
  156. QObject::connect(this->SourceDirectory, SIGNAL(textChanged(QString)),
  157. this, SLOT(onSourceDirectoryChanged(QString)));
  158. QObject::connect(this->CMakeThread->cmakeInstance(),
  159. SIGNAL(sourceDirChanged(QString)),
  160. this, SLOT(updateSourceDirectory(QString)));
  161. QObject::connect(this->CMakeThread->cmakeInstance(),
  162. SIGNAL(binaryDirChanged(QString)),
  163. this, SLOT(updateBinaryDirectory(QString)));
  164. QObject::connect(this->CMakeThread->cmakeInstance(),
  165. SIGNAL(progressChanged(QString, float)),
  166. this, SLOT(showProgress(QString,float)));
  167. QObject::connect(this->CMakeThread->cmakeInstance(),
  168. SIGNAL(errorMessage(QString)),
  169. this, SLOT(error(QString)));
  170. QObject::connect(this->CMakeThread->cmakeInstance(),
  171. SIGNAL(outputMessage(QString)),
  172. this, SLOT(message(QString)));
  173. QObject::connect(this->Advanced, SIGNAL(clicked(bool)),
  174. this->CacheValues, SLOT(setShowAdvanced(bool)));
  175. QObject::connect(this->Search, SIGNAL(textChanged(QString)),
  176. this->CacheValues, SLOT(setSearchFilter(QString)));
  177. QObject::connect(this->CMakeThread->cmakeInstance(),
  178. SIGNAL(generatorChanged(QString)),
  179. this, SLOT(updateGeneratorLabel(QString)));
  180. this->updateGeneratorLabel(QString());
  181. QObject::connect(this->CacheValues->cacheModel(),
  182. SIGNAL(dataChanged(QModelIndex,QModelIndex)),
  183. this, SLOT(setCacheModified()));
  184. QObject::connect(this->CacheValues->selectionModel(),
  185. SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
  186. this, SLOT(selectionChanged()));
  187. QObject::connect(this->RemoveEntry, SIGNAL(clicked(bool)),
  188. this, SLOT(removeSelectedCacheEntries()));
  189. QObject::connect(this->AddEntry, SIGNAL(clicked(bool)),
  190. this, SLOT(addCacheEntry()));
  191. QObject::connect(this->SuppressDevWarningsAction, SIGNAL(triggered(bool)),
  192. this->CMakeThread->cmakeInstance(), SLOT(setSuppressDevWarnings(bool)));
  193. if(!this->SourceDirectory->text().isEmpty() ||
  194. !this->BinaryDirectory->lineEdit()->text().isEmpty())
  195. {
  196. this->onSourceDirectoryChanged(this->SourceDirectory->text());
  197. this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
  198. }
  199. else
  200. {
  201. this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
  202. }
  203. }
  204. CMakeSetupDialog::~CMakeSetupDialog()
  205. {
  206. QSettings settings;
  207. settings.beginGroup("Settings/StartPath");
  208. settings.setValue("Height", this->height());
  209. settings.setValue("Width", this->width());
  210. // wait for thread to stop
  211. this->CMakeThread->quit();
  212. this->CMakeThread->wait(2000);
  213. }
  214. void CMakeSetupDialog::doConfigure()
  215. {
  216. if(this->CurrentState == Configuring)
  217. {
  218. // stop configure
  219. doInterrupt();
  220. return;
  221. }
  222. // make sure build directory exists
  223. QString bindir = this->CMakeThread->cmakeInstance()->binaryDirectory();
  224. QDir dir(bindir);
  225. if(!dir.exists())
  226. {
  227. QString message = tr("Build directory does not exist, "
  228. "should I create it?")
  229. + "\n\n"
  230. + tr("Directory: ");
  231. message += bindir;
  232. QString title = tr("Create Directory");
  233. QMessageBox::StandardButton btn;
  234. btn = QMessageBox::information(this, title, message,
  235. QMessageBox::Yes | QMessageBox::No);
  236. if(btn == QMessageBox::No)
  237. {
  238. return;
  239. }
  240. dir.mkpath(".");
  241. }
  242. // if no generator, prompt for it and other setup stuff
  243. if(this->CMakeThread->cmakeInstance()->generator().isEmpty())
  244. {
  245. if(!this->setupFirstConfigure())
  246. {
  247. return;
  248. }
  249. }
  250. // remember path
  251. this->addBinaryPath(dir.absolutePath());
  252. this->enterState(Configuring);
  253. this->CacheValues->selectionModel()->clear();
  254. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  255. "setProperties", Qt::QueuedConnection,
  256. Q_ARG(QCMakePropertyList,
  257. this->CacheValues->cacheModel()->properties()));
  258. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  259. "configure", Qt::QueuedConnection);
  260. }
  261. void CMakeSetupDialog::finishConfigure(int err)
  262. {
  263. if(0 == err && !this->CacheValues->cacheModel()->hasNewProperties())
  264. {
  265. this->enterState(ReadyGenerate);
  266. }
  267. else
  268. {
  269. this->enterState(ReadyConfigure);
  270. this->CacheValues->scrollToTop();
  271. }
  272. if(err != 0)
  273. {
  274. QMessageBox::critical(this, tr("Error"),
  275. tr("Error in configuration process, project files may be invalid"),
  276. QMessageBox::Ok);
  277. }
  278. }
  279. void CMakeSetupDialog::finishGenerate(int err)
  280. {
  281. this->enterState(ReadyGenerate);
  282. if(err != 0)
  283. {
  284. QMessageBox::critical(this, tr("Error"),
  285. tr("Error in generation process, project files may be invalid"),
  286. QMessageBox::Ok);
  287. }
  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::setupFirstConfigure()
  476. {
  477. CMakeFirstConfigure dialog;
  478. // initialize dialog and restore saved settings
  479. // add generators
  480. dialog.setGenerators(this->CMakeThread->cmakeInstance()->availableGenerators());
  481. // restore from settings
  482. dialog.loadFromSettings();
  483. if(dialog.exec() == QDialog::Accepted)
  484. {
  485. dialog.saveToSettings();
  486. this->CMakeThread->cmakeInstance()->setGenerator(dialog.getGenerator());
  487. QCMakeCacheModel* m = this->CacheValues->cacheModel();
  488. if(dialog.compilerSetup())
  489. {
  490. QString fortranCompiler = dialog.getFortranCompiler();
  491. if(!fortranCompiler.isEmpty())
  492. {
  493. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
  494. "Fortran compiler.", fortranCompiler, false);
  495. }
  496. QString cxxCompiler = dialog.getCXXCompiler();
  497. if(!cxxCompiler.isEmpty())
  498. {
  499. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
  500. "CXX compiler.", cxxCompiler, false);
  501. }
  502. QString cCompiler = dialog.getCCompiler();
  503. if(!cCompiler.isEmpty())
  504. {
  505. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
  506. "C compiler.", cCompiler, false);
  507. }
  508. }
  509. else if(dialog.crossCompilerSetup())
  510. {
  511. QString toolchainFile = dialog.crossCompilerToolChainFile();
  512. if(!toolchainFile.isEmpty())
  513. {
  514. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE",
  515. "Cross Compile ToolChain File", toolchainFile, false);
  516. }
  517. else
  518. {
  519. QString fortranCompiler = dialog.getFortranCompiler();
  520. if(!fortranCompiler.isEmpty())
  521. {
  522. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
  523. "Fortran compiler.", fortranCompiler, false);
  524. }
  525. QString mode = dialog.getCrossIncludeMode();
  526. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE",
  527. "CMake Find Include Mode", mode, false);
  528. mode = dialog.getCrossLibraryMode();
  529. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY",
  530. "CMake Find Library Mode", mode, false);
  531. mode = dialog.getCrossProgramMode();
  532. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM",
  533. "CMake Find Program Mode", mode, false);
  534. QString rootPath = dialog.getCrossRoot();
  535. m->insertProperty(QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH",
  536. "CMake Find Root Path", rootPath, false);
  537. QString systemName = dialog.getSystemName();
  538. m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME",
  539. "CMake System Name", systemName, false);
  540. QString cxxCompiler = dialog.getCXXCompiler();
  541. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
  542. "CXX compiler.", cxxCompiler, false);
  543. QString cCompiler = dialog.getCCompiler();
  544. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
  545. "C compiler.", cCompiler, false);
  546. }
  547. }
  548. return true;
  549. }
  550. return false;
  551. }
  552. void CMakeSetupDialog::updateGeneratorLabel(const QString& gen)
  553. {
  554. QString str = tr("Current Generator: ");
  555. if(gen.isEmpty())
  556. {
  557. str += tr("None");
  558. }
  559. else
  560. {
  561. str += gen;
  562. }
  563. this->Generator->setText(str);
  564. }
  565. void CMakeSetupDialog::doReloadCache()
  566. {
  567. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  568. "reloadCache", Qt::QueuedConnection);
  569. }
  570. void CMakeSetupDialog::doDeleteCache()
  571. {
  572. QString title = tr("Delete Cache");
  573. QString message = "Are you sure you want to delete the cache?";
  574. QMessageBox::StandardButton btn;
  575. btn = QMessageBox::information(this, title, message,
  576. QMessageBox::Yes | QMessageBox::No);
  577. if(btn == QMessageBox::No)
  578. {
  579. return;
  580. }
  581. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  582. "deleteCache", Qt::QueuedConnection);
  583. }
  584. void CMakeSetupDialog::doAbout()
  585. {
  586. QString msg = "CMake\nwww.cmake.org";
  587. QDialog dialog;
  588. dialog.setWindowTitle(tr("About"));
  589. QVBoxLayout* l = new QVBoxLayout(&dialog);
  590. QLabel* lab = new QLabel(&dialog);
  591. l->addWidget(lab);
  592. lab->setText(msg);
  593. lab->setWordWrap(true);
  594. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
  595. Qt::Horizontal, &dialog);
  596. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  597. l->addWidget(btns);
  598. dialog.exec();
  599. }
  600. void CMakeSetupDialog::setExitAfterGenerate(bool b)
  601. {
  602. this->ExitAfterGenerate = b;
  603. }
  604. void CMakeSetupDialog::addBinaryPath(const QString& path)
  605. {
  606. QString cleanpath = QDir::cleanPath(path);
  607. // update UI
  608. this->BinaryDirectory->blockSignals(true);
  609. int idx = this->BinaryDirectory->findText(cleanpath);
  610. if(idx != -1)
  611. {
  612. this->BinaryDirectory->removeItem(idx);
  613. }
  614. this->BinaryDirectory->insertItem(0, cleanpath);
  615. this->BinaryDirectory->setCurrentIndex(0);
  616. this->BinaryDirectory->blockSignals(false);
  617. // save to registry
  618. QStringList buildPaths = this->loadBuildPaths();
  619. buildPaths.removeAll(cleanpath);
  620. buildPaths.prepend(cleanpath);
  621. this->saveBuildPaths(buildPaths);
  622. }
  623. void CMakeSetupDialog::dragEnterEvent(QDragEnterEvent* e)
  624. {
  625. if(!(this->CurrentState == ReadyConfigure ||
  626. this->CurrentState == ReadyGenerate))
  627. {
  628. e->ignore();
  629. return;
  630. }
  631. const QMimeData* dat = e->mimeData();
  632. QList<QUrl> urls = dat->urls();
  633. QString file = urls.count() ? urls[0].toLocalFile() : QString();
  634. if(!file.isEmpty() &&
  635. (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive) ||
  636. file.endsWith("CMakeLists.txt", Qt::CaseInsensitive) ) )
  637. {
  638. e->accept();
  639. }
  640. else
  641. {
  642. e->ignore();
  643. }
  644. }
  645. void CMakeSetupDialog::dropEvent(QDropEvent* e)
  646. {
  647. if(!(this->CurrentState == ReadyConfigure ||
  648. this->CurrentState == ReadyGenerate))
  649. {
  650. return;
  651. }
  652. const QMimeData* dat = e->mimeData();
  653. QList<QUrl> urls = dat->urls();
  654. QString file = urls.count() ? urls[0].toLocalFile() : QString();
  655. if(file.endsWith("CMakeCache.txt", Qt::CaseInsensitive))
  656. {
  657. QFileInfo info(file);
  658. if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
  659. {
  660. this->setBinaryDirectory(info.absolutePath());
  661. }
  662. }
  663. else if(file.endsWith("CMakeLists.txt", Qt::CaseInsensitive))
  664. {
  665. QFileInfo info(file);
  666. if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
  667. {
  668. this->setSourceDirectory(info.absolutePath());
  669. this->setBinaryDirectory(info.absolutePath());
  670. }
  671. }
  672. }
  673. QStringList CMakeSetupDialog::loadBuildPaths()
  674. {
  675. QSettings settings;
  676. settings.beginGroup("Settings/StartPath");
  677. QStringList buildPaths;
  678. for(int i=0; i<10; i++)
  679. {
  680. QString p = settings.value(QString("WhereBuild%1").arg(i)).toString();
  681. if(!p.isEmpty())
  682. {
  683. buildPaths.append(p);
  684. }
  685. }
  686. return buildPaths;
  687. }
  688. void CMakeSetupDialog::saveBuildPaths(const QStringList& paths)
  689. {
  690. QSettings settings;
  691. settings.beginGroup("Settings/StartPath");
  692. int num = paths.count();
  693. if(num > 10)
  694. {
  695. num = 10;
  696. }
  697. for(int i=0; i<num; i++)
  698. {
  699. settings.setValue(QString("WhereBuild%1").arg(i), paths[i]);
  700. }
  701. }
  702. void CMakeSetupDialog::setCacheModified()
  703. {
  704. this->CacheModified = true;
  705. this->enterState(ReadyConfigure);
  706. }
  707. void CMakeSetupDialog::removeSelectedCacheEntries()
  708. {
  709. QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
  710. QList<QPersistentModelIndex> pidxs;
  711. foreach(QModelIndex i, idxs)
  712. {
  713. pidxs.append(i);
  714. }
  715. foreach(QPersistentModelIndex pi, pidxs)
  716. {
  717. this->CacheValues->model()->removeRow(pi.row(), pi.parent());
  718. }
  719. }
  720. void CMakeSetupDialog::selectionChanged()
  721. {
  722. QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
  723. if(idxs.count() &&
  724. (this->CurrentState == ReadyConfigure ||
  725. this->CurrentState == ReadyGenerate) )
  726. {
  727. this->RemoveEntry->setEnabled(true);
  728. }
  729. else
  730. {
  731. this->RemoveEntry->setEnabled(false);
  732. }
  733. }
  734. void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
  735. {
  736. if(s == this->CurrentState)
  737. {
  738. return;
  739. }
  740. this->CurrentState = s;
  741. if(s == Interrupting)
  742. {
  743. this->ConfigureButton->setEnabled(false);
  744. this->GenerateButton->setEnabled(false);
  745. }
  746. else if(s == Configuring)
  747. {
  748. this->Output->clear();
  749. this->setEnabledState(false);
  750. this->GenerateButton->setEnabled(false);
  751. this->GenerateAction->setEnabled(false);
  752. this->ConfigureButton->setText(tr("&Stop"));
  753. }
  754. else if(s == Generating)
  755. {
  756. this->CacheModified = false;
  757. this->setEnabledState(false);
  758. this->ConfigureButton->setEnabled(false);
  759. this->GenerateAction->setEnabled(false);
  760. this->GenerateButton->setText(tr("&Stop"));
  761. }
  762. else if(s == ReadyConfigure)
  763. {
  764. this->ProgressBar->reset();
  765. this->setEnabledState(true);
  766. this->GenerateButton->setEnabled(false);
  767. this->GenerateAction->setEnabled(false);
  768. this->ConfigureButton->setEnabled(true);
  769. this->ConfigureButton->setText(tr("&Configure"));
  770. this->GenerateButton->setText(tr("&Generate"));
  771. }
  772. else if(s == ReadyGenerate)
  773. {
  774. this->ProgressBar->reset();
  775. this->setEnabledState(true);
  776. this->GenerateButton->setEnabled(true);
  777. this->GenerateAction->setEnabled(true);
  778. this->ConfigureButton->setEnabled(true);
  779. this->ConfigureButton->setText(tr("&Configure"));
  780. this->GenerateButton->setText(tr("&Generate"));
  781. }
  782. }
  783. void CMakeSetupDialog::addCacheEntry()
  784. {
  785. QDialog dialog(this);
  786. dialog.resize(400, 200);
  787. dialog.setWindowTitle(tr("Add Cache Entry"));
  788. QVBoxLayout* l = new QVBoxLayout(&dialog);
  789. AddCacheEntry* w = new AddCacheEntry(&dialog);
  790. QDialogButtonBox* btns = new QDialogButtonBox(
  791. QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
  792. Qt::Horizontal, &dialog);
  793. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  794. QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(reject()));
  795. l->addWidget(w);
  796. l->addStretch();
  797. l->addWidget(btns);
  798. if(QDialog::Accepted == dialog.exec())
  799. {
  800. QCMakeCacheModel* m = this->CacheValues->cacheModel();
  801. m->insertProperty(w->type(), w->name(), w->description(), w->value(), false);
  802. }
  803. }
  804. void CMakeSetupDialog::startSearch()
  805. {
  806. this->Search->setFocus(Qt::OtherFocusReason);
  807. this->Search->selectAll();
  808. }
  809. void CMakeSetupDialog::setDebugOutput(bool flag)
  810. {
  811. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  812. "setDebugOutput", Qt::QueuedConnection, Q_ARG(bool, flag));
  813. }