fix issue 9346. add binary directory to window title to make it easier to deal with...
[cmake.git] / Source / QtDialog / CMakeSetupDialog.cxx
blob74b842860fd0933d22195b16d23e4c2c6d9c23cd
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: CMakeSetupDialog.cxx,v $
5 Language: C++
6 Date: $Date: 2009-09-22 22:29:35 $
7 Version: $Revision: 1.62 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
18 #include "CMakeSetupDialog.h"
19 #include <QFileDialog>
20 #include <QProgressBar>
21 #include <QMessageBox>
22 #include <QStatusBar>
23 #include <QToolButton>
24 #include <QDialogButtonBox>
25 #include <QCloseEvent>
26 #include <QCoreApplication>
27 #include <QSettings>
28 #include <QMenu>
29 #include <QMenuBar>
30 #include <QDragEnterEvent>
31 #include <QMimeData>
32 #include <QUrl>
33 #include <QShortcut>
34 #include <QMacInstallDialog.h>
36 #include "QCMake.h"
37 #include "QCMakeCacheView.h"
38 #include "AddCacheEntry.h"
39 #include "FirstConfigure.h"
40 #include "cmVersion.h"
42 QCMakeThread::QCMakeThread(QObject* p)
43 : QThread(p), CMakeInstance(NULL)
47 QCMake* QCMakeThread::cmakeInstance() const
49 return this->CMakeInstance;
52 void QCMakeThread::run()
54 this->CMakeInstance = new QCMake;
55 // emit that this cmake thread is ready for use
56 emit this->cmakeInitialized();
57 this->exec();
58 delete this->CMakeInstance;
59 this->CMakeInstance = NULL;
62 CMakeSetupDialog::CMakeSetupDialog()
63 : ExitAfterGenerate(true), CacheModified(false), CurrentState(Interrupting)
65 QString title = QString(tr("CMake %1"));
66 title = title.arg(cmVersion::GetCMakeVersion());
67 this->setWindowTitle(title);
69 // create the GUI
70 QSettings settings;
71 settings.beginGroup("Settings/StartPath");
72 int h = settings.value("Height", 500).toInt();
73 int w = settings.value("Width", 700).toInt();
74 this->resize(w, h);
76 QWidget* cont = new QWidget(this);
77 this->setupUi(cont);
78 this->Splitter->setStretchFactor(0, 3);
79 this->Splitter->setStretchFactor(1, 1);
80 this->setCentralWidget(cont);
81 this->ProgressBar->reset();
82 this->RemoveEntry->setEnabled(false);
83 this->AddEntry->setEnabled(false);
85 QByteArray p = settings.value("SplitterSizes").toByteArray();
86 this->Splitter->restoreState(p);
88 bool groupView = settings.value("GroupView", false).toBool();
89 if(groupView)
91 this->setViewType(2);
92 this->ViewType->setCurrentIndex(2);
95 QMenu* FileMenu = this->menuBar()->addMenu(tr("&File"));
96 this->ReloadCacheAction = FileMenu->addAction(tr("&Reload Cache"));
97 QObject::connect(this->ReloadCacheAction, SIGNAL(triggered(bool)),
98 this, SLOT(doReloadCache()));
99 this->DeleteCacheAction = FileMenu->addAction(tr("&Delete Cache"));
100 QObject::connect(this->DeleteCacheAction, SIGNAL(triggered(bool)),
101 this, SLOT(doDeleteCache()));
102 this->ExitAction = FileMenu->addAction(tr("E&xit"));
103 QObject::connect(this->ExitAction, SIGNAL(triggered(bool)),
104 this, SLOT(close()));
106 QMenu* ToolsMenu = this->menuBar()->addMenu(tr("&Tools"));
107 this->ConfigureAction = ToolsMenu->addAction(tr("&Configure"));
108 // prevent merging with Preferences menu item on Mac OS X
109 this->ConfigureAction->setMenuRole(QAction::NoRole);
110 QObject::connect(this->ConfigureAction, SIGNAL(triggered(bool)),
111 this, SLOT(doConfigure()));
112 this->GenerateAction = ToolsMenu->addAction(tr("&Generate"));
113 QObject::connect(this->GenerateAction, SIGNAL(triggered(bool)),
114 this, SLOT(doGenerate()));
115 QAction* showChangesAction = ToolsMenu->addAction(tr("&Show My Changes"));
116 QObject::connect(showChangesAction, SIGNAL(triggered(bool)),
117 this, SLOT(showUserChanges()));
118 #if defined(Q_WS_MAC)
119 this->InstallForCommandLineAction
120 = ToolsMenu->addAction(tr("&Install For Command Line Use"));
121 QObject::connect(this->InstallForCommandLineAction, SIGNAL(triggered(bool)),
122 this, SLOT(doInstallForCommandLine()));
123 #endif
124 QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options"));
125 this->SuppressDevWarningsAction = OptionsMenu->addAction(tr("&Suppress dev Warnings (-Wno-dev)"));
126 this->SuppressDevWarningsAction->setCheckable(true);
128 QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output"));
129 debugAction->setCheckable(true);
130 QObject::connect(debugAction, SIGNAL(toggled(bool)),
131 this, SLOT(setDebugOutput(bool)));
133 OptionsMenu->addSeparator();
134 QAction* expandAction = OptionsMenu->addAction(tr("&Expand Grouped Entries"));
135 QObject::connect(expandAction, SIGNAL(triggered(bool)),
136 this->CacheValues, SLOT(expandAll()));
137 QAction* collapseAction = OptionsMenu->addAction(tr("&Collapse Grouped Entries"));
138 QObject::connect(collapseAction, SIGNAL(triggered(bool)),
139 this->CacheValues, SLOT(collapseAll()));
141 QMenu* HelpMenu = this->menuBar()->addMenu(tr("&Help"));
142 QAction* a = HelpMenu->addAction(tr("About"));
143 QObject::connect(a, SIGNAL(triggered(bool)),
144 this, SLOT(doAbout()));
145 a = HelpMenu->addAction(tr("Help"));
146 QObject::connect(a, SIGNAL(triggered(bool)),
147 this, SLOT(doHelp()));
149 QShortcut* filterShortcut = new QShortcut(QKeySequence::Find, this);
150 QObject::connect(filterShortcut, SIGNAL(activated()),
151 this, SLOT(startSearch()));
153 this->setAcceptDrops(true);
155 // get the saved binary directories
156 QStringList buildPaths = this->loadBuildPaths();
157 this->BinaryDirectory->addItems(buildPaths);
159 this->BinaryDirectory->setCompleter(new QCMakeFileCompleter(this, true));
160 this->SourceDirectory->setCompleter(new QCMakeFileCompleter(this, true));
162 // fixed pitch font in output window
163 QFont outputFont("Courier");
164 this->Output->setFont(outputFont);
165 this->ErrorFormat.setForeground(QBrush(Qt::red));
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();
173 this->enterState(ReadyConfigure);
176 void CMakeSetupDialog::initialize()
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&)));
184 QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)),
185 this, SLOT(doConfigure()));
186 QObject::connect(this->CMakeThread->cmakeInstance(),
187 SIGNAL(configureDone(int)),
188 this, SLOT(finishConfigure(int)));
189 QObject::connect(this->CMakeThread->cmakeInstance(),
190 SIGNAL(generateDone(int)),
191 this, SLOT(finishGenerate(int)));
193 QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)),
194 this, SLOT(doGenerate()));
196 QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)),
197 this, SLOT(doSourceBrowse()));
198 QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)),
199 this, SLOT(doBinaryBrowse()));
201 QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)),
202 this, SLOT(onBinaryDirectoryChanged(QString)));
203 QObject::connect(this->SourceDirectory, SIGNAL(textChanged(QString)),
204 this, SLOT(onSourceDirectoryChanged(QString)));
206 QObject::connect(this->CMakeThread->cmakeInstance(),
207 SIGNAL(sourceDirChanged(QString)),
208 this, SLOT(updateSourceDirectory(QString)));
209 QObject::connect(this->CMakeThread->cmakeInstance(),
210 SIGNAL(binaryDirChanged(QString)),
211 this, SLOT(updateBinaryDirectory(QString)));
213 QObject::connect(this->CMakeThread->cmakeInstance(),
214 SIGNAL(progressChanged(QString, float)),
215 this, SLOT(showProgress(QString,float)));
217 QObject::connect(this->CMakeThread->cmakeInstance(),
218 SIGNAL(errorMessage(QString)),
219 this, SLOT(error(QString)));
221 QObject::connect(this->CMakeThread->cmakeInstance(),
222 SIGNAL(outputMessage(QString)),
223 this, SLOT(message(QString)));
225 QObject::connect(this->ViewType, SIGNAL(currentIndexChanged(int)),
226 this, SLOT(setViewType(int)));
227 QObject::connect(this->Search, SIGNAL(textChanged(QString)),
228 this, SLOT(setSearchFilter(QString)));
230 QObject::connect(this->CMakeThread->cmakeInstance(),
231 SIGNAL(generatorChanged(QString)),
232 this, SLOT(updateGeneratorLabel(QString)));
233 this->updateGeneratorLabel(QString());
235 QObject::connect(this->CacheValues->cacheModel(),
236 SIGNAL(dataChanged(QModelIndex,QModelIndex)),
237 this, SLOT(setCacheModified()));
239 QObject::connect(this->CacheValues->selectionModel(),
240 SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
241 this, SLOT(selectionChanged()));
242 QObject::connect(this->RemoveEntry, SIGNAL(clicked(bool)),
243 this, SLOT(removeSelectedCacheEntries()));
244 QObject::connect(this->AddEntry, SIGNAL(clicked(bool)),
245 this, SLOT(addCacheEntry()));
247 QObject::connect(this->SuppressDevWarningsAction, SIGNAL(triggered(bool)),
248 this->CMakeThread->cmakeInstance(), SLOT(setSuppressDevWarnings(bool)));
250 if(!this->SourceDirectory->text().isEmpty() ||
251 !this->BinaryDirectory->lineEdit()->text().isEmpty())
253 this->onSourceDirectoryChanged(this->SourceDirectory->text());
254 this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
256 else
258 this->onBinaryDirectoryChanged(this->BinaryDirectory->lineEdit()->text());
262 CMakeSetupDialog::~CMakeSetupDialog()
264 QSettings settings;
265 settings.beginGroup("Settings/StartPath");
266 settings.setValue("Height", this->height());
267 settings.setValue("Width", this->width());
268 settings.setValue("SplitterSizes", this->Splitter->saveState());
270 // wait for thread to stop
271 this->CMakeThread->quit();
272 this->CMakeThread->wait(2000);
275 void CMakeSetupDialog::doConfigure()
277 if(this->CurrentState == Configuring)
279 // stop configure
280 doInterrupt();
281 return;
284 // make sure build directory exists
285 QString bindir = this->CMakeThread->cmakeInstance()->binaryDirectory();
286 QDir dir(bindir);
287 if(!dir.exists())
289 QString message = tr("Build directory does not exist, "
290 "should I create it?")
291 + "\n\n"
292 + tr("Directory: ");
293 message += bindir;
294 QString title = tr("Create Directory");
295 QMessageBox::StandardButton btn;
296 btn = QMessageBox::information(this, title, message,
297 QMessageBox::Yes | QMessageBox::No);
298 if(btn == QMessageBox::No)
300 return;
302 dir.mkpath(".");
305 // if no generator, prompt for it and other setup stuff
306 if(this->CMakeThread->cmakeInstance()->generator().isEmpty())
308 if(!this->setupFirstConfigure())
310 return;
314 // remember path
315 this->addBinaryPath(dir.absolutePath());
317 this->enterState(Configuring);
319 this->CacheValues->selectionModel()->clear();
320 QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
321 "setProperties", Qt::QueuedConnection,
322 Q_ARG(QCMakePropertyList,
323 this->CacheValues->cacheModel()->properties()));
324 QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
325 "configure", Qt::QueuedConnection);
328 void CMakeSetupDialog::finishConfigure(int err)
330 if(0 == err && !this->CacheValues->cacheModel()->newPropertyCount())
332 this->enterState(ReadyGenerate);
334 else
336 this->enterState(ReadyConfigure);
337 this->CacheValues->scrollToTop();
340 if(err != 0)
342 QMessageBox::critical(this, tr("Error"),
343 tr("Error in configuration process, project files may be invalid"),
344 QMessageBox::Ok);
348 void CMakeSetupDialog::finishGenerate(int err)
350 this->enterState(ReadyGenerate);
351 if(err != 0)
353 QMessageBox::critical(this, tr("Error"),
354 tr("Error in generation process, project files may be invalid"),
355 QMessageBox::Ok);
359 void CMakeSetupDialog::doInstallForCommandLine()
361 QMacInstallDialog setupdialog(0);
362 setupdialog.exec();
365 void CMakeSetupDialog::doGenerate()
367 if(this->CurrentState == Generating)
369 // stop generate
370 doInterrupt();
371 return;
373 this->enterState(Generating);
374 QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
375 "generate", Qt::QueuedConnection);
378 void CMakeSetupDialog::closeEvent(QCloseEvent* e)
380 // prompt for close if there are unsaved changes, and we're not busy
381 if(this->CacheModified)
383 QString message = tr("You have changed options but not rebuilt, "
384 "are you sure you want to exit?");
385 QString title = tr("Confirm Exit");
386 QMessageBox::StandardButton btn;
387 btn = QMessageBox::critical(this, title, message,
388 QMessageBox::Yes | QMessageBox::No);
389 if(btn == QMessageBox::No)
391 e->ignore();
395 // don't close if we're busy, unless the user really wants to
396 if(this->CurrentState == Configuring)
398 QString message = "You are in the middle of a Configure.\n"
399 "If you Exit now the configure information will be lost.\n"
400 "Are you sure you want to Exit?";
401 QString title = tr("Confirm Exit");
402 QMessageBox::StandardButton btn;
403 btn = QMessageBox::critical(this, title, message,
404 QMessageBox::Yes | QMessageBox::No);
405 if(btn == QMessageBox::No)
407 e->ignore();
409 else
411 this->doInterrupt();
415 // let the generate finish
416 if(this->CurrentState == Generating)
418 e->ignore();
422 void CMakeSetupDialog::doHelp()
424 QString msg = tr("CMake is used to configure and generate build files for "
425 "software projects. The basic steps for configuring a project are as "
426 "follows:\r\n\r\n1. Select the source directory for the project. This should "
427 "contain the CMakeLists.txt files for the project.\r\n\r\n2. Select the build "
428 "directory for the project. This is the directory where the project will be "
429 "built. It can be the same or a different directory than the source "
430 "directory. For easy clean up, a separate build directory is recommended. "
431 "CMake will create the directory if it does not exist.\r\n\r\n3. Once the "
432 "source and binary directories are selected, it is time to press the "
433 "Configure button. This will cause CMake to read all of the input files and "
434 "discover all the variables used by the project. The first time a variable "
435 "is displayed it will be in Red. Users should inspect red variables making "
436 "sure the values are correct. For some projects the Configure process can "
437 "be iterative, so continue to press the Configure button until there are no "
438 "longer red entries.\r\n\r\n4. Once there are no longer red entries, you "
439 "should click the Generate button. This will write the build files to the build "
440 "directory.");
442 QDialog dialog;
443 QFontMetrics met(this->font());
444 int msgWidth = met.width(msg);
445 dialog.setMinimumSize(msgWidth/15,20);
446 dialog.setWindowTitle(tr("Help"));
447 QVBoxLayout* l = new QVBoxLayout(&dialog);
448 QLabel* lab = new QLabel(&dialog);
449 lab->setText(msg);
450 lab->setWordWrap(true);
451 QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
452 Qt::Horizontal, &dialog);
453 QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
454 l->addWidget(lab);
455 l->addWidget(btns);
456 dialog.exec();
459 void CMakeSetupDialog::doInterrupt()
461 this->enterState(Interrupting);
462 QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
463 "interrupt", Qt::QueuedConnection);
466 void CMakeSetupDialog::doSourceBrowse()
468 QString dir = QFileDialog::getExistingDirectory(this,
469 tr("Enter Path to Source"), this->SourceDirectory->text());
470 if(!dir.isEmpty())
472 this->setSourceDirectory(dir);
476 void CMakeSetupDialog::updateSourceDirectory(const QString& dir)
478 if(this->SourceDirectory->text() != dir)
480 this->SourceDirectory->blockSignals(true);
481 this->SourceDirectory->setText(dir);
482 this->SourceDirectory->blockSignals(false);
486 void CMakeSetupDialog::updateBinaryDirectory(const QString& dir)
488 if(this->BinaryDirectory->currentText() != dir)
490 this->BinaryDirectory->blockSignals(true);
491 this->BinaryDirectory->setEditText(dir);
492 this->BinaryDirectory->blockSignals(false);
496 void CMakeSetupDialog::doBinaryBrowse()
498 QString dir = QFileDialog::getExistingDirectory(this,
499 tr("Enter Path to Build"), this->BinaryDirectory->currentText());
500 if(!dir.isEmpty() && dir != this->BinaryDirectory->currentText())
502 this->setBinaryDirectory(dir);
506 void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
508 this->BinaryDirectory->setEditText(dir);
511 void CMakeSetupDialog::onSourceDirectoryChanged(const QString& dir)
513 this->Output->clear();
514 QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
515 "setSourceDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
518 void CMakeSetupDialog::onBinaryDirectoryChanged(const QString& dir)
520 QString title = QString(tr("CMake %1 - %2"));
521 title = title.arg(cmVersion::GetCMakeVersion());
522 title = title.arg(dir);
523 this->setWindowTitle(title);
525 this->CacheModified = false;
526 this->CacheValues->cacheModel()->clear();
527 qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())->clearChanges();
528 this->Output->clear();
529 QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
530 "setBinaryDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
533 void CMakeSetupDialog::setSourceDirectory(const QString& dir)
535 this->SourceDirectory->setText(dir);
538 void CMakeSetupDialog::showProgress(const QString& /*msg*/, float percent)
540 this->ProgressBar->setValue(qRound(percent * 100));
543 void CMakeSetupDialog::error(const QString& message)
545 this->Output->setCurrentCharFormat(this->ErrorFormat);
546 this->Output->append(message);
549 void CMakeSetupDialog::message(const QString& message)
551 this->Output->setCurrentCharFormat(this->MessageFormat);
552 this->Output->append(message);
555 void CMakeSetupDialog::setEnabledState(bool enabled)
557 // disable parts of the GUI during configure/generate
558 this->CacheValues->cacheModel()->setEditEnabled(enabled);
559 this->SourceDirectory->setEnabled(enabled);
560 this->BrowseSourceDirectoryButton->setEnabled(enabled);
561 this->BinaryDirectory->setEnabled(enabled);
562 this->BrowseBinaryDirectoryButton->setEnabled(enabled);
563 this->ReloadCacheAction->setEnabled(enabled);
564 this->DeleteCacheAction->setEnabled(enabled);
565 this->ExitAction->setEnabled(enabled);
566 this->ConfigureAction->setEnabled(enabled);
567 this->AddEntry->setEnabled(enabled);
568 this->RemoveEntry->setEnabled(false); // let selection re-enable it
571 bool CMakeSetupDialog::setupFirstConfigure()
573 FirstConfigure dialog;
575 // initialize dialog and restore saved settings
577 // add generators
578 dialog.setGenerators(this->CMakeThread->cmakeInstance()->availableGenerators());
580 // restore from settings
581 dialog.loadFromSettings();
583 if(dialog.exec() == QDialog::Accepted)
585 dialog.saveToSettings();
586 this->CMakeThread->cmakeInstance()->setGenerator(dialog.getGenerator());
588 QCMakeCacheModel* m = this->CacheValues->cacheModel();
590 if(dialog.compilerSetup())
592 QString fortranCompiler = dialog.getFortranCompiler();
593 if(!fortranCompiler.isEmpty())
595 m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
596 "Fortran compiler.", fortranCompiler, false);
598 QString cxxCompiler = dialog.getCXXCompiler();
599 if(!cxxCompiler.isEmpty())
601 m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
602 "CXX compiler.", cxxCompiler, false);
605 QString cCompiler = dialog.getCCompiler();
606 if(!cCompiler.isEmpty())
608 m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
609 "C compiler.", cCompiler, false);
612 else if(dialog.crossCompilerSetup())
614 QString fortranCompiler = dialog.getFortranCompiler();
615 if(!fortranCompiler.isEmpty())
617 m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER",
618 "Fortran compiler.", fortranCompiler, false);
621 QString mode = dialog.getCrossIncludeMode();
622 m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE",
623 "CMake Find Include Mode", mode, false);
624 mode = dialog.getCrossLibraryMode();
625 m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY",
626 "CMake Find Library Mode", mode, false);
627 mode = dialog.getCrossProgramMode();
628 m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM",
629 "CMake Find Program Mode", mode, false);
631 QString rootPath = dialog.getCrossRoot();
632 m->insertProperty(QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH",
633 "CMake Find Root Path", rootPath, false);
635 QString systemName = dialog.getSystemName();
636 m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME",
637 "CMake System Name", systemName, false);
638 QString cxxCompiler = dialog.getCXXCompiler();
639 m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER",
640 "CXX compiler.", cxxCompiler, false);
641 QString cCompiler = dialog.getCCompiler();
642 m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER",
643 "C compiler.", cCompiler, false);
645 else if(dialog.crossCompilerToolChainFile())
647 QString toolchainFile = dialog.getCrossCompilerToolChainFile();
648 m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE",
649 "Cross Compile ToolChain File", toolchainFile, false);
651 return true;
654 return false;
657 void CMakeSetupDialog::updateGeneratorLabel(const QString& gen)
659 QString str = tr("Current Generator: ");
660 if(gen.isEmpty())
662 str += tr("None");
664 else
666 str += gen;
668 this->Generator->setText(str);
671 void CMakeSetupDialog::doReloadCache()
673 QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
674 "reloadCache", Qt::QueuedConnection);
677 void CMakeSetupDialog::doDeleteCache()
679 QString title = tr("Delete Cache");
680 QString message = "Are you sure you want to delete the cache?";
681 QMessageBox::StandardButton btn;
682 btn = QMessageBox::information(this, title, message,
683 QMessageBox::Yes | QMessageBox::No);
684 if(btn == QMessageBox::No)
686 return;
688 QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
689 "deleteCache", Qt::QueuedConnection);
692 void CMakeSetupDialog::doAbout()
694 QString msg = "CMake %1\n"
695 "Using Qt %2\n"
696 "www.cmake.org";
698 msg = msg.arg(cmVersion::GetCMakeVersion());
699 msg = msg.arg(qVersion());
701 QDialog dialog;
702 dialog.setWindowTitle(tr("About"));
703 QVBoxLayout* l = new QVBoxLayout(&dialog);
704 QLabel* lab = new QLabel(&dialog);
705 l->addWidget(lab);
706 lab->setText(msg);
707 lab->setWordWrap(true);
708 QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
709 Qt::Horizontal, &dialog);
710 QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
711 l->addWidget(btns);
712 dialog.exec();
715 void CMakeSetupDialog::setExitAfterGenerate(bool b)
717 this->ExitAfterGenerate = b;
720 void CMakeSetupDialog::addBinaryPath(const QString& path)
722 QString cleanpath = QDir::cleanPath(path);
724 // update UI
725 this->BinaryDirectory->blockSignals(true);
726 int idx = this->BinaryDirectory->findText(cleanpath);
727 if(idx != -1)
729 this->BinaryDirectory->removeItem(idx);
731 this->BinaryDirectory->insertItem(0, cleanpath);
732 this->BinaryDirectory->setCurrentIndex(0);
733 this->BinaryDirectory->blockSignals(false);
735 // save to registry
736 QStringList buildPaths = this->loadBuildPaths();
737 buildPaths.removeAll(cleanpath);
738 buildPaths.prepend(cleanpath);
739 this->saveBuildPaths(buildPaths);
742 void CMakeSetupDialog::dragEnterEvent(QDragEnterEvent* e)
744 if(!(this->CurrentState == ReadyConfigure ||
745 this->CurrentState == ReadyGenerate))
747 e->ignore();
748 return;
751 const QMimeData* dat = e->mimeData();
752 QList<QUrl> urls = dat->urls();
753 QString file = urls.count() ? urls[0].toLocalFile() : QString();
754 if(!file.isEmpty() &&
755 (file.endsWith("CMakeCache.txt", Qt::CaseInsensitive) ||
756 file.endsWith("CMakeLists.txt", Qt::CaseInsensitive) ) )
758 e->accept();
760 else
762 e->ignore();
766 void CMakeSetupDialog::dropEvent(QDropEvent* e)
768 if(!(this->CurrentState == ReadyConfigure ||
769 this->CurrentState == ReadyGenerate))
771 return;
774 const QMimeData* dat = e->mimeData();
775 QList<QUrl> urls = dat->urls();
776 QString file = urls.count() ? urls[0].toLocalFile() : QString();
777 if(file.endsWith("CMakeCache.txt", Qt::CaseInsensitive))
779 QFileInfo info(file);
780 if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
782 this->setBinaryDirectory(info.absolutePath());
785 else if(file.endsWith("CMakeLists.txt", Qt::CaseInsensitive))
787 QFileInfo info(file);
788 if(this->CMakeThread->cmakeInstance()->binaryDirectory() != info.absolutePath())
790 this->setSourceDirectory(info.absolutePath());
791 this->setBinaryDirectory(info.absolutePath());
796 QStringList CMakeSetupDialog::loadBuildPaths()
798 QSettings settings;
799 settings.beginGroup("Settings/StartPath");
801 QStringList buildPaths;
802 for(int i=0; i<10; i++)
804 QString p = settings.value(QString("WhereBuild%1").arg(i)).toString();
805 if(!p.isEmpty())
807 buildPaths.append(p);
810 return buildPaths;
813 void CMakeSetupDialog::saveBuildPaths(const QStringList& paths)
815 QSettings settings;
816 settings.beginGroup("Settings/StartPath");
818 int num = paths.count();
819 if(num > 10)
821 num = 10;
824 for(int i=0; i<num; i++)
826 settings.setValue(QString("WhereBuild%1").arg(i), paths[i]);
830 void CMakeSetupDialog::setCacheModified()
832 this->CacheModified = true;
833 this->enterState(ReadyConfigure);
836 void CMakeSetupDialog::removeSelectedCacheEntries()
838 QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
839 QList<QPersistentModelIndex> pidxs;
840 foreach(QModelIndex i, idxs)
842 pidxs.append(i);
844 foreach(QPersistentModelIndex pi, pidxs)
846 this->CacheValues->model()->removeRow(pi.row(), pi.parent());
850 void CMakeSetupDialog::selectionChanged()
852 QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows();
853 if(idxs.count() &&
854 (this->CurrentState == ReadyConfigure ||
855 this->CurrentState == ReadyGenerate) )
857 this->RemoveEntry->setEnabled(true);
859 else
861 this->RemoveEntry->setEnabled(false);
865 void CMakeSetupDialog::enterState(CMakeSetupDialog::State s)
867 if(s == this->CurrentState)
869 return;
872 this->CurrentState = s;
874 if(s == Interrupting)
876 this->ConfigureButton->setEnabled(false);
877 this->GenerateButton->setEnabled(false);
879 else if(s == Configuring)
881 this->Output->clear();
882 this->setEnabledState(false);
883 this->GenerateButton->setEnabled(false);
884 this->GenerateAction->setEnabled(false);
885 this->ConfigureButton->setText(tr("&Stop"));
887 else if(s == Generating)
889 this->CacheModified = false;
890 this->setEnabledState(false);
891 this->ConfigureButton->setEnabled(false);
892 this->GenerateAction->setEnabled(false);
893 this->GenerateButton->setText(tr("&Stop"));
895 else if(s == ReadyConfigure)
897 this->ProgressBar->reset();
898 this->setEnabledState(true);
899 this->GenerateButton->setEnabled(false);
900 this->GenerateAction->setEnabled(false);
901 this->ConfigureButton->setEnabled(true);
902 this->ConfigureButton->setText(tr("&Configure"));
903 this->GenerateButton->setText(tr("&Generate"));
905 else if(s == ReadyGenerate)
907 this->ProgressBar->reset();
908 this->setEnabledState(true);
909 this->GenerateButton->setEnabled(true);
910 this->GenerateAction->setEnabled(true);
911 this->ConfigureButton->setEnabled(true);
912 this->ConfigureButton->setText(tr("&Configure"));
913 this->GenerateButton->setText(tr("&Generate"));
917 void CMakeSetupDialog::addCacheEntry()
919 QDialog dialog(this);
920 dialog.resize(400, 200);
921 dialog.setWindowTitle(tr("Add Cache Entry"));
922 QVBoxLayout* l = new QVBoxLayout(&dialog);
923 AddCacheEntry* w = new AddCacheEntry(&dialog);
924 QDialogButtonBox* btns = new QDialogButtonBox(
925 QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
926 Qt::Horizontal, &dialog);
927 QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
928 QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(reject()));
929 l->addWidget(w);
930 l->addStretch();
931 l->addWidget(btns);
932 if(QDialog::Accepted == dialog.exec())
934 QCMakeCacheModel* m = this->CacheValues->cacheModel();
935 m->insertProperty(w->type(), w->name(), w->description(), w->value(), false);
939 void CMakeSetupDialog::startSearch()
941 this->Search->setFocus(Qt::OtherFocusReason);
942 this->Search->selectAll();
945 void CMakeSetupDialog::setDebugOutput(bool flag)
947 QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
948 "setDebugOutput", Qt::QueuedConnection, Q_ARG(bool, flag));
951 void CMakeSetupDialog::setViewType(int v)
953 if(v == 0) // simple view
955 this->CacheValues->cacheModel()->setViewType(QCMakeCacheModel::FlatView);
956 this->CacheValues->setRootIsDecorated(false);
957 this->CacheValues->setShowAdvanced(false);
959 else if(v == 1) // advanced view
961 this->CacheValues->cacheModel()->setViewType(QCMakeCacheModel::FlatView);
962 this->CacheValues->setRootIsDecorated(false);
963 this->CacheValues->setShowAdvanced(true);
965 else if(v == 2) // grouped view
967 this->CacheValues->cacheModel()->setViewType(QCMakeCacheModel::GroupView);
968 this->CacheValues->setRootIsDecorated(true);
969 this->CacheValues->setShowAdvanced(true);
972 QSettings settings;
973 settings.beginGroup("Settings/StartPath");
974 settings.setValue("GroupView", v == 2);
978 void CMakeSetupDialog::showUserChanges()
980 QSet<QCMakeProperty> changes =
981 qobject_cast<QCMakeCacheModelDelegate*>(this->CacheValues->itemDelegate())->changes();
983 QDialog dialog(this);
984 dialog.setWindowTitle(tr("My Changes"));
985 dialog.resize(600, 400);
986 QVBoxLayout* l = new QVBoxLayout(&dialog);
987 QTextEdit* textedit = new QTextEdit(&dialog);
988 textedit->setReadOnly(true);
989 l->addWidget(textedit);
990 QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Close,
991 Qt::Horizontal, &dialog);
992 QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(accept()));
993 l->addWidget(btns);
995 QString command;
996 QString cache;
998 foreach(QCMakeProperty prop, changes)
1000 QString type;
1001 switch(prop.Type)
1003 case QCMakeProperty::BOOL:
1004 type = "BOOL";
1005 break;
1006 case QCMakeProperty::PATH:
1007 type = "PATH";
1008 break;
1009 case QCMakeProperty::FILEPATH:
1010 type = "FILEPATH";
1011 break;
1012 case QCMakeProperty::STRING:
1013 type = "STRING";
1014 break;
1016 QString value;
1017 if(prop.Type == QCMakeProperty::BOOL)
1019 value = prop.Value.toBool() ? "1" : "0";
1021 else
1023 value = prop.Value.toString();
1026 QString line("%1:%2=");
1027 line = line.arg(prop.Key);
1028 line = line.arg(type);
1030 command += QString("-D%1\"%2\" ").arg(line).arg(value);
1031 cache += QString("%1%2\n").arg(line).arg(value);
1034 textedit->append(tr("Commandline options:"));
1035 textedit->append(command);
1036 textedit->append("\n");
1037 textedit->append(tr("Cache file:"));
1038 textedit->append(cache);
1040 dialog.exec();
1043 void CMakeSetupDialog::setSearchFilter(const QString& str)
1045 this->CacheValues->selectionModel()->clear();
1046 this->CacheValues->setSearchFilter(str);