diff --git a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp index 45889da996c183b293f8b14d7ee28f7508bee530..2f1417c7d6df20ecca3f258001510b19760cdcc8 100644 --- a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp @@ -261,11 +261,35 @@ void CMakeRunPage::initWidgets() { QFormLayout *fl = new QFormLayout; setLayout(fl); + // Description Label m_descriptionLabel = new QLabel(this); m_descriptionLabel->setWordWrap(true); fl->addRow(m_descriptionLabel); + if (m_cmakeWizard->cmakeManager()->isCMakeExecutableValid()) { + m_cmakeExecutable = 0; + } else { + QString text = tr("Please specify the path to the cmake executable. No cmake executable was found in the path."); + QString cmakeExecutable = m_cmakeWizard->cmakeManager()->cmakeExecutable(); + if (!cmakeExecutable.isEmpty()) { + QFileInfo fi(cmakeExecutable); + if (!fi.exists()) + text += tr(" The cmake executable (%1) does not exist.").arg(cmakeExecutable); + else if (!fi.isExecutable()) + text += tr(" The path %1 is not a executable.").arg(cmakeExecutable); + else + text += tr(" The path %1 is not a valid cmake.").arg(cmakeExecutable); + } + + fl->addRow(new QLabel(text, this)); + // Show a field for the user to enter + m_cmakeExecutable = new Core::Utils::PathChooser(this); + m_cmakeExecutable->setExpectedKind(Core::Utils::PathChooser::Command); + fl->addRow("CMake Executable", m_cmakeExecutable); + } + + // Run CMake Line (with arguments) m_argumentsLineEdit = new QLineEdit(this); connect(m_argumentsLineEdit,SIGNAL(returnPressed()), this, SLOT(runCMake())); @@ -282,7 +306,7 @@ void CMakeRunPage::initWidgets() fl->addRow(tr("Arguments"), hbox); - + // Bottom output window m_output = new QPlainTextEdit(this); m_output->setReadOnly(true); QSizePolicy pl = m_output->sizePolicy(); @@ -347,9 +371,8 @@ void CMakeRunPage::initializePage() } } m_generatorComboBox->clear(); - // Find out whether we have multiple mvc versions + // Find out whether we have multiple msvc versions QStringList msvcVersions = ProjectExplorer::ToolChain::availableMSVCVersions(); - qDebug()<<"msvcVersions:"<<msvcVersions; if (msvcVersions.isEmpty()) { } else if (msvcVersions.count() == 1) { @@ -403,9 +426,22 @@ void CMakeRunPage::runCMake() delete tc; } - m_cmakeProcess = cmakeManager->createXmlFile(arguments, m_cmakeWizard->sourceDirectory(), m_buildDirectory, env, generator); - connect(m_cmakeProcess, SIGNAL(readyRead()), this, SLOT(cmakeReadyRead())); - connect(m_cmakeProcess, SIGNAL(finished(int)), this, SLOT(cmakeFinished())); + if (m_cmakeExecutable) { + // We asked the user for the cmake executable + m_cmakeWizard->cmakeManager()->setCMakeExecutable(m_cmakeExecutable->path()); + } + + m_output->clear(); + + if (m_cmakeWizard->cmakeManager()->isCMakeExecutableValid()) { + m_cmakeProcess = cmakeManager->createXmlFile(arguments, m_cmakeWizard->sourceDirectory(), m_buildDirectory, env, generator); + connect(m_cmakeProcess, SIGNAL(readyRead()), this, SLOT(cmakeReadyRead())); + connect(m_cmakeProcess, SIGNAL(finished(int)), this, SLOT(cmakeFinished())); + } else { + m_runCMake->setEnabled(true); + m_argumentsLineEdit->setEnabled(true); + m_output->appendPlainText(tr("No valid cmake executable specified.")); + } } void CMakeRunPage::cmakeReadyRead() diff --git a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h index cd62bceadad667ebac6c748c4ee78f29b85aeb36..6a74741b5f4759dbbef54e8154981e91c72d6313 100644 --- a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h +++ b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h @@ -139,6 +139,7 @@ private: QPushButton *m_runCMake; QProcess *m_cmakeProcess; QLineEdit *m_argumentsLineEdit; + Core::Utils::PathChooser *m_cmakeExecutable; QComboBox *m_generatorComboBox; QLabel *m_descriptionLabel; bool m_complete; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index f980f7a6ac8a6104a782354b817f49143d402507..23265bcfc1a88962784cb915de2f77688d37952e 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -42,6 +42,7 @@ #include <QtGui/QFormLayout> #include <QtGui/QDesktopServices> #include <QtGui/QApplication> +#include <QtGui/QLabel> using namespace CMakeProjectManager::Internal; @@ -50,12 +51,7 @@ CMakeManager::CMakeManager(CMakeSettingsPage *cmakeSettingsPage) { Core::UniqueIDManager *uidm = Core::UniqueIDManager::instance(); m_projectContext = uidm->uniqueIdentifier(CMakeProjectManager::Constants::PROJECTCONTEXT); - m_projectLanguage = uidm->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX); -} - -CMakeSettingsPage::~CMakeSettingsPage() -{ - + m_projectLanguage = uidm->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX); } int CMakeManager::projectContext() const @@ -71,14 +67,6 @@ int CMakeManager::projectLanguage() const ProjectExplorer::Project *CMakeManager::openProject(const QString &fileName) { // TODO check wheter this project is already opened - // Check that we have a cmake executable first - // Look at the settings first - QString cmakeExecutable = m_settingsPage->cmakeExecutable(); - if (cmakeExecutable.isNull()) - m_settingsPage->askUserForCMakeExecutable(); - cmakeExecutable = m_settingsPage->cmakeExecutable(); - if (cmakeExecutable.isNull()) - return 0; return new CMakeProject(this, fileName); } @@ -92,6 +80,16 @@ QString CMakeManager::cmakeExecutable() const return m_settingsPage->cmakeExecutable(); } +bool CMakeManager::isCMakeExecutableValid() const +{ + return m_settingsPage->isCMakeExecutableValid(); +} + +void CMakeManager::setCMakeExecutable(const QString &executable) +{ + m_settingsPage->setCMakeExecutable(executable); +} + bool CMakeManager::hasCodeBlocksMsvcGenerator() const { return m_settingsPage->hasCodeBlocksMsvcGenerator(); @@ -110,18 +108,15 @@ QProcess *CMakeManager::createXmlFile(const QStringList &arguments, const QStrin // The mid term plan is to move away from the CodeBlocks Generator and use our own // QtCreator generator, which actually can be very similar to the CodeBlock Generator - // TODO we need to pass on the same paremeters as the cmakestep QString buildDirectoryPath = buildDirectory.absolutePath(); - qDebug()<<"Creating cbp file in"<<buildDirectoryPath; buildDirectory.mkpath(buildDirectoryPath); QProcess *cmake = new QProcess; cmake->setWorkingDirectory(buildDirectoryPath); cmake->setProcessChannelMode(QProcess::MergedChannels); cmake->setEnvironment(env.toStringList()); - const QString srcdir = buildDirectory.exists(QLatin1String("CMakeCache.txt")) ? QString(QLatin1Char('.')) : sourceDirectory; - qDebug()<<cmakeExecutable()<<srcdir<<arguments<<generator; + const QString srcdir = buildDirectory.exists(QLatin1String("CMakeCache.txt")) ? QString(QLatin1Char('.')) : sourceDirectory; cmake->start(cmakeExecutable(), QStringList() << srcdir << arguments << generator); return cmake; } @@ -157,106 +152,85 @@ QString CMakeManager::qtVersionForQMake(const QString &qmakePath) return QString(); } +///// +// CMakeSettingsPage //// -// CMakeRunner -//// -// TODO give a better name, what this class is to update cached information -// about a cmake executable, with qtconcurrent -// The nifty feature of this class is that it does so in a seperate thread, -// not blocking the main thread -CMakeRunner::CMakeRunner() - : m_cacheUpToDate(false) + +CMakeSettingsPage::CMakeSettingsPage() + : m_process(0), + m_pathchooser(0) { + Core::ICore *core = Core::ICore::instance(); + QSettings * settings = core->settings(); + settings->beginGroup(QLatin1String("CMakeSettings")); + m_cmakeExecutable = settings->value(QLatin1String("cmakeExecutable")).toString(); + QFileInfo fi(m_cmakeExecutable); + if (!fi.exists() || !fi.isExecutable()) + m_cmakeExecutable = findCmakeExecutable(); + fi.setFile(m_cmakeExecutable); + if (fi.exists() && fi.isExecutable()) { + // Run it to find out more + m_state = RUNNING; + startProcess(); + } else { + m_state = INVALID; + } + settings->endGroup(); } -void CMakeRunner::run(QFutureInterface<void> &fi) +void CMakeSettingsPage::startProcess() { - m_mutex.lock(); - QString executable = m_executable; - m_mutex.unlock(); - QProcess cmake; - cmake.start(executable, QStringList(QLatin1String("--help"))); - cmake.waitForFinished(); - QString response = cmake.readAll(); - QRegExp versionRegexp(QLatin1String("^cmake version ([*\\d\\.]*)-(|patch (\\d*))(|\\r)\\n")); - versionRegexp.indexIn(response); - - m_mutex.lock(); - m_supportsQtCreator = response.contains(QLatin1String("QtCreator")); - m_hasCodeBlocksMsvcGenerator = response.contains(QLatin1String("CodeBlocks - NMake Makefiles")); - m_version = versionRegexp.cap(1); - if (!(versionRegexp.capturedTexts().size() > 3)) - m_version += QLatin1Char('.') + versionRegexp.cap(3); - m_cacheUpToDate = true; - m_mutex.unlock(); - fi.reportFinished(); -} + m_process = new QProcess(); -void CMakeRunner::setExecutable(const QString &executable) -{ - waitForUpToDate(); - m_mutex.lock(); - m_executable = executable; - m_cacheUpToDate = false; - m_mutex.unlock(); - m_future = QtConcurrent::run(&CMakeRunner::run, this); -} + connect(m_process, SIGNAL(finished(int)), + this, SLOT(cmakeFinished())); -QString CMakeRunner::executable() const -{ - waitForUpToDate(); - m_mutex.lock(); - QString result = m_executable; - m_mutex.unlock(); - return result; + m_process->start(m_cmakeExecutable, QStringList(QLatin1String("--help"))); + m_process->waitForStarted(); } -QString CMakeRunner::version() const +void CMakeSettingsPage::cmakeFinished() { - waitForUpToDate(); - m_mutex.lock(); - QString result = m_version; - m_mutex.unlock(); - return result; -} + if (m_process) { + QString response = m_process->readAll(); + QRegExp versionRegexp(QLatin1String("^cmake version ([\\d\\.]*)")); + versionRegexp.indexIn(response); -bool CMakeRunner::supportsQtCreator() const -{ - waitForUpToDate(); - m_mutex.lock(); - bool result = m_supportsQtCreator; - m_mutex.unlock(); - return result; -} + //m_supportsQtCreator = response.contains(QLatin1String("QtCreator")); + m_hasCodeBlocksMsvcGenerator = response.contains(QLatin1String("CodeBlocks - NMake Makefiles")); + m_version = versionRegexp.cap(1); + if (!(versionRegexp.capturedTexts().size() > 3)) + m_version += QLatin1Char('.') + versionRegexp.cap(3); -bool CMakeRunner::hasCodeBlocksMsvcGenerator() const -{ - waitForUpToDate(); - m_mutex.lock(); - bool result = m_hasCodeBlocksMsvcGenerator; - m_mutex.unlock(); - return result; + if (m_version.isEmpty()) + m_state = INVALID; + else + m_state = VALID; + + m_process->deleteLater(); + m_process = 0; + } } -void CMakeRunner::waitForUpToDate() const +bool CMakeSettingsPage::isCMakeExecutableValid() { - m_future.waitForFinished(); + if (m_state == RUNNING) { + disconnect(m_process, SIGNAL(finished(int)), + this, SLOT(cmakeFinished())); + m_process->waitForFinished(); + // Parse the output now + cmakeFinished(); + } + return m_state == VALID; } -///// -// CMakeSettingsPage -//// - - -CMakeSettingsPage::CMakeSettingsPage() +CMakeSettingsPage::~CMakeSettingsPage() { - Core::ICore *core = Core::ICore::instance(); - QSettings * settings = core->settings(); - settings->beginGroup(QLatin1String("CMakeSettings")); - m_cmakeRunner.setExecutable(settings->value(QLatin1String("cmakeExecutable")).toString()); - settings->endGroup(); + if (m_process) + m_process->waitForFinished(); + delete m_process; } QString CMakeSettingsPage::findCmakeExecutable() const @@ -296,18 +270,33 @@ QWidget *CMakeSettingsPage::createPage(QWidget *parent) return w; } +void CMakeSettingsPage::updateInfo() +{ + QFileInfo fi(m_cmakeExecutable); + if (fi.exists() && fi.isExecutable()) { + // Run it to find out more + m_state = RUNNING; + startProcess(); + } else { + m_state = INVALID; + } + saveSettings(); +} + void CMakeSettingsPage::saveSettings() const { QSettings *settings = Core::ICore::instance()->settings(); settings->beginGroup(QLatin1String("CMakeSettings")); - settings->setValue(QLatin1String("cmakeExecutable"), m_cmakeRunner.executable()); + settings->setValue(QLatin1String("cmakeExecutable"), m_cmakeExecutable); settings->endGroup(); } void CMakeSettingsPage::apply() { - m_cmakeRunner.setExecutable(m_pathchooser->path()); - saveSettings(); + if (m_cmakeExecutable == m_pathchooser->path()) + return; + m_cmakeExecutable = m_pathchooser->path(); + updateInfo(); } void CMakeSettingsPage::finish() @@ -317,28 +306,18 @@ void CMakeSettingsPage::finish() QString CMakeSettingsPage::cmakeExecutable() const { - if (m_cmakeRunner.executable().isEmpty()) { - QString cmakeExecutable = findCmakeExecutable(); - if (!cmakeExecutable.isEmpty()) { - m_cmakeRunner.setExecutable(cmakeExecutable); - saveSettings(); - } - } - return m_cmakeRunner.executable(); + return m_cmakeExecutable; } -bool CMakeSettingsPage::hasCodeBlocksMsvcGenerator() const +void CMakeSettingsPage::setCMakeExecutable(const QString &executable) { - return m_cmakeRunner.hasCodeBlocksMsvcGenerator(); + if (m_cmakeExecutable == executable) + return; + m_cmakeExecutable = executable; + updateInfo(); } - -void CMakeSettingsPage::askUserForCMakeExecutable() +bool CMakeSettingsPage::hasCodeBlocksMsvcGenerator() const { - // TODO implement - // That is ideally add a label to the settings page, which says something - // to the effect: please configure the cmake executable - // and show the settings page - // ensure that we rehide the label in the finish() function - // But to test that i need an environment without cmake, e.g. windows + return m_hasCodeBlocksMsvcGenerator; } diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h index ba0fa181ca4d3a9868890b725b5ae1321e6069bb..904094b1a17369e12f5cda3f23c1d1ac123c9981 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h @@ -39,12 +39,12 @@ #include <QtCore/QDir> QT_FORWARD_DECLARE_CLASS(QProcess) +QT_FORWARD_DECLARE_CLASS(QLabel) namespace CMakeProjectManager { namespace Internal { class CMakeSettingsPage; -class CMakeRunner; class CMakeManager : public ProjectExplorer::IProjectManager { @@ -57,7 +57,11 @@ public: virtual ProjectExplorer::Project *openProject(const QString &fileName); virtual QString mimeType() const; + QString cmakeExecutable() const; + bool isCMakeExecutableValid() const; + + void setCMakeExecutable(const QString &executable); QProcess* createXmlFile(const QStringList &arguments, const QString &sourceDirectory, @@ -76,28 +80,6 @@ private: CMakeSettingsPage *m_settingsPage; }; -class CMakeRunner -{ -public: - CMakeRunner(); - void setExecutable(const QString &executable); - QString executable() const; - QString version() const; - bool supportsQtCreator() const; - bool hasCodeBlocksMsvcGenerator() const; - -private: - void run(QFutureInterface<void> &fi); - void waitForUpToDate() const; - QString m_executable; - QString m_version; - bool m_supportsQtCreator; - bool m_hasCodeBlocksMsvcGenerator; - bool m_cacheUpToDate; - mutable QFuture<void> m_future; - mutable QMutex m_mutex; -}; - class CMakeSettingsPage : public Core::IOptionsPage { Q_OBJECT @@ -114,15 +96,23 @@ public: virtual void finish(); QString cmakeExecutable() const; - void askUserForCMakeExecutable(); + void setCMakeExecutable(const QString &executable); + bool isCMakeExecutableValid(); bool hasCodeBlocksMsvcGenerator() const; +private slots: + void cmakeFinished(); private: - void updateCachedInformation() const; void saveSettings() const; + void startProcess(); QString findCmakeExecutable() const; + void updateInfo(); - mutable CMakeRunner m_cmakeRunner; Core::Utils::PathChooser *m_pathchooser; + QString m_cmakeExecutable; + enum STATE { VALID, INVALID, RUNNING } m_state; + QProcess *m_process; + QString m_version; + bool m_hasCodeBlocksMsvcGenerator; }; } // namespace Internal