CMakeSetupDialog.cxx 32 KB

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