CMakeSetupDialog.cxx 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326
  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. if(!dir.isEmpty())
  499. {
  500. this->setSourceDirectory(dir);
  501. }
  502. }
  503. void CMakeSetupDialog::updateSourceDirectory(const QString& dir)
  504. {
  505. if(this->SourceDirectory->text() != dir)
  506. {
  507. this->SourceDirectory->blockSignals(true);
  508. this->SourceDirectory->setText(dir);
  509. this->SourceDirectory->blockSignals(false);
  510. }
  511. }
  512. void CMakeSetupDialog::updateBinaryDirectory(const QString& dir)
  513. {
  514. if(this->BinaryDirectory->currentText() != dir)
  515. {
  516. this->BinaryDirectory->blockSignals(true);
  517. this->BinaryDirectory->setEditText(dir);
  518. this->BinaryDirectory->blockSignals(false);
  519. }
  520. }
  521. void CMakeSetupDialog::doBinaryBrowse()
  522. {
  523. QString dir = QFileDialog::getExistingDirectory(this,
  524. tr("Enter Path to Build"), this->BinaryDirectory->currentText());
  525. if(!dir.isEmpty() && dir != this->BinaryDirectory->currentText())
  526. {
  527. this->setBinaryDirectory(dir);
  528. }
  529. }
  530. void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
  531. {
  532. this->BinaryDirectory->setEditText(dir);
  533. }
  534. void CMakeSetupDialog::onSourceDirectoryChanged(const QString& dir)
  535. {
  536. this->Output->clear();
  537. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  538. "setSourceDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
  539. }
  540. void CMakeSetupDialog::onBinaryDirectoryChanged(const QString& dir)
  541. {
  542. QString title = QString(tr("CMake %1 - %2"));
  543. title = title.arg(cmVersion::GetCMakeVersion());
  544. title = title.arg(dir);
  545. this->setWindowTitle(title);
  546. this->CacheModified = false;
  547. this->CacheValues->cacheModel()->clear();
  548. qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())->clearChanges();
  549. this->Output->clear();
  550. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  551. "setBinaryDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
  552. }
  553. void CMakeSetupDialog::setSourceDirectory(const QString& dir)
  554. {
  555. this->SourceDirectory->setText(dir);
  556. }
  557. void CMakeSetupDialog::showProgress(const QString& /*msg*/, float percent)
  558. {
  559. percent = (percent * ProgressFactor) + ProgressOffset;
  560. this->ProgressBar->setValue(qRound(percent * 100));
  561. }
  562. void CMakeSetupDialog::error(const QString& msg)
  563. {
  564. this->Output->setCurrentCharFormat(this->ErrorFormat);
  565. //QTextEdit will terminate the msg with a ParagraphSeparator, but it also replaces
  566. //all newlines with ParagraphSeparators. By replacing the newlines by ourself, one
  567. //error msg will be one paragraph.
  568. QString paragraph(msg);
  569. paragraph.replace(QLatin1Char('\n'), QChar::LineSeparator);
  570. this->Output->append(paragraph);
  571. }
  572. void CMakeSetupDialog::message(const QString& msg)
  573. {
  574. this->Output->setCurrentCharFormat(this->MessageFormat);
  575. this->Output->append(msg);
  576. }
  577. void CMakeSetupDialog::setEnabledState(bool enabled)
  578. {
  579. // disable parts of the GUI during configure/generate
  580. this->CacheValues->cacheModel()->setEditEnabled(enabled);
  581. this->SourceDirectory->setEnabled(enabled);
  582. this->BrowseSourceDirectoryButton->setEnabled(enabled);
  583. this->BinaryDirectory->setEnabled(enabled);
  584. this->BrowseBinaryDirectoryButton->setEnabled(enabled);
  585. this->ReloadCacheAction->setEnabled(enabled);
  586. this->DeleteCacheAction->setEnabled(enabled);
  587. this->ExitAction->setEnabled(enabled);
  588. this->ConfigureAction->setEnabled(enabled);
  589. this->AddEntry->setEnabled(enabled);
  590. this->RemoveEntry->setEnabled(false); // let selection re-enable it
  591. }
  592. bool CMakeSetupDialog::setupFirstConfigure()
  593. {
  594. FirstConfigure dialog;
  595. // initialize dialog and restore saved settings
  596. // add generators
  597. dialog.setGenerators(this->CMakeThread->cmakeInstance()->availableGenerators());
  598. // restore from settings
  599. dialog.loadFromSettings();
  600. if(dialog.exec() == QDialog::Accepted)
  601. {
  602. dialog.saveToSettings();
  603. this->CMakeThread->cmakeInstance()->setGenerator(dialog.getGenerator());
  604. QCMakeCacheModel* m = this->CacheValues->cacheModel();
  605. if(dialog.compilerSetup())
  606. {
  607. QString fortranCompiler = dialog.getFortranCompiler();
  608. if(!fortranCompiler.isEmpty())
  609. {
  610. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
  611. "Fortran compiler.", fortranCompiler, false);
  612. }
  613. QString cxxCompiler = dialog.getCXXCompiler();
  614. if(!cxxCompiler.isEmpty())
  615. {
  616. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
  617. "CXX compiler.", cxxCompiler, false);
  618. }
  619. QString cCompiler = dialog.getCCompiler();
  620. if(!cCompiler.isEmpty())
  621. {
  622. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
  623. "C compiler.", cCompiler, false);
  624. }
  625. }
  626. else if(dialog.crossCompilerSetup())
  627. {
  628. QString fortranCompiler = dialog.getFortranCompiler();
  629. if(!fortranCompiler.isEmpty())
  630. {
  631. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
  632. "Fortran compiler.", fortranCompiler, false);
  633. }
  634. QString mode = dialog.getCrossIncludeMode();
  635. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE",
  636. tr("CMake Find Include Mode"), mode, false);
  637. mode = dialog.getCrossLibraryMode();
  638. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY",
  639. tr("CMake Find Library Mode"), mode, false);
  640. mode = dialog.getCrossProgramMode();
  641. m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM",
  642. tr("CMake Find Program Mode"), mode, false);
  643. QString rootPath = dialog.getCrossRoot();
  644. m->insertProperty(QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH",
  645. tr("CMake Find Root Path"), rootPath, false);
  646. QString systemName = dialog.getSystemName();
  647. m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME",
  648. tr("CMake System Name"), systemName, false);
  649. QString cxxCompiler = dialog.getCXXCompiler();
  650. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
  651. tr("CXX compiler."), cxxCompiler, false);
  652. QString cCompiler = dialog.getCCompiler();
  653. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
  654. tr("C compiler."), cCompiler, false);
  655. }
  656. else if(dialog.crossCompilerToolChainFile())
  657. {
  658. QString toolchainFile = dialog.getCrossCompilerToolChainFile();
  659. m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE",
  660. tr("Cross Compile ToolChain File"), toolchainFile, false);
  661. }
  662. return true;
  663. }
  664. return false;
  665. }
  666. void CMakeSetupDialog::updateGeneratorLabel(const QString& gen)
  667. {
  668. QString str = tr("Current Generator: ");
  669. if(gen.isEmpty())
  670. {
  671. str += tr("None");
  672. }
  673. else
  674. {
  675. str += gen;
  676. }
  677. this->Generator->setText(str);
  678. }
  679. void CMakeSetupDialog::doReloadCache()
  680. {
  681. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  682. "reloadCache", Qt::QueuedConnection);
  683. }
  684. void CMakeSetupDialog::doDeleteCache()
  685. {
  686. QString title = tr("Delete Cache");
  687. QString msg = tr("Are you sure you want to delete the cache?");
  688. QMessageBox::StandardButton btn;
  689. btn = QMessageBox::information(this, title, msg,
  690. QMessageBox::Yes | QMessageBox::No);
  691. if(btn == QMessageBox::No)
  692. {
  693. return;
  694. }
  695. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  696. "deleteCache", Qt::QueuedConnection);
  697. }
  698. void CMakeSetupDialog::doAbout()
  699. {
  700. QString msg = tr(
  701. "CMake %1 (cmake.org).\n"
  702. "CMake suite maintained and supported by Kitware (kitware.com/cmake).\n"
  703. "Distributed under terms of the BSD 3-Clause License.\n"
  704. "\n"
  705. "CMake GUI maintained by csimsoft,\n"
  706. "built using Qt %2 (qt-project.org).\n"
  707. #ifdef CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL
  708. "\n"
  709. "The Qt Toolkit is Copyright (C) Digia Plc and/or its subsidiary(-ies).\n"
  710. "Qt is licensed under terms of the GNU LGPLv2.1, available at:\n"
  711. " \"%3\""
  712. #endif
  713. );
  714. msg = msg.arg(cmVersion::GetCMakeVersion());
  715. msg = msg.arg(qVersion());
  716. #ifdef CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL
  717. std::string lgpl = cmSystemTools::GetCMakeRoot()+"/Licenses/LGPLv2.1.txt";
  718. msg = msg.arg(lgpl.c_str());
  719. #endif
  720. QDialog dialog;
  721. dialog.setWindowTitle(tr("About"));
  722. QVBoxLayout* l = new QVBoxLayout(&dialog);
  723. QLabel* lab = new QLabel(&dialog);
  724. l->addWidget(lab);
  725. lab->setText(msg);
  726. lab->setWordWrap(true);
  727. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
  728. Qt::Horizontal, &dialog);
  729. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  730. l->addWidget(btns);
  731. dialog.exec();
  732. }
  733. void CMakeSetupDialog::setExitAfterGenerate(bool b)
  734. {
  735. this->ExitAfterGenerate = b;
  736. }
  737. void CMakeSetupDialog::addBinaryPath(const QString& path)
  738. {
  739. QString cleanpath = QDir::cleanPath(path);
  740. // update UI
  741. this->BinaryDirectory->blockSignals(true);
  742. int idx = this->BinaryDirectory->findText(cleanpath);
  743. if(idx != -1)
  744. {
  745. this->BinaryDirectory->removeItem(idx);
  746. }
  747. this->BinaryDirectory->insertItem(0, cleanpath);
  748. this->BinaryDirectory->setCurrentIndex(0);
  749. this->BinaryDirectory->blockSignals(false);
  750. // save to registry
  751. QStringList buildPaths = this->loadBuildPaths();
  752. buildPaths.removeAll(cleanpath);
  753. buildPaths.prepend(cleanpath);
  754. this->saveBuildPaths(buildPaths);
  755. }
  756. void CMakeSetupDialog::dragEnterEvent(QDragEnterEvent* e)
  757. {
  758. if(!(this->CurrentState == ReadyConfigure ||
  759. this->CurrentState == ReadyGenerate))
  760. {
  761. e->ignore();
  762. return;
  763. }
  764. const QMimeData* dat = e->mimeData();
  765. QList<QUrl> urls = dat->urls();
  766. QString file = urls.count() ? urls[0].toLocalFile() : QString();
  767. if(!file.isEmpty() &&
  768. (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive) ||
  769. file.endsWith("CMakeLists.txt", Qt::CaseInsensitive) ) )
  770. {
  771. e->accept();
  772. }
  773. else
  774. {
  775. e->ignore();
  776. }
  777. }
  778. void CMakeSetupDialog::dropEvent(QDropEvent* e)
  779. {
  780. if(!(this->CurrentState == ReadyConfigure ||
  781. this->CurrentState == ReadyGenerate))
  782. {
  783. return;
  784. }
  785. const QMimeData* dat = e->mimeData();
  786. QList<QUrl> urls = dat->urls();
  787. QString file = urls.count() ? urls[0].toLocalFile() : QString();
  788. if(file.endsWith("CMakeCache.txt", Qt::CaseInsensitive))
  789. {
  790. QFileInfo info(file);
  791. if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
  792. {
  793. this->setBinaryDirectory(info.absolutePath());
  794. }
  795. }
  796. else if(file.endsWith("CMakeLists.txt", Qt::CaseInsensitive))
  797. {
  798. QFileInfo info(file);
  799. if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
  800. {
  801. this->setSourceDirectory(info.absolutePath());
  802. this->setBinaryDirectory(info.absolutePath());
  803. }
  804. }
  805. }
  806. QStringList CMakeSetupDialog::loadBuildPaths()
  807. {
  808. QSettings settings;
  809. settings.beginGroup("Settings/StartPath");
  810. QStringList buildPaths;
  811. for(int i=0; i<10; i++)
  812. {
  813. QString p = settings.value(QString("WhereBuild%1").arg(i)).toString();
  814. if(!p.isEmpty())
  815. {
  816. buildPaths.append(p);
  817. }
  818. }
  819. return buildPaths;
  820. }
  821. void CMakeSetupDialog::saveBuildPaths(const QStringList& paths)
  822. {
  823. QSettings settings;
  824. settings.beginGroup("Settings/StartPath");
  825. int num = paths.count();
  826. if(num > 10)
  827. {
  828. num = 10;
  829. }
  830. for(int i=0; i<num; i++)
  831. {
  832. settings.setValue(QString("WhereBuild%1").arg(i), paths[i]);
  833. }
  834. }
  835. void CMakeSetupDialog::setCacheModified()
  836. {
  837. this->CacheModified = true;
  838. this->ConfigureNeeded = true;
  839. this->enterState(ReadyConfigure);
  840. }
  841. void CMakeSetupDialog::removeSelectedCacheEntries()
  842. {
  843. QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
  844. QList<QPersistentModelIndex> pidxs;
  845. foreach(QModelIndex i, idxs)
  846. {
  847. pidxs.append(i);
  848. }
  849. foreach(QPersistentModelIndex pi, pidxs)
  850. {
  851. this->CacheValues->model()->removeRow(pi.row(), pi.parent());
  852. }
  853. }
  854. void CMakeSetupDialog::selectionChanged()
  855. {
  856. QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
  857. if(idxs.count() &&
  858. (this->CurrentState == ReadyConfigure ||
  859. this->CurrentState == ReadyGenerate) )
  860. {
  861. this->RemoveEntry->setEnabled(true);
  862. }
  863. else
  864. {
  865. this->RemoveEntry->setEnabled(false);
  866. }
  867. }
  868. void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
  869. {
  870. if(s == this->CurrentState)
  871. {
  872. return;
  873. }
  874. this->CurrentState = s;
  875. if(s == Interrupting)
  876. {
  877. this->ConfigureButton->setEnabled(false);
  878. this->GenerateButton->setEnabled(false);
  879. }
  880. else if(s == Configuring)
  881. {
  882. this->setEnabledState(false);
  883. this->GenerateButton->setEnabled(false);
  884. this->GenerateAction->setEnabled(false);
  885. this->ConfigureButton->setText(tr("&Stop"));
  886. }
  887. else if(s == Generating)
  888. {
  889. this->CacheModified = false;
  890. this->setEnabledState(false);
  891. this->ConfigureButton->setEnabled(false);
  892. this->GenerateAction->setEnabled(false);
  893. this->GenerateButton->setText(tr("&Stop"));
  894. }
  895. else if(s == ReadyConfigure)
  896. {
  897. this->setEnabledState(true);
  898. this->GenerateButton->setEnabled(true);
  899. this->GenerateAction->setEnabled(true);
  900. this->ConfigureButton->setEnabled(true);
  901. this->ConfigureButton->setText(tr("&Configure"));
  902. this->GenerateButton->setText(tr("&Generate"));
  903. }
  904. else if(s == ReadyGenerate)
  905. {
  906. this->setEnabledState(true);
  907. this->GenerateButton->setEnabled(true);
  908. this->GenerateAction->setEnabled(true);
  909. this->ConfigureButton->setEnabled(true);
  910. this->ConfigureButton->setText(tr("&Configure"));
  911. this->GenerateButton->setText(tr("&Generate"));
  912. }
  913. }
  914. void CMakeSetupDialog::addCacheEntry()
  915. {
  916. QDialog dialog(this);
  917. dialog.resize(400, 200);
  918. dialog.setWindowTitle(tr("Add Cache Entry"));
  919. QVBoxLayout* l = new QVBoxLayout(&dialog);
  920. AddCacheEntry* w = new AddCacheEntry(&dialog, this->AddVariableNames,
  921. this->AddVariableTypes);
  922. QDialogButtonBox* btns = new QDialogButtonBox(
  923. QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
  924. Qt::Horizontal, &dialog);
  925. QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
  926. QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(reject()));
  927. l->addWidget(w);
  928. l->addStretch();
  929. l->addWidget(btns);
  930. if(QDialog::Accepted == dialog.exec())
  931. {
  932. QCMakeCacheModel* m = this->CacheValues->cacheModel();
  933. m->insertProperty(w->type(), w->name(), w->description(), w->value(), false);
  934. // only add variable names to the completion which are new
  935. if (!this->AddVariableNames.contains(w->name()))
  936. {
  937. this->AddVariableNames << w->name();
  938. this->AddVariableTypes << w->typeString();
  939. // limit to at most 100 completion items
  940. if (this->AddVariableNames.size() > 100)
  941. {
  942. this->AddVariableNames.removeFirst();
  943. this->AddVariableTypes.removeFirst();
  944. }
  945. // make sure CMAKE_INSTALL_PREFIX is always there
  946. if (!this->AddVariableNames.contains("CMAKE_INSTALL_PREFIX"))
  947. {
  948. this->AddVariableNames << "CMAKE_INSTALL_PREFIX";
  949. this->AddVariableTypes << "PATH";
  950. }
  951. QSettings settings;
  952. settings.beginGroup("Settings/StartPath");
  953. settings.setValue("AddVariableNames", this->AddVariableNames);
  954. settings.setValue("AddVariableTypes", this->AddVariableTypes);
  955. }
  956. }
  957. }
  958. void CMakeSetupDialog::startSearch()
  959. {
  960. this->Search->setFocus(Qt::OtherFocusReason);
  961. this->Search->selectAll();
  962. }
  963. void CMakeSetupDialog::setDebugOutput(bool flag)
  964. {
  965. QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
  966. "setDebugOutput", Qt::QueuedConnection, Q_ARG(bool, flag));
  967. }
  968. void CMakeSetupDialog::setGroupedView(bool v)
  969. {
  970. this->CacheValues->cacheModel()->setViewType(v ? QCMakeCacheModel::GroupView : QCMakeCacheModel::FlatView);
  971. this->CacheValues->setRootIsDecorated(v);
  972. QSettings settings;
  973. settings.beginGroup("Settings/StartPath");
  974. settings.setValue("GroupView", v);
  975. }
  976. void CMakeSetupDialog::setAdvancedView(bool v)
  977. {
  978. this->CacheValues->setShowAdvanced(v);
  979. QSettings settings;
  980. settings.beginGroup("Settings/StartPath");
  981. settings.setValue("AdvancedView", v);
  982. }
  983. void CMakeSetupDialog::showUserChanges()
  984. {
  985. QSet<QCMakeProperty> changes =
  986. qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())->changes();
  987. QDialog dialog(this);
  988. dialog.setWindowTitle(tr("My Changes"));
  989. dialog.resize(600, 400);
  990. QVBoxLayout* l = new QVBoxLayout(&dialog);
  991. QTextEdit* textedit = new QTextEdit(&dialog);
  992. textedit->setReadOnly(true);
  993. l->addWidget(textedit);
  994. QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Close,
  995. Qt::Horizontal, &dialog);
  996. QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(accept()));
  997. l->addWidget(btns);
  998. QString command;
  999. QString cache;
  1000. foreach(QCMakeProperty prop, changes)
  1001. {
  1002. QString type;
  1003. switch(prop.Type)
  1004. {
  1005. case QCMakeProperty::BOOL:
  1006. type = "BOOL";
  1007. break;
  1008. case QCMakeProperty::PATH:
  1009. type = "PATH";
  1010. break;
  1011. case QCMakeProperty::FILEPATH:
  1012. type = "FILEPATH";
  1013. break;
  1014. case QCMakeProperty::STRING:
  1015. type = "STRING";
  1016. break;
  1017. }
  1018. QString value;
  1019. if(prop.Type == QCMakeProperty::BOOL)
  1020. {
  1021. value = prop.Value.toBool() ? "1" : "0";
  1022. }
  1023. else
  1024. {
  1025. value = prop.Value.toString();
  1026. }
  1027. QString line("%1:%2=");
  1028. line = line.arg(prop.Key);
  1029. line = line.arg(type);
  1030. command += QString("-D%1\"%2\" ").arg(line).arg(value);
  1031. cache += QString("%1%2\n").arg(line).arg(value);
  1032. }
  1033. textedit->append(tr("Commandline options:"));
  1034. textedit->append(command);
  1035. textedit->append("\n");
  1036. textedit->append(tr("Cache file:"));
  1037. textedit->append(cache);
  1038. dialog.exec();
  1039. }
  1040. void CMakeSetupDialog::setSearchFilter(const QString& str)
  1041. {
  1042. this->CacheValues->selectionModel()->clear();
  1043. this->CacheValues->setSearchFilter(str);
  1044. }
  1045. void CMakeSetupDialog::doOutputContextMenu(const QPoint &pt)
  1046. {
  1047. QMenu *menu = this->Output->createStandardContextMenu();
  1048. menu->addSeparator();
  1049. menu->addAction(tr("Find..."),
  1050. this, SLOT(doOutputFindDialog()), QKeySequence::Find);
  1051. menu->addAction(tr("Find Next"),
  1052. this, SLOT(doOutputFindNext()), QKeySequence::FindNext);
  1053. menu->addAction(tr("Find Previous"),
  1054. this, SLOT(doOutputFindPrev()), QKeySequence::FindPrevious);
  1055. menu->addSeparator();
  1056. menu->addAction(tr("Goto Next Error"),
  1057. this, SLOT(doOutputErrorNext()), QKeySequence(Qt::Key_F8));
  1058. menu->exec(this->Output->mapToGlobal(pt));
  1059. delete menu;
  1060. }
  1061. void CMakeSetupDialog::doOutputFindDialog()
  1062. {
  1063. QStringList strings(this->FindHistory);
  1064. QString selection = this->Output->textCursor().selectedText();
  1065. if (!selection.isEmpty() &&
  1066. !selection.contains(QChar::ParagraphSeparator) &&
  1067. !selection.contains(QChar::LineSeparator))
  1068. {
  1069. strings.push_front(selection);
  1070. }
  1071. bool ok;
  1072. QString search = QInputDialog::getItem(this, tr("Find in Output"),
  1073. tr("Find:"), strings, 0, true, &ok);
  1074. if (ok && !search.isEmpty())
  1075. {
  1076. if (!this->FindHistory.contains(search))
  1077. {
  1078. this->FindHistory.push_front(search);
  1079. }
  1080. doOutputFindNext();
  1081. }
  1082. }
  1083. void CMakeSetupDialog::doOutputFindPrev()
  1084. {
  1085. doOutputFindNext(false);
  1086. }
  1087. void CMakeSetupDialog::doOutputFindNext(bool directionForward)
  1088. {
  1089. if (this->FindHistory.isEmpty())
  1090. {
  1091. doOutputFindDialog(); //will re-call this function again
  1092. return;
  1093. }
  1094. QString search = this->FindHistory.front();
  1095. QTextCursor textCursor = this->Output->textCursor();
  1096. QTextDocument* document = this->Output->document();
  1097. QTextDocument::FindFlags flags;
  1098. if (!directionForward)
  1099. {
  1100. flags |= QTextDocument::FindBackward;
  1101. }
  1102. textCursor = document->find(search, textCursor, flags);
  1103. if (textCursor.isNull())
  1104. {
  1105. // first search found nothing, wrap around and search again
  1106. textCursor = this->Output->textCursor();
  1107. textCursor.movePosition(directionForward ? QTextCursor::Start
  1108. : QTextCursor::End);
  1109. textCursor = document->find(search, textCursor, flags);
  1110. }
  1111. if (textCursor.hasSelection())
  1112. {
  1113. this->Output->setTextCursor(textCursor);
  1114. }
  1115. }
  1116. void CMakeSetupDialog::doOutputErrorNext()
  1117. {
  1118. QTextCursor textCursor = this->Output->textCursor();
  1119. bool atEnd = false;
  1120. // move cursor out of current error-block
  1121. if (textCursor.blockCharFormat() == this->ErrorFormat)
  1122. {
  1123. atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
  1124. }
  1125. // move cursor to next error-block
  1126. while (textCursor.blockCharFormat() != this->ErrorFormat && !atEnd)
  1127. {
  1128. atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
  1129. }
  1130. if (atEnd)
  1131. {
  1132. // first search found nothing, wrap around and search again
  1133. atEnd = !textCursor.movePosition(QTextCursor::Start);
  1134. // move cursor to next error-block
  1135. while (textCursor.blockCharFormat() != this->ErrorFormat && !atEnd)
  1136. {
  1137. atEnd = !textCursor.movePosition(QTextCursor::NextBlock);
  1138. }
  1139. }
  1140. if (!atEnd)
  1141. {
  1142. textCursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
  1143. QTextCharFormat selectionFormat;
  1144. selectionFormat.setBackground(Qt::yellow);
  1145. QTextEdit::ExtraSelection extraSelection = {textCursor, selectionFormat};
  1146. this->Output->setExtraSelections(QList<QTextEdit::ExtraSelection>()
  1147. << extraSelection);
  1148. // make the whole error-block visible
  1149. this->Output->setTextCursor(textCursor);
  1150. // remove the selection to see the extraSelection
  1151. textCursor.setPosition(textCursor.anchor());
  1152. this->Output->setTextCursor(textCursor);
  1153. }
  1154. }