CMakeSetupDialog.cxx 30 KB

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