CMakeSetupDialog.cxx 42 KB

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