| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386 | /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying   file Copyright.txt or https://cmake.org/licensing for details.  */#include "CMakeSetupDialog.h"#include <cm/memory>#include <QCloseEvent>#include <QCoreApplication>#include <QDesktopServices>#include <QDialogButtonBox>#include <QDragEnterEvent>#include <QFileDialog>#include <QInputDialog>#include <QKeySequence>#include <QMenu>#include <QMenuBar>#include <QMessageBox>#include <QMimeData>#include <QProcessEnvironment>#include <QProgressBar>#include <QSettings>#include <QShortcut>#include <QStatusBar>#include <QToolButton>#include <QUrl>#ifdef QT_WINEXTRAS#  include <QWinTaskbarButton>#  include <QWinTaskbarProgress>#endif#include "QCMake.h"#include "QCMakeCacheView.h"#include "cmSystemTools.h"#include "cmVersion.h"#include "AddCacheEntry.h"#include "EnvironmentDialog.h"#include "FirstConfigure.h"#include "RegexExplorer.h"#include "WarningMessagesDialog.h"QCMakeThread::QCMakeThread(QObject* p)  : QThread(p){}QCMake* QCMakeThread::cmakeInstance() const{  return this->CMakeInstance.get();}void QCMakeThread::run(){  this->CMakeInstance = cm::make_unique<QCMake>();  // emit that this cmake thread is ready for use  emit this->cmakeInitialized();  this->exec();  this->CMakeInstance.reset();}CMakeSetupDialog::CMakeSetupDialog()  : ExitAfterGenerate(true)  , CacheModified(false)  , ConfigureNeeded(true)  , CurrentState(Interrupting){  QString title = QString(tr("CMake %1"));  title = title.arg(cmVersion::GetCMakeVersion());  this->setWindowTitle(title);  // create the GUI  QSettings settings;  settings.beginGroup("Settings/StartPath");  restoreGeometry(settings.value("geometry").toByteArray());  restoreState(settings.value("windowState").toByteArray());  this->AddVariableNames =    settings.value("AddVariableNames", QStringList("CMAKE_INSTALL_PREFIX"))      .toStringList();  this->AddVariableTypes =    settings.value("AddVariableTypes", QStringList("PATH")).toStringList();  QWidget* cont = new QWidget(this);  this->setupUi(cont);  this->Splitter->setStretchFactor(0, 3);  this->Splitter->setStretchFactor(1, 1);  this->setCentralWidget(cont);  this->ProgressBar->reset();  this->RemoveEntry->setEnabled(false);  this->AddEntry->setEnabled(false);  QByteArray p = settings.value("SplitterSizes").toByteArray();  this->Splitter->restoreState(p);  bool groupView = settings.value("GroupView", false).toBool();  this->setGroupedView(groupView);  this->groupedCheck->setCheckState(groupView ? Qt::Checked : Qt::Unchecked);  bool advancedView = settings.value("AdvancedView", false).toBool();  this->setAdvancedView(advancedView);  this->advancedCheck->setCheckState(advancedView ? Qt::Checked                                                  : Qt::Unchecked);  QMenu* FileMenu = this->menuBar()->addMenu(tr("&File"));  this->ReloadCacheAction = FileMenu->addAction(tr("&Reload Cache"));  QObject::connect(this->ReloadCacheAction, &QAction::triggered, this,                   &CMakeSetupDialog::doReloadCache);  this->DeleteCacheAction = FileMenu->addAction(tr("&Delete Cache"));  QObject::connect(this->DeleteCacheAction, &QAction::triggered, this,                   &CMakeSetupDialog::doDeleteCache);  this->ExitAction = FileMenu->addAction(tr("E&xit"));  QObject::connect(this->ExitAction, &QAction::triggered, this,                   &CMakeSetupDialog::close);  this->ExitAction->setShortcut(QKeySequence::Quit);  QMenu* ToolsMenu = this->menuBar()->addMenu(tr("&Tools"));  this->ConfigureAction = ToolsMenu->addAction(tr("&Configure"));  QObject::connect(this->ConfigureAction, &QAction::triggered, this,                   &CMakeSetupDialog::doConfigure);  // prevent merging with Preferences menu item on macOS  this->ConfigureAction->setMenuRole(QAction::NoRole);  this->GenerateAction = ToolsMenu->addAction(tr("&Generate"));  QObject::connect(this->GenerateAction, &QAction::triggered, this,                   &CMakeSetupDialog::doGenerate);  auto* a = ToolsMenu->addAction(tr("&Show My Changes"));  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::showUserChanges);#if defined(Q_WS_MAC) || defined(Q_OS_MAC)  this->InstallForCommandLineAction =    ToolsMenu->addAction(tr("&How to Install For Command Line Use"));  QObject::connect(this->InstallForCommandLineAction, &QAction::triggered,                   this, &CMakeSetupDialog::doInstallForCommandLine);#endif  ToolsMenu->addSeparator();  a = ToolsMenu->addAction(tr("Regular Expression Explorer..."));  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::doRegexExplorerDialog);  ToolsMenu->addSeparator();  a = ToolsMenu->addAction(tr("&Find in Output..."));  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::doOutputFindDialog);  a->setShortcut(QKeySequence::Find);  a = ToolsMenu->addAction(tr("Find Next"));  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::doOutputFindNext);  a->setShortcut(QKeySequence::FindNext);  a = ToolsMenu->addAction(tr("Find Previous"));  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::doOutputFindPrev);  a->setShortcut(QKeySequence::FindPrevious);  a = ToolsMenu->addAction(tr("Goto Next Error")); // in Visual Studio  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::doOutputErrorNext);  a->setShortcut(QKeySequence(Qt::Key_F8));  auto* s = new QShortcut(this);  s->setKey(QKeySequence(Qt::CTRL + Qt::Key_Period));  QObject::connect(s, &QShortcut::activated, this,                   &CMakeSetupDialog::doOutputErrorNext); // in Eclipse  QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options"));  a = OptionsMenu->addAction(tr("Warning Messages..."));  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::doWarningMessagesDialog);  this->WarnUninitializedAction =    OptionsMenu->addAction(tr("&Warn Uninitialized (--warn-uninitialized)"));  this->WarnUninitializedAction->setCheckable(true);  QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output"));  debugAction->setCheckable(true);  QObject::connect(debugAction, &QAction::toggled, this,                   &CMakeSetupDialog::setDebugOutput);  OptionsMenu->addSeparator();  a = OptionsMenu->addAction(tr("&Expand Grouped Entries"));  QObject::connect(a, &QAction::triggered, this->CacheValues,                   &QCMakeCacheView::expandAll);  a = OptionsMenu->addAction(tr("&Collapse Grouped Entries"));  QObject::connect(a, &QAction::triggered, this->CacheValues,                   &QCMakeCacheView::collapseAll);  QMenu* HelpMenu = this->menuBar()->addMenu(tr("&Help"));  a = HelpMenu->addAction(tr("Help"));  QObject::connect(a, &QAction::triggered, this, &CMakeSetupDialog::doHelp);  a->setShortcut(QKeySequence::HelpContents);  a = HelpMenu->addAction(tr("CMake Reference Manual"));  QObject::connect(a, &QAction::triggered, this, []() {    QString urlFormat("https://cmake.org/cmake/help/v%1.%2/");    QUrl url(urlFormat.arg(QString::number(cmVersion::GetMajorVersion()),                           QString::number(cmVersion::GetMinorVersion())));    if (!cmSystemTools::GetHTMLDoc().empty()) {      url = QUrl::fromLocalFile(        QDir(QString::fromLocal8Bit(cmSystemTools::GetHTMLDoc().data()))          .filePath("index.html"));    }    QDesktopServices::openUrl(url);  });  a = HelpMenu->addAction(tr("About"));  QObject::connect(a, &QAction::triggered, this, &CMakeSetupDialog::doAbout);  this->setAcceptDrops(true);  // get the saved binary directories  QStringList buildPaths = this->loadBuildPaths();  this->BinaryDirectory->addItems(buildPaths);  this->BinaryDirectory->setCompleter(new QCMakeFileCompleter(this, true));  this->SourceDirectory->setCompleter(new QCMakeFileCompleter(this, true));  // fixed pitch font in output window  QFont outputFont("Courier");  this->Output->setFont(outputFont);  this->ErrorFormat.setForeground(QBrush(Qt::red));  this->Output->setContextMenuPolicy(Qt::CustomContextMenu);  connect(this->Output, &QTextEdit::customContextMenuRequested, this,          &CMakeSetupDialog::doOutputContextMenu);  // disable open project button  this->OpenProjectButton->setDisabled(true);  // start the cmake worker thread  this->CMakeThread = new QCMakeThread(this);  QObject::connect(this->CMakeThread, &QCMakeThread::cmakeInitialized, this,                   &CMakeSetupDialog::initialize, Qt::QueuedConnection);  this->CMakeThread->start();  this->enterState(ReadyConfigure);  ProgressOffset = 0.0;  ProgressFactor = 1.0;}void CMakeSetupDialog::initialize(){  // now the cmake worker thread is running, lets make our connections to it  QObject::connect(this->CMakeThread->cmakeInstance(),                   &QCMake::propertiesChanged, this->CacheValues->cacheModel(),                   &QCMakeCacheModel::setProperties);  QObject::connect(this->ConfigureButton, &QPushButton::clicked, this,                   &CMakeSetupDialog::doConfigure);  QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::configureDone,                   this, &CMakeSetupDialog::exitLoop);  QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::generateDone,                   this, &CMakeSetupDialog::exitLoop);  QObject::connect(this->GenerateButton, &QPushButton::clicked, this,                   &CMakeSetupDialog::doGenerate);  QObject::connect(this->OpenProjectButton, &QPushButton::clicked, this,                   &CMakeSetupDialog::doOpenProject);  QObject::connect(this->BrowseSourceDirectoryButton, &QPushButton::clicked,                   this, &CMakeSetupDialog::doSourceBrowse);  QObject::connect(this->BrowseBinaryDirectoryButton, &QPushButton::clicked,                   this, &CMakeSetupDialog::doBinaryBrowse);  QObject::connect(this->BinaryDirectory, &QComboBox::editTextChanged, this,                   &CMakeSetupDialog::onBinaryDirectoryChanged);  QObject::connect(this->SourceDirectory, &QLineEdit::textChanged, this,                   &CMakeSetupDialog::onSourceDirectoryChanged);  QObject::connect(this->CMakeThread->cmakeInstance(),                   &QCMake::sourceDirChanged, this,                   &CMakeSetupDialog::updateSourceDirectory);  QObject::connect(this->CMakeThread->cmakeInstance(),                   &QCMake::binaryDirChanged, this,                   &CMakeSetupDialog::updateBinaryDirectory);  QObject::connect(this->CMakeThread->cmakeInstance(),                   &QCMake::progressChanged, this,                   &CMakeSetupDialog::showProgress);  QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::errorMessage,                   this, &CMakeSetupDialog::error);  QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::outputMessage,                   this, &CMakeSetupDialog::message);  QObject::connect(this->CMakeThread->cmakeInstance(), &QCMake::openPossible,                   this->OpenProjectButton, &CMakeSetupDialog::setEnabled);  QObject::connect(this->groupedCheck, &QCheckBox::toggled, this,                   &CMakeSetupDialog::setGroupedView);  QObject::connect(this->advancedCheck, &QCheckBox::toggled, this,                   &CMakeSetupDialog::setAdvancedView);  QObject::connect(this->Search, &QLineEdit::textChanged, this,                   &CMakeSetupDialog::setSearchFilter);  QObject::connect(this->CMakeThread->cmakeInstance(),                   &QCMake::generatorChanged, this,                   &CMakeSetupDialog::updateGeneratorLabel);  this->updateGeneratorLabel(QString());  QObject::connect(this->CacheValues->cacheModel(),                   &QCMakeCacheModel::dataChanged, this,                   &CMakeSetupDialog::setCacheModified);  QObject::connect(this->CacheValues->selectionModel(),                   &QItemSelectionModel::selectionChanged, this,                   &CMakeSetupDialog::selectionChanged);  QObject::connect(this->RemoveEntry, &QToolButton::clicked, this,                   &CMakeSetupDialog::removeSelectedCacheEntries);  QObject::connect(this->AddEntry, &QToolButton::clicked, this,                   &CMakeSetupDialog::addCacheEntry);  QObject::connect(this->Environment, &QToolButton::clicked, this,                   &CMakeSetupDialog::editEnvironment);  QObject::connect(this->WarnUninitializedAction, &QAction::triggered,                   this->CMakeThread->cmakeInstance(),                   &QCMake::setWarnUninitializedMode);  if (!this->SourceDirectory->text().isEmpty() ||      !this->BinaryDirectory->lineEdit()->text().isEmpty()) {    this->onSourceDirectoryChanged(this->SourceDirectory->text());    this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());  } else {    this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());  }#ifdef QT_WINEXTRAS  this->TaskbarButton = new QWinTaskbarButton(this);  this->TaskbarButton->setWindow(this->windowHandle());#endif}CMakeSetupDialog::~CMakeSetupDialog(){  QSettings settings;  settings.beginGroup("Settings/StartPath");  settings.setValue("windowState", QVariant(saveState()));  settings.setValue("geometry", QVariant(saveGeometry()));  settings.setValue("SplitterSizes", this->Splitter->saveState());  // wait for thread to stop  this->CMakeThread->quit();  this->CMakeThread->wait();}bool CMakeSetupDialog::prepareConfigure(){  // make sure build directory exists  QString bindir = this->CMakeThread->cmakeInstance()->binaryDirectory();  QDir dir(bindir);  if (!dir.exists()) {    QString msg = tr("Build directory does not exist, "                     "should I create it?\n\n"                     "Directory: ");    msg += bindir;    QString title = tr("Create Directory");    QMessageBox::StandardButton btn;    btn = QMessageBox::information(this, title, msg,                                   QMessageBox::Yes | QMessageBox::No);    if (btn == QMessageBox::No) {      return false;    }    if (!dir.mkpath(".")) {      QMessageBox::information(        this, tr("Create Directory Failed"),        QString(tr("Failed to create directory %1")).arg(dir.path()),        QMessageBox::Ok);      return false;    }  }  // if no generator, prompt for it and other setup stuff  if (this->CMakeThread->cmakeInstance()->generator().isEmpty()) {    if (!this->setupFirstConfigure()) {      return false;    }  }  // remember path  this->addBinaryPath(dir.absolutePath());  return true;}void CMakeSetupDialog::exitLoop(int err){  this->LocalLoop.exit(err);}void CMakeSetupDialog::doConfigure(){  if (this->CurrentState == Configuring) {    // stop configure    doInterrupt();    return;  }  if (!prepareConfigure()) {    return;  }  this->enterState(Configuring);  bool ret = doConfigureInternal();  if (ret) {    this->ConfigureNeeded = false;  }  if (ret && !this->CacheValues->cacheModel()->newPropertyCount()) {    this->enterState(ReadyGenerate);  } else {    this->enterState(ReadyConfigure);    this->CacheValues->scrollToTop();  }  this->ProgressBar->reset();#ifdef QT_WINEXTRAS  this->TaskbarButton->progress()->reset();#endif}bool CMakeSetupDialog::doConfigureInternal(){  this->Output->clear();  this->CacheValues->selectionModel()->clear();  QMetaObject::invokeMethod(    this->CMakeThread->cmakeInstance(), "setProperties", Qt::QueuedConnection,    Q_ARG(QCMakePropertyList, this->CacheValues->cacheModel()->properties()));  QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "configure",                            Qt::QueuedConnection);  int err = this->LocalLoop.exec();  if (err != 0) {    QMessageBox::critical(      this, tr("Error"),      tr("Error in configuration process, project files may be invalid"),      QMessageBox::Ok);  }  return 0 == err;}void CMakeSetupDialog::doInstallForCommandLine(){  QString title = tr("How to Install For Command Line Use");  QString msg = tr("One may add CMake to the PATH:\n"                   "\n"                   " PATH=\"%1\":\"$PATH\"\n"                   "\n"                   "Or, to install symlinks to '/usr/local/bin', run:\n"                   "\n"                   " sudo \"%2\" --install\n"                   "\n"                   "Or, to install symlinks to another directory, run:\n"                   "\n"                   " sudo \"%3\" --install=/path/to/bin\n");  msg = msg.arg(    cmSystemTools::GetFilenamePath(cmSystemTools::GetCMakeCommand()).c_str());  msg = msg.arg(cmSystemTools::GetCMakeGUICommand().c_str());  msg = msg.arg(cmSystemTools::GetCMakeGUICommand().c_str());  QDialog dialog;  dialog.setWindowTitle(title);  QVBoxLayout* l = new QVBoxLayout(&dialog);  QLabel* lab = new QLabel(&dialog);  l->addWidget(lab);  lab->setText(msg);  lab->setWordWrap(false);  lab->setTextInteractionFlags(Qt::TextSelectableByMouse);  QDialogButtonBox* btns =    new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);  QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,                   &QDialog::accept);  l->addWidget(btns);  dialog.exec();}bool CMakeSetupDialog::doGenerateInternal(){  QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "generate",                            Qt::QueuedConnection);  int err = this->LocalLoop.exec();  if (err != 0) {    QMessageBox::critical(      this, tr("Error"),      tr("Error in generation process, project files may be invalid"),      QMessageBox::Ok);  }  return 0 == err;}void CMakeSetupDialog::doGenerate(){  if (this->CurrentState == Generating) {    // stop generate    doInterrupt();    return;  }  // see if we need to configure  // we'll need to configure if:  //   the configure step hasn't been done yet  //   generate was the last step done  if (this->ConfigureNeeded) {    if (!prepareConfigure()) {      return;    }  }  this->enterState(Generating);  bool config_passed = true;  if (this->ConfigureNeeded) {    this->CacheValues->cacheModel()->setShowNewProperties(false);    this->ProgressFactor = 0.5;    config_passed = doConfigureInternal();    this->ProgressOffset = 0.5;  }  if (config_passed) {    doGenerateInternal();  }  this->ProgressOffset = 0.0;  this->ProgressFactor = 1.0;  this->CacheValues->cacheModel()->setShowNewProperties(true);  this->enterState(ReadyConfigure);  this->ProgressBar->reset();#ifdef QT_WINEXTRAS  this->TaskbarButton->progress()->reset();#endif  this->ConfigureNeeded = true;}void CMakeSetupDialog::doOpenProject(){  QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "open",                            Qt::QueuedConnection);}void CMakeSetupDialog::closeEvent(QCloseEvent* e){  // prompt for close if there are unsaved changes, and we're not busy  if (this->CacheModified) {    QString msg = tr("You have changed options but not rebuilt, "                     "are you sure you want to exit?");    QString title = tr("Confirm Exit");    QMessageBox::StandardButton btn;    btn = QMessageBox::critical(this, title, msg,                                QMessageBox::Yes | QMessageBox::No);    if (btn == QMessageBox::No) {      e->ignore();    }  }  // don't close if we're busy, unless the user really wants to  if (this->CurrentState == Configuring) {    QString msg =      tr("You are in the middle of a Configure.\n"         "If you Exit now the configure information will be lost.\n"         "Are you sure you want to Exit?");    QString title = tr("Confirm Exit");    QMessageBox::StandardButton btn;    btn = QMessageBox::critical(this, title, msg,                                QMessageBox::Yes | QMessageBox::No);    if (btn == QMessageBox::No) {      e->ignore();    } else {      this->doInterrupt();    }  }  // let the generate finish  if (this->CurrentState == Generating) {    e->ignore();  }}void CMakeSetupDialog::doHelp(){  QString msg = tr(    "CMake is used to configure and generate build files for "    "software projects.   The basic steps for configuring a project are as "    "follows:\r\n\r\n1. Select the source directory for the project.  This "    "should "    "contain the CMakeLists.txt files for the project.\r\n\r\n2. Select the "    "build "    "directory for the project.   This is the directory where the project "    "will be "    "built.  It can be the same or a different directory than the source "    "directory.   For easy clean up, a separate build directory is "    "recommended. "    "CMake will create the directory if it does not exist.\r\n\r\n3. Once the "    "source and binary directories are selected, it is time to press the "    "Configure button.  This will cause CMake to read all of the input files "    "and "    "discover all the variables used by the project.   The first time a "    "variable "    "is displayed it will be in Red.   Users should inspect red variables "    "making "    "sure the values are correct.   For some projects the Configure process "    "can "    "be iterative, so continue to press the Configure button until there are "    "no "    "longer red entries.\r\n\r\n4. Once there are no longer red entries, you "    "should click the Generate button.  This will write the build files to "    "the build "    "directory.");  QDialog dialog;  QFontMetrics met(this->font());#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)  int msgWidth = met.horizontalAdvance(msg);#else  int msgWidth = met.width(msg);#endif  dialog.setMinimumSize(msgWidth / 15, 20);  dialog.setWindowTitle(tr("Help"));  QVBoxLayout* l = new QVBoxLayout(&dialog);  QLabel* lab = new QLabel(&dialog);  lab->setText(msg);  lab->setWordWrap(true);  QDialogButtonBox* btns =    new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);  QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,                   &QDialog::accept);  l->addWidget(lab);  l->addWidget(btns);  dialog.exec();}void CMakeSetupDialog::doInterrupt(){  this->enterState(Interrupting);  this->CMakeThread->cmakeInstance()->interrupt();}void CMakeSetupDialog::doSourceBrowse(){  QString dir = QFileDialog::getExistingDirectory(    this, tr("Enter Path to Source"), this->SourceDirectory->text(),    QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);  if (!dir.isEmpty()) {    this->setSourceDirectory(dir);  }}void CMakeSetupDialog::updateSourceDirectory(const QString& dir){  if (this->SourceDirectory->text() != dir) {    this->SourceDirectory->blockSignals(true);    this->SourceDirectory->setText(dir);    this->SourceDirectory->blockSignals(false);  }}void CMakeSetupDialog::updateBinaryDirectory(const QString& dir){  if (this->BinaryDirectory->currentText() != dir) {    this->BinaryDirectory->blockSignals(true);    this->BinaryDirectory->setEditText(dir);    this->BinaryDirectory->blockSignals(false);  }}void CMakeSetupDialog::doBinaryBrowse(){  QString dir = QFileDialog::getExistingDirectory(    this, tr("Enter Path to Build"), this->BinaryDirectory->currentText(),    QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);  if (!dir.isEmpty() && dir != this->BinaryDirectory->currentText()) {    this->setBinaryDirectory(dir);  }}void CMakeSetupDialog::setBinaryDirectory(const QString& dir){  this->BinaryDirectory->setEditText(dir);}void CMakeSetupDialog::onSourceDirectoryChanged(const QString& dir){  this->Output->clear();  QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),                            "setSourceDirectory", Qt::QueuedConnection,                            Q_ARG(QString, dir));}void CMakeSetupDialog::onBinaryDirectoryChanged(const QString& dir){  QString title = QString(tr("CMake %1 - %2"));  title = title.arg(cmVersion::GetCMakeVersion());  title = title.arg(dir);  this->setWindowTitle(title);  this->CacheModified = false;  this->CacheValues->cacheModel()->clear();  qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())    ->clearChanges();  this->Output->clear();  QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),                            "setBinaryDirectory", Qt::QueuedConnection,                            Q_ARG(QString, dir));}void CMakeSetupDialog::setSourceDirectory(const QString& dir){  this->SourceDirectory->setText(dir);}void CMakeSetupDialog::showProgress(const QString& /*msg*/, float percent){  percent = (percent * ProgressFactor) + ProgressOffset;  this->ProgressBar->setValue(qRound(percent * 100));#ifdef QT_WINEXTRAS  QWinTaskbarProgress* progress = this->TaskbarButton->progress();  progress->setVisible(true);  progress->setValue(qRound(percent * 100));#endif}void CMakeSetupDialog::error(const QString& msg){  this->Output->setCurrentCharFormat(this->ErrorFormat);  // QTextEdit will terminate the msg with a ParagraphSeparator, but it also  // replaces  // all newlines with ParagraphSeparators. By replacing the newlines by  // ourself, one  // error msg will be one paragraph.  QString paragraph(msg);  paragraph.replace(QLatin1Char('\n'), QChar::LineSeparator);  this->Output->append(paragraph);}void CMakeSetupDialog::message(const QString& msg){  this->Output->setCurrentCharFormat(this->MessageFormat);  this->Output->append(msg);}void CMakeSetupDialog::setEnabledState(bool enabled){  // disable parts of the GUI during configure/generate  this->CacheValues->cacheModel()->setEditEnabled(enabled);  this->SourceDirectory->setEnabled(enabled);  this->BrowseSourceDirectoryButton->setEnabled(enabled);  this->BinaryDirectory->setEnabled(enabled);  this->BrowseBinaryDirectoryButton->setEnabled(enabled);  this->ReloadCacheAction->setEnabled(enabled);  this->DeleteCacheAction->setEnabled(enabled);  this->ExitAction->setEnabled(enabled);  this->ConfigureAction->setEnabled(enabled);  this->AddEntry->setEnabled(enabled);  this->RemoveEntry->setEnabled(false); // let selection re-enable it  this->Environment->setEnabled(enabled);}bool CMakeSetupDialog::setupFirstConfigure(){  FirstConfigure dialog;  // initialize dialog and restore saved settings  // add generators  dialog.setGenerators(    this->CMakeThread->cmakeInstance()->availableGenerators());  // restore from settings  dialog.loadFromSettings();  if (dialog.exec() == QDialog::Accepted) {    dialog.saveToSettings();    this->CMakeThread->cmakeInstance()->setGenerator(dialog.getGenerator());    this->CMakeThread->cmakeInstance()->setPlatform(dialog.getPlatform());    this->CMakeThread->cmakeInstance()->setToolset(dialog.getToolset());    QCMakeCacheModel* m = this->CacheValues->cacheModel();    if (dialog.compilerSetup()) {      QString fortranCompiler = dialog.getFortranCompiler();      if (!fortranCompiler.isEmpty()) {        m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",                          "Fortran compiler.", fortranCompiler, false);      }      QString cxxCompiler = dialog.getCXXCompiler();      if (!cxxCompiler.isEmpty()) {        m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",                          "CXX compiler.", cxxCompiler, false);      }      QString cCompiler = dialog.getCCompiler();      if (!cCompiler.isEmpty()) {        m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",                          "C compiler.", cCompiler, false);      }    } else if (dialog.crossCompilerSetup()) {      QString fortranCompiler = dialog.getFortranCompiler();      if (!fortranCompiler.isEmpty()) {        m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",                          "Fortran compiler.", fortranCompiler, false);      }      QString mode = dialog.getCrossIncludeMode();      m->insertProperty(QCMakeProperty::STRING,                        "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE",                        tr("CMake Find Include Mode"), mode, false);      mode = dialog.getCrossLibraryMode();      m->insertProperty(QCMakeProperty::STRING,                        "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY",                        tr("CMake Find Library Mode"), mode, false);      mode = dialog.getCrossProgramMode();      m->insertProperty(QCMakeProperty::STRING,                        "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM",                        tr("CMake Find Program Mode"), mode, false);      QString rootPath = dialog.getCrossRoot();      m->insertProperty(QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH",                        tr("CMake Find Root Path"), rootPath, false);      QString systemName = dialog.getSystemName();      m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME",                        tr("CMake System Name"), systemName, false);      QString systemVersion = dialog.getSystemVersion();      m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_VERSION",                        tr("CMake System Version"), systemVersion, false);      QString systemProcessor = dialog.getSystemProcessor();      m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_PROCESSOR",                        tr("CMake System Processor"), systemProcessor, false);      QString cxxCompiler = dialog.getCXXCompiler();      if (!cxxCompiler.isEmpty()) {        m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",                          tr("CXX compiler."), cxxCompiler, false);      }      QString cCompiler = dialog.getCCompiler();      if (!cCompiler.isEmpty()) {        m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",                          tr("C compiler."), cCompiler, false);      }    } else if (dialog.crossCompilerToolChainFile()) {      QString toolchainFile = dialog.getCrossCompilerToolChainFile();      m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE",                        tr("Cross Compile ToolChain File"), toolchainFile,                        false);    }    return true;  }  return false;}void CMakeSetupDialog::updateGeneratorLabel(const QString& gen){  QString str = tr("Current Generator: ");  if (gen.isEmpty()) {    str += tr("None");  } else {    str += gen;  }  this->Generator->setText(str);}void CMakeSetupDialog::doReloadCache(){  QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "reloadCache",                            Qt::QueuedConnection);}void CMakeSetupDialog::doDeleteCache(){  QString title = tr("Delete Cache");  QString msg = tr("Are you sure you want to delete the cache?");  QMessageBox::StandardButton btn;  btn = QMessageBox::information(this, title, msg,                                 QMessageBox::Yes | QMessageBox::No);  if (btn == QMessageBox::No) {    return;  }  QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(), "deleteCache",                            Qt::QueuedConnection);}void CMakeSetupDialog::doAbout(){  QString msg = tr(    "CMake %1 (cmake.org).\n"    "CMake suite maintained and supported by Kitware (kitware.com/cmake).\n"    "Distributed under terms of the BSD 3-Clause License.\n"    "\n"    "CMake GUI maintained by csimsoft,\n"    "built using Qt %2 (qt-project.org).\n"#ifdef USE_LGPL    "\n"    "The Qt Toolkit is Copyright (C) The Qt Company Ltd.\n"    "Qt is licensed under terms of the GNU LGPLv" USE_LGPL ", available at:\n"    " \"%3\""#endif  );  msg = msg.arg(cmVersion::GetCMakeVersion());  msg = msg.arg(qVersion());#ifdef USE_LGPL  std::string lgpl =    cmSystemTools::GetCMakeRoot() + "/Licenses/LGPLv" USE_LGPL ".txt";  msg = msg.arg(lgpl.c_str());#endif  QDialog dialog;  dialog.setWindowTitle(tr("About"));  QVBoxLayout* l = new QVBoxLayout(&dialog);  QLabel* lab = new QLabel(&dialog);  l->addWidget(lab);  lab->setText(msg);  lab->setWordWrap(true);  QDialogButtonBox* btns =    new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog);  QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,                   &QDialog::accept);  l->addWidget(btns);  dialog.exec();}void CMakeSetupDialog::setExitAfterGenerate(bool b){  this->ExitAfterGenerate = b;}void CMakeSetupDialog::addBinaryPath(const QString& path){  QString cleanpath = QDir::cleanPath(path);  // update UI  this->BinaryDirectory->blockSignals(true);  int idx = this->BinaryDirectory->findText(cleanpath);  if (idx != -1) {    this->BinaryDirectory->removeItem(idx);  }  this->BinaryDirectory->insertItem(0, cleanpath);  this->BinaryDirectory->setCurrentIndex(0);  this->BinaryDirectory->blockSignals(false);  // save to registry  QStringList buildPaths = this->loadBuildPaths();  buildPaths.removeAll(cleanpath);  buildPaths.prepend(cleanpath);  this->saveBuildPaths(buildPaths);}void CMakeSetupDialog::dragEnterEvent(QDragEnterEvent* e){  if (!(this->CurrentState == ReadyConfigure ||        this->CurrentState == ReadyGenerate)) {    e->ignore();    return;  }  const QMimeData* dat = e->mimeData();  QList<QUrl> urls = dat->urls();  QString file = urls.count() ? urls[0].toLocalFile() : QString();  if (!file.isEmpty() &&      (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive) ||       file.endsWith("CMakeLists.txt", Qt::CaseInsensitive))) {    e->accept();  } else {    e->ignore();  }}void CMakeSetupDialog::dropEvent(QDropEvent* e){  if (!(this->CurrentState == ReadyConfigure ||        this->CurrentState == ReadyGenerate)) {    return;  }  const QMimeData* dat = e->mimeData();  QList<QUrl> urls = dat->urls();  QString file = urls.count() ? urls[0].toLocalFile() : QString();  if (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive)) {    QFileInfo info(file);    if (this->CMakeThread->cmakeInstance()->binaryDirectory() !=        info.absolutePath()) {      this->setBinaryDirectory(info.absolutePath());    }  } else if (file.endsWith("CMakeLists.txt", Qt::CaseInsensitive)) {    QFileInfo info(file);    if (this->CMakeThread->cmakeInstance()->binaryDirectory() !=        info.absolutePath()) {      this->setSourceDirectory(info.absolutePath());      this->setBinaryDirectory(info.absolutePath());    }  }}QStringList CMakeSetupDialog::loadBuildPaths(){  QSettings settings;  settings.beginGroup("Settings/StartPath");  QStringList buildPaths;  for (int i = 0; i < 10; i++) {    QString p = settings.value(QString("WhereBuild%1").arg(i)).toString();    if (!p.isEmpty()) {      buildPaths.append(p);    }  }  return buildPaths;}void CMakeSetupDialog::saveBuildPaths(const QStringList& paths){  QSettings settings;  settings.beginGroup("Settings/StartPath");  int num = paths.count();  if (num > 10) {    num = 10;  }  for (int i = 0; i < num; i++) {    settings.setValue(QString("WhereBuild%1").arg(i), paths[i]);  }}void CMakeSetupDialog::setCacheModified(){  this->CacheModified = true;  this->ConfigureNeeded = true;  this->enterState(ReadyConfigure);}void CMakeSetupDialog::removeSelectedCacheEntries(){  QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();  QList<QPersistentModelIndex> pidxs;  foreach (QModelIndex const& i, idxs) {    pidxs.append(i);  }  foreach (QPersistentModelIndex const& pi, pidxs) {    this->CacheValues->model()->removeRow(pi.row(), pi.parent());  }}void CMakeSetupDialog::selectionChanged(){  QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();  if (idxs.count() &&      (this->CurrentState == ReadyConfigure ||       this->CurrentState == ReadyGenerate)) {    this->RemoveEntry->setEnabled(true);  } else {    this->RemoveEntry->setEnabled(false);  }}void CMakeSetupDialog::enterState(CMakeSetupDialog::State s){  if (s == this->CurrentState) {    return;  }  this->CurrentState = s;  if (s == Interrupting) {    this->ConfigureButton->setEnabled(false);    this->GenerateButton->setEnabled(false);    this->OpenProjectButton->setEnabled(false);  } else if (s == Configuring) {    this->setEnabledState(false);    this->GenerateButton->setEnabled(false);    this->GenerateAction->setEnabled(false);    this->OpenProjectButton->setEnabled(false);    this->ConfigureButton->setText(tr("&Stop"));  } else if (s == Generating) {    this->CacheModified = false;    this->setEnabledState(false);    this->ConfigureButton->setEnabled(false);    this->GenerateAction->setEnabled(false);    this->OpenProjectButton->setEnabled(false);    this->GenerateButton->setText(tr("&Stop"));  } else if (s == ReadyConfigure || s == ReadyGenerate) {    this->setEnabledState(true);    this->GenerateButton->setEnabled(true);    this->GenerateAction->setEnabled(true);    this->ConfigureButton->setEnabled(true);    this->ConfigureButton->setText(tr("&Configure"));    this->GenerateButton->setText(tr("&Generate"));  }}void CMakeSetupDialog::editEnvironment(){  EnvironmentDialog dialog(this->CMakeThread->cmakeInstance()->environment(),                           this);  if (dialog.exec() == QDialog::Accepted) {    QMetaObject::invokeMethod(      this->CMakeThread->cmakeInstance(), "setEnvironment",      Q_ARG(QProcessEnvironment, dialog.environment()));  }}void CMakeSetupDialog::addCacheEntry(){  QDialog dialog(this);  dialog.resize(400, 200);  dialog.setWindowTitle(tr("Add Cache Entry"));  QVBoxLayout* l = new QVBoxLayout(&dialog);  AddCacheEntry* w =    new AddCacheEntry(&dialog, this->AddVariableNames, this->AddVariableTypes);  QDialogButtonBox* btns = new QDialogButtonBox(    QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);  QObject::connect(btns, &QDialogButtonBox::accepted, &dialog,                   &QDialog::accept);  QObject::connect(btns, &QDialogButtonBox::rejected, &dialog,                   &QDialog::reject);  l->addWidget(w);  l->addStretch();  l->addWidget(btns);  if (QDialog::Accepted == dialog.exec()) {    QCMakeCacheModel* m = this->CacheValues->cacheModel();    m->insertProperty(w->type(), w->name(), w->description(), w->value(),                      false);    // only add variable names to the completion which are new    if (!this->AddVariableNames.contains(w->name())) {      this->AddVariableNames << w->name();      this->AddVariableTypes << w->typeString();      // limit to at most 100 completion items      if (this->AddVariableNames.size() > 100) {        this->AddVariableNames.removeFirst();        this->AddVariableTypes.removeFirst();      }      // make sure CMAKE_INSTALL_PREFIX is always there      if (!this->AddVariableNames.contains("CMAKE_INSTALL_PREFIX")) {        this->AddVariableNames << "CMAKE_INSTALL_PREFIX";        this->AddVariableTypes << "PATH";      }      QSettings settings;      settings.beginGroup("Settings/StartPath");      settings.setValue("AddVariableNames", this->AddVariableNames);      settings.setValue("AddVariableTypes", this->AddVariableTypes);    }  }}void CMakeSetupDialog::startSearch(){  this->Search->setFocus(Qt::OtherFocusReason);  this->Search->selectAll();}void CMakeSetupDialog::setDebugOutput(bool flag){  QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),                            "setDebugOutput", Qt::QueuedConnection,                            Q_ARG(bool, flag));}void CMakeSetupDialog::setGroupedView(bool v){  this->CacheValues->cacheModel()->setViewType(v ? QCMakeCacheModel::GroupView                                                 : QCMakeCacheModel::FlatView);  this->CacheValues->setRootIsDecorated(v);  QSettings settings;  settings.beginGroup("Settings/StartPath");  settings.setValue("GroupView", v);}void CMakeSetupDialog::setAdvancedView(bool v){  this->CacheValues->setShowAdvanced(v);  QSettings settings;  settings.beginGroup("Settings/StartPath");  settings.setValue("AdvancedView", v);}void CMakeSetupDialog::showUserChanges(){  QSet<QCMakeProperty> changes =    qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())      ->changes();  QDialog dialog(this);  dialog.setWindowTitle(tr("My Changes"));  dialog.resize(600, 400);  QVBoxLayout* l = new QVBoxLayout(&dialog);  QTextEdit* textedit = new QTextEdit(&dialog);  textedit->setReadOnly(true);  l->addWidget(textedit);  QDialogButtonBox* btns =    new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);  QObject::connect(btns, &QDialogButtonBox::rejected, &dialog,                   &QDialog::accept);  l->addWidget(btns);  QString command;  QString cache;  foreach (QCMakeProperty const& prop, changes) {    QString type;    switch (prop.Type) {      case QCMakeProperty::BOOL:        type = "BOOL";        break;      case QCMakeProperty::PATH:        type = "PATH";        break;      case QCMakeProperty::FILEPATH:        type = "FILEPATH";        break;      case QCMakeProperty::STRING:        type = "STRING";        break;    }    QString value;    if (prop.Type == QCMakeProperty::BOOL) {      value = prop.Value.toBool() ? "1" : "0";    } else {      value = prop.Value.toString();    }    QString const line = QString("%1:%2=").arg(prop.Key, type);    command += QString("-D%1\"%2\" ").arg(line, value);    cache += QString("%1%2\n").arg(line, value);  }  textedit->append(tr("Commandline options:"));  textedit->append(command);  textedit->append("\n");  textedit->append(tr("Cache file:"));  textedit->append(cache);  dialog.exec();}void CMakeSetupDialog::setSearchFilter(const QString& str){  this->CacheValues->selectionModel()->clear();  this->CacheValues->setSearchFilter(str);}void CMakeSetupDialog::doOutputContextMenu(QPoint pt){  std::unique_ptr<QMenu> menu(this->Output->createStandardContextMenu());  menu->addSeparator();  auto* a = menu->addAction(tr("Find..."));  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::doOutputFindDialog);  a->setShortcut(QKeySequence::Find);  a = menu->addAction(tr("Find Next"));  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::doOutputFindNext);  a->setShortcut(QKeySequence::FindNext);  a = menu->addAction(tr("Find Previous"));  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::doOutputFindPrev);  a->setShortcut(QKeySequence::FindPrevious);  menu->addSeparator();  a = menu->addAction(tr("Goto Next Error"));  QObject::connect(a, &QAction::triggered, this,                   &CMakeSetupDialog::doOutputErrorNext);  a->setShortcut(QKeySequence(Qt::Key_F8));  menu->exec(this->Output->mapToGlobal(pt));}void CMakeSetupDialog::doOutputFindDialog(){  QStringList strings(this->FindHistory);  QString selection = this->Output->textCursor().selectedText();  if (!selection.isEmpty() && !selection.contains(QChar::ParagraphSeparator) &&      !selection.contains(QChar::LineSeparator)) {    strings.push_front(selection);  }  bool ok;  QString search = QInputDialog::getItem(this, tr("Find in Output"),                                         tr("Find:"), strings, 0, true, &ok);  if (ok && !search.isEmpty()) {    if (!this->FindHistory.contains(search)) {      this->FindHistory.push_front(search);    }    doOutputFindNext();  }}void CMakeSetupDialog::doRegexExplorerDialog(){  RegexExplorer dialog(this);  dialog.exec();}void CMakeSetupDialog::doOutputFindPrev(){  doOutputFindNext(false);}void CMakeSetupDialog::doOutputFindNext(bool directionForward){  if (this->FindHistory.isEmpty()) {    doOutputFindDialog(); // will re-call this function again    return;  }  QString search = this->FindHistory.front();  QTextCursor textCursor = this->Output->textCursor();  QTextDocument* document = this->Output->document();  QTextDocument::FindFlags flags;  if (!directionForward) {    flags |= QTextDocument::FindBackward;  }  textCursor = document->find(search, textCursor, flags);  if (textCursor.isNull()) {    // first search found nothing, wrap around and search again    textCursor = this->Output->textCursor();    textCursor.movePosition(directionForward ? QTextCursor::Start                                             : QTextCursor::End);    textCursor = document->find(search, textCursor, flags);  }  if (textCursor.hasSelection()) {    this->Output->setTextCursor(textCursor);  }}void CMakeSetupDialog::doOutputErrorNext(){  QTextCursor textCursor = this->Output->textCursor();  bool atEnd = false;  // move cursor out of current error-block  if (textCursor.blockCharFormat() == this->ErrorFormat) {    atEnd = !textCursor.movePosition(QTextCursor::NextBlock);  }  // move cursor to next error-block  while (textCursor.blockCharFormat() != this->ErrorFormat && !atEnd) {    atEnd = !textCursor.movePosition(QTextCursor::NextBlock);  }  if (atEnd) {    // first search found nothing, wrap around and search again    atEnd = !textCursor.movePosition(QTextCursor::Start);    // move cursor to next error-block    while (textCursor.blockCharFormat() != this->ErrorFormat && !atEnd) {      atEnd = !textCursor.movePosition(QTextCursor::NextBlock);    }  }  if (!atEnd) {    textCursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);    QTextCharFormat selectionFormat;    selectionFormat.setBackground(Qt::yellow);    QTextEdit::ExtraSelection extraSelection = { textCursor, selectionFormat };    this->Output->setExtraSelections(QList<QTextEdit::ExtraSelection>()                                     << extraSelection);    // make the whole error-block visible    this->Output->setTextCursor(textCursor);    // remove the selection to see the extraSelection    textCursor.setPosition(textCursor.anchor());    this->Output->setTextCursor(textCursor);  }}void CMakeSetupDialog::doWarningMessagesDialog(){  WarningMessagesDialog dialog(this, this->CMakeThread->cmakeInstance());  dialog.exec();}
 |