CMakeSetupDialog.cxx 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331
  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 <QKeySequence>
  27. #include <QMacInstallDialog.h>
  28. #include <QInputDialog>
  29. #include "QCMake.h"
  30. #include "QCMakeCacheView.h"
  31. #include "AddCacheEntry.h"
  32. #include "FirstConfigure.h"
  33. #include "cmSystemTools.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), ConfigureNeeded(true), CurrentState(Interrupting)
  54. {
  55. QString title = QString(tr("CMake %1"));
  56. title = title.arg(cmVersion::GetCMakeVersion());
  57. this->setWindowTitle(title);
  58. // create the GUI
  59. QSettings settings;
  60. settings.beginGroup("Settings/StartPath");
  61. restoreGeometry(settings.value("geometry").toByteArray());
  62. restoreState(settings.value("windowState").toByteArray());
  63. this->AddVariableNames = settings.value("AddVariableNames",
  64. QStringList("CMAKE_INSTALL_PREFIX")).toStringList();
  65. this->AddVariableTypes = settings.value("AddVariableTypes",
  66. QStringList("PATH")).toStringList();
  67. QWidget* cont = new QWidget(this);
  68. this->setupUi(cont);
  69. this->Splitter->setStretchFactor(0, 3);
  70. this->Splitter->setStretchFactor(1, 1);
  71. this->setCentralWidget(cont);
  72. this->ProgressBar->reset();
  73. this->RemoveEntry->setEnabled(false);
  74. this->AddEntry->setEnabled(false);
  75. QByteArray p = settings.value("SplitterSizes").toByteArray();
  76. this->Splitter->restoreState(p);
  77. bool groupView = settings.value("GroupView", false).toBool();
  78. this->setGroupedView(groupView);
  79. this->groupedCheck->setCheckState(groupView ? Qt::Checked : Qt::Unchecked);
  80. bool advancedView = settings.value("AdvancedView", false).toBool();
  81. this->setAdvancedView(advancedView);
  82. this->advancedCheck->setCheckState(advancedView?Qt::Checked : Qt::Unchecked);
  83. QMenu* FileMenu = this->menuBar()->addMenu(tr("&File"));
  84. this->ReloadCacheAction = FileMenu->addAction(tr("&Reload Cache"));
  85. QObject::connect(this->ReloadCacheAction, SIGNAL(triggered(bool)),
  86. this, SLOT(doReloadCache()));
  87. this->DeleteCacheAction = FileMenu->addAction(tr("&Delete Cache"));
  88. QObject::connect(this->DeleteCacheAction, SIGNAL(triggered(bool)),
  89. this, SLOT(doDeleteCache()));
  90. this->ExitAction = FileMenu->addAction(tr("E&xit"));
  91. this->ExitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
  92. QObject::connect(this->ExitAction, SIGNAL(triggered(bool)),
  93. this, SLOT(close()));
  94. QMenu* ToolsMenu = this->menuBar()->addMenu(tr("&Tools"));
  95. this->ConfigureAction = ToolsMenu->addAction(tr("&Configure"));
  96. // prevent merging with Preferences menu item on Mac OS X
  97. this->ConfigureAction->setMenuRole(QAction::NoRole);
  98. QObject::connect(this->ConfigureAction, SIGNAL(triggered(bool)),
  99. this, SLOT(doConfigure()));
  100. this->GenerateAction = ToolsMenu->addAction(tr("&Generate"));
  101. QObject::connect(this->GenerateAction, SIGNAL(triggered(bool)),
  102. this, SLOT(doGenerate()));
  103. QAction* showChangesAction = ToolsMenu->addAction(tr("&Show My Changes"));
  104. QObject::connect(showChangesAction, SIGNAL(triggered(bool)),
  105. this, SLOT(showUserChanges()));
  106. #if defined(Q_WS_MAC)
  107. this->InstallForCommandLineAction
  108. = ToolsMenu->addAction(tr("&Install For Command Line Use"));
  109. QObject::connect(this->InstallForCommandLineAction, SIGNAL(triggered(bool)),
  110. this, SLOT(doInstallForCommandLine()));
  111. #endif
  112. ToolsMenu->addSeparator();
  113. ToolsMenu->addAction(tr("&Find in Output..."),
  114. this, SLOT(doOutputFindDialog()),
  115. QKeySequence::Find);
  116. ToolsMenu->addAction(tr("Find Next"),
  117. this, SLOT(doOutputFindNext()),
  118. QKeySequence::FindNext);
  119. ToolsMenu->addAction(tr("Find Previous"),
  120. this, SLOT(doOutputFindPrev()),
  121. QKeySequence::FindPrevious);
  122. ToolsMenu->addAction(tr("Goto Next Error"),
  123. this, SLOT(doOutputErrorNext()),
  124. QKeySequence(Qt::Key_F8)); // in Visual Studio
  125. new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Period),
  126. this, SLOT(doOutputErrorNext())); // in Eclipse
  127. QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options"));
  128. this->SuppressDevWarningsAction =
  129. OptionsMenu->addAction(tr("&Suppress dev Warnings (-Wno-dev)"));
  130. this->SuppressDevWarningsAction->setCheckable(true);
  131. this->WarnUninitializedAction =
  132. OptionsMenu->addAction(tr("&Warn Uninitialized (--warn-uninitialized)"));
  133. this->WarnUninitializedAction->setCheckable(true);
  134. this->WarnUnusedAction =
  135. OptionsMenu->addAction(tr("&Warn Unused (--warn-unused-vars)"));
  136. this->WarnUnusedAction->setCheckable(true);
  137. QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output"));
  138. debugAction->setCheckable(true);
  139. QObject::connect(debugAction, SIGNAL(toggled(bool)),
  140. this, SLOT(setDebugOutput(bool)));
  141. OptionsMenu->addSeparator();
  142. QAction* expandAction = OptionsMenu->addAction(tr("&Expand Grouped Entries"));
  143. QObject::connect(expandAction, SIGNAL(triggered(bool)),
  144. this->CacheValues, SLOT(expandAll()));
  145. QAction* collapseAction = OptionsMenu->addAction(tr("&Collapse Grouped Entries"));
  146. QObject::connect(collapseAction, SIGNAL(triggered(bool)),
  147. this->CacheValues, SLOT(collapseAll()));
  148. QMenu* HelpMenu = this->menuBar()->addMenu(tr("&Help"));
  149. QAction* a = HelpMenu->addAction(tr("About"));
  150. QObject::connect(a, SIGNAL(triggered(bool)),
  151. this, SLOT(doAbout()));
  152. a = HelpMenu->addAction(tr("Help"));
  153. QObject::connect(a, SIGNAL(triggered(bool)),
  154. this, SLOT(doHelp()));
  155. this->setAcceptDrops(true);
  156. // get the saved binary directories
  157. QStringList buildPaths = this->loadBuildPaths();
  158. this->BinaryDirectory->addItems(buildPaths);
  159. this->BinaryDirectory->setCompleter(new QCMakeFileCompleter(this, true));
  160. this->SourceDirectory->setCompleter(new QCMakeFileCompleter(this, true));
  161. // fixed pitch font in output window
  162. QFont outputFont("Courier");
  163. this->Output->setFont(outputFont);
  164. this->ErrorFormat.setForeground(QBrush(Qt::red));
  165. this->Output->setContextMenuPolicy(Qt::CustomContextMenu);
  166. connect(this->Output, SIGNAL(customContextMenuRequested(const QPoint&)),
  167. this, SLOT(doOutputContextMenu(const QPoint &)));
  168. // start the cmake worker thread
  169. this->CMakeThread = new QCMakeThread(this);
  170. QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()),
  171. this, SLOT(initialize()), Qt::QueuedConnection);
  172. this->CMakeThread->start();
  173. this->enterState(ReadyConfigure);
  174. ProgressOffset = 0.0;
  175. ProgressFactor = 1.0;
  176. }
  177. void CMakeSetupDialog::initialize()
  178. {
  179. // now the cmake worker thread is running, lets make our connections to it
  180. QObject::connect(this->CMakeThread->cmakeInstance(),
  181. SIGNAL(propertiesChanged(const QCMakePropertyList&)),
  182. this->CacheValues->cacheModel(),
  183. SLOT(setProperties(const QCMakePropertyList&)));
  184. QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)),
  185. this, SLOT(doConfigure()));
  186. QObject::connect(this->CMakeThread->cmakeInstance(), SIGNAL(configureDone(int)),
  187. this, SLOT(exitLoop(int)));
  188. QObject::connect(this->CMakeThread->cmakeInstance(), SIGNAL(generateDone(int)),
  189. this, SLOT(exitLoop(int)));
  190. QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)),
  191. this, SLOT(doGenerate()));
  192. QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)),
  193. this, SLOT(doSourceBrowse()));
  194. QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)),
  195. this, SLOT(doBinaryBrowse()));
  196. QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)),
  197. this, SLOT(onBinaryDirectoryChanged(QString)));
  198. QObject::connect(this->SourceDirectory, SIGNAL(textChanged(QString)),
  199. this, SLOT(onSourceDirectoryChanged(QString)));
  200. QObject::connect(this->CMakeThread->cmakeInstance(),
  201. SIGNAL(sourceDirChanged(QString)),
  202. this, SLOT(updateSourceDirectory(QString)));
  203. QObject::connect(this->CMakeThread->cmakeInstance(),
  204. SIGNAL(binaryDirChanged(QString)),
  205. this, SLOT(updateBinaryDirectory(QString)));
  206. QObject::connect(this->CMakeThread->cmakeInstance(),
  207. SIGNAL(progressChanged(QString, float)),
  208. this, SLOT(showProgress(QString,float)));
  209. QObject::connect(this->CMakeThread->cmakeInstance(),
  210. SIGNAL(errorMessage(QString)),
  211. this, SLOT(error(QString)));
  212. QObject::connect(this->CMakeThread->cmakeInstance(),
  213. SIGNAL(outputMessage(QString)),
  214. this, SLOT(message(QString)));
  215. QObject::connect(this->groupedCheck, SIGNAL(toggled(bool)),
  216. this, SLOT(setGroupedView(bool)));
  217. QObject::connect(this->advancedCheck, SIGNAL(toggled(bool)),
  218. this, SLOT(setAdvancedView(bool)));
  219. QObject::connect(this->Search, SIGNAL(textChanged(QString)),
  220. this, SLOT(setSearchFilter(QString)));
  221. QObject::connect(this->CMakeThread->cmakeInstance(),
  222. SIGNAL(generatorChanged(QString)),
  223. this, SLOT(updateGeneratorLabel(QString)));
  224. this->updateGeneratorLabel(QString());
  225. QObject::connect(this->CacheValues->cacheModel(),
  226. SIGNAL(dataChanged(QModelIndex,QModelIndex)),
  227. this, SLOT(setCacheModified()));
  228. QObject::connect(this->CacheValues->selectionModel(),
  229. SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
  230. this, SLOT(selectionChanged()));
  231. QObject::connect(this->RemoveEntry, SIGNAL(clicked(bool)),
  232. this, SLOT(removeSelectedCacheEntries()));
  233. QObject::connect(this->AddEntry, SIGNAL(clicked(bool)),
  234. this, SLOT(addCacheEntry()));
  235. QObject::connect(this->SuppressDevWarningsAction, SIGNAL(triggered(bool)),
  236. this->CMakeThread->cmakeInstance(), SLOT(setSuppressDevWarnings(bool)));
  237. QObject::connect(this->WarnUninitializedAction, SIGNAL(triggered(bool)),
  238. this->CMakeThread->cmakeInstance(),
  239. SLOT(setWarnUninitializedMode(bool)));
  240. QObject::connect(this->WarnUnusedAction, SIGNAL(triggered(bool)),
  241. this->CMakeThread->cmakeInstance(),
  242. SLOT(setWarnUnusedMode(bool)));
  243. if(!this->SourceDirectory->text().isEmpty() ||
  244. !this->BinaryDirectory->lineEdit()->text().isEmpty())
  245. {
  246. this->onSourceDirectoryChanged(this->SourceDirectory->text());
  247. this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
  248. }
  249. else
  250. {
  251. this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
  252. }
  253. }
  254. CMakeSetupDialog::~CMakeSetupDialog()
  255. {
  256. QSettings settings;
  257. settings.beginGroup("Settings/StartPath");
  258. settings.setValue("windowState", QVariant(saveState()));
  259. settings.setValue("geometry", QVariant(saveGeometry()));
  260. settings.setValue("SplitterSizes", this->Splitter->saveState());
  261. // wait for thread to stop
  262. this->CMakeThread->quit();
  263. this->CMakeThread->wait();
  264. }
  265. bool CMakeSetupDialog::prepareConfigure()
  266. {
  267. // make sure build directory exists
  268. QString bindir = this->CMakeThread->cmakeInstance()->binaryDirectory();
  269. QDir dir(bindir);
  270. if(!dir.exists())
  271. {
  272. QString msg = tr("Build directory does not exist, "
  273. "should I create it?\n\n"
  274. "Directory: ");
  275. msg += bindir;
  276. QString title = tr("Create Directory");
  277. QMessageBox::StandardButton btn;
  278. btn = QMessageBox::information(this, title, msg,
  279. QMessageBox::Yes | QMessageBox::No);
  280. if(btn == QMessageBox::No)
  281. {
  282. return false;
  283. }
  284. if(!dir.mkpath("."))
  285. {
  286. QMessageBox::information(this, tr("Create Directory Failed"),
  287. QString(tr("Failed to create directory %1")).arg(dir.path()),
  288. QMessageBox::Ok);
  289. return false;
  290. }
  291. }
  292. // if no generator, prompt for it and other setup stuff
  293. if(this->CMakeThread->cmakeInstance()->generator().isEmpty())
  294. {
  295. if(!this->setupFirstConfigure())
  296. {
  297. return false;
  298. }
  299. }
  300. // remember path
  301. this->addBinaryPath(dir.absolutePath());
  302. return true;
  303. }
  304. void CMakeSetupDialog::exitLoop(int err)
  305. {
  306. this->LocalLoop.exit(err);
  307. }
  308. void CMakeSetupDialog::doConfigure()
  309. {
  310. if(this->CurrentState == Configuring)
  311. {
  312. // stop configure
  313. doInterrupt();
  314. return;
  315. }
  316. if(!prepareConfigure())
  317. {
  318. return;
  319. }
  320. this->enterState(Configuring);
  321. bool ret = doConfigureInternal();
  322. if(ret)
  323. {
  324. this->ConfigureNeeded = false;
  325. }
  326. if(ret && !this->CacheValues->cacheModel()->newPropertyCount())
  327. {
  328. this->enterState(ReadyGenerate);
  329. }
  330. else
  331. {
  332. this->enterState(ReadyConfigure);
  333. this->CacheValues->scrollToTop();
  334. }
  335. this->ProgressBar->reset();
  336. }
  337. bool CMakeSetupDialog::doConfigureInternal()
  338. {
  339. this->Output->clear();
  340. this->CacheValues->selectionModel()->clear();
  341. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  342. "setProperties", Qt::QueuedConnection,
  343. Q_ARG(QCMakePropertyList,
  344. this->CacheValues->cacheModel()->properties()));
  345. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  346. "configure", Qt::QueuedConnection);
  347. int err = this->LocalLoop.exec();
  348. if(err != 0)
  349. {
  350. QMessageBox::critical(this, tr("Error"),
  351. tr("Error in configuration process, project files may be invalid"),
  352. QMessageBox::Ok);
  353. }
  354. return 0 == err;
  355. }
  356. void CMakeSetupDialog::doInstallForCommandLine()
  357. {
  358. QMacInstallDialog setupdialog(0);
  359. setupdialog.exec();
  360. }
  361. bool CMakeSetupDialog::doGenerateInternal()
  362. {
  363. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  364. "generate", Qt::QueuedConnection);
  365. int err = this->LocalLoop.exec();
  366. if(err != 0)
  367. {
  368. QMessageBox::critical(this, tr("Error"),
  369. tr("Error in generation process, project files may be invalid"),
  370. QMessageBox::Ok);
  371. }
  372. return 0 == err;
  373. }
  374. void CMakeSetupDialog::doGenerate()
  375. {
  376. if(this->CurrentState == Generating)
  377. {
  378. // stop generate
  379. doInterrupt();
  380. return;
  381. }
  382. // see if we need to configure
  383. // we'll need to configure if:
  384. // the configure step hasn't been done yet
  385. // generate was the last step done
  386. if(this->ConfigureNeeded)
  387. {
  388. if(!prepareConfigure())
  389. {
  390. return;
  391. }
  392. }
  393. this->enterState(Generating);
  394. bool config_passed = true;
  395. if(this->ConfigureNeeded)
  396. {
  397. this->CacheValues->cacheModel()->setShowNewProperties(false);
  398. this->ProgressFactor = 0.5;
  399. config_passed = doConfigureInternal();
  400. this->ProgressOffset = 0.5;
  401. }
  402. if(config_passed)
  403. {
  404. doGenerateInternal();
  405. }
  406. this->ProgressOffset = 0.0;
  407. this->ProgressFactor = 1.0;
  408. this->CacheValues->cacheModel()->setShowNewProperties(true);
  409. this->enterState(ReadyConfigure);
  410. this->ProgressBar->reset();
  411. this->ConfigureNeeded = true;
  412. }
  413. void CMakeSetupDialog::closeEvent(QCloseEvent* e)
  414. {
  415. // prompt for close if there are unsaved changes, and we're not busy
  416. if(this->CacheModified)
  417. {
  418. QString msg = tr("You have changed options but not rebuilt, "
  419. "are you sure you want to exit?");
  420. QString title = tr("Confirm Exit");
  421. QMessageBox::StandardButton btn;
  422. btn = QMessageBox::critical(this, title, msg,
  423. QMessageBox::Yes | QMessageBox::No);
  424. if(btn == QMessageBox::No)
  425. {
  426. e->ignore();
  427. }
  428. }
  429. // don't close if we're busy, unless the user really wants to
  430. if(this->CurrentState == Configuring)
  431. {
  432. QString msg = tr("You are in the middle of a Configure.\n"
  433. "If you Exit now the configure information will be lost.\n"
  434. "Are you sure you want to Exit?");
  435. QString title = tr("Confirm Exit");
  436. QMessageBox::StandardButton btn;
  437. btn = QMessageBox::critical(this, title, msg,
  438. QMessageBox::Yes | QMessageBox::No);
  439. if(btn == QMessageBox::No)
  440. {
  441. e->ignore();
  442. }
  443. else
  444. {
  445. this->doInterrupt();
  446. }
  447. }
  448. // let the generate finish
  449. if(this->CurrentState == Generating)
  450. {
  451. e->ignore();
  452. }
  453. }
  454. void CMakeSetupDialog::doHelp()
  455. {
  456. QString msg = tr("CMake is used to configure and generate build files for "
  457. "software projects. The basic steps for configuring a project are as "
  458. "follows:\r\n\r\n1. Select the source directory for the project. This should "
  459. "contain the CMakeLists.txt files for the project.\r\n\r\n2. Select the build "
  460. "directory for the project. This is the directory where the project will be "
  461. "built. It can be the same or a different directory than the source "
  462. "directory. For easy clean up, a separate build directory is recommended. "
  463. "CMake will create the directory if it does not exist.\r\n\r\n3. Once the "
  464. "source and binary directories are selected, it is time to press the "
  465. "Configure button. This will cause CMake to read all of the input files and "
  466. "discover all the variables used by the project. The first time a variable "
  467. "is displayed it will be in Red. Users should inspect red variables making "
  468. "sure the values are correct. For some projects the Configure process can "
  469. "be iterative, so continue to press the Configure button until there are no "
  470. "longer red entries.\r\n\r\n4. Once there are no longer red entries, you "
  471. "should click the Generate button. This will write the build files to the build "
  472. "directory.");
  473. QDialog dialog;
  474. QFontMetrics met(this->font());
  475. int msgWidth = met.width(msg);
  476. dialog.setMinimumSize(msgWidth/15,20);
  477. dialog.setWindowTitle(tr("Help"));
  478. QVBoxLayout* l = new QVBoxLayout(&dialog);
  479. QLabel* lab = new QLabel(&dialog);
  480. lab->setText(msg);
  481. lab->setWordWrap(true);
  482. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
  483. Qt::Horizontal, &dialog);
  484. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  485. l->addWidget(lab);
  486. l->addWidget(btns);
  487. dialog.exec();
  488. }
  489. void CMakeSetupDialog::doInterrupt()
  490. {
  491. this->enterState(Interrupting);
  492. this->CMakeThread->cmakeInstance()->interrupt();
  493. }
  494. void CMakeSetupDialog::doSourceBrowse()
  495. {
  496. QString dir = QFileDialog::getExistingDirectory(this,
  497. tr("Enter Path to Source"), this->SourceDirectory->text(),
  498. QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
  499. if(!dir.isEmpty())
  500. {
  501. this->setSourceDirectory(dir);
  502. }
  503. }
  504. void CMakeSetupDialog::updateSourceDirectory(const QString& dir)
  505. {
  506. if(this->SourceDirectory->text() != dir)
  507. {
  508. this->SourceDirectory->blockSignals(true);
  509. this->SourceDirectory->setText(dir);
  510. this->SourceDirectory->blockSignals(false);
  511. }
  512. }
  513. void CMakeSetupDialog::updateBinaryDirectory(const QString& dir)
  514. {
  515. if(this->BinaryDirectory->currentText() != dir)
  516. {
  517. this->BinaryDirectory->blockSignals(true);
  518. this->BinaryDirectory->setEditText(dir);
  519. this->BinaryDirectory->blockSignals(false);
  520. }
  521. }
  522. void CMakeSetupDialog::doBinaryBrowse()
  523. {
  524. QString dir = QFileDialog::getExistingDirectory(this,
  525. tr("Enter Path to Build"), this->BinaryDirectory->currentText(),
  526. QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
  527. if(!dir.isEmpty() && dir != this->BinaryDirectory->currentText())
  528. {
  529. this->setBinaryDirectory(dir);
  530. }
  531. }
  532. void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
  533. {
  534. this->BinaryDirectory->setEditText(dir);
  535. }
  536. void CMakeSetupDialog::onSourceDirectoryChanged(const QString& dir)
  537. {
  538. this->Output->clear();
  539. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  540. "setSourceDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
  541. }
  542. void CMakeSetupDialog::onBinaryDirectoryChanged(const QString& dir)
  543. {
  544. QString title = QString(tr("CMake %1 - %2"));
  545. title = title.arg(cmVersion::GetCMakeVersion());
  546. title = title.arg(dir);
  547. this->setWindowTitle(title);
  548. this->CacheModified = false;
  549. this->CacheValues->cacheModel()->clear();
  550. qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())->clearChanges();
  551. this->Output->clear();
  552. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  553. "setBinaryDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
  554. }
  555. void CMakeSetupDialog::setSourceDirectory(const QString& dir)
  556. {
  557. this->SourceDirectory->setText(dir);
  558. }
  559. void CMakeSetupDialog::showProgress(const QString& /*msg*/, float percent)
  560. {
  561. percent = (percent * ProgressFactor) + ProgressOffset;
  562. this->ProgressBar->setValue(qRound(percent * 100));
  563. }
  564. void CMakeSetupDialog::error(const QString& msg)
  565. {
  566. this->Output->setCurrentCharFormat(this->ErrorFormat);
  567. //QTextEdit will terminate the msg with a ParagraphSeparator, but it also replaces
  568. //all newlines with ParagraphSeparators. By replacing the newlines by ourself, one
  569. //error msg will be one paragraph.
  570. QString paragraph(msg);
  571. paragraph.replace(QLatin1Char('\n'), QChar::LineSeparator);
  572. this->Output->append(paragraph);
  573. }
  574. void CMakeSetupDialog::message(const QString& msg)
  575. {
  576. this->Output->setCurrentCharFormat(this->MessageFormat);
  577. this->Output->append(msg);
  578. }
  579. void CMakeSetupDialog::setEnabledState(bool enabled)
  580. {
  581. // disable parts of the GUI during configure/generate
  582. this->CacheValues->cacheModel()->setEditEnabled(enabled);
  583. this->SourceDirectory->setEnabled(enabled);
  584. this->BrowseSourceDirectoryButton->setEnabled(enabled);
  585. this->BinaryDirectory->setEnabled(enabled);
  586. this->BrowseBinaryDirectoryButton->setEnabled(enabled);
  587. this->ReloadCacheAction->setEnabled(enabled);
  588. this->DeleteCacheAction->setEnabled(enabled);
  589. this->ExitAction->setEnabled(enabled);
  590. this->ConfigureAction->setEnabled(enabled);
  591. this->AddEntry->setEnabled(enabled);
  592. this->RemoveEntry->setEnabled(false); // let selection re-enable it
  593. }
  594. bool CMakeSetupDialog::setupFirstConfigure()
  595. {
  596. FirstConfigure dialog;
  597. // initialize dialog and restore saved settings
  598. // add generators
  599. dialog.setGenerators(this->CMakeThread->cmakeInstance()->availableGenerators());
  600. // restore from settings
  601. dialog.loadFromSettings();
  602. if(dialog.exec() == QDialog::Accepted)
  603. {
  604. dialog.saveToSettings();
  605. this->CMakeThread->cmakeInstance()->setGenerator(dialog.getGenerator());
  606. QCMakeCacheModel* m = this->CacheValues->cacheModel();
  607. if(dialog.compilerSetup())
  608. {
  609. QString fortranCompiler = dialog.getFortranCompiler();
  610. if(!fortranCompiler.isEmpty())
  611. {
  612. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
  613. "Fortran compiler.", fortranCompiler, false);
  614. }
  615. QString cxxCompiler = dialog.getCXXCompiler();
  616. if(!cxxCompiler.isEmpty())
  617. {
  618. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
  619. "CXX compiler.", cxxCompiler, false);
  620. }
  621. QString cCompiler = dialog.getCCompiler();
  622. if(!cCompiler.isEmpty())
  623. {
  624. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
  625. "C compiler.", cCompiler, false);
  626. }
  627. }
  628. else if(dialog.crossCompilerSetup())
  629. {
  630. QString fortranCompiler = dialog.getFortranCompiler();
  631. if(!fortranCompiler.isEmpty())
  632. {
  633. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
  634. "Fortran compiler.", fortranCompiler, false);
  635. }
  636. QString mode = dialog.getCrossIncludeMode();
  637. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE",
  638. tr("CMake Find Include Mode"), mode, false);
  639. mode = dialog.getCrossLibraryMode();
  640. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY",
  641. tr("CMake Find Library Mode"), mode, false);
  642. mode = dialog.getCrossProgramMode();
  643. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM",
  644. tr("CMake Find Program Mode"), mode, false);
  645. QString rootPath = dialog.getCrossRoot();
  646. m->insertProperty(QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH",
  647. tr("CMake Find Root Path"), rootPath, false);
  648. QString systemName = dialog.getSystemName();
  649. m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME",
  650. tr("CMake System Name"), systemName, false);
  651. QString systemVersion = dialog.getSystemVersion();
  652. m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_VERSION",
  653. tr("CMake System Version"), systemVersion, false);
  654. QString cxxCompiler = dialog.getCXXCompiler();
  655. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
  656. tr("CXX compiler."), cxxCompiler, false);
  657. QString cCompiler = dialog.getCCompiler();
  658. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
  659. tr("C compiler."), cCompiler, false);
  660. }
  661. else if(dialog.crossCompilerToolChainFile())
  662. {
  663. QString toolchainFile = dialog.getCrossCompilerToolChainFile();
  664. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE",
  665. tr("Cross Compile ToolChain File"), toolchainFile, false);
  666. }
  667. return true;
  668. }
  669. return false;
  670. }
  671. void CMakeSetupDialog::updateGeneratorLabel(const QString& gen)
  672. {
  673. QString str = tr("Current Generator: ");
  674. if(gen.isEmpty())
  675. {
  676. str += tr("None");
  677. }
  678. else
  679. {
  680. str += gen;
  681. }
  682. this->Generator->setText(str);
  683. }
  684. void CMakeSetupDialog::doReloadCache()
  685. {
  686. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  687. "reloadCache", Qt::QueuedConnection);
  688. }
  689. void CMakeSetupDialog::doDeleteCache()
  690. {
  691. QString title = tr("Delete Cache");
  692. QString msg = tr("Are you sure you want to delete the cache?");
  693. QMessageBox::StandardButton btn;
  694. btn = QMessageBox::information(this, title, msg,
  695. QMessageBox::Yes | QMessageBox::No);
  696. if(btn == QMessageBox::No)
  697. {
  698. return;
  699. }
  700. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  701. "deleteCache", Qt::QueuedConnection);
  702. }
  703. void CMakeSetupDialog::doAbout()
  704. {
  705. QString msg = tr(
  706. "CMake %1 (cmake.org).\n"
  707. "CMake suite maintained and supported by Kitware (kitware.com/cmake).\n"
  708. "Distributed under terms of the BSD 3-Clause License.\n"
  709. "\n"
  710. "CMake GUI maintained by csimsoft,\n"
  711. "built using Qt %2 (qt-project.org).\n"
  712. #ifdef CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL
  713. "\n"
  714. "The Qt Toolkit is Copyright (C) Digia Plc and/or its subsidiary(-ies).\n"
  715. "Qt is licensed under terms of the GNU LGPLv2.1, available at:\n"
  716. " \"%3\""
  717. #endif
  718. );
  719. msg = msg.arg(cmVersion::GetCMakeVersion());
  720. msg = msg.arg(qVersion());
  721. #ifdef CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL
  722. std::string lgpl = cmSystemTools::GetCMakeRoot()+"/Licenses/LGPLv2.1.txt";
  723. msg = msg.arg(lgpl.c_str());
  724. #endif
  725. QDialog dialog;
  726. dialog.setWindowTitle(tr("About"));
  727. QVBoxLayout* l = new QVBoxLayout(&dialog);
  728. QLabel* lab = new QLabel(&dialog);
  729. l->addWidget(lab);
  730. lab->setText(msg);
  731. lab->setWordWrap(true);
  732. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
  733. Qt::Horizontal, &dialog);
  734. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  735. l->addWidget(btns);
  736. dialog.exec();
  737. }
  738. void CMakeSetupDialog::setExitAfterGenerate(bool b)
  739. {
  740. this->ExitAfterGenerate = b;
  741. }
  742. void CMakeSetupDialog::addBinaryPath(const QString& path)
  743. {
  744. QString cleanpath = QDir::cleanPath(path);
  745. // update UI
  746. this->BinaryDirectory->blockSignals(true);
  747. int idx = this->BinaryDirectory->findText(cleanpath);
  748. if(idx != -1)
  749. {
  750. this->BinaryDirectory->removeItem(idx);
  751. }
  752. this->BinaryDirectory->insertItem(0, cleanpath);
  753. this->BinaryDirectory->setCurrentIndex(0);
  754. this->BinaryDirectory->blockSignals(false);
  755. // save to registry
  756. QStringList buildPaths = this->loadBuildPaths();
  757. buildPaths.removeAll(cleanpath);
  758. buildPaths.prepend(cleanpath);
  759. this->saveBuildPaths(buildPaths);
  760. }
  761. void CMakeSetupDialog::dragEnterEvent(QDragEnterEvent* e)
  762. {
  763. if(!(this->CurrentState == ReadyConfigure ||
  764. this->CurrentState == ReadyGenerate))
  765. {
  766. e->ignore();
  767. return;
  768. }
  769. const QMimeData* dat = e->mimeData();
  770. QList<QUrl> urls = dat->urls();
  771. QString file = urls.count() ? urls[0].toLocalFile() : QString();
  772. if(!file.isEmpty() &&
  773. (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive) ||
  774. file.endsWith("CMakeLists.txt", Qt::CaseInsensitive) ) )
  775. {
  776. e->accept();
  777. }
  778. else
  779. {
  780. e->ignore();
  781. }
  782. }
  783. void CMakeSetupDialog::dropEvent(QDropEvent* e)
  784. {
  785. if(!(this->CurrentState == ReadyConfigure ||
  786. this->CurrentState == ReadyGenerate))
  787. {
  788. return;
  789. }
  790. const QMimeData* dat = e->mimeData();
  791. QList<QUrl> urls = dat->urls();
  792. QString file = urls.count() ? urls[0].toLocalFile() : QString();
  793. if(file.endsWith("CMakeCache.txt", Qt::CaseInsensitive))
  794. {
  795. QFileInfo info(file);
  796. if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
  797. {
  798. this->setBinaryDirectory(info.absolutePath());
  799. }
  800. }
  801. else if(file.endsWith("CMakeLists.txt", Qt::CaseInsensitive))
  802. {
  803. QFileInfo info(file);
  804. if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
  805. {
  806. this->setSourceDirectory(info.absolutePath());
  807. this->setBinaryDirectory(info.absolutePath());
  808. }
  809. }
  810. }
  811. QStringList CMakeSetupDialog::loadBuildPaths()
  812. {
  813. QSettings settings;
  814. settings.beginGroup("Settings/StartPath");
  815. QStringList buildPaths;
  816. for(int i=0; i<10; i++)
  817. {
  818. QString p = settings.value(QString("WhereBuild%1").arg(i)).toString();
  819. if(!p.isEmpty())
  820. {
  821. buildPaths.append(p);
  822. }
  823. }
  824. return buildPaths;
  825. }
  826. void CMakeSetupDialog::saveBuildPaths(const QStringList& paths)
  827. {
  828. QSettings settings;
  829. settings.beginGroup("Settings/StartPath");
  830. int num = paths.count();
  831. if(num > 10)
  832. {
  833. num = 10;
  834. }
  835. for(int i=0; i<num; i++)
  836. {
  837. settings.setValue(QString("WhereBuild%1").arg(i), paths[i]);
  838. }
  839. }
  840. void CMakeSetupDialog::setCacheModified()
  841. {
  842. this->CacheModified = true;
  843. this->ConfigureNeeded = true;
  844. this->enterState(ReadyConfigure);
  845. }
  846. void CMakeSetupDialog::removeSelectedCacheEntries()
  847. {
  848. QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
  849. QList<QPersistentModelIndex> pidxs;
  850. foreach(QModelIndex i, idxs)
  851. {
  852. pidxs.append(i);
  853. }
  854. foreach(QPersistentModelIndex pi, pidxs)
  855. {
  856. this->CacheValues->model()->removeRow(pi.row(), pi.parent());
  857. }
  858. }
  859. void CMakeSetupDialog::selectionChanged()
  860. {
  861. QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
  862. if(idxs.count() &&
  863. (this->CurrentState == ReadyConfigure ||
  864. this->CurrentState == ReadyGenerate) )
  865. {
  866. this->RemoveEntry->setEnabled(true);
  867. }
  868. else
  869. {
  870. this->RemoveEntry->setEnabled(false);
  871. }
  872. }
  873. void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
  874. {
  875. if(s == this->CurrentState)
  876. {
  877. return;
  878. }
  879. this->CurrentState = s;
  880. if(s == Interrupting)
  881. {
  882. this->ConfigureButton->setEnabled(false);
  883. this->GenerateButton->setEnabled(false);
  884. }
  885. else if(s == Configuring)
  886. {
  887. this->setEnabledState(false);
  888. this->GenerateButton->setEnabled(false);
  889. this->GenerateAction->setEnabled(false);
  890. this->ConfigureButton->setText(tr("&Stop"));
  891. }
  892. else if(s == Generating)
  893. {
  894. this->CacheModified = false;
  895. this->setEnabledState(false);
  896. this->ConfigureButton->setEnabled(false);
  897. this->GenerateAction->setEnabled(false);
  898. this->GenerateButton->setText(tr("&Stop"));
  899. }
  900. else if(s == ReadyConfigure)
  901. {
  902. this->setEnabledState(true);
  903. this->GenerateButton->setEnabled(true);
  904. this->GenerateAction->setEnabled(true);
  905. this->ConfigureButton->setEnabled(true);
  906. this->ConfigureButton->setText(tr("&Configure"));
  907. this->GenerateButton->setText(tr("&Generate"));
  908. }
  909. else if(s == ReadyGenerate)
  910. {
  911. this->setEnabledState(true);
  912. this->GenerateButton->setEnabled(true);
  913. this->GenerateAction->setEnabled(true);
  914. this->ConfigureButton->setEnabled(true);
  915. this->ConfigureButton->setText(tr("&Configure"));
  916. this->GenerateButton->setText(tr("&Generate"));
  917. }
  918. }
  919. void CMakeSetupDialog::addCacheEntry()
  920. {
  921. QDialog dialog(this);
  922. dialog.resize(400, 200);
  923. dialog.setWindowTitle(tr("Add Cache Entry"));
  924. QVBoxLayout* l = new QVBoxLayout(&dialog);
  925. AddCacheEntry* w = new AddCacheEntry(&dialog, this->AddVariableNames,
  926. this->AddVariableTypes);
  927. QDialogButtonBox* btns = new QDialogButtonBox(
  928. QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
  929. Qt::Horizontal, &dialog);
  930. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  931. QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(reject()));
  932. l->addWidget(w);
  933. l->addStretch();
  934. l->addWidget(btns);
  935. if(QDialog::Accepted == dialog.exec())
  936. {
  937. QCMakeCacheModel* m = this->CacheValues->cacheModel();
  938. m->insertProperty(w->type(), w->name(), w->description(), w->value(), false);
  939. // only add variable names to the completion which are new
  940. if (!this->AddVariableNames.contains(w->name()))
  941. {
  942. this->AddVariableNames << w->name();
  943. this->AddVariableTypes << w->typeString();
  944. // limit to at most 100 completion items
  945. if (this->AddVariableNames.size() > 100)
  946. {
  947. this->AddVariableNames.removeFirst();
  948. this->AddVariableTypes.removeFirst();
  949. }
  950. // make sure CMAKE_INSTALL_PREFIX is always there
  951. if (!this->AddVariableNames.contains("CMAKE_INSTALL_PREFIX"))
  952. {
  953. this->AddVariableNames << "CMAKE_INSTALL_PREFIX";
  954. this->AddVariableTypes << "PATH";
  955. }
  956. QSettings settings;
  957. settings.beginGroup("Settings/StartPath");
  958. settings.setValue("AddVariableNames", this->AddVariableNames);
  959. settings.setValue("AddVariableTypes", this->AddVariableTypes);
  960. }
  961. }
  962. }
  963. void CMakeSetupDialog::startSearch()
  964. {
  965. this->Search->setFocus(Qt::OtherFocusReason);
  966. this->Search->selectAll();
  967. }
  968. void CMakeSetupDialog::setDebugOutput(bool flag)
  969. {
  970. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  971. "setDebugOutput", Qt::QueuedConnection, Q_ARG(bool, flag));
  972. }
  973. void CMakeSetupDialog::setGroupedView(bool v)
  974. {
  975. this->CacheValues->cacheModel()->setViewType(v ? QCMakeCacheModel::GroupView : QCMakeCacheModel::FlatView);
  976. this->CacheValues->setRootIsDecorated(v);
  977. QSettings settings;
  978. settings.beginGroup("Settings/StartPath");
  979. settings.setValue("GroupView", v);
  980. }
  981. void CMakeSetupDialog::setAdvancedView(bool v)
  982. {
  983. this->CacheValues->setShowAdvanced(v);
  984. QSettings settings;
  985. settings.beginGroup("Settings/StartPath");
  986. settings.setValue("AdvancedView", v);
  987. }
  988. void CMakeSetupDialog::showUserChanges()
  989. {
  990. QSet<QCMakeProperty> changes =
  991. qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())->changes();
  992. QDialog dialog(this);
  993. dialog.setWindowTitle(tr("My Changes"));
  994. dialog.resize(600, 400);
  995. QVBoxLayout* l = new QVBoxLayout(&dialog);
  996. QTextEdit* textedit = new QTextEdit(&dialog);
  997. textedit->setReadOnly(true);
  998. l->addWidget(textedit);
  999. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Close,
  1000. Qt::Horizontal, &dialog);
  1001. QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(accept()));
  1002. l->addWidget(btns);
  1003. QString command;
  1004. QString cache;
  1005. foreach(QCMakeProperty prop, changes)
  1006. {
  1007. QString type;
  1008. switch(prop.Type)
  1009. {
  1010. case QCMakeProperty::BOOL:
  1011. type = "BOOL";
  1012. break;
  1013. case QCMakeProperty::PATH:
  1014. type = "PATH";
  1015. break;
  1016. case QCMakeProperty::FILEPATH:
  1017. type = "FILEPATH";
  1018. break;
  1019. case QCMakeProperty::STRING:
  1020. type = "STRING";
  1021. break;
  1022. }
  1023. QString value;
  1024. if(prop.Type == QCMakeProperty::BOOL)
  1025. {
  1026. value = prop.Value.toBool() ? "1" : "0";
  1027. }
  1028. else
  1029. {
  1030. value = prop.Value.toString();
  1031. }
  1032. QString line("%1:%2=");
  1033. line = line.arg(prop.Key);
  1034. line = line.arg(type);
  1035. command += QString("-D%1\"%2\" ").arg(line).arg(value);
  1036. cache += QString("%1%2\n").arg(line).arg(value);
  1037. }
  1038. textedit->append(tr("Commandline options:"));
  1039. textedit->append(command);
  1040. textedit->append("\n");
  1041. textedit->append(tr("Cache file:"));
  1042. textedit->append(cache);
  1043. dialog.exec();
  1044. }
  1045. void CMakeSetupDialog::setSearchFilter(const QString& str)
  1046. {
  1047. this->CacheValues->selectionModel()->clear();
  1048. this->CacheValues->setSearchFilter(str);
  1049. }
  1050. void CMakeSetupDialog::doOutputContextMenu(const QPoint &pt)
  1051. {
  1052. QMenu *menu = this->Output->createStandardContextMenu();
  1053. menu->addSeparator();
  1054. menu->addAction(tr("Find..."),
  1055. this, SLOT(doOutputFindDialog()), QKeySequence::Find);
  1056. menu->addAction(tr("Find Next"),
  1057. this, SLOT(doOutputFindNext()), QKeySequence::FindNext);
  1058. menu->addAction(tr("Find Previous"),
  1059. this, SLOT(doOutputFindPrev()), QKeySequence::FindPrevious);
  1060. menu->addSeparator();
  1061. menu->addAction(tr("Goto Next Error"),
  1062. this, SLOT(doOutputErrorNext()), QKeySequence(Qt::Key_F8));
  1063. menu->exec(this->Output->mapToGlobal(pt));
  1064. delete menu;
  1065. }
  1066. void CMakeSetupDialog::doOutputFindDialog()
  1067. {
  1068. QStringList strings(this->FindHistory);
  1069. QString selection = this->Output->textCursor().selectedText();
  1070. if (!selection.isEmpty() &&
  1071. !selection.contains(QChar::ParagraphSeparator) &&
  1072. !selection.contains(QChar::LineSeparator))
  1073. {
  1074. strings.push_front(selection);
  1075. }
  1076. bool ok;
  1077. QString search = QInputDialog::getItem(this, tr("Find in Output"),
  1078. tr("Find:"), strings, 0, true, &ok);
  1079. if (ok && !search.isEmpty())
  1080. {
  1081. if (!this->FindHistory.contains(search))
  1082. {
  1083. this->FindHistory.push_front(search);
  1084. }
  1085. doOutputFindNext();
  1086. }
  1087. }
  1088. void CMakeSetupDialog::doOutputFindPrev()
  1089. {
  1090. doOutputFindNext(false);
  1091. }
  1092. void CMakeSetupDialog::doOutputFindNext(bool directionForward)
  1093. {
  1094. if (this->FindHistory.isEmpty())
  1095. {
  1096. doOutputFindDialog(); //will re-call this function again
  1097. return;
  1098. }
  1099. QString search = this->FindHistory.front();
  1100. QTextCursor textCursor = this->Output->textCursor();
  1101. QTextDocument* document = this->Output->document();
  1102. QTextDocument::FindFlags flags;
  1103. if (!directionForward)
  1104. {
  1105. flags |= QTextDocument::FindBackward;
  1106. }
  1107. textCursor = document->find(search, textCursor, flags);
  1108. if (textCursor.isNull())
  1109. {
  1110. // first search found nothing, wrap around and search again
  1111. textCursor = this->Output->textCursor();
  1112. textCursor.movePosition(directionForward ? QTextCursor::Start
  1113. : QTextCursor::End);
  1114. textCursor = document->find(search, textCursor, flags);
  1115. }
  1116. if (textCursor.hasSelection())
  1117. {
  1118. this->Output->setTextCursor(textCursor);
  1119. }
  1120. }
  1121. void CMakeSetupDialog::doOutputErrorNext()
  1122. {
  1123. QTextCursor textCursor = this->Output->textCursor();
  1124. bool atEnd = false;
  1125. // move cursor out of current error-block
  1126. if (textCursor.blockCharFormat() == this->ErrorFormat)
  1127. {
  1128. atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
  1129. }
  1130. // move cursor to next error-block
  1131. while (textCursor.blockCharFormat() != this->ErrorFormat && !atEnd)
  1132. {
  1133. atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
  1134. }
  1135. if (atEnd)
  1136. {
  1137. // first search found nothing, wrap around and search again
  1138. atEnd = !textCursor.movePosition(QTextCursor::Start);
  1139. // move cursor to next error-block
  1140. while (textCursor.blockCharFormat() != this->ErrorFormat && !atEnd)
  1141. {
  1142. atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
  1143. }
  1144. }
  1145. if (!atEnd)
  1146. {
  1147. textCursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
  1148. QTextCharFormat selectionFormat;
  1149. selectionFormat.setBackground(Qt::yellow);
  1150. QTextEdit::ExtraSelection extraSelection = {textCursor, selectionFormat};
  1151. this->Output->setExtraSelections(QList<QTextEdit::ExtraSelection>()
  1152. << extraSelection);
  1153. // make the whole error-block visible
  1154. this->Output->setTextCursor(textCursor);
  1155. // remove the selection to see the extraSelection
  1156. textCursor.setPosition(textCursor.anchor());
  1157. this->Output->setTextCursor(textCursor);
  1158. }
  1159. }