diff options
Diffstat (limited to 'Source/QtDialog')
35 files changed, 5171 insertions, 0 deletions
diff --git a/Source/QtDialog/AddCacheEntry.cxx b/Source/QtDialog/AddCacheEntry.cxx new file mode 100644 index 000000000..e7fedc5c5 --- /dev/null +++ b/Source/QtDialog/AddCacheEntry.cxx @@ -0,0 +1,83 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "AddCacheEntry.h" +#include <QMetaProperty> +#include <QCompleter> + +static const int NumTypes = 4; +static const QByteArray TypeStrings[NumTypes] = + { "BOOL", "PATH", "FILEPATH", "STRING" }; +static const QCMakeProperty::PropertyType Types[NumTypes] = + { QCMakeProperty::BOOL, QCMakeProperty::PATH, + QCMakeProperty::FILEPATH, QCMakeProperty::STRING}; + +AddCacheEntry::AddCacheEntry(QWidget* p, const QStringList& completions) + : QWidget(p) +{ + this->setupUi(this); + for(int i=0; i<NumTypes; i++) + { + this->Type->addItem(TypeStrings[i]); + } + QWidget* cb = new QCheckBox(); + QWidget* path = new QCMakePathEditor(); + QWidget* filepath = new QCMakeFilePathEditor(); + QWidget* string = new QLineEdit(); + this->StackedWidget->addWidget(cb); + this->StackedWidget->addWidget(path); + this->StackedWidget->addWidget(filepath); + this->StackedWidget->addWidget(string); + this->setTabOrder(this->Name, this->Type); + this->setTabOrder(this->Type, cb); + this->setTabOrder(cb, path); + this->setTabOrder(path, filepath); + this->setTabOrder(filepath, string); + this->setTabOrder(string, this->Description); + this->Name->setCompleter(new QCompleter(completions, this)); +} + +QString AddCacheEntry::name() const +{ + return this->Name->text(); +} + +QVariant AddCacheEntry::value() const +{ + QWidget* w = this->StackedWidget->currentWidget(); + if(qobject_cast<QLineEdit*>(w)) + { + return static_cast<QLineEdit*>(w)->text(); + } + else if(qobject_cast<QCheckBox*>(w)) + { + return static_cast<QCheckBox*>(w)->isChecked(); + } + return QVariant(); +} + +QString AddCacheEntry::description() const +{ + return this->Description->text(); +} + +QCMakeProperty::PropertyType AddCacheEntry::type() const +{ + int idx = this->Type->currentIndex(); + if(idx >= 0 && idx < NumTypes) + { + return Types[idx]; + } + return QCMakeProperty::BOOL; +} + + diff --git a/Source/QtDialog/AddCacheEntry.h b/Source/QtDialog/AddCacheEntry.h new file mode 100644 index 000000000..e219d4ee7 --- /dev/null +++ b/Source/QtDialog/AddCacheEntry.h @@ -0,0 +1,36 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef AddCacheEntry_h +#define AddCacheEntry_h + +#include <QWidget> +#include <QCheckBox> +#include <QStringList> + +#include "QCMake.h" +#include "ui_AddCacheEntry.h" + +class AddCacheEntry : public QWidget, public Ui::AddCacheEntry +{ + Q_OBJECT +public: + AddCacheEntry(QWidget* p, const QStringList& completions); + + QString name() const; + QVariant value() const; + QString description() const; + QCMakeProperty::PropertyType type() const; +}; + +#endif + diff --git a/Source/QtDialog/AddCacheEntry.ui b/Source/QtDialog/AddCacheEntry.ui new file mode 100644 index 000000000..a81587473 --- /dev/null +++ b/Source/QtDialog/AddCacheEntry.ui @@ -0,0 +1,97 @@ +<ui version="4.0" > + <class>AddCacheEntry</class> + <widget class="QWidget" name="AddCacheEntry" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>380</width> + <height>158</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>0</number> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Name:</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLineEdit" name="Name" /> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Type:</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QComboBox" name="Type" > + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="label_5" > + <property name="text" > + <string>Value:</string> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QStackedWidget" name="StackedWidget" > + <property name="currentIndex" > + <number>0</number> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="label_3" > + <property name="text" > + <string>Description:</string> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QLineEdit" name="Description" /> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QCMakePathEditor</class> + <extends>QLineEdit</extends> + <header>QCMakeWidgets.h</header> + </customwidget> + <customwidget> + <class>QCMakeFilePathEditor</class> + <extends>QLineEdit</extends> + <header>QCMakeWidgets.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>Type</sender> + <signal>currentIndexChanged(int)</signal> + <receiver>StackedWidget</receiver> + <slot>setCurrentIndex(int)</slot> + <hints> + <hint type="sourcelabel" > + <x>229</x> + <y>34</y> + </hint> + <hint type="destinationlabel" > + <x>287</x> + <y>65</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Source/QtDialog/CMake.desktop b/Source/QtDialog/CMake.desktop new file mode 100644 index 000000000..645eb76e9 --- /dev/null +++ b/Source/QtDialog/CMake.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=1.0 +Name=CMake +Comment=Cross-platform buildsystem +Exec=cmake-gui %f +Icon=CMakeSetup32.png +Terminal=false +X-MultipleArgs=false +Type=Application +Categories=Development; +StartupNotify=true +MimeType=application/x-cmakecache; diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt new file mode 100644 index 000000000..07ec10674 --- /dev/null +++ b/Source/QtDialog/CMakeLists.txt @@ -0,0 +1,123 @@ +#============================================================================= +# CMake - Cross Platform Makefile Generator +# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +PROJECT(QtDialog) +SET(QT_MIN_VERSION "4.4.0") +FIND_PACKAGE(Qt4 REQUIRED) + +IF(NOT QT4_FOUND) + MESSAGE(SEND_ERROR "Failed to find Qt 4.4 or greater.") +ELSE(NOT QT4_FOUND) + + INCLUDE(${QT_USE_FILE}) + SET(CMAKE_PACKAGE_QTGUI TRUE) + SET(SRCS + AddCacheEntry.cxx + AddCacheEntry.h + CMakeSetup.cxx + CMakeSetupDialog.cxx + CMakeSetupDialog.h + FirstConfigure.cxx + FirstConfigure.h + QCMake.cxx + QCMake.h + QCMakeCacheView.cxx + QCMakeCacheView.h + QCMakeWidgets.cxx + QCMakeWidgets.h + QMacInstallDialog.cxx + QMacInstallDialog.h + ) + QT4_WRAP_UI(UI_SRCS + CMakeSetupDialog.ui + Compilers.ui + CrossCompiler.ui + AddCacheEntry.ui + MacInstallDialog.ui + ) + QT4_WRAP_CPP(MOC_SRCS + AddCacheEntry.h + Compilers.h + CMakeSetupDialog.h + FirstConfigure.h + QCMake.h + QCMakeCacheView.h + QCMakeWidgets.h + QMacInstallDialog.h + ) + QT4_ADD_RESOURCES(RC_SRCS CMakeSetup.qrc) + + SET(SRCS ${SRCS} ${UI_SRCS} ${MOC_SRCS} ${RC_SRCS}) + IF(Q_WS_WIN) + SET(SRCS ${SRCS} CMakeSetup.rc) + ENDIF(Q_WS_WIN) + IF(Q_WS_MAC) + SET(SRCS ${SRCS} CMakeSetup.icns) + SET(MACOSX_BUNDLE_ICON_FILE CMakeSetup.icns) + SET_SOURCE_FILES_PROPERTIES(CMakeSetup.icns PROPERTIES + MACOSX_PACKAGE_LOCATION Resources) + ENDIF(Q_WS_MAC) + + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + + ADD_EXECUTABLE(cmake-gui WIN32 MACOSX_BUNDLE ${SRCS}) + TARGET_LINK_LIBRARIES(cmake-gui CMakeLib ${QT_QTMAIN_LIBRARY} ${QT_LIBRARIES}) + IF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.4) + IF(APPLE) + SET_TARGET_PROPERTIES(cmake-gui PROPERTIES + OUTPUT_NAME ${CMAKE_BUNDLE_NAME}) + ENDIF(APPLE) + SET(CMAKE_INSTALL_DESTINATION_ARGS + BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}") + ENDIF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.4) + + INSTALL(TARGETS cmake-gui RUNTIME DESTINATION bin ${CMAKE_INSTALL_DESTINATION_ARGS}) + + IF(UNIX) + # install a desktop file so CMake appears in the application start menu + # with an icon + INSTALL(FILES CMake.desktop DESTINATION share/applications ) + INSTALL(FILES CMakeSetup32.png DESTINATION share/pixmaps ) + INSTALL(FILES cmakecache.xml DESTINATION share/mime/packages ) + ENDIF(UNIX) + + IF(APPLE) + SET(CMAKE_POSTFLIGHT_SCRIPT + "${CMake_BINARY_DIR}/Source/QtDialog/postflight.sh") + SET(CMAKE_POSTUPGRADE_SCRIPT + "${CMake_BINARY_DIR}/Source/QtDialog/postupgrade.sh") + configure_file("${CMake_SOURCE_DIR}/Source/QtDialog/postflight.sh.in" + "${CMake_BINARY_DIR}/Source/QtDialog/postflight.sh") + configure_file("${CMake_SOURCE_DIR}/Source/QtDialog/postupgrade.sh.in" + "${CMake_BINARY_DIR}/Source/QtDialog/postupgrade.sh") + INSTALL(CODE "execute_process(COMMAND ln -s \"../MacOS/${CMAKE_BUNDLE_NAME}\" cmake-gui + WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin)") + ENDIF(APPLE) + + if(APPLE OR WIN32) + # install rules for including 3rd party libs such as Qt + # if a system Qt is used (e.g. installed in /usr/lib/), it will not be included in the installation + set(fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin/cmake-gui${CMAKE_EXECUTABLE_SUFFIX}") + if(APPLE) + set(fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/MacOS/${CMAKE_BUNDLE_NAME}") + endif(APPLE) + install(CODE " + include(\"${CMake_SOURCE_DIR}/Modules/BundleUtilities.cmake\") + set(BU_CHMOD_BUNDLE_ITEMS ON) + fixup_bundle(\"${fixup_exe}\" \"\" \"${QT_LIBRARY_DIR};${QT_BINARY_DIR}\") + ") + endif(APPLE OR WIN32) + + CONFIGURE_FILE("${QtDialog_SOURCE_DIR}/QtDialogCPack.cmake.in" + "${QtDialog_BINARY_DIR}/QtDialogCPack.cmake" @ONLY) +ENDIF(NOT QT4_FOUND) + diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx new file mode 100644 index 000000000..c942bc4ad --- /dev/null +++ b/Source/QtDialog/CMakeSetup.cxx @@ -0,0 +1,205 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "QCMake.h" // include to disable MS warnings +#include <QApplication> +#include <QDir> +#include <QTranslator> +#include <QLocale> +#include "QMacInstallDialog.h" +#include "CMakeSetupDialog.h" +#include "cmDocumentation.h" +#include "cmake.h" +#include "cmVersion.h" +#include <cmsys/CommandLineArguments.hxx> +#include <cmsys/SystemTools.hxx> + +//---------------------------------------------------------------------------- +static const char * cmDocumentationName[][3] = +{ + {0, + " cmake-gui - CMake GUI.", 0}, + {0,0,0} +}; + +//---------------------------------------------------------------------------- +static const char * cmDocumentationUsage[][3] = +{ + {0, + " cmake-gui [options]\n" + " cmake-gui [options] <path-to-source>\n" + " cmake-gui [options] <path-to-existing-build>", 0}, + {0,0,0} +}; + +//---------------------------------------------------------------------------- +static const char * cmDocumentationDescription[][3] = +{ + {0, + "The \"cmake-gui\" executable is the CMake GUI. Project " + "configuration settings may be specified interactively. " + "Brief instructions are provided at the bottom of the " + "window when the program is running.", 0}, + CMAKE_STANDARD_INTRODUCTION, + {0,0,0} +}; + +//---------------------------------------------------------------------------- +static const char * cmDocumentationOptions[][3] = +{ + {0,0,0} +}; + +int main(int argc, char** argv) +{ + cmSystemTools::FindExecutableDirectory(argv[0]); + // check docs first so that X is not need to get docs + // do docs, if args were given + cmDocumentation doc; + doc.addCMakeStandardDocSections(); + if(argc >1 && doc.CheckOptions(argc, argv)) + { + // Construct and print requested documentation. + cmake hcm; + hcm.AddCMakePaths(); + // just incase the install is bad avoid a seg fault + const char* root = hcm.GetCacheDefinition("CMAKE_ROOT"); + if(root) + { + doc.SetCMakeRoot(root); + } + std::vector<cmDocumentationEntry> commands; + std::vector<cmDocumentationEntry> compatCommands; + std::map<std::string,cmDocumentationSection *> propDocs; + + std::vector<cmDocumentationEntry> generators; + hcm.GetCommandDocumentation(commands, true, false); + hcm.GetCommandDocumentation(compatCommands, false, true); + hcm.GetGeneratorDocumentation(generators); + hcm.GetPropertiesDocumentation(propDocs); + doc.SetName("cmake"); + doc.SetSection("Name",cmDocumentationName); + doc.SetSection("Usage",cmDocumentationUsage); + doc.SetSection("Description",cmDocumentationDescription); + doc.AppendSection("Generators",generators); + doc.PrependSection("Options",cmDocumentationOptions); + doc.SetSection("Commands",commands); + doc.SetSection("Compatilbility Commands", compatCommands); + doc.SetSections(propDocs); + + return (doc.PrintRequestedDocumentation(std::cout)? 0:1); + } + + QApplication app(argc, argv); + + // clean out standard Qt paths for plugins, which we don't use anyway + // when creating Mac bundles, it potentially causes problems + foreach(QString p, QApplication::libraryPaths()) + { + QApplication::removeLibraryPath(p); + } + + // if arg for install + for(int i =0; i < argc; i++) + { + if(strcmp(argv[i], "--mac-install") == 0) + { + QMacInstallDialog setupdialog(0); + setupdialog.exec(); + return 0; + } + } + // tell the cmake library where cmake is + QDir cmExecDir(QApplication::applicationDirPath()); +#if defined(Q_OS_MAC) + cmExecDir.cd("../../../"); +#endif + + // pick up translation files if they exists in the data directory + QDir translationsDir = cmExecDir; + translationsDir.cd(QString::fromLocal8Bit(".." CMAKE_DATA_DIR)); + translationsDir.cd("i18n"); + QTranslator translator; + QString transfile = QString("cmake_%1").arg(QLocale::system().name()); + translator.load(transfile, translationsDir.path()); + app.installTranslator(&translator); + + // app setup + app.setApplicationName("CMakeSetup"); + app.setOrganizationName("Kitware"); + QIcon appIcon; + appIcon.addFile(":/Icons/CMakeSetup32.png"); + appIcon.addFile(":/Icons/CMakeSetup128.png"); + app.setWindowIcon(appIcon); + + CMakeSetupDialog dialog; + dialog.show(); + + cmsys::CommandLineArguments arg; + arg.Initialize(argc, argv); + std::string binaryDirectory; + std::string sourceDirectory; + typedef cmsys::CommandLineArguments argT; + arg.AddArgument("-B", argT::CONCAT_ARGUMENT, + &binaryDirectory, "Binary Directory"); + arg.AddArgument("-H", argT::CONCAT_ARGUMENT, + &sourceDirectory, "Source Directory"); + // do not complain about unknown options + arg.StoreUnusedArguments(true); + arg.Parse(); + if(!sourceDirectory.empty() && !binaryDirectory.empty()) + { + dialog.setSourceDirectory(QString::fromLocal8Bit(sourceDirectory.c_str())); + dialog.setBinaryDirectory(QString::fromLocal8Bit(binaryDirectory.c_str())); + } + else + { + QStringList args = app.arguments(); + if(args.count() == 2) + { + cmsys_stl::string filePath = cmSystemTools::CollapseFullPath(args[1].toLocal8Bit().data()); + + // check if argument is a directory containing CMakeCache.txt + cmsys_stl::string buildFilePath = + cmSystemTools::CollapseFullPath("CMakeCache.txt", filePath.c_str()); + + // check if argument is a CMakeCache.txt file + if(cmSystemTools::GetFilenameName(filePath) == "CMakeCache.txt" && + cmSystemTools::FileExists(filePath.c_str())) + { + buildFilePath = filePath; + } + + // check if argument is a directory containing CMakeLists.txt + cmsys_stl::string srcFilePath = + cmSystemTools::CollapseFullPath("CMakeLists.txt", filePath.c_str()); + + if(cmSystemTools::FileExists(buildFilePath.c_str())) + { + dialog.setBinaryDirectory( + QString::fromLocal8Bit( + cmSystemTools::GetFilenamePath(buildFilePath).c_str() + ) + ); + } + else if(cmSystemTools::FileExists(srcFilePath.c_str())) + { + dialog.setSourceDirectory(QString::fromLocal8Bit(filePath.c_str())); + dialog.setBinaryDirectory( + QString::fromLocal8Bit(cmSystemTools::CollapseFullPath(".").c_str()) + ); + } + } + } + + return app.exec(); +} + diff --git a/Source/QtDialog/CMakeSetup.icns b/Source/QtDialog/CMakeSetup.icns Binary files differnew file mode 100644 index 000000000..4a50c0416 --- /dev/null +++ b/Source/QtDialog/CMakeSetup.icns diff --git a/Source/QtDialog/CMakeSetup.ico b/Source/QtDialog/CMakeSetup.ico Binary files differnew file mode 100644 index 000000000..e13bb156f --- /dev/null +++ b/Source/QtDialog/CMakeSetup.ico diff --git a/Source/QtDialog/CMakeSetup.qrc b/Source/QtDialog/CMakeSetup.qrc new file mode 100644 index 000000000..eaac19223 --- /dev/null +++ b/Source/QtDialog/CMakeSetup.qrc @@ -0,0 +1,8 @@ +<RCC> + <qresource prefix="/Icons" > + <file>CMakeSetup128.png</file> + <file>CMakeSetup32.png</file> + <file>Delete16.png</file> + <file>Plus16.png</file> + </qresource> +</RCC> diff --git a/Source/QtDialog/CMakeSetup.rc b/Source/QtDialog/CMakeSetup.rc new file mode 100644 index 000000000..fcc887ddb --- /dev/null +++ b/Source/QtDialog/CMakeSetup.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "CMakeSetup.ico" diff --git a/Source/QtDialog/CMakeSetup128.png b/Source/QtDialog/CMakeSetup128.png Binary files differnew file mode 100644 index 000000000..12f1d9a9a --- /dev/null +++ b/Source/QtDialog/CMakeSetup128.png diff --git a/Source/QtDialog/CMakeSetup32.png b/Source/QtDialog/CMakeSetup32.png Binary files differnew file mode 100644 index 000000000..7bbcee413 --- /dev/null +++ b/Source/QtDialog/CMakeSetup32.png diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx new file mode 100644 index 000000000..c0dde1c2c --- /dev/null +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -0,0 +1,1152 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "CMakeSetupDialog.h" +#include <QFileDialog> +#include <QProgressBar> +#include <QMessageBox> +#include <QStatusBar> +#include <QToolButton> +#include <QDialogButtonBox> +#include <QCloseEvent> +#include <QCoreApplication> +#include <QSettings> +#include <QMenu> +#include <QMenuBar> +#include <QDragEnterEvent> +#include <QMimeData> +#include <QUrl> +#include <QShortcut> +#include <QKeySequence> +#include <QMacInstallDialog.h> + +#include "QCMake.h" +#include "QCMakeCacheView.h" +#include "AddCacheEntry.h" +#include "FirstConfigure.h" +#include "cmVersion.h" + +QCMakeThread::QCMakeThread(QObject* p) + : QThread(p), CMakeInstance(NULL) +{ +} + +QCMake* QCMakeThread::cmakeInstance() const +{ + return this->CMakeInstance; +} + +void QCMakeThread::run() +{ + this->CMakeInstance = new QCMake; + // emit that this cmake thread is ready for use + emit this->cmakeInitialized(); + this->exec(); + delete this->CMakeInstance; + this->CMakeInstance = NULL; +} + +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"); + int h = settings.value("Height", 500).toInt(); + int w = settings.value("Width", 700).toInt(); + this->resize(w, h); + + this->AddVariableCompletions = settings.value("AddVariableCompletionEntries", + QStringList("CMAKE_INSTALL_PREFIX")).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, SIGNAL(triggered(bool)), + this, SLOT(doReloadCache())); + this->DeleteCacheAction = FileMenu->addAction(tr("&Delete Cache")); + QObject::connect(this->DeleteCacheAction, SIGNAL(triggered(bool)), + this, SLOT(doDeleteCache())); + this->ExitAction = FileMenu->addAction(tr("E&xit")); + this->ExitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); + QObject::connect(this->ExitAction, SIGNAL(triggered(bool)), + this, SLOT(close())); + + QMenu* ToolsMenu = this->menuBar()->addMenu(tr("&Tools")); + this->ConfigureAction = ToolsMenu->addAction(tr("&Configure")); + // prevent merging with Preferences menu item on Mac OS X + this->ConfigureAction->setMenuRole(QAction::NoRole); + QObject::connect(this->ConfigureAction, SIGNAL(triggered(bool)), + this, SLOT(doConfigure())); + this->GenerateAction = ToolsMenu->addAction(tr("&Generate")); + QObject::connect(this->GenerateAction, SIGNAL(triggered(bool)), + this, SLOT(doGenerate())); + QAction* showChangesAction = ToolsMenu->addAction(tr("&Show My Changes")); + QObject::connect(showChangesAction, SIGNAL(triggered(bool)), + this, SLOT(showUserChanges())); +#if defined(Q_WS_MAC) + this->InstallForCommandLineAction + = ToolsMenu->addAction(tr("&Install For Command Line Use")); + QObject::connect(this->InstallForCommandLineAction, SIGNAL(triggered(bool)), + this, SLOT(doInstallForCommandLine())); +#endif + QMenu* OptionsMenu = this->menuBar()->addMenu(tr("&Options")); + this->SuppressDevWarningsAction = + OptionsMenu->addAction(tr("&Suppress dev Warnings (-Wno-dev)")); + this->SuppressDevWarningsAction->setCheckable(true); + this->WarnUninitializedAction = + OptionsMenu->addAction(tr("&Warn Uninitialized (--warn-uninitialized)")); + this->WarnUninitializedAction->setCheckable(true); + this->WarnUnusedAction = + OptionsMenu->addAction(tr("&Warn Unused (--warn-unused-vars)")); + this->WarnUnusedAction->setCheckable(true); + + QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output")); + debugAction->setCheckable(true); + QObject::connect(debugAction, SIGNAL(toggled(bool)), + this, SLOT(setDebugOutput(bool))); + + OptionsMenu->addSeparator(); + QAction* expandAction = OptionsMenu->addAction(tr("&Expand Grouped Entries")); + QObject::connect(expandAction, SIGNAL(triggered(bool)), + this->CacheValues, SLOT(expandAll())); + QAction* collapseAction = OptionsMenu->addAction(tr("&Collapse Grouped Entries")); + QObject::connect(collapseAction, SIGNAL(triggered(bool)), + this->CacheValues, SLOT(collapseAll())); + + QMenu* HelpMenu = this->menuBar()->addMenu(tr("&Help")); + QAction* a = HelpMenu->addAction(tr("About")); + QObject::connect(a, SIGNAL(triggered(bool)), + this, SLOT(doAbout())); + a = HelpMenu->addAction(tr("Help")); + QObject::connect(a, SIGNAL(triggered(bool)), + this, SLOT(doHelp())); + + QShortcut* filterShortcut = new QShortcut(QKeySequence::Find, this); + QObject::connect(filterShortcut, SIGNAL(activated()), + this, SLOT(startSearch())); + + 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)); + + // start the cmake worker thread + this->CMakeThread = new QCMakeThread(this); + QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()), + this, SLOT(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(), + SIGNAL(propertiesChanged(const QCMakePropertyList&)), + this->CacheValues->cacheModel(), + SLOT(setProperties(const QCMakePropertyList&))); + + QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)), + this, SLOT(doConfigure())); + + QObject::connect(this->CMakeThread->cmakeInstance(), SIGNAL(configureDone(int)), + this, SLOT(exitLoop(int))); + QObject::connect(this->CMakeThread->cmakeInstance(), SIGNAL(generateDone(int)), + this, SLOT(exitLoop(int))); + + QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)), + this, SLOT(doGenerate())); + + QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)), + this, SLOT(doSourceBrowse())); + QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)), + this, SLOT(doBinaryBrowse())); + + QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)), + this, SLOT(onBinaryDirectoryChanged(QString))); + QObject::connect(this->SourceDirectory, SIGNAL(textChanged(QString)), + this, SLOT(onSourceDirectoryChanged(QString))); + + QObject::connect(this->CMakeThread->cmakeInstance(), + SIGNAL(sourceDirChanged(QString)), + this, SLOT(updateSourceDirectory(QString))); + QObject::connect(this->CMakeThread->cmakeInstance(), + SIGNAL(binaryDirChanged(QString)), + this, SLOT(updateBinaryDirectory(QString))); + + QObject::connect(this->CMakeThread->cmakeInstance(), + SIGNAL(progressChanged(QString, float)), + this, SLOT(showProgress(QString,float))); + + QObject::connect(this->CMakeThread->cmakeInstance(), + SIGNAL(errorMessage(QString)), + this, SLOT(error(QString))); + + QObject::connect(this->CMakeThread->cmakeInstance(), + SIGNAL(outputMessage(QString)), + this, SLOT(message(QString))); + + QObject::connect(this->groupedCheck, SIGNAL(toggled(bool)), + this, SLOT(setGroupedView(bool))); + QObject::connect(this->advancedCheck, SIGNAL(toggled(bool)), + this, SLOT(setAdvancedView(bool))); + QObject::connect(this->Search, SIGNAL(textChanged(QString)), + this, SLOT(setSearchFilter(QString))); + + QObject::connect(this->CMakeThread->cmakeInstance(), + SIGNAL(generatorChanged(QString)), + this, SLOT(updateGeneratorLabel(QString))); + this->updateGeneratorLabel(QString()); + + QObject::connect(this->CacheValues->cacheModel(), + SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(setCacheModified())); + + QObject::connect(this->CacheValues->selectionModel(), + SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(selectionChanged())); + QObject::connect(this->RemoveEntry, SIGNAL(clicked(bool)), + this, SLOT(removeSelectedCacheEntries())); + QObject::connect(this->AddEntry, SIGNAL(clicked(bool)), + this, SLOT(addCacheEntry())); + + QObject::connect(this->SuppressDevWarningsAction, SIGNAL(triggered(bool)), + this->CMakeThread->cmakeInstance(), SLOT(setSuppressDevWarnings(bool))); + + QObject::connect(this->WarnUninitializedAction, SIGNAL(triggered(bool)), + this->CMakeThread->cmakeInstance(), + SLOT(setWarnUninitializedMode(bool))); + QObject::connect(this->WarnUnusedAction, SIGNAL(triggered(bool)), + this->CMakeThread->cmakeInstance(), + SLOT(setWarnUnusedMode(bool))); + + 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()); + } +} + +CMakeSetupDialog::~CMakeSetupDialog() +{ + QSettings settings; + settings.beginGroup("Settings/StartPath"); + settings.setValue("Height", this->height()); + settings.setValue("Width", this->width()); + 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(); +} + +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() +{ + QMacInstallDialog setupdialog(0); + setupdialog.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(); + + this->ConfigureNeeded = true; +} + +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()); + int msgWidth = met.width(msg); + 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, SIGNAL(accepted()), &dialog, SLOT(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()); + 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()); + 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)); +} + +void CMakeSetupDialog::error(const QString& msg) +{ + this->Output->setCurrentCharFormat(this->ErrorFormat); + this->Output->append(msg); +} + +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 +} + +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()); + + 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 cxxCompiler = dialog.getCXXCompiler(); + m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER", + tr("CXX compiler."), cxxCompiler, false); + QString cCompiler = dialog.getCCompiler(); + 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\n" + "Using Qt %2\n" + "www.cmake.org"); + + msg = msg.arg(cmVersion::GetCMakeVersion()); + msg = msg.arg(qVersion()); + + 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, SIGNAL(accepted()), &dialog, SLOT(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->enterState(ReadyConfigure); +} + +void CMakeSetupDialog::removeSelectedCacheEntries() +{ + QModelIndexList idxs = this->CacheValues->selectionModel()->selectedRows(); + QList<QPersistentModelIndex> pidxs; + foreach(QModelIndex i, idxs) + { + pidxs.append(i); + } + foreach(QPersistentModelIndex 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); + } + else if(s == Configuring) + { + this->setEnabledState(false); + this->GenerateButton->setEnabled(false); + this->GenerateAction->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->GenerateButton->setText(tr("&Stop")); + } + else if(s == ReadyConfigure) + { + 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")); + } + else if(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::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->AddVariableCompletions); + QDialogButtonBox* btns = new QDialogButtonBox( + QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + Qt::Horizontal, &dialog); + QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept())); + QObject::connect(btns, SIGNAL(rejected()), &dialog, SLOT(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->AddVariableCompletions.contains(w->name())) + { + this->AddVariableCompletions << w->name(); + // limit to at most 100 completion items + if (this->AddVariableCompletions.size() > 100) + { + this->AddVariableCompletions.removeFirst(); + } + // make sure CMAKE_INSTALL_PREFIX is always there + if (!this->AddVariableCompletions.contains("CMAKE_INSTALL_PREFIX")) + { + this->AddVariableCompletions << QString("CMAKE_INSTALL_PREFIX"); + } + QSettings settings; + settings.beginGroup("Settings/StartPath"); + settings.setValue("AddVariableCompletionEntries", + this->AddVariableCompletions); + } + } +} + +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, SIGNAL(rejected()), &dialog, SLOT(accept())); + l->addWidget(btns); + + QString command; + QString cache; + + foreach(QCMakeProperty 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 line("%1:%2="); + line = line.arg(prop.Key); + line = line.arg(type); + + command += QString("-D%1\"%2\" ").arg(line).arg(value); + cache += QString("%1%2\n").arg(line).arg(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); +} + + diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h new file mode 100644 index 000000000..259967580 --- /dev/null +++ b/Source/QtDialog/CMakeSetupDialog.h @@ -0,0 +1,132 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef CMakeSetupDialog_h +#define CMakeSetupDialog_h + +#include "QCMake.h" +#include <QMainWindow> +#include <QThread> +#include <QEventLoop> +#include "ui_CMakeSetupDialog.h" + +class QCMakeThread; +class CMakeCacheModel; +class QProgressBar; +class QToolButton; + +/// Qt user interface for CMake +class CMakeSetupDialog : public QMainWindow, public Ui::CMakeSetupDialog +{ + Q_OBJECT +public: + CMakeSetupDialog(); + ~CMakeSetupDialog(); + +public slots: + void setBinaryDirectory(const QString& dir); + void setSourceDirectory(const QString& dir); + +protected slots: + void initialize(); + void doConfigure(); + void doGenerate(); + void doInstallForCommandLine(); + void doHelp(); + void doAbout(); + void doInterrupt(); + void error(const QString& message); + void message(const QString& message); + + void doSourceBrowse(); + void doBinaryBrowse(); + void doReloadCache(); + void doDeleteCache(); + void updateSourceDirectory(const QString& dir); + void updateBinaryDirectory(const QString& dir); + void showProgress(const QString& msg, float percent); + void setEnabledState(bool); + bool setupFirstConfigure(); + void updateGeneratorLabel(const QString& gen); + void setExitAfterGenerate(bool); + void addBinaryPath(const QString&); + QStringList loadBuildPaths(); + void saveBuildPaths(const QStringList&); + void onBinaryDirectoryChanged(const QString& dir); + void onSourceDirectoryChanged(const QString& dir); + void setCacheModified(); + void removeSelectedCacheEntries(); + void selectionChanged(); + void addCacheEntry(); + void startSearch(); + void setDebugOutput(bool); + void setAdvancedView(bool); + void setGroupedView(bool); + void showUserChanges(); + void setSearchFilter(const QString& str); + bool prepareConfigure(); + bool doConfigureInternal(); + bool doGenerateInternal(); + void exitLoop(int); + +protected: + + enum State { Interrupting, ReadyConfigure, ReadyGenerate, Configuring, Generating }; + void enterState(State s); + + void closeEvent(QCloseEvent*); + void dragEnterEvent(QDragEnterEvent*); + void dropEvent(QDropEvent*); + + QCMakeThread* CMakeThread; + bool ExitAfterGenerate; + bool CacheModified; + bool ConfigureNeeded; + QAction* ReloadCacheAction; + QAction* DeleteCacheAction; + QAction* ExitAction; + QAction* ConfigureAction; + QAction* GenerateAction; + QAction* SuppressDevWarningsAction; + QAction* WarnUninitializedAction; + QAction* WarnUnusedAction; + QAction* InstallForCommandLineAction; + State CurrentState; + + QTextCharFormat ErrorFormat; + QTextCharFormat MessageFormat; + + QStringList AddVariableCompletions; + + QEventLoop LocalLoop; + + float ProgressOffset; + float ProgressFactor; +}; + +// QCMake instance on a thread +class QCMakeThread : public QThread +{ + Q_OBJECT +public: + QCMakeThread(QObject* p); + QCMake* cmakeInstance() const; + +signals: + void cmakeInitialized(); + +protected: + virtual void run(); + QCMake* CMakeInstance; +}; + +#endif // CMakeSetupDialog_h diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui new file mode 100644 index 000000000..dc8ee3fbd --- /dev/null +++ b/Source/QtDialog/CMakeSetupDialog.ui @@ -0,0 +1,310 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CMakeSetupDialog</class> + <widget class="QWidget" name="CMakeSetupDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>707</width> + <height>582</height> + </rect> + </property> + <layout class="QGridLayout"> + <property name="margin"> + <number>9</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <item row="0" column="0"> + <layout class="QGridLayout"> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Where is the source code:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="SourceDirectory"/> + </item> + <item row="0" column="2"> + <widget class="QPushButton" name="BrowseSourceDirectoryButton"> + <property name="text"> + <string>Browse &Source...</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Where to build the binaries:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="BinaryDirectory"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Ignored" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QPushButton" name="BrowseBinaryDirectoryButton"> + <property name="text"> + <string>Browse &Build...</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="0"> + <widget class="QSplitter" name="Splitter"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <layout class="QHBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Search:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="Search"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>23</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="groupedCheck"> + <property name="text"> + <string>Grouped</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="advancedCheck"> + <property name="text"> + <string>Advanced</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="AddEntry"> + <property name="toolTip"> + <string>Add New Entry</string> + </property> + <property name="text"> + <string>&Add Entry</string> + </property> + <property name="icon"> + <iconset resource="CMakeSetup.qrc"> + <normaloff>:/Icons/Plus16.png</normaloff>:/Icons/Plus16.png</iconset> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="RemoveEntry"> + <property name="toolTip"> + <string>Remove Selected Entries</string> + </property> + <property name="text"> + <string>&Remove Entry</string> + </property> + <property name="icon"> + <iconset resource="CMakeSetup.qrc"> + <normaloff>:/Icons/Delete16.png</normaloff>:/Icons/Delete16.png</iconset> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QCMakeCacheView" name="CacheValues"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::ExtendedSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Press Configure to update and display new values in red, then press Generate to generate selected build files.</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="ConfigureButton"> + <property name="text"> + <string>&Configure</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="GenerateButton"> + <property name="text"> + <string>&Generate</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="Generator"> + <property name="text"> + <string>Current Generator:</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>121</width> + <height>27</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QProgressBar" name="ProgressBar"> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="value"> + <number>0</number> + </property> + <property name="textVisible"> + <bool>false</bool> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="textDirection"> + <enum>QProgressBar::BottomToTop</enum> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QTextEdit" name="Output"> + <property name="lineWrapMode"> + <enum>QTextEdit::NoWrap</enum> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QCMakeCacheView</class> + <extends>QTreeView</extends> + <header>QCMakeCacheView.h</header> + </customwidget> + </customwidgets> + <resources> + <include location="CMakeSetup.qrc"/> + </resources> + <connections/> +</ui> diff --git a/Source/QtDialog/Compilers.h b/Source/QtDialog/Compilers.h new file mode 100644 index 000000000..e9c90a504 --- /dev/null +++ b/Source/QtDialog/Compilers.h @@ -0,0 +1,21 @@ + + +#ifndef COMPILERS_HPP +#define COMPILERS_HPP + +#include <QWidget> +#include <ui_Compilers.h> + +class Compilers : public QWidget, public Ui::Compilers +{ + Q_OBJECT +public: + Compilers(QWidget* p=NULL) : + QWidget(p) + { + this->setupUi(this); + } +}; + +#endif + diff --git a/Source/QtDialog/Compilers.ui b/Source/QtDialog/Compilers.ui new file mode 100644 index 000000000..41f70acdb --- /dev/null +++ b/Source/QtDialog/Compilers.ui @@ -0,0 +1,87 @@ +<ui version="4.0" > + <class>Compilers</class> + <widget class="QWidget" name="Compilers" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>506</width> + <height>115</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <property name="leftMargin" > + <number>0</number> + </property> + <property name="topMargin" > + <number>0</number> + </property> + <property name="rightMargin" > + <number>0</number> + </property> + <property name="bottomMargin" > + <number>0</number> + </property> + <item row="0" column="0" > + <widget class="QGroupBox" name="groupBox_4" > + <property name="title" > + <string>Compilers</string> + </property> + <layout class="QGridLayout" > + <property name="leftMargin" > + <number>4</number> + </property> + <property name="topMargin" > + <number>4</number> + </property> + <property name="rightMargin" > + <number>4</number> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="label_16" > + <property name="text" > + <string>C</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QCMakeFilePathEditor" name="CCompiler" /> + </item> + <item row="0" column="2" > + <widget class="QLabel" name="label_17" > + <property name="text" > + <string>C++</string> + </property> + </widget> + </item> + <item row="0" column="3" > + <widget class="QCMakeFilePathEditor" name="CXXCompiler" /> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_18" > + <property name="text" > + <string>Fortran</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QCMakeFilePathEditor" name="FortranCompiler" /> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QCMakeFilePathEditor</class> + <extends>QLineEdit</extends> + <header>QCMakeWidgets.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/Source/QtDialog/CrossCompiler.ui b/Source/QtDialog/CrossCompiler.ui new file mode 100644 index 000000000..1fb1ebf49 --- /dev/null +++ b/Source/QtDialog/CrossCompiler.ui @@ -0,0 +1,213 @@ +<ui version="4.0" > + <class>CrossCompiler</class> + <widget class="QWidget" name="CrossCompiler" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>433</width> + <height>319</height> + </rect> + </property> + <property name="windowTitle" > + <string>CrossCompiler</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QGroupBox" name="groupBox" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title" > + <string>Target System</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="label_6" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Operating System</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLineEdit" name="systemName" /> + </item> + <item row="0" column="2" colspan="2" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_10" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Version</string> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLineEdit" name="systemVersion" /> + </item> + <item row="1" column="2" > + <widget class="QLabel" name="label_11" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Processor</string> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="3" > + <widget class="QLineEdit" name="systemProcessor" /> + </item> + </layout> + </widget> + </item> + <item row="2" column="0" > + <widget class="QGroupBox" name="groupBox_2" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title" > + <string>Find Program/Library/Include</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="label_9" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Target Root</string> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QCMakePathEditor" name="crossFindRoot" /> + </item> + <item row="0" column="2" > + <widget class="QLabel" name="label_12" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Program Mode</string> + </property> + </widget> + </item> + <item row="0" column="3" > + <widget class="QComboBox" name="crossProgramMode" /> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_13" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Library Mode</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QComboBox" name="crossLibraryMode" /> + </item> + <item row="1" column="2" > + <widget class="QLabel" name="label_14" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text" > + <string>Include Mode</string> + </property> + </widget> + </item> + <item row="1" column="3" > + <widget class="QComboBox" name="crossIncludeMode" /> + </item> + </layout> + </widget> + </item> + <item row="1" column="0" > + <widget class="Compilers" native="1" name="CrossCompilers" > + <property name="focusPolicy" > + <enum>Qt::TabFocus</enum> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QCMakePathEditor</class> + <extends>QLineEdit</extends> + <header>QCMakeWidgets.h</header> + </customwidget> + <customwidget> + <class>Compilers</class> + <extends>QWidget</extends> + <header>Compilers.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>systemVersion</tabstop> + <tabstop>systemProcessor</tabstop> + <tabstop>CrossCompilers</tabstop> + <tabstop>crossFindRoot</tabstop> + <tabstop>crossProgramMode</tabstop> + <tabstop>crossLibraryMode</tabstop> + <tabstop>crossIncludeMode</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/Source/QtDialog/Delete16.png b/Source/QtDialog/Delete16.png Binary files differnew file mode 100644 index 000000000..16989fee1 --- /dev/null +++ b/Source/QtDialog/Delete16.png diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx new file mode 100644 index 000000000..2a79877da --- /dev/null +++ b/Source/QtDialog/FirstConfigure.cxx @@ -0,0 +1,509 @@ + +#include "FirstConfigure.h" +#include "Compilers.h" + +#include <QSettings> +#include <QRadioButton> +#include <QComboBox> +#include <QVBoxLayout> + + +StartCompilerSetup::StartCompilerSetup(QWidget* p) + : QWizardPage(p) +{ + QVBoxLayout* l = new QVBoxLayout(this); + l->addWidget(new QLabel(tr("Specify the generator for this project"))); + this->GeneratorOptions = new QComboBox(this); + l->addWidget(this->GeneratorOptions); + l->addSpacing(6); + + this->CompilerSetupOptions[0] = new QRadioButton(tr("Use default native compilers"), this); + this->CompilerSetupOptions[1] = new QRadioButton(tr("Specify native compilers"), this); + this->CompilerSetupOptions[2] = new QRadioButton(tr("Specify toolchain file for cross-compiling"), this); + this->CompilerSetupOptions[3] = new QRadioButton(tr("Specify options for cross-compiling"), this); + l->addWidget(this->CompilerSetupOptions[0]); + l->addWidget(this->CompilerSetupOptions[1]); + l->addWidget(this->CompilerSetupOptions[2]); + l->addWidget(this->CompilerSetupOptions[3]); + + this->CompilerSetupOptions[0]->setChecked(true); + + QObject::connect(this->CompilerSetupOptions[0], SIGNAL(toggled(bool)), + this, SLOT(onSelectionChanged(bool))); + QObject::connect(this->CompilerSetupOptions[1], SIGNAL(toggled(bool)), + this, SLOT(onSelectionChanged(bool))); + QObject::connect(this->CompilerSetupOptions[2], SIGNAL(toggled(bool)), + this, SLOT(onSelectionChanged(bool))); + QObject::connect(this->CompilerSetupOptions[3], SIGNAL(toggled(bool)), + this, SLOT(onSelectionChanged(bool))); +} + +StartCompilerSetup::~StartCompilerSetup() +{ +} + +void StartCompilerSetup::setGenerators(const QStringList& gens) +{ + this->GeneratorOptions->clear(); + this->GeneratorOptions->addItems(gens); +}; + +void StartCompilerSetup::setCurrentGenerator(const QString& gen) +{ + int idx = this->GeneratorOptions->findText(gen); + if(idx != -1) + { + this->GeneratorOptions->setCurrentIndex(idx); + } +} + +QString StartCompilerSetup::getGenerator() const +{ + return this->GeneratorOptions->currentText(); +}; + +bool StartCompilerSetup::defaultSetup() const +{ + return this->CompilerSetupOptions[0]->isChecked(); +} + +bool StartCompilerSetup::compilerSetup() const +{ + return this->CompilerSetupOptions[1]->isChecked(); +} + +bool StartCompilerSetup::crossCompilerToolChainFile() const +{ + return this->CompilerSetupOptions[2]->isChecked(); +} + +bool StartCompilerSetup::crossCompilerSetup() const +{ + return this->CompilerSetupOptions[3]->isChecked(); +} + +void StartCompilerSetup::onSelectionChanged(bool on) +{ + if(on) + selectionChanged(); +} + +int StartCompilerSetup::nextId() const +{ + if(compilerSetup()) + return NativeSetup; + if(crossCompilerSetup()) + return CrossSetup; + if(crossCompilerToolChainFile()) + return ToolchainSetup; + return -1; +} + +NativeCompilerSetup::NativeCompilerSetup(QWidget* p) + : QWizardPage(p) +{ + QVBoxLayout* l = new QVBoxLayout(this); + QWidget* c = new QWidget(this); + l->addWidget(c); + this->setupUi(c); +} + +NativeCompilerSetup::~NativeCompilerSetup() +{ +} + +QString NativeCompilerSetup::getCCompiler() const +{ + return this->CCompiler->text(); +} + +void NativeCompilerSetup::setCCompiler(const QString& s) +{ + this->CCompiler->setText(s); +} + +QString NativeCompilerSetup::getCXXCompiler() const +{ + return this->CXXCompiler->text(); +} + +void NativeCompilerSetup::setCXXCompiler(const QString& s) +{ + this->CXXCompiler->setText(s); +} + +QString NativeCompilerSetup::getFortranCompiler() const +{ + return this->FortranCompiler->text(); +} + +void NativeCompilerSetup::setFortranCompiler(const QString& s) +{ + this->FortranCompiler->setText(s); +} + + +CrossCompilerSetup::CrossCompilerSetup(QWidget* p) + : QWizardPage(p) +{ + this->setupUi(this); + QWidget::setTabOrder(systemName, systemVersion); + QWidget::setTabOrder(systemVersion, systemProcessor); + QWidget::setTabOrder(systemProcessor, CrossCompilers->CCompiler); + QWidget::setTabOrder(CrossCompilers->CCompiler, CrossCompilers->CXXCompiler); + QWidget::setTabOrder(CrossCompilers->CXXCompiler, CrossCompilers->FortranCompiler); + QWidget::setTabOrder(CrossCompilers->FortranCompiler, crossFindRoot); + QWidget::setTabOrder(crossFindRoot, crossProgramMode); + QWidget::setTabOrder(crossProgramMode, crossLibraryMode); + QWidget::setTabOrder(crossLibraryMode, crossIncludeMode); + + // fill in combo boxes + QStringList modes; + modes << tr("Search in Target Root, then native system"); + modes << tr("Search only in Target Root"); + modes << tr("Search only in native system"); + crossProgramMode->addItems(modes); + crossLibraryMode->addItems(modes); + crossIncludeMode->addItems(modes); + crossProgramMode->setCurrentIndex(2); + crossLibraryMode->setCurrentIndex(1); + crossIncludeMode->setCurrentIndex(1); + + this->registerField("systemName*", this->systemName); +} + +CrossCompilerSetup::~CrossCompilerSetup() +{ +} + +QString CrossCompilerSetup::getCCompiler() const +{ + return this->CrossCompilers->CCompiler->text(); +} + +void CrossCompilerSetup::setCCompiler(const QString& s) +{ + this->CrossCompilers->CCompiler->setText(s); +} + +QString CrossCompilerSetup::getCXXCompiler() const +{ + return this->CrossCompilers->CXXCompiler->text(); +} + +void CrossCompilerSetup::setCXXCompiler(const QString& s) +{ + this->CrossCompilers->CXXCompiler->setText(s); +} + +QString CrossCompilerSetup::getFortranCompiler() const +{ + return this->CrossCompilers->FortranCompiler->text(); +} + +void CrossCompilerSetup::setFortranCompiler(const QString& s) +{ + this->CrossCompilers->FortranCompiler->setText(s); +} + +QString CrossCompilerSetup::getSystem() const +{ + return this->systemName->text(); +} + +void CrossCompilerSetup::setSystem(const QString& t) +{ + this->systemName->setText(t); +} + + +QString CrossCompilerSetup::getVersion() const +{ + return this->systemVersion->text(); +} + +void CrossCompilerSetup::setVersion(const QString& t) +{ + this->systemVersion->setText(t); +} + + +QString CrossCompilerSetup::getProcessor() const +{ + return this->systemProcessor->text(); +} + +void CrossCompilerSetup::setProcessor(const QString& t) +{ + this->systemProcessor->setText(t); +} + +QString CrossCompilerSetup::getFindRoot() const +{ + return this->crossFindRoot->text(); +} + +void CrossCompilerSetup::setFindRoot(const QString& t) +{ + return this->crossFindRoot->setText(t); +} + +int CrossCompilerSetup::getProgramMode() const +{ + return this->crossProgramMode->currentIndex(); +} + +int CrossCompilerSetup::getLibraryMode() const +{ + return this->crossLibraryMode->currentIndex(); +} + +int CrossCompilerSetup::getIncludeMode() const +{ + return this->crossIncludeMode->currentIndex(); +} + +void CrossCompilerSetup::setProgramMode(int m) +{ + this->crossProgramMode->setCurrentIndex(m); +} + +void CrossCompilerSetup::setLibraryMode(int m) +{ + this->crossLibraryMode->setCurrentIndex(m); +} + +void CrossCompilerSetup::setIncludeMode(int m) +{ + this->crossIncludeMode->setCurrentIndex(m); +} + +ToolchainCompilerSetup::ToolchainCompilerSetup(QWidget* p) + : QWizardPage(p) +{ + QVBoxLayout* l = new QVBoxLayout(this); + l->addWidget(new QLabel(tr("Specify the Toolchain file"))); + this->ToolchainFile = new QCMakeFilePathEditor(this); + l->addWidget(this->ToolchainFile); +} + +ToolchainCompilerSetup::~ToolchainCompilerSetup() +{ +} + +QString ToolchainCompilerSetup::toolchainFile() const +{ + return this->ToolchainFile->text(); +} + +void ToolchainCompilerSetup::setToolchainFile(const QString& t) +{ + this->ToolchainFile->setText(t); +} + + + +FirstConfigure::FirstConfigure() +{ + //this->setOption(QWizard::HaveFinishButtonOnEarlyPages, true); + this->mStartCompilerSetupPage = new StartCompilerSetup(this); + this->setPage(Start, this->mStartCompilerSetupPage); + QObject::connect(this->mStartCompilerSetupPage, SIGNAL(selectionChanged()), + this, SLOT(restart())); + + this->mNativeCompilerSetupPage = new NativeCompilerSetup(this); + this->setPage(NativeSetup, this->mNativeCompilerSetupPage); + + this->mCrossCompilerSetupPage = new CrossCompilerSetup(this); + this->setPage(CrossSetup, this->mCrossCompilerSetupPage); + + this->mToolchainCompilerSetupPage = new ToolchainCompilerSetup(this); + this->setPage(ToolchainSetup, this->mToolchainCompilerSetupPage); +} + +FirstConfigure::~FirstConfigure() +{ +} + +void FirstConfigure::setGenerators(const QStringList& gens) +{ + this->mStartCompilerSetupPage->setGenerators(gens); +} + +QString FirstConfigure::getGenerator() const +{ + return this->mStartCompilerSetupPage->getGenerator(); +} + +void FirstConfigure::loadFromSettings() +{ + QSettings settings; + // restore generator + settings.beginGroup("Settings/StartPath"); + QString lastGen = settings.value("LastGenerator").toString(); + this->mStartCompilerSetupPage->setCurrentGenerator(lastGen); + settings.endGroup(); + + // restore compiler setup + settings.beginGroup("Settings/Compiler"); + this->mNativeCompilerSetupPage->setCCompiler(settings.value("CCompiler").toString()); + this->mNativeCompilerSetupPage->setCXXCompiler(settings.value("CXXCompiler").toString()); + this->mNativeCompilerSetupPage->setFortranCompiler(settings.value("FortranCompiler").toString()); + settings.endGroup(); + + // restore cross compiler setup + settings.beginGroup("Settings/CrossCompiler"); + this->mCrossCompilerSetupPage->setCCompiler(settings.value("CCompiler").toString()); + this->mCrossCompilerSetupPage->setCXXCompiler(settings.value("CXXCompiler").toString()); + this->mCrossCompilerSetupPage->setFortranCompiler(settings.value("FortranCompiler").toString()); + this->mToolchainCompilerSetupPage->setToolchainFile(settings.value("ToolChainFile").toString()); + this->mCrossCompilerSetupPage->setSystem(settings.value("SystemName").toString()); + this->mCrossCompilerSetupPage->setVersion(settings.value("SystemVersion").toString()); + this->mCrossCompilerSetupPage->setProcessor(settings.value("SystemProcessor").toString()); + this->mCrossCompilerSetupPage->setFindRoot(settings.value("FindRoot").toString()); + this->mCrossCompilerSetupPage->setProgramMode(settings.value("ProgramMode", 0).toInt()); + this->mCrossCompilerSetupPage->setLibraryMode(settings.value("LibraryMode", 0).toInt()); + this->mCrossCompilerSetupPage->setIncludeMode(settings.value("IncludeMode", 0).toInt()); + settings.endGroup(); +} + +void FirstConfigure::saveToSettings() +{ + QSettings settings; + + // save generator + settings.beginGroup("Settings/StartPath"); + QString lastGen = this->mStartCompilerSetupPage->getGenerator(); + settings.setValue("LastGenerator", lastGen); + settings.endGroup(); + + // save compiler setup + settings.beginGroup("Settings/Compiler"); + settings.setValue("CCompiler", this->mNativeCompilerSetupPage->getCCompiler()); + settings.setValue("CXXCompiler", this->mNativeCompilerSetupPage->getCXXCompiler()); + settings.setValue("FortranCompiler", this->mNativeCompilerSetupPage->getFortranCompiler()); + settings.endGroup(); + + // save cross compiler setup + settings.beginGroup("Settings/CrossCompiler"); + settings.setValue("CCompiler", this->mCrossCompilerSetupPage->getCCompiler()); + settings.setValue("CXXCompiler", this->mCrossCompilerSetupPage->getCXXCompiler()); + settings.setValue("FortranCompiler", this->mCrossCompilerSetupPage->getFortranCompiler()); + settings.setValue("ToolChainFile", this->getCrossCompilerToolChainFile()); + settings.setValue("SystemName", this->mCrossCompilerSetupPage->getSystem()); + settings.setValue("SystemVersion", this->mCrossCompilerSetupPage->getVersion()); + settings.setValue("SystemProcessor", this->mCrossCompilerSetupPage->getProcessor()); + settings.setValue("FindRoot", this->mCrossCompilerSetupPage->getFindRoot()); + settings.setValue("ProgramMode", this->mCrossCompilerSetupPage->getProgramMode()); + settings.setValue("LibraryMode", this->mCrossCompilerSetupPage->getLibraryMode()); + settings.setValue("IncludeMode", this->mCrossCompilerSetupPage->getIncludeMode()); + settings.endGroup(); +} + +bool FirstConfigure::defaultSetup() const +{ + return this->mStartCompilerSetupPage->defaultSetup(); +} + +bool FirstConfigure::compilerSetup() const +{ + return this->mStartCompilerSetupPage->compilerSetup(); +} + +bool FirstConfigure::crossCompilerSetup() const +{ + return this->mStartCompilerSetupPage->crossCompilerSetup(); +} + +bool FirstConfigure::crossCompilerToolChainFile() const +{ + return this->mStartCompilerSetupPage->crossCompilerToolChainFile(); +} + +QString FirstConfigure::getCrossCompilerToolChainFile() const +{ + return this->mToolchainCompilerSetupPage->toolchainFile(); +} + +QString FirstConfigure::getSystemName() const +{ + return this->mCrossCompilerSetupPage->getSystem(); +} + +QString FirstConfigure::getCCompiler() const +{ + if(this->compilerSetup()) + { + return this->mNativeCompilerSetupPage->getCCompiler(); + } + else if(this->crossCompilerSetup()) + { + return this->mCrossCompilerSetupPage->getCCompiler(); + } + return QString(); +} + +QString FirstConfigure::getCXXCompiler() const +{ + if(this->compilerSetup()) + { + return this->mNativeCompilerSetupPage->getCXXCompiler(); + } + else if(this->crossCompilerSetup()) + { + return this->mCrossCompilerSetupPage->getCXXCompiler(); + } + return QString(); +} + +QString FirstConfigure::getFortranCompiler() const +{ + if(this->compilerSetup()) + { + return this->mNativeCompilerSetupPage->getFortranCompiler(); + } + else if(this->crossCompilerSetup()) + { + return this->mCrossCompilerSetupPage->getFortranCompiler(); + } + return QString(); +} + + +QString FirstConfigure::getSystemVersion() const +{ + return this->mCrossCompilerSetupPage->getVersion(); +} + +QString FirstConfigure::getSystemProcessor() const +{ + return this->mCrossCompilerSetupPage->getProcessor(); +} + +QString FirstConfigure::getCrossRoot() const +{ + return this->mCrossCompilerSetupPage->getFindRoot(); +} + +const QString CrossModes[] = +{ + "BOTH", + "ONLY", + "NEVER" +}; + +QString FirstConfigure::getCrossProgramMode() const +{ + return CrossModes[this->mCrossCompilerSetupPage->getProgramMode()]; +} + +QString FirstConfigure::getCrossLibraryMode() const +{ + return CrossModes[this->mCrossCompilerSetupPage->getLibraryMode()]; +} + +QString FirstConfigure::getCrossIncludeMode() const +{ + return CrossModes[this->mCrossCompilerSetupPage->getIncludeMode()]; +} + diff --git a/Source/QtDialog/FirstConfigure.h b/Source/QtDialog/FirstConfigure.h new file mode 100644 index 000000000..f4e368bfc --- /dev/null +++ b/Source/QtDialog/FirstConfigure.h @@ -0,0 +1,177 @@ + +#ifndef FirstConfigure_h +#define FirstConfigure_h + +#include <QWizard> +#include <QWizardPage> +#include "ui_Compilers.h" +#include "ui_CrossCompiler.h" + +class QRadioButton; +class QComboBox; + +//! the wizard pages we'll use for the first configure of a build +enum FirstConfigurePages +{ + Start, + NativeSetup, + ToolchainSetup, + CrossSetup, + Done +}; + +//! the first page that gives basic options for what compilers setup to choose from +class StartCompilerSetup : public QWizardPage +{ + Q_OBJECT + public: + StartCompilerSetup(QWidget* p); + ~StartCompilerSetup(); + void setGenerators(const QStringList& gens); + void setCurrentGenerator(const QString& gen); + QString getGenerator() const; + + bool defaultSetup() const; + bool compilerSetup() const; + bool crossCompilerSetup() const; + bool crossCompilerToolChainFile() const; + + int nextId() const; + + signals: + void selectionChanged(); + + protected slots: + void onSelectionChanged(bool); + + protected: + QComboBox* GeneratorOptions; + QRadioButton* CompilerSetupOptions[4]; +}; + +//! the page that gives basic options for native compilers +class NativeCompilerSetup : public QWizardPage, protected Ui::Compilers +{ + Q_OBJECT + public: + NativeCompilerSetup(QWidget* p); + ~NativeCompilerSetup(); + + QString getCCompiler() const; + void setCCompiler(const QString&); + + QString getCXXCompiler() const; + void setCXXCompiler(const QString&); + + QString getFortranCompiler() const; + void setFortranCompiler(const QString&); + + int nextId() const { return -1; } +}; + +//! the page that gives options for cross compilers +class CrossCompilerSetup : public QWizardPage, protected Ui::CrossCompiler +{ + Q_OBJECT + public: + CrossCompilerSetup(QWidget* p); + ~CrossCompilerSetup(); + + QString getSystem() const; + void setSystem(const QString&); + + QString getVersion() const; + void setVersion(const QString&); + + QString getProcessor() const; + void setProcessor(const QString&); + + QString getCCompiler() const; + void setCCompiler(const QString&); + + QString getCXXCompiler() const; + void setCXXCompiler(const QString&); + + QString getFortranCompiler() const; + void setFortranCompiler(const QString&); + + QString getFindRoot() const; + void setFindRoot(const QString&); + + enum CrossMode + { + BOTH, + ONLY, + NEVER + }; + + int getProgramMode() const; + void setProgramMode(int); + int getLibraryMode() const; + void setLibraryMode(int); + int getIncludeMode() const; + void setIncludeMode(int); + + int nextId() const { return -1; } +}; + +//! the page that gives options for a toolchain file +class ToolchainCompilerSetup : public QWizardPage +{ + Q_OBJECT + public: + ToolchainCompilerSetup(QWidget* p); + ~ToolchainCompilerSetup(); + + QString toolchainFile() const; + void setToolchainFile(const QString&); + + int nextId() const { return -1; } + + protected: + QCMakeFilePathEditor* ToolchainFile; +}; + +//! the wizard with the pages +class FirstConfigure : public QWizard +{ + Q_OBJECT +public: + FirstConfigure(); + ~FirstConfigure(); + + void setGenerators(const QStringList& gens); + QString getGenerator() const; + + bool defaultSetup() const; + bool compilerSetup() const; + bool crossCompilerSetup() const; + bool crossCompilerToolChainFile() const; + + QString getCCompiler() const; + QString getCXXCompiler() const; + QString getFortranCompiler() const; + + QString getSystemName() const; + QString getSystemVersion() const; + QString getSystemProcessor() const; + QString getCrossRoot() const; + QString getCrossProgramMode() const; + QString getCrossLibraryMode() const; + QString getCrossIncludeMode() const; + + QString getCrossCompilerToolChainFile() const; + + void loadFromSettings(); + void saveToSettings(); + +protected: + StartCompilerSetup* mStartCompilerSetupPage; + NativeCompilerSetup* mNativeCompilerSetupPage; + CrossCompilerSetup* mCrossCompilerSetupPage; + ToolchainCompilerSetup* mToolchainCompilerSetupPage; + +}; + +#endif // FirstConfigure_h + diff --git a/Source/QtDialog/MacInstallDialog.ui b/Source/QtDialog/MacInstallDialog.ui new file mode 100644 index 000000000..c7e31dbbe --- /dev/null +++ b/Source/QtDialog/MacInstallDialog.ui @@ -0,0 +1,103 @@ +<ui version="4.0" > + <class>Dialog</class> + <widget class="QDialog" name="Dialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>470</width> + <height>159</height> + </rect> + </property> + <property name="windowTitle" > + <string>Install Command Line Tools</string> + </property> + <layout class="QGridLayout" > + <property name="margin" > + <number>9</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item row="3" column="1" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0" colspan="3" > + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="skipInstallButton" > + <property name="text" > + <string>Skip Install Command Line </string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="doInstallButton" > + <property name="text" > + <string>Install Command Line Links</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="0" column="2" > + <widget class="QPushButton" name="choosePathButton" > + <property name="text" > + <string>Choose...</string> + </property> + </widget> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Install Folder:</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLineEdit" name="InstallPrefix" /> + </item> + <item row="1" column="0" colspan="3" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>This will create symbolic links to the command line tools of cmake into the specified install folder.</string> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/Source/QtDialog/Plus16.png b/Source/QtDialog/Plus16.png Binary files differnew file mode 100644 index 000000000..552f6f004 --- /dev/null +++ b/Source/QtDialog/Plus16.png diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx new file mode 100644 index 000000000..8554ff894 --- /dev/null +++ b/Source/QtDialog/QCMake.cxx @@ -0,0 +1,448 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "QCMake.h" + +#include <QDir> +#include <QCoreApplication> + +#include "cmake.h" +#include "cmCacheManager.h" +#include "cmSystemTools.h" +#include "cmExternalMakefileProjectGenerator.h" + +#ifdef Q_OS_WIN +#include "qt_windows.h" // For SetErrorMode +#endif + +QCMake::QCMake(QObject* p) + : QObject(p) +{ + this->SuppressDevWarnings = false; + this->WarnUninitializedMode = false; + this->WarnUnusedMode = false; + qRegisterMetaType<QCMakeProperty>(); + qRegisterMetaType<QCMakePropertyList>(); + + QDir execDir(QCoreApplication::applicationDirPath()); + +#if defined(Q_OS_MAC) + if(execDir.exists("../bin/cmake")) + { + execDir.cd("../bin"); + } + else + { + execDir.cd("../../../"); // path to cmake in build directory (need to fix for deployment) + } +#endif + + QString cmakeCommand = QString("cmake")+QString::fromLocal8Bit(cmSystemTools::GetExecutableExtension()); + cmakeCommand = execDir.filePath(cmakeCommand); + + cmSystemTools::DisableRunCommandOutput(); + cmSystemTools::SetRunCommandHideConsole(true); + cmSystemTools::SetErrorCallback(QCMake::errorCallback, this); + cmSystemTools::FindExecutableDirectory(cmakeCommand.toLocal8Bit().data()); + + this->CMakeInstance = new cmake; + this->CMakeInstance->SetCMakeCommand(cmakeCommand.toLocal8Bit().data()); +#if defined(Q_OS_MAC) + this->CMakeInstance->SetCMakeEditCommand("cmake-gui.app/Contents/MacOS/cmake-gui"); +#else + this->CMakeInstance->SetCMakeEditCommand("cmake-gui"); +#endif + this->CMakeInstance->SetProgressCallback(QCMake::progressCallback, this); + + cmSystemTools::SetInterruptCallback(QCMake::interruptCallback, this); + + std::vector<std::string> generators; + this->CMakeInstance->GetRegisteredGenerators(generators); + std::vector<std::string>::iterator iter; + for(iter = generators.begin(); iter != generators.end(); ++iter) + { + // Skip the generator "KDevelop3", since there is also + // "KDevelop3 - Unix Makefiles", which is the full and official name. + // The short name is actually only still there since this was the name + // in CMake 2.4, to keep "command line argument compatibility", but + // this is not necessary in the GUI. + if (*iter == "KDevelop3") + { + continue; + } + this->AvailableGenerators.append(QString::fromLocal8Bit(iter->c_str())); + } +} + +QCMake::~QCMake() +{ + delete this->CMakeInstance; + //cmDynamicLoader::FlushCache(); +} + +void QCMake::loadCache(const QString& dir) +{ + this->setBinaryDirectory(dir); +} + +void QCMake::setSourceDirectory(const QString& _dir) +{ + QString dir = + QString::fromLocal8Bit(cmSystemTools::GetActualCaseForPath(_dir.toLocal8Bit().data()).c_str()); + if(this->SourceDirectory != dir) + { + this->SourceDirectory = QDir::fromNativeSeparators(dir); + emit this->sourceDirChanged(this->SourceDirectory); + } +} + +void QCMake::setBinaryDirectory(const QString& _dir) +{ + QString dir = + QString::fromLocal8Bit(cmSystemTools::GetActualCaseForPath(_dir.toLocal8Bit().data()).c_str()); + if(this->BinaryDirectory != dir) + { + this->BinaryDirectory = QDir::fromNativeSeparators(dir); + emit this->binaryDirChanged(this->BinaryDirectory); + cmCacheManager *cachem = this->CMakeInstance->GetCacheManager(); + this->setGenerator(QString()); + if(!this->CMakeInstance->GetCacheManager()->LoadCache( + this->BinaryDirectory.toLocal8Bit().data())) + { + QDir testDir(this->BinaryDirectory); + if(testDir.exists("CMakeCache.txt")) + { + cmSystemTools::Error("There is a CMakeCache.txt file for the current binary " + "tree but cmake does not have permission to read it. " + "Please check the permissions of the directory you are trying to run CMake on."); + } + } + + QCMakePropertyList props = this->properties(); + emit this->propertiesChanged(props); + cmCacheManager::CacheIterator itm = cachem->NewIterator(); + if ( itm.Find("CMAKE_HOME_DIRECTORY")) + { + setSourceDirectory(QString::fromLocal8Bit(itm.GetValue())); + } + if ( itm.Find("CMAKE_GENERATOR")) + { + const char* extraGen = cachem->GetCacheValue("CMAKE_EXTRA_GENERATOR"); + std::string curGen = cmExternalMakefileProjectGenerator:: + CreateFullGeneratorName(itm.GetValue(), extraGen); + this->setGenerator(QString::fromLocal8Bit(curGen.c_str())); + } + } +} + + +void QCMake::setGenerator(const QString& gen) +{ + if(this->Generator != gen) + { + this->Generator = gen; + emit this->generatorChanged(this->Generator); + } +} + +void QCMake::configure() +{ +#ifdef Q_OS_WIN + UINT lastErrorMode = SetErrorMode(0); +#endif + + this->CMakeInstance->SetHomeDirectory(this->SourceDirectory.toLocal8Bit().data()); + this->CMakeInstance->SetStartDirectory(this->SourceDirectory.toLocal8Bit().data()); + this->CMakeInstance->SetHomeOutputDirectory(this->BinaryDirectory.toLocal8Bit().data()); + this->CMakeInstance->SetStartOutputDirectory(this->BinaryDirectory.toLocal8Bit().data()); + this->CMakeInstance->SetGlobalGenerator( + this->CMakeInstance->CreateGlobalGenerator(this->Generator.toLocal8Bit().data())); + this->CMakeInstance->LoadCache(); + this->CMakeInstance->SetSuppressDevWarnings(this->SuppressDevWarnings); + this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode); + this->CMakeInstance->SetWarnUnused(this->WarnUnusedMode); + this->CMakeInstance->PreLoadCMakeFiles(); + + InterruptFlag = 0; + cmSystemTools::ResetErrorOccuredFlag(); + + int err = this->CMakeInstance->Configure(); + +#ifdef Q_OS_WIN + SetErrorMode(lastErrorMode); +#endif + + emit this->propertiesChanged(this->properties()); + emit this->configureDone(err); +} + +void QCMake::generate() +{ +#ifdef Q_OS_WIN + UINT lastErrorMode = SetErrorMode(0); +#endif + + InterruptFlag = 0; + cmSystemTools::ResetErrorOccuredFlag(); + + int err = this->CMakeInstance->Generate(); + +#ifdef Q_OS_WIN + SetErrorMode(lastErrorMode); +#endif + + emit this->generateDone(err); +} + +void QCMake::setProperties(const QCMakePropertyList& newProps) +{ + QCMakePropertyList props = newProps; + + QStringList toremove; + + // set the value of properties + cmCacheManager *cachem = this->CMakeInstance->GetCacheManager(); + for(cmCacheManager::CacheIterator i = cachem->NewIterator(); + !i.IsAtEnd(); i.Next()) + { + + if(i.GetType() == cmCacheManager::INTERNAL || + i.GetType() == cmCacheManager::STATIC) + { + continue; + } + + QCMakeProperty prop; + prop.Key = QString::fromLocal8Bit(i.GetName()); + int idx = props.indexOf(prop); + if(idx == -1) + { + toremove.append(QString::fromLocal8Bit(i.GetName())); + } + else + { + prop = props[idx]; + if(prop.Value.type() == QVariant::Bool) + { + i.SetValue(prop.Value.toBool() ? "ON" : "OFF"); + } + else + { + i.SetValue(prop.Value.toString().toLocal8Bit().data()); + } + props.removeAt(idx); + } + + } + + // remove some properites + foreach(QString s, toremove) + { + this->CMakeInstance->UnwatchUnusedCli(s.toLocal8Bit().data()); + + cachem->RemoveCacheEntry(s.toLocal8Bit().data()); + } + + // add some new properites + foreach(QCMakeProperty s, props) + { + this->CMakeInstance->WatchUnusedCli(s.Key.toLocal8Bit().data()); + + if(s.Type == QCMakeProperty::BOOL) + { + this->CMakeInstance->AddCacheEntry(s.Key.toLocal8Bit().data(), + s.Value.toBool() ? "ON" : "OFF", + s.Help.toLocal8Bit().data(), + cmCacheManager::BOOL); + } + else if(s.Type == QCMakeProperty::STRING) + { + this->CMakeInstance->AddCacheEntry(s.Key.toLocal8Bit().data(), + s.Value.toString().toLocal8Bit().data(), + s.Help.toLocal8Bit().data(), + cmCacheManager::STRING); + } + else if(s.Type == QCMakeProperty::PATH) + { + this->CMakeInstance->AddCacheEntry(s.Key.toLocal8Bit().data(), + s.Value.toString().toLocal8Bit().data(), + s.Help.toLocal8Bit().data(), + cmCacheManager::PATH); + } + else if(s.Type == QCMakeProperty::FILEPATH) + { + this->CMakeInstance->AddCacheEntry(s.Key.toLocal8Bit().data(), + s.Value.toString().toLocal8Bit().data(), + s.Help.toLocal8Bit().data(), + cmCacheManager::FILEPATH); + } + } + + cachem->SaveCache(this->BinaryDirectory.toLocal8Bit().data()); +} + +QCMakePropertyList QCMake::properties() const +{ + QCMakePropertyList ret; + + cmCacheManager *cachem = this->CMakeInstance->GetCacheManager(); + for(cmCacheManager::CacheIterator i = cachem->NewIterator(); + !i.IsAtEnd(); i.Next()) + { + + if(i.GetType() == cmCacheManager::INTERNAL || + i.GetType() == cmCacheManager::STATIC || + i.GetType() == cmCacheManager::UNINITIALIZED) + { + continue; + } + + QCMakeProperty prop; + prop.Key = QString::fromLocal8Bit(i.GetName()); + prop.Help = QString::fromLocal8Bit(i.GetProperty("HELPSTRING")); + prop.Value = QString::fromLocal8Bit(i.GetValue()); + prop.Advanced = i.GetPropertyAsBool("ADVANCED"); + + if(i.GetType() == cmCacheManager::BOOL) + { + prop.Type = QCMakeProperty::BOOL; + prop.Value = cmSystemTools::IsOn(i.GetValue()); + } + else if(i.GetType() == cmCacheManager::PATH) + { + prop.Type = QCMakeProperty::PATH; + } + else if(i.GetType() == cmCacheManager::FILEPATH) + { + prop.Type = QCMakeProperty::FILEPATH; + } + else if(i.GetType() == cmCacheManager::STRING) + { + prop.Type = QCMakeProperty::STRING; + if (i.PropertyExists("STRINGS")) + { + prop.Strings = QString::fromLocal8Bit(i.GetProperty("STRINGS")).split(";"); + } + } + + ret.append(prop); + } + + return ret; +} + +void QCMake::interrupt() +{ + this->InterruptFlag.ref(); +} + +bool QCMake::interruptCallback(void* cd) +{ + QCMake* self = reinterpret_cast<QCMake*>(cd); + return self->InterruptFlag; +} + +void QCMake::progressCallback(const char* msg, float percent, void* cd) +{ + QCMake* self = reinterpret_cast<QCMake*>(cd); + if(percent >= 0) + { + emit self->progressChanged(QString::fromLocal8Bit(msg), percent); + } + else + { + emit self->outputMessage(QString::fromLocal8Bit(msg)); + } + QCoreApplication::processEvents(); +} + +void QCMake::errorCallback(const char* msg, const char* /*title*/, + bool& /*stop*/, void* cd) +{ + QCMake* self = reinterpret_cast<QCMake*>(cd); + emit self->errorMessage(QString::fromLocal8Bit(msg)); + QCoreApplication::processEvents(); +} + +QString QCMake::binaryDirectory() const +{ + return this->BinaryDirectory; +} + +QString QCMake::sourceDirectory() const +{ + return this->SourceDirectory; +} + +QString QCMake::generator() const +{ + return this->Generator; +} + +QStringList QCMake::availableGenerators() const +{ + return this->AvailableGenerators; +} + +void QCMake::deleteCache() +{ + // delete cache + this->CMakeInstance->GetCacheManager()->DeleteCache(this->BinaryDirectory.toLocal8Bit().data()); + // reload to make our cache empty + this->CMakeInstance->GetCacheManager()->LoadCache(this->BinaryDirectory.toLocal8Bit().data()); + // emit no generator and no properties + this->setGenerator(QString()); + QCMakePropertyList props = this->properties(); + emit this->propertiesChanged(props); +} + +void QCMake::reloadCache() +{ + // emit that the cache was cleaned out + QCMakePropertyList props; + emit this->propertiesChanged(props); + // reload + this->CMakeInstance->GetCacheManager()->LoadCache(this->BinaryDirectory.toLocal8Bit().data()); + // emit new cache properties + props = this->properties(); + emit this->propertiesChanged(props); +} + +void QCMake::setDebugOutput(bool flag) +{ + if(flag != this->CMakeInstance->GetDebugOutput()) + { + this->CMakeInstance->SetDebugOutputOn(flag); + emit this->debugOutputChanged(flag); + } +} + +bool QCMake::getDebugOutput() const +{ + return this->CMakeInstance->GetDebugOutput(); +} + + +void QCMake::setSuppressDevWarnings(bool value) +{ + this->SuppressDevWarnings = value; +} + +void QCMake::setWarnUninitializedMode(bool value) +{ + this->WarnUninitializedMode = value; +} + +void QCMake::setWarnUnusedMode(bool value) +{ + this->WarnUnusedMode = value; +} diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h new file mode 100644 index 000000000..0d68586f2 --- /dev/null +++ b/Source/QtDialog/QCMake.h @@ -0,0 +1,154 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef __QCMake_h +#define __QCMake_h +#ifdef _MSC_VER +#pragma warning ( disable : 4127 ) +#pragma warning ( disable : 4512 ) +#endif + +#include <QObject> +#include <QString> +#include <QVariant> +#include <QList> +#include <QStringList> +#include <QMetaType> +#include <QAtomicInt> + +class cmake; + +/// struct to represent cmake properties in Qt +/// Value is of type String or Bool +struct QCMakeProperty +{ + enum PropertyType { BOOL, PATH, FILEPATH, STRING }; + QString Key; + QVariant Value; + QStringList Strings; + QString Help; + PropertyType Type; + bool Advanced; + bool operator==(const QCMakeProperty& other) const + { + return this->Key == other.Key; + } + bool operator<(const QCMakeProperty& other) const + { + return this->Key < other.Key; + } +}; + +// list of properties +typedef QList<QCMakeProperty> QCMakePropertyList; + +// allow QVariant to be a property or list of properties +Q_DECLARE_METATYPE(QCMakeProperty) +Q_DECLARE_METATYPE(QCMakePropertyList) + +/// Qt API for CMake library. +/// Wrapper like class allows for easier integration with +/// Qt features such as, signal/slot connections, multi-threading, etc.. +class QCMake : public QObject +{ + Q_OBJECT +public: + QCMake(QObject* p=0); + ~QCMake(); +public slots: + /// load the cache file in a directory + void loadCache(const QString& dir); + /// set the source directory containing the source + void setSourceDirectory(const QString& dir); + /// set the binary directory to build in + void setBinaryDirectory(const QString& dir); + /// set the desired generator to use + void setGenerator(const QString& generator); + /// do the configure step + void configure(); + /// generate the files + void generate(); + /// set the property values + void setProperties(const QCMakePropertyList&); + /// interrupt the configure or generate process (if connecting, make a direct connection) + void interrupt(); + /// delete the cache in binary directory + void deleteCache(); + /// reload the cache in binary directory + void reloadCache(); + /// set whether to do debug output + void setDebugOutput(bool); + /// set whether to do suppress dev warnings + void setSuppressDevWarnings(bool value); + /// set whether to run cmake with warnings about uninitialized variables + void setWarnUninitializedMode(bool value); + /// set whether to run cmake with warnings about unused variables + void setWarnUnusedMode(bool value); + +public: + /// get the list of cache properties + QCMakePropertyList properties() const; + /// get the current binary directory + QString binaryDirectory() const; + /// get the current source directory + QString sourceDirectory() const; + /// get the current generator + QString generator() const; + /// get the available generators + QStringList availableGenerators() const; + /// get whether to do debug output + bool getDebugOutput() const; + +signals: + /// signal when properties change (during read from disk or configure process) + void propertiesChanged(const QCMakePropertyList& vars); + /// signal when the generator changes + void generatorChanged(const QString& gen); + /// signal when the source directory changes (binary directory already + /// containing a CMakeCache.txt file) + void sourceDirChanged(const QString& dir); + /// signal when the binary directory changes + void binaryDirChanged(const QString& dir); + /// signal for progress events + void progressChanged(const QString& msg, float percent); + /// signal when configure is done + void configureDone(int error); + /// signal when generate is done + void generateDone(int error); + /// signal when there is an output message + void outputMessage(const QString& msg); + /// signal when there is an error message + void errorMessage(const QString& msg); + /// signal when debug output changes + void debugOutputChanged(bool); + +protected: + cmake* CMakeInstance; + + static bool interruptCallback(void*); + static void progressCallback(const char* msg, float percent, void* cd); + static void errorCallback(const char* msg, const char* title, + bool&, void* cd); + bool SuppressDevWarnings; + bool WarnUninitializedMode; + bool WarnUnusedMode; + bool WarnUnusedAllMode; + QString SourceDirectory; + QString BinaryDirectory; + QString Generator; + QStringList AvailableGenerators; + QString CMakeExecutable; + QAtomicInt InterruptFlag; +}; + +#endif // __QCMake_h + diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx new file mode 100644 index 000000000..72e9b2464 --- /dev/null +++ b/Source/QtDialog/QCMakeCacheView.cxx @@ -0,0 +1,735 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "QCMakeCacheView.h" + +#include <QHBoxLayout> +#include <QHeaderView> +#include <QEvent> +#include <QStyle> +#include <QKeyEvent> +#include <QSortFilterProxyModel> +#include <QMetaProperty> +#include <QApplication> + +#include "QCMakeWidgets.h" + +// filter for searches +class QCMakeSearchFilter : public QSortFilterProxyModel +{ +public: + QCMakeSearchFilter(QObject* o) : QSortFilterProxyModel(o) {} +protected: + bool filterAcceptsRow(int row, const QModelIndex& p) const + { + QStringList strs; + const QAbstractItemModel* m = this->sourceModel(); + QModelIndex idx = m->index(row, 0, p); + + // if there are no children, get strings for column 0 and 1 + if(!m->hasChildren(idx)) + { + strs.append(m->data(idx).toString()); + idx = m->index(row, 1, p); + strs.append(m->data(idx).toString()); + } + else + { + // get strings for children entries to compare with + // instead of comparing with the parent + int num = m->rowCount(idx); + for(int i=0; i<num; i++) + { + QModelIndex tmpidx = m->index(i, 0, idx); + strs.append(m->data(tmpidx).toString()); + tmpidx = m->index(i, 1, idx); + strs.append(m->data(tmpidx).toString()); + } + } + + // check all strings for a match + foreach(QString str, strs) + { + if(str.contains(this->filterRegExp())) + { + return true; + } + } + + return false; + } +}; + +// filter for searches +class QCMakeAdvancedFilter : public QSortFilterProxyModel +{ +public: + QCMakeAdvancedFilter(QObject* o) + : QSortFilterProxyModel(o), ShowAdvanced(false) {} + + void setShowAdvanced(bool f) + { + this->ShowAdvanced = f; + this->invalidate(); + } + bool showAdvanced() const { return this->ShowAdvanced; } + +protected: + + bool ShowAdvanced; + + bool filterAcceptsRow(int row, const QModelIndex& p) const + { + const QAbstractItemModel* m = this->sourceModel(); + QModelIndex idx = m->index(row, 0, p); + + // if there are no children + if(!m->hasChildren(idx)) + { + bool adv = m->data(idx, QCMakeCacheModel::AdvancedRole).toBool(); + if(!adv || (adv && this->ShowAdvanced)) + { + return true; + } + return false; + } + + // check children + int num = m->rowCount(idx); + for(int i=0; i<num; i++) + { + bool accept = this->filterAcceptsRow(i, idx); + if(accept) + { + return true; + } + } + return false; + } +}; + +QCMakeCacheView::QCMakeCacheView(QWidget* p) + : QTreeView(p) +{ + // hook up our model and search/filter proxies + this->CacheModel = new QCMakeCacheModel(this); + this->AdvancedFilter = new QCMakeAdvancedFilter(this); + this->AdvancedFilter->setSourceModel(this->CacheModel); + this->AdvancedFilter->setDynamicSortFilter(true); + this->SearchFilter = new QCMakeSearchFilter(this); + this->SearchFilter->setSourceModel(this->AdvancedFilter); + this->SearchFilter->setFilterCaseSensitivity(Qt::CaseInsensitive); + this->SearchFilter->setDynamicSortFilter(true); + this->setModel(this->SearchFilter); + + // our delegate for creating our editors + QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this); + this->setItemDelegate(delegate); + + this->setUniformRowHeights(true); + + this->setEditTriggers(QAbstractItemView::AllEditTriggers); + + // tab, backtab doesn't step through items + this->setTabKeyNavigation(false); + + this->setRootIsDecorated(false); +} + +bool QCMakeCacheView::event(QEvent* e) +{ + if(e->type() == QEvent::Show) + { + this->header()->setDefaultSectionSize(this->viewport()->width()/2); + } + return QTreeView::event(e); +} + +QCMakeCacheModel* QCMakeCacheView::cacheModel() const +{ + return this->CacheModel; +} + +QModelIndex QCMakeCacheView::moveCursor(CursorAction act, + Qt::KeyboardModifiers mod) +{ + // want home/end to go to begin/end of rows, not columns + if(act == MoveHome) + { + return this->model()->index(0, 1); + } + else if(act == MoveEnd) + { + return this->model()->index(this->model()->rowCount()-1, 1); + } + return QTreeView::moveCursor(act, mod); +} + +void QCMakeCacheView::setShowAdvanced(bool s) +{ +#if QT_VERSION >= 040300 + // new 4.3 api that needs to be called. what about an older Qt? + this->SearchFilter->invalidate(); +#endif + + this->AdvancedFilter->setShowAdvanced(s); +} + +bool QCMakeCacheView::showAdvanced() const +{ + return this->AdvancedFilter->showAdvanced(); +} + +void QCMakeCacheView::setSearchFilter(const QString& s) +{ + this->SearchFilter->setFilterFixedString(s); +} + +QCMakeCacheModel::QCMakeCacheModel(QObject* p) + : QStandardItemModel(p), + EditEnabled(true), + NewPropertyCount(0), + View(FlatView) +{ + this->ShowNewProperties = true; + QStringList labels; + labels << tr("Name") << tr("Value"); + this->setHorizontalHeaderLabels(labels); +} + +QCMakeCacheModel::~QCMakeCacheModel() +{ +} + +static uint qHash(const QCMakeProperty& p) +{ + return qHash(p.Key); +} + +void QCMakeCacheModel::setShowNewProperties(bool f) +{ + this->ShowNewProperties = f; +} + +void QCMakeCacheModel::clear() +{ + this->QStandardItemModel::clear(); + this->NewPropertyCount = 0; + + QStringList labels; + labels << tr("Name") << tr("Value"); + this->setHorizontalHeaderLabels(labels); +} + +void QCMakeCacheModel::setProperties(const QCMakePropertyList& props) +{ + QSet<QCMakeProperty> newProps, newProps2; + + if(this->ShowNewProperties) + { + newProps = props.toSet(); + newProps2 = newProps; + QSet<QCMakeProperty> oldProps = this->properties().toSet(); + oldProps.intersect(newProps); + newProps.subtract(oldProps); + newProps2.subtract(newProps); + } + else + { + newProps2 = props.toSet(); + } + + bool b = this->blockSignals(true); + + this->clear(); + this->NewPropertyCount = newProps.size(); + + if(View == FlatView) + { + QCMakePropertyList newP = newProps.toList(); + QCMakePropertyList newP2 = newProps2.toList(); + qSort(newP); + qSort(newP2); + int row_count = 0; + foreach(QCMakeProperty p, newP) + { + this->insertRow(row_count); + this->setPropertyData(this->index(row_count, 0), p, true); + row_count++; + } + foreach(QCMakeProperty p, newP2) + { + this->insertRow(row_count); + this->setPropertyData(this->index(row_count, 0), p, false); + row_count++; + } + } + else if(this->View == GroupView) + { + QMap<QString, QCMakePropertyList> newPropsTree; + this->breakProperties(newProps, newPropsTree); + QMap<QString, QCMakePropertyList> newPropsTree2; + this->breakProperties(newProps2, newPropsTree2); + + QStandardItem* root = this->invisibleRootItem(); + + foreach(QString key, newPropsTree.keys()) + { + QCMakePropertyList props2 = newPropsTree[key]; + + QList<QStandardItem*> parentItems; + parentItems.append( + new QStandardItem(key.isEmpty() ? tr("Ungrouped Entries") : key) + ); + parentItems.append(new QStandardItem()); + parentItems[0]->setData(QBrush(QColor(255,100,100)), Qt::BackgroundColorRole); + parentItems[1]->setData(QBrush(QColor(255,100,100)), Qt::BackgroundColorRole); + parentItems[0]->setData(1, GroupRole); + parentItems[1]->setData(1, GroupRole); + root->appendRow(parentItems); + + int num = props2.size(); + for(int i=0; i<num; i++) + { + QCMakeProperty prop = props2[i]; + QList<QStandardItem*> items; + items.append(new QStandardItem()); + items.append(new QStandardItem()); + parentItems[0]->appendRow(items); + this->setPropertyData(this->indexFromItem(items[0]), prop, true); + } + } + + foreach(QString key, newPropsTree2.keys()) + { + QCMakePropertyList props2 = newPropsTree2[key]; + + QStandardItem* parentItem = + new QStandardItem(key.isEmpty() ? tr("Ungrouped Entries") : key); + root->appendRow(parentItem); + parentItem->setData(1, GroupRole); + + int num = props2.size(); + for(int i=0; i<num; i++) + { + QCMakeProperty prop = props2[i]; + QList<QStandardItem*> items; + items.append(new QStandardItem()); + items.append(new QStandardItem()); + parentItem->appendRow(items); + this->setPropertyData(this->indexFromItem(items[0]), prop, false); + } + } + } + + this->blockSignals(b); + this->reset(); +} + +QCMakeCacheModel::ViewType QCMakeCacheModel::viewType() const +{ + return this->View; +} + +void QCMakeCacheModel::setViewType(QCMakeCacheModel::ViewType t) +{ + this->View = t; + + QCMakePropertyList props = this->properties(); + QCMakePropertyList oldProps; + int numNew = this->NewPropertyCount; + int numTotal = props.count(); + for(int i=numNew; i<numTotal; i++) + { + oldProps.append(props[i]); + } + + bool b = this->blockSignals(true); + this->clear(); + this->setProperties(oldProps); + this->setProperties(props); + this->blockSignals(b); + this->reset(); +} + +void QCMakeCacheModel::setPropertyData(const QModelIndex& idx1, + const QCMakeProperty& prop, bool isNew) +{ + QModelIndex idx2 = idx1.sibling(idx1.row(), 1); + + this->setData(idx1, prop.Key, Qt::DisplayRole); + this->setData(idx1, prop.Help, QCMakeCacheModel::HelpRole); + this->setData(idx1, prop.Type, QCMakeCacheModel::TypeRole); + this->setData(idx1, prop.Advanced, QCMakeCacheModel::AdvancedRole); + + if(prop.Type == QCMakeProperty::BOOL) + { + int check = prop.Value.toBool() ? Qt::Checked : Qt::Unchecked; + this->setData(idx2, check, Qt::CheckStateRole); + } + else + { + this->setData(idx2, prop.Value, Qt::DisplayRole); + } + this->setData(idx2, prop.Help, QCMakeCacheModel::HelpRole); + + if (!prop.Strings.isEmpty()) + { + this->setData(idx1, prop.Strings, QCMakeCacheModel::StringsRole); + } + + if(isNew) + { + this->setData(idx1, QBrush(QColor(255,100,100)), Qt::BackgroundColorRole); + this->setData(idx2, QBrush(QColor(255,100,100)), Qt::BackgroundColorRole); + } +} + +void QCMakeCacheModel::getPropertyData(const QModelIndex& idx1, + QCMakeProperty& prop) const +{ + QModelIndex idx2 = idx1.sibling(idx1.row(), 1); + + prop.Key = this->data(idx1, Qt::DisplayRole).toString(); + prop.Help = this->data(idx1, HelpRole).toString(); + prop.Type = static_cast<QCMakeProperty::PropertyType>(this->data(idx1, TypeRole).toInt()); + prop.Advanced = this->data(idx1, AdvancedRole).toBool(); + prop.Strings = this->data(idx1, QCMakeCacheModel::StringsRole).toStringList(); + if(prop.Type == QCMakeProperty::BOOL) + { + int check = this->data(idx2, Qt::CheckStateRole).toInt(); + prop.Value = check == Qt::Checked; + } + else + { + prop.Value = this->data(idx2, Qt::DisplayRole).toString(); + } +} + +QString QCMakeCacheModel::prefix(const QString& s) +{ + QString prefix = s.section('_', 0, 0); + if(prefix == s) + { + prefix = QString(); + } + return prefix; +} + +void QCMakeCacheModel::breakProperties(const QSet<QCMakeProperty>& props, + QMap<QString, QCMakePropertyList>& result) +{ + QMap<QString, QCMakePropertyList> tmp; + // return a map of properties grouped by prefixes, and sorted + foreach(QCMakeProperty p, props) + { + QString prefix = QCMakeCacheModel::prefix(p.Key); + tmp[prefix].append(p); + } + // sort it and re-org any properties with only one sub item + QCMakePropertyList reorgProps; + QMap<QString, QCMakePropertyList>::iterator iter; + for(iter = tmp.begin(); iter != tmp.end();) + { + if(iter->count() == 1) + { + reorgProps.append((*iter)[0]); + iter = tmp.erase(iter); + } + else + { + qSort(*iter); + ++iter; + } + } + if(reorgProps.count()) + { + tmp[QString()] += reorgProps; + } + result = tmp; +} + +QCMakePropertyList QCMakeCacheModel::properties() const +{ + QCMakePropertyList props; + + if(!this->rowCount()) + { + return props; + } + + QList<QModelIndex> idxs; + idxs.append(this->index(0,0)); + + // walk the entire model for property entries + // this works regardless of a flat view or a tree view + while(!idxs.isEmpty()) + { + QModelIndex idx = idxs.last(); + if(this->hasChildren(idx) && this->rowCount(idx)) + { + idxs.append(this->index(0,0, idx)); + } + else + { + if(!data(idx, GroupRole).toInt()) + { + // get data + QCMakeProperty prop; + this->getPropertyData(idx, prop); + props.append(prop); + } + + // go to the next in the tree + while(!idxs.isEmpty() && !idxs.last().sibling(idxs.last().row()+1, 0).isValid()) + { + idxs.removeLast(); + } + if(!idxs.isEmpty()) + { + idxs.last() = idxs.last().sibling(idxs.last().row()+1, 0); + } + } + } + + return props; +} + +bool QCMakeCacheModel::insertProperty(QCMakeProperty::PropertyType t, + const QString& name, const QString& description, + const QVariant& value, bool advanced) +{ + QCMakeProperty prop; + prop.Key = name; + prop.Value = value; + prop.Help = description; + prop.Type = t; + prop.Advanced = advanced; + + //insert at beginning + this->insertRow(0); + this->setPropertyData(this->index(0,0), prop, true); + this->NewPropertyCount++; + return true; +} + +void QCMakeCacheModel::setEditEnabled(bool e) +{ + this->EditEnabled = e; +} + +bool QCMakeCacheModel::editEnabled() const +{ + return this->EditEnabled; +} + +int QCMakeCacheModel::newPropertyCount() const +{ + return this->NewPropertyCount; +} + +Qt::ItemFlags QCMakeCacheModel::flags (const QModelIndex& idx) const +{ + Qt::ItemFlags f = QStandardItemModel::flags(idx); + if(!this->EditEnabled) + { + f &= ~Qt::ItemIsEditable; + return f; + } + if(QCMakeProperty::BOOL == this->data(idx, TypeRole).toInt()) + { + f |= Qt::ItemIsUserCheckable; + } + return f; +} + +QModelIndex QCMakeCacheModel::buddy(const QModelIndex& idx) const +{ + if(!this->hasChildren(idx) && + this->data(idx, TypeRole).toInt() != QCMakeProperty::BOOL) + { + return this->index(idx.row(), 1, idx.parent()); + } + return idx; +} + +QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p) + : QItemDelegate(p), FileDialogFlag(false) +{ +} + +void QCMakeCacheModelDelegate::setFileDialogFlag(bool f) +{ + this->FileDialogFlag = f; +} + +QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* p, + const QStyleOptionViewItem&, const QModelIndex& idx) const +{ + QModelIndex var = idx.sibling(idx.row(), 0); + int type = var.data(QCMakeCacheModel::TypeRole).toInt(); + if(type == QCMakeProperty::BOOL) + { + return NULL; + } + else if(type == QCMakeProperty::PATH) + { + QCMakePathEditor* editor = + new QCMakePathEditor(p, + var.data(Qt::DisplayRole).toString()); + QObject::connect(editor, SIGNAL(fileDialogExists(bool)), this, + SLOT(setFileDialogFlag(bool))); + return editor; + } + else if(type == QCMakeProperty::FILEPATH) + { + QCMakeFilePathEditor* editor = + new QCMakeFilePathEditor(p, + var.data(Qt::DisplayRole).toString()); + QObject::connect(editor, SIGNAL(fileDialogExists(bool)), this, + SLOT(setFileDialogFlag(bool))); + return editor; + } + else if(type == QCMakeProperty::STRING && + var.data(QCMakeCacheModel::StringsRole).isValid()) + { + QCMakeComboBox* editor = + new QCMakeComboBox(p, var.data(QCMakeCacheModel::StringsRole).toStringList()); + editor->setFrame(false); + return editor; + } + + QLineEdit* editor = new QLineEdit(p); + editor->setFrame(false); + return editor; +} + +bool QCMakeCacheModelDelegate::editorEvent(QEvent* e, QAbstractItemModel* model, + const QStyleOptionViewItem& option, const QModelIndex& index) +{ + Qt::ItemFlags flags = model->flags(index); + if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled) + || !(flags & Qt::ItemIsEnabled)) + { + return false; + } + + QVariant value = index.data(Qt::CheckStateRole); + if (!value.isValid()) + { + return false; + } + + if ((e->type() == QEvent::MouseButtonRelease) + || (e->type() == QEvent::MouseButtonDblClick)) + { + // eat the double click events inside the check rect + if (e->type() == QEvent::MouseButtonDblClick) + { + return true; + } + } + else if (e->type() == QEvent::KeyPress) + { + if(static_cast<QKeyEvent*>(e)->key() != Qt::Key_Space && + static_cast<QKeyEvent*>(e)->key() != Qt::Key_Select) + { + return false; + } + } + else + { + return false; + } + + Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked + ? Qt::Unchecked : Qt::Checked); + bool success = model->setData(index, state, Qt::CheckStateRole); + if(success) + { + this->recordChange(model, index); + } + return success; +} + +// Issue 205903 fixed in Qt 4.5.0. +// Can remove this function and FileDialogFlag when minimum Qt version is 4.5 +bool QCMakeCacheModelDelegate::eventFilter(QObject* object, QEvent* evt) +{ + // workaround for what looks like a bug in Qt on Mac OS X + // where it doesn't create a QWidget wrapper for the native file dialog + // so the Qt library ends up assuming the focus was lost to something else + + if(evt->type() == QEvent::FocusOut && this->FileDialogFlag) + { + return false; + } + return QItemDelegate::eventFilter(object, evt); +} + +void QCMakeCacheModelDelegate::setModelData(QWidget* editor, + QAbstractItemModel* model, const QModelIndex& index ) const +{ + QItemDelegate::setModelData(editor, model, index); + const_cast<QCMakeCacheModelDelegate*>(this)->recordChange(model, index); +} + +QSize QCMakeCacheModelDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + QSize sz = QItemDelegate::sizeHint(option, index); + QStyle *style = QApplication::style(); + + // increase to checkbox size + QStyleOptionButton opt; + opt.QStyleOption::operator=(option); + sz = sz.expandedTo(style->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt, NULL).size()); + + return sz; +} + +QSet<QCMakeProperty> QCMakeCacheModelDelegate::changes() const +{ + return mChanges; +} + +void QCMakeCacheModelDelegate::clearChanges() +{ + mChanges.clear(); +} + +void QCMakeCacheModelDelegate::recordChange(QAbstractItemModel* model, const QModelIndex& index) +{ + QModelIndex idx = index; + QAbstractItemModel* mymodel = model; + while(qobject_cast<QAbstractProxyModel*>(mymodel)) + { + idx = static_cast<QAbstractProxyModel*>(mymodel)->mapToSource(idx); + mymodel = static_cast<QAbstractProxyModel*>(mymodel)->sourceModel(); + } + QCMakeCacheModel* cache_model = qobject_cast<QCMakeCacheModel*>(mymodel); + if(cache_model && idx.isValid()) + { + QCMakeProperty prop; + idx = idx.sibling(idx.row(), 0); + cache_model->getPropertyData(idx, prop); + + // clean out an old one + QSet<QCMakeProperty>::iterator iter = mChanges.find(prop); + if(iter != mChanges.end()) + { + mChanges.erase(iter); + } + // now add the new item + mChanges.insert(prop); + } +} + diff --git a/Source/QtDialog/QCMakeCacheView.h b/Source/QtDialog/QCMakeCacheView.h new file mode 100644 index 000000000..0a628b90a --- /dev/null +++ b/Source/QtDialog/QCMakeCacheView.h @@ -0,0 +1,172 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef QCMakeCacheView_h +#define QCMakeCacheView_h + +#include "QCMake.h" +#include <QTreeView> +#include <QSet> +#include <QStandardItemModel> +#include <QItemDelegate> + +class QSortFilterProxyModel; +class QCMakeCacheModel; +class QCMakeAdvancedFilter; + +/// Qt view class for cache properties +class QCMakeCacheView : public QTreeView +{ + Q_OBJECT +public: + QCMakeCacheView(QWidget* p); + + // retrieve the QCMakeCacheModel storing all the pointers + // this isn't necessarily the model one would get from model() + QCMakeCacheModel* cacheModel() const; + + // get whether to show advanced entries + bool showAdvanced() const; + + QSize sizeHint() const { return QSize(200,200); } + +public slots: + // set whether to show advanced entries + void setShowAdvanced(bool); + // set the search filter string. any property key or value not matching will + // be filtered out + void setSearchFilter(const QString&); + +protected: + QModelIndex moveCursor(CursorAction, Qt::KeyboardModifiers); + bool event(QEvent* e); + QCMakeCacheModel* CacheModel; + QCMakeAdvancedFilter* AdvancedFilter; + QSortFilterProxyModel* SearchFilter; +}; + +/// Qt model class for cache properties +class QCMakeCacheModel : public QStandardItemModel +{ + Q_OBJECT +public: + QCMakeCacheModel(QObject* parent); + ~QCMakeCacheModel(); + + // roles used to retrieve extra data such has help strings, types of + // properties, and the advanced flag + enum { HelpRole = Qt::ToolTipRole, + TypeRole = Qt::UserRole, + AdvancedRole, + StringsRole, + GroupRole + }; + + enum ViewType { FlatView, GroupView }; + +public slots: + // set a list of properties. This list will be sorted and grouped according + // to prefix. Any property that existed already and which is found in this + // list of properties to set will become an old property. All others will + // become new properties and be marked red. + void setProperties(const QCMakePropertyList& props); + + // set whether to show new properties in red + void setShowNewProperties(bool); + + // clear everything from the model + void clear(); + + // set flag whether the model can currently be edited. + void setEditEnabled(bool); + + // insert a new property at a row specifying all the information about the + // property + bool insertProperty(QCMakeProperty::PropertyType t, + const QString& name, const QString& description, + const QVariant& value, bool advanced); + + // set the view type + void setViewType(ViewType t); + ViewType viewType() const; + +public: + // get the properties + QCMakePropertyList properties() const; + + // editing enabled + bool editEnabled() const; + + // returns how many new properties there are + int newPropertyCount() const; + + // return flags (overloaded to modify flag based on EditEnabled flag) + Qt::ItemFlags flags (const QModelIndex& index) const; + QModelIndex buddy(const QModelIndex& idx) const; + + // get the data in the model for this property + void getPropertyData(const QModelIndex& idx1, + QCMakeProperty& prop) const; + +protected: + bool EditEnabled; + int NewPropertyCount; + bool ShowNewProperties; + ViewType View; + + // set the data in the model for this property + void setPropertyData(const QModelIndex& idx1, + const QCMakeProperty& p, bool isNew); + + // breaks up he property list into groups + // where each group has the same prefix up to the first underscore + static void breakProperties(const QSet<QCMakeProperty>& props, + QMap<QString, QCMakePropertyList>& result); + + // gets the prefix of a string up to the first _ + static QString prefix(const QString& s); + +}; + +/// Qt delegate class for interaction (or other customization) +/// with cache properties +class QCMakeCacheModelDelegate : public QItemDelegate +{ + Q_OBJECT +public: + QCMakeCacheModelDelegate(QObject* p); + /// create our own editors for cache properties + QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, + const QModelIndex& index ) const; + bool editorEvent (QEvent* event, QAbstractItemModel* model, + const QStyleOptionViewItem& option, const QModelIndex& index); + bool eventFilter(QObject* object, QEvent* event); + void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index ) const; + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + + QSet<QCMakeProperty> changes() const; + void clearChanges(); + +protected slots: + void setFileDialogFlag(bool); +protected: + bool FileDialogFlag; + // record a change to an item in the model. + // this simply saves the item in the set of changes + void recordChange(QAbstractItemModel* model, const QModelIndex& index); + + // properties changed by user via this delegate + QSet<QCMakeProperty> mChanges; +}; + +#endif + diff --git a/Source/QtDialog/QCMakeWidgets.cxx b/Source/QtDialog/QCMakeWidgets.cxx new file mode 100644 index 000000000..144e1f32e --- /dev/null +++ b/Source/QtDialog/QCMakeWidgets.cxx @@ -0,0 +1,134 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "QCMakeWidgets.h" + +#include <QDirModel> +#include <QFileInfo> +#include <QFileDialog> +#include <QToolButton> +#include <QResizeEvent> + +QCMakeFileEditor::QCMakeFileEditor(QWidget* p, const QString& var) + : QLineEdit(p), Variable(var) +{ + this->ToolButton = new QToolButton(this); + this->ToolButton->setText("..."); + this->ToolButton->setCursor(QCursor(Qt::ArrowCursor)); + QObject::connect(this->ToolButton, SIGNAL(clicked(bool)), + this, SLOT(chooseFile())); +} + +QCMakeFilePathEditor::QCMakeFilePathEditor(QWidget* p, const QString& var) + : QCMakeFileEditor(p, var) +{ + this->setCompleter(new QCMakeFileCompleter(this, false)); +} + +QCMakePathEditor::QCMakePathEditor(QWidget* p, const QString& var) + : QCMakeFileEditor(p, var) +{ + this->setCompleter(new QCMakeFileCompleter(this, true)); +} + +void QCMakeFileEditor::resizeEvent(QResizeEvent* e) +{ + // make the tool button fit on the right side + int h = e->size().height(); + // move the line edit to make room for the tool button + this->setContentsMargins(0, 0, h, 0); + // put the tool button in its place + this->ToolButton->resize(h, h); + this->ToolButton->move(this->width() - h, 0); +} + +void QCMakeFilePathEditor::chooseFile() +{ + // choose a file and set it + QString path; + QFileInfo info(this->text()); + QString title; + if(this->Variable.isEmpty()) + { + title = tr("Select File"); + } + else + { + title = tr("Select File for %1"); + title = title.arg(this->Variable); + } + this->fileDialogExists(true); + path = QFileDialog::getOpenFileName(this, title, info.absolutePath()); + this->fileDialogExists(false); + + if(!path.isEmpty()) + { + this->setText(QDir::fromNativeSeparators(path)); + } +} + +void QCMakePathEditor::chooseFile() +{ + // choose a file and set it + QString path; + QString title; + if(this->Variable.isEmpty()) + { + title = tr("Select Path"); + } + else + { + title = tr("Select Path for %1"); + title = title.arg(this->Variable); + } + this->fileDialogExists(true); + path = QFileDialog::getExistingDirectory(this, title, this->text()); + this->fileDialogExists(false); + if(!path.isEmpty()) + { + this->setText(QDir::fromNativeSeparators(path)); + } +} + +// use same QDirModel for all completers +static QDirModel* fileDirModel() +{ + static QDirModel* m = NULL; + if(!m) + { + m = new QDirModel(); + } + return m; +} +static QDirModel* pathDirModel() +{ + static QDirModel* m = NULL; + if(!m) + { + m = new QDirModel(); + m->setFilter(QDir::AllDirs | QDir::Drives | QDir::NoDotAndDotDot); + } + return m; +} + +QCMakeFileCompleter::QCMakeFileCompleter(QObject* o, bool dirs) + : QCompleter(o) +{ + QDirModel* m = dirs ? pathDirModel() : fileDirModel(); + this->setModel(m); +} + +QString QCMakeFileCompleter::pathFromIndex(const QModelIndex& idx) const +{ + return QDir::fromNativeSeparators(QCompleter::pathFromIndex(idx)); +} + diff --git a/Source/QtDialog/QCMakeWidgets.h b/Source/QtDialog/QCMakeWidgets.h new file mode 100644 index 000000000..8f58df2bb --- /dev/null +++ b/Source/QtDialog/QCMakeWidgets.h @@ -0,0 +1,87 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef QCMakeWidgets_h +#define QCMakeWidgets_h + +#include <QLineEdit> +#include <QComboBox> +#include <QCompleter> +class QToolButton; + +// common widgets for Qt based CMake + +/// Editor widget for editing paths or file paths +class QCMakeFileEditor : public QLineEdit +{ + Q_OBJECT +public: + QCMakeFileEditor(QWidget* p, const QString& var); +protected slots: + virtual void chooseFile() = 0; +signals: + void fileDialogExists(bool); +protected: + void resizeEvent(QResizeEvent* e); + QToolButton* ToolButton; + QString Variable; +}; + +/// editor widget for editing files +class QCMakePathEditor : public QCMakeFileEditor +{ + Q_OBJECT +public: + QCMakePathEditor(QWidget* p = NULL, const QString& var = QString()); + void chooseFile(); +}; + +/// editor widget for editing paths +class QCMakeFilePathEditor : public QCMakeFileEditor +{ + Q_OBJECT +public: + QCMakeFilePathEditor(QWidget* p = NULL, const QString& var = QString()); + void chooseFile(); +}; + +/// completer class that returns native cmake paths +class QCMakeFileCompleter : public QCompleter +{ + Q_OBJECT +public: + QCMakeFileCompleter(QObject* o, bool dirs); + virtual QString pathFromIndex(const QModelIndex& idx) const; +}; + +// editor for strings +class QCMakeComboBox : public QComboBox +{ + Q_OBJECT + Q_PROPERTY(QString value READ currentText WRITE setValue USER true); +public: + QCMakeComboBox(QWidget* p, QStringList strings) : QComboBox(p) + { + this->addItems(strings); + } + void setValue(const QString& v) + { + int i = this->findText(v); + if(i != -1) + { + this->setCurrentIndex(i); + } + } +}; + +#endif + diff --git a/Source/QtDialog/QMacInstallDialog.cxx b/Source/QtDialog/QMacInstallDialog.cxx new file mode 100644 index 000000000..6eb053b21 --- /dev/null +++ b/Source/QtDialog/QMacInstallDialog.cxx @@ -0,0 +1,121 @@ +#include "QMacInstallDialog.h" +#include <QMessageBox> +#include "cmSystemTools.h" +#include <iostream> +#include <QFileDialog> +#include "ui_MacInstallDialog.h" + +class QMacInstallDialog::QMacInstallDialogInternals : public Ui::Dialog +{ +public: +}; + +QMacInstallDialog::QMacInstallDialog(QWidget*w) + :QDialog(w) +{ + this->Internals = new QMacInstallDialogInternals; + this->Internals->setupUi(this); + QObject::connect(this->Internals->choosePathButton, SIGNAL(pressed()), + this, SLOT(ShowBrowser())); + QObject::connect(this->Internals->skipInstallButton, SIGNAL(pressed()), + this, SLOT(SkipInstall())); + QObject::connect(this->Internals->doInstallButton, SIGNAL(pressed()), + this, SLOT(DoInstall())); + this->Internals->InstallPrefix->setText("/usr/bin/"); + +} + +QMacInstallDialog::~QMacInstallDialog() +{ + delete this->Internals; +} + +void QMacInstallDialog::DoInstall() +{ + QDir installDir(this->Internals->InstallPrefix->text()); + QString installTo = installDir.path(); + if(!cmSystemTools::FileExists(installTo.toLocal8Bit().data())) + { + QString message = tr("Build install does not exist, " + "should I create it?\n\n" + "Directory: "); + message += installDir.path(); + QString title = tr("Create Directory"); + QMessageBox::StandardButton btn; + btn = QMessageBox::information(this, title, message, + QMessageBox::Yes | QMessageBox::No); + if(btn == QMessageBox::Yes) + { + cmSystemTools::MakeDirectory(installTo.toLocal8Bit().data()); + } + } + QDir cmExecDir(QApplication::applicationDirPath()); + cmExecDir.cd("../bin"); + QFileInfoList list = cmExecDir.entryInfoList(); + for (int i = 0; i < list.size(); ++i) + { + QFileInfo fileInfo = list.at(i); + QString filename = fileInfo.fileName(); + if(filename.size() && filename[0] == '.') + { + continue; + } + QString file = fileInfo.absoluteFilePath(); + QString newName = installTo; + newName += "/"; + newName += filename; + // Remove the old files + if(cmSystemTools::FileExists(newName.toLocal8Bit().data())) + { + std::cout << "rm [" << newName.toLocal8Bit().data() << "]\n"; + if(!cmSystemTools::RemoveFile(newName.toLocal8Bit().data())) + { + QString message = tr("Failed to remove file " + "installation may be incomplete: "); + message += newName; + QString title = tr("Error Removing file"); + QMessageBox::StandardButton btn = + QMessageBox::critical(this, title, message, + QMessageBox::Ok|QMessageBox::Abort); + if(btn == QMessageBox::Abort) + { + return; + } + } + } + std::cout << "ln -s [" << file.toLocal8Bit().data() << "] ["; + std::cout << newName.toLocal8Bit().data() << "]\n"; + if(!cmSystemTools::CreateSymlink(file.toLocal8Bit().data(), + newName.toLocal8Bit().data())) + { + QString message = tr("Failed create symlink " + "installation may be incomplete: "); + message += newName; + QString title = tr("Error Creating Symlink"); + QMessageBox::StandardButton btn = + QMessageBox::critical(this, title, message, + QMessageBox::Ok|QMessageBox::Abort); + if(btn == QMessageBox::Abort) + { + return; + } + } + } + this->done(0); +} + +void QMacInstallDialog::SkipInstall() +{ + this->done(0); +} + + +void QMacInstallDialog::ShowBrowser() +{ + QString dir = QFileDialog::getExistingDirectory(this, + tr("Enter Install Prefix"), this->Internals->InstallPrefix->text()); + if(!dir.isEmpty()) + { + this->Internals->InstallPrefix->setText(dir); + } +} diff --git a/Source/QtDialog/QMacInstallDialog.h b/Source/QtDialog/QMacInstallDialog.h new file mode 100644 index 000000000..efe67dfaf --- /dev/null +++ b/Source/QtDialog/QMacInstallDialog.h @@ -0,0 +1,20 @@ +#ifndef QMacInstallDialog_h +#define QMacInstallDialog_h +#include <QDialog> + +class QMacInstallDialog : public QDialog +{ + Q_OBJECT; +public: + QMacInstallDialog(QWidget*w); + ~QMacInstallDialog(); +private slots: + void ShowBrowser(); + void SkipInstall(); + void DoInstall(); +private: + class QMacInstallDialogInternals; + QMacInstallDialogInternals* Internals; +}; + +#endif diff --git a/Source/QtDialog/QtDialogCPack.cmake.in b/Source/QtDialog/QtDialogCPack.cmake.in new file mode 100644 index 000000000..701991b7a --- /dev/null +++ b/Source/QtDialog/QtDialogCPack.cmake.in @@ -0,0 +1,18 @@ +SET(IS_APPLE @APPLE@) +SET(CMAKE_PACKAGE_QTGUI @CMAKE_PACKAGE_QTGUI@) + +IF(CMAKE_PACKAGE_QTGUI) + SET(CPACK_PACKAGE_EXECUTABLES "cmake-gui" "CMake (cmake-gui)" ${CPACK_PACKAGE_EXECUTABLES}) + SET(CPACK_CREATE_DESKTOP_LINKS "cmake-gui" ${CPACK_CREATE_DESKTOP_LINKS}) + IF(IS_APPLE) + # for apple install we set the install prefix to + # / and then install + # cmake into the bundle for cmake-gui and must use DESTDIR + SET(CPACK_SET_DESTDIR TRUE) + # we also want to run post install stuff to setup command line + SET(CPACK_POSTFLIGHT_SCRIPT "@CMAKE_POSTFLIGHT_SCRIPT@") + SET(CPACK_POSTUPGRADE_SCRIPT "@CMAKE_POSTUPGRADE_SCRIPT@") + ENDIF(IS_APPLE) +ENDIF(CMAKE_PACKAGE_QTGUI) + + diff --git a/Source/QtDialog/cmakecache.xml b/Source/QtDialog/cmakecache.xml new file mode 100644 index 000000000..a13b5b19c --- /dev/null +++ b/Source/QtDialog/cmakecache.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> + <mime-type type="application/x-cmakecache"> + <comment>CMake cache file</comment> + <glob pattern="CMakeCache.txt"/> + <sub-class-of type="text/plain"/> + </mime-type> +</mime-info> diff --git a/Source/QtDialog/postflight.sh.in b/Source/QtDialog/postflight.sh.in new file mode 100755 index 000000000..33be35206 --- /dev/null +++ b/Source/QtDialog/postflight.sh.in @@ -0,0 +1,3 @@ +#!/bin/bash +"$2@CMAKE_INSTALL_SUBDIR@/@CMAKE_BUNDLE_NAME@.app/Contents/MacOS/@CMAKE_BUNDLE_NAME@" --mac-install +exit 0 diff --git a/Source/QtDialog/postupgrade.sh.in b/Source/QtDialog/postupgrade.sh.in new file mode 100755 index 000000000..06bd98656 --- /dev/null +++ b/Source/QtDialog/postupgrade.sh.in @@ -0,0 +1,2 @@ +#!/bin/bash +exit 0 |