CMakeSetupDialog.cxx 30 KB

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