From 00951b6b969c439a36530bc5ec8dfbf8d8641288 Mon Sep 17 00:00:00 2001 From: dt <qtc-committer@nokia.com> Date: Mon, 16 Mar 2009 17:33:05 +0100 Subject: [PATCH] More progress on the CMake plugin Made the cmake plugin even more usable by implementing: Pop up a wizard if there is a .user file but no .cbp file. (Fixes empty project reported on irc.) Pop up a wizard if the .cbp file is older then the CMakeLists.txt file, thus reparsing the file. (Note: There is a bug that we need to actually also check the last modified of all included files.) Reparse the cbp file to add new RunConfigurations / delete no longer existing RunConfigurations and update those that have changed.- Show a nicer title in the Projects/RunConfiguration pane --- .../cmakeopenprojectwizard.cpp | 60 ++++++++-- .../cmakeopenprojectwizard.h | 7 ++ .../cmakeprojectmanager/cmakeproject.cpp | 113 +++++++++++++----- .../cmakerunconfiguration.cpp | 28 ++++- .../cmakerunconfiguration.h | 8 +- src/plugins/qt4projectmanager/qt4project.cpp | 1 + 6 files changed, 172 insertions(+), 45 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp index e8db79ed21c..4803f26b9f1 100644 --- a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp @@ -10,6 +10,7 @@ #include <QtGui/QPushButton> #include <QtGui/QPlainTextEdit> #include <QtCore/QDateTime> +#include <QtCore/QStringList> using namespace CMakeProjectManager; using namespace CMakeProjectManager::Internal; @@ -27,7 +28,8 @@ using namespace CMakeProjectManager::Internal; CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory) : m_cmakeManager(cmakeManager), - m_sourceDirectory(sourceDirectory) + m_sourceDirectory(sourceDirectory), + m_creatingCbpFiles(false) { int startid; if (hasInSourceBuild()) { @@ -46,6 +48,18 @@ CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const setStartId(startid); } +CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, + const QStringList &needToCreate, const QStringList &needToUpdate) + : m_cmakeManager(cmakeManager), + m_sourceDirectory(sourceDirectory), + m_creatingCbpFiles(true) +{ + foreach(const QString &buildDirectory, needToCreate) + addPage(new CMakeRunPage(this, buildDirectory, false)); + foreach(const QString &buildDirectory, needToUpdate) + addPage(new CMakeRunPage(this, buildDirectory, true)); +} + CMakeManager *CMakeOpenProjectWizard::cmakeManager() const { return m_cmakeManager; @@ -53,6 +67,8 @@ CMakeManager *CMakeOpenProjectWizard::cmakeManager() const int CMakeOpenProjectWizard::nextId() const { + if (m_creatingCbpFiles) + return QWizard::nextId(); int cid = currentId(); if (cid == InSourcePageId) { if (existsUpToDateXmlFile()) @@ -169,15 +185,43 @@ void ShadowBuildPage::buildDirectoryChanged() CMakeRunPage::CMakeRunPage(CMakeOpenProjectWizard *cmakeWizard) : QWizardPage(cmakeWizard), m_cmakeWizard(cmakeWizard), - m_complete(false) + m_complete(false), + m_buildDirectory(m_cmakeWizard->buildDirectory()) +{ + initWidgets(); +} + +CMakeRunPage::CMakeRunPage(CMakeOpenProjectWizard *cmakeWizard, const QString &buildDirectory, bool update) + : QWizardPage(cmakeWizard), + m_cmakeWizard(cmakeWizard), + m_complete(false), + m_buildDirectory(buildDirectory) +{ + initWidgets(); + // TODO tell the user more? + if (update) + m_descriptionLabel->setText(tr("The directory %1 contains an outdated .cbp file. Qt " + "Creator needs to update this file by running cmake. " + "If you want to add additional command line arguments, " + "add them in the below.").arg(m_buildDirectory)); + else + m_descriptionLabel->setText(tr("The directory %1, specified in a buildconfiguration, " + "does not contain a cbp file. Qt Creator needs to " + "recreate this file, by running cmake. " + "Some projects require command line arguments to " + "the initial cmake call.").arg(m_buildDirectory)); +} + +void CMakeRunPage::initWidgets() { QFormLayout *fl = new QFormLayout; setLayout(fl); - QLabel *label = new QLabel(this); - label->setWordWrap(true); - label->setText(tr("The directory %1 does not contain a cbp file. Qt Creator needs to create this file, by running cmake. " - "Some projects require command line arguments to the initial cmake call.").arg(m_cmakeWizard->buildDirectory())); - fl->addRow(label); + m_descriptionLabel = new QLabel(this); + m_descriptionLabel->setWordWrap(true); + m_descriptionLabel->setText(tr("The directory %1 does not contain a cbp file. Qt Creator needs to create this file, by running cmake. " + "Some projects require command line arguments to the initial cmake call.").arg(m_buildDirectory)); + + fl->addRow(m_descriptionLabel); m_argumentsLineEdit = new QLineEdit(this); fl->addRow(tr("Arguments:"), m_argumentsLineEdit); @@ -198,7 +242,7 @@ void CMakeRunPage::runCMake() m_argumentsLineEdit->setEnabled(false); QStringList arguments = ProjectExplorer::Environment::parseCombinedArgString(m_argumentsLineEdit->text()); CMakeManager *cmakeManager = m_cmakeWizard->cmakeManager(); - m_cmakeProcess = cmakeManager->createXmlFile(arguments, m_cmakeWizard->sourceDirectory(), m_cmakeWizard->buildDirectory()); + m_cmakeProcess = cmakeManager->createXmlFile(arguments, m_cmakeWizard->sourceDirectory(), m_buildDirectory); connect(m_cmakeProcess, SIGNAL(readyRead()), this, SLOT(cmakeReadyRead())); connect(m_cmakeProcess, SIGNAL(finished(int)), this, SLOT(cmakeFinished())); } diff --git a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h index 0cbdc49c8e9..8d7e212620d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h +++ b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h @@ -4,6 +4,7 @@ #include <QtCore/QProcess> #include <QtGui/QPushButton> #include <QtGui/QLineEdit> +#include <QtGui/QLabel> #include <QtGui/QWizard> #include <QtGui/QPlainTextEdit> @@ -29,6 +30,7 @@ public: CMakeRunPageId }; CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory); + CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, const QStringList &needToCreate, const QStringList &needToUpdate); virtual int nextId() const; QString buildDirectory() const; QString sourceDirectory() const; @@ -43,6 +45,7 @@ private: QString m_buildDirectory; QString m_sourceDirectory; QStringList m_arguments; + bool m_creatingCbpFiles; }; class InSourceBuildPage : public QWizardPage @@ -82,6 +85,7 @@ class CMakeRunPage : public QWizardPage Q_OBJECT public: CMakeRunPage(CMakeOpenProjectWizard *cmakeWizard); + CMakeRunPage(CMakeOpenProjectWizard *cmakeWizard, const QString &buildDirectory, bool update); virtual void cleanupPage(); virtual bool isComplete() const; private slots: @@ -89,12 +93,15 @@ private slots: void cmakeFinished(); void cmakeReadyRead(); private: + void initWidgets(); CMakeOpenProjectWizard *m_cmakeWizard; QPlainTextEdit *m_output; QPushButton *m_runCMake; QProcess *m_cmakeProcess; QLineEdit *m_argumentsLineEdit; + QLabel *m_descriptionLabel; bool m_complete; + QString m_buildDirectory; }; } diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index e7114fc63dc..dd568b05848 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -40,8 +40,10 @@ #include <utils/qtcassert.h> #include <coreplugin/icore.h> +#include <QtCore/QMap> #include <QtCore/QDebug> #include <QtCore/QDir> +#include <QtCore/QDateTime> #include <QtCore/QProcess> #include <QtGui/QFormLayout> #include <QtGui/QMainWindow> @@ -80,15 +82,14 @@ CMakeProject::~CMakeProject() // TODO make this function work even if it is reparsing void CMakeProject::parseCMakeLists() { - ProjectExplorer::ToolChain *newToolChain = 0; QString sourceDirectory = QFileInfo(m_fileName).absolutePath(); - QString cbpFile = CMakeManager::findCbpFile(buildDirectory(activeBuildConfiguration())); m_rootNode->setFolderName(QFileInfo(cbpFile).baseName()); CMakeCbpParser cbpparser; qDebug()<<"Parsing file "<<cbpFile; if (cbpparser.parseCbpFile(cbpFile)) { qDebug()<<"CodeBlocks Compilername"<<cbpparser.compilerName(); + ProjectExplorer::ToolChain *newToolChain = 0; if (cbpparser.compilerName() == "gcc") { newToolChain = ProjectExplorer::ToolChain::createGccToolChain("gcc"); } else if (cbpparser.compilerName() == "msvc8") { @@ -97,7 +98,9 @@ void CMakeProject::parseCMakeLists() Q_ASSERT(false); } else { // TODO hmm? + qDebug()<<"Not implemented yet!!! Qt Creator doesn't know which toolchain to use for"<<cbpparser.compilerName(); } + if (ProjectExplorer::ToolChain::equals(newToolChain, m_toolChain)) { delete newToolChain; newToolChain = 0; @@ -107,27 +110,29 @@ void CMakeProject::parseCMakeLists() } m_projectName = cbpparser.projectName(); + m_rootNode->setFolderName(cbpparser.projectName()); qDebug()<<"Building Tree"; - // TODO do a intelligent updating of the tree + // TODO do a intelligent updating of the tree QList<ProjectExplorer::FileNode *> fileList = cbpparser.fileList(); // Manually add the CMakeLists.txt file fileList.append(new ProjectExplorer::FileNode(sourceDirectory + "/CMakeLists.txt", ProjectExplorer::ProjectFileType, false)); buildTree(m_rootNode, fileList); + m_files.clear(); foreach (ProjectExplorer::FileNode *fn, fileList) m_files.append(fn->path()); m_files.sort(); qDebug()<<"Adding Targets"; m_targets = cbpparser.targets(); - qDebug()<<"Printing targets"; - foreach(CMakeTarget ct, m_targets) { - qDebug()<<ct.title<<" with executable:"<<ct.executable; - qDebug()<<"WD:"<<ct.workingDirectory; - qDebug()<<ct.makeCommand<<ct.makeCleanCommand; - qDebug()<<""; - } +// qDebug()<<"Printing targets"; +// foreach(CMakeTarget ct, m_targets) { +// qDebug()<<ct.title<<" with executable:"<<ct.executable; +// qDebug()<<"WD:"<<ct.workingDirectory; +// qDebug()<<ct.makeCommand<<ct.makeCleanCommand; +// qDebug()<<""; +// } qDebug()<<"Updating CodeModel"; @@ -147,12 +152,62 @@ void CMakeProject::parseCMakeLists() pinfo.includePaths = allIncludePaths; // TODO we only want C++ files, not all other stuff that might be in the project pinfo.sourceFiles = m_files; - pinfo.defines = m_toolChain->predefinedMacros(); + pinfo.defines = m_toolChain->predefinedMacros(); // TODO this is to simplistic pinfo.frameworkPaths = allFrameworkPaths; modelmanager->updateProjectInfo(pinfo); } + + // Create run configurations for m_targets + qDebug()<<"Create run configurations of m_targets"; + QMap<QString, QSharedPointer<CMakeRunConfiguration> > existingRunConfigurations; + foreach(QSharedPointer<ProjectExplorer::RunConfiguration> cmakeRunConfiguration, runConfigurations()) { + if (QSharedPointer<CMakeRunConfiguration> rc = cmakeRunConfiguration.dynamicCast<CMakeRunConfiguration>()) { + existingRunConfigurations.insert(rc->title(), rc); + } + } + + bool setActive = false; + foreach(const CMakeTarget &ct, m_targets) { + if (ct.executable.isEmpty()) + continue; + if (ct.title.endsWith("/fast")) + continue; + QMap<QString, QSharedPointer<CMakeRunConfiguration> >::iterator it = + existingRunConfigurations.find(ct.title); + if (it != existingRunConfigurations.end()) { + // Already exists, so override the settings... + QSharedPointer<CMakeRunConfiguration> rc = it.value(); + qDebug()<<"Updating Run Configuration with title"<<ct.title; + qDebug()<<" Executable new:"<<ct.executable<< "old:"<<rc->executable(); + qDebug()<<" WD new:"<<ct.workingDirectory<<"old:"<<rc->workingDirectory(); + rc->setExecutable(ct.executable); + rc->setWorkingDirectory(ct.workingDirectory); + existingRunConfigurations.erase(it); + } else { + // Does not exist yet + qDebug()<<"Adding new run configuration with title"<<ct.title; + qDebug()<<" Executable:"<<ct.executable<<"WD:"<<ct.workingDirectory; + QSharedPointer<ProjectExplorer::RunConfiguration> rc(new CMakeRunConfiguration(this, ct.executable, ct.workingDirectory, ct.title)); + addRunConfiguration(rc); + // The first one gets the honour of beeing the active one + if (!setActive) { + setActiveRunConfiguration(rc); + setActive = true; + } + } + } + QMap<QString, QSharedPointer<CMakeRunConfiguration> >::const_iterator it = + existingRunConfigurations.constBegin(); + for( ; it != existingRunConfigurations.constEnd(); ++it) { + QSharedPointer<CMakeRunConfiguration> rc = it.value(); + qDebug()<<"Removing old RunConfiguration with title:"<<rc->title(); + qDebug()<<" Executable:"<<rc->executable()<<rc->workingDirectory(); + removeRunConfiguration(rc); + } + qDebug()<<"\n"; } else { // TODO report error + qDebug()<<"Parsing failed"; delete m_toolChain; m_toolChain = 0; } @@ -341,31 +396,27 @@ void CMakeProject::restoreSettingsImpl(ProjectExplorer::PersistentSettingsReader // We have a user file, but we could still be missing the cbp file // TODO check that we have a cbp file and if not, open up a dialog ? // or simply run createXml with the saved settings - + QFileInfo sourceFileInfo(m_fileName); + QStringList needToCreate; + QStringList needToUpdate; + foreach(const QString &buildConfiguration, buildConfigurations()) { + QString buildDirectory = value(buildConfiguration, "buildDirectory").toString(); + QString cbpFile = CMakeManager::findCbpFile(QDir(buildDirectory)); + QFileInfo cbpFileFi(cbpFile); + if (!cbpFileFi.exists()) + needToCreate << buildDirectory; + else if (cbpFileFi.lastModified() < sourceFileInfo.lastModified()) + needToUpdate << buildDirectory; + } + if (!needToCreate.isEmpty() || !needToUpdate.isEmpty()) { + CMakeOpenProjectWizard copw(m_manager, sourceFileInfo.absolutePath(), needToCreate, needToUpdate); + copw.exec(); + } } parseCMakeLists(); // Gets the directory from the active buildconfiguration - - if (!hasUserFile) { - // Create run configurations for m_targets - qDebug()<<"Create run configurations of m_targets"; - bool setActive = false; - foreach(const CMakeTarget &ct, m_targets) { - if (ct.executable.isEmpty()) - continue; - QSharedPointer<ProjectExplorer::RunConfiguration> rc(new CMakeRunConfiguration(this, ct.executable, ct.workingDirectory)); - addRunConfiguration(rc); - // The first one gets the honour of beeing the active one - if (!setActive) { - setActiveRunConfiguration(rc); - setActive = true; - } - } - - } } - CMakeFile::CMakeFile(CMakeProject *parent, QString fileName) : Core::IFile(parent), m_project(parent), m_fileName(fileName) { diff --git a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp index 73007ad7d16..c86d50f0b06 100644 --- a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp @@ -38,10 +38,10 @@ using namespace CMakeProjectManager; using namespace CMakeProjectManager::Internal; -CMakeRunConfiguration::CMakeRunConfiguration(CMakeProject *pro, const QString &target, const QString &workingDirectory) - : ProjectExplorer::ApplicationRunConfiguration(pro), m_runMode(Gui), m_target(target), m_workingDirectory(workingDirectory) +CMakeRunConfiguration::CMakeRunConfiguration(CMakeProject *pro, const QString &target, const QString &workingDirectory, const QString &title) + : ProjectExplorer::ApplicationRunConfiguration(pro), m_runMode(Gui), m_target(target), m_workingDirectory(workingDirectory), m_title(title) { - setName(target); + setName(title); } CMakeRunConfiguration::~CMakeRunConfiguration() @@ -80,12 +80,28 @@ ProjectExplorer::Environment CMakeRunConfiguration::environment() const return ProjectExplorer::Environment::systemEnvironment(); } +QString CMakeRunConfiguration::title() const +{ + return m_title; +} + +void CMakeRunConfiguration::setExecutable(const QString &executable) +{ + m_target = executable; +} + +void CMakeRunConfiguration::setWorkingDirectory(const QString &workingDirectory) +{ + m_workingDirectory = workingDirectory; +} + void CMakeRunConfiguration::save(ProjectExplorer::PersistentSettingsWriter &writer) const { ProjectExplorer::ApplicationRunConfiguration::save(writer); writer.saveValue("CMakeRunConfiguration.Target", m_target); writer.saveValue("CMakeRunConfiguration.WorkingDirectory", m_workingDirectory); writer.saveValue("CMakeRunConfiguration.UseTerminal", m_runMode == Console); + writer.saveValue("CMakeRunConfiguation.Title", m_title); } void CMakeRunConfiguration::restore(const ProjectExplorer::PersistentSettingsReader &reader) @@ -94,6 +110,7 @@ void CMakeRunConfiguration::restore(const ProjectExplorer::PersistentSettingsRea m_target = reader.restoreValue("CMakeRunConfiguration.Target").toString(); m_workingDirectory = reader.restoreValue("CMakeRunConfiguration.WorkingDirectory").toString(); m_runMode = reader.restoreValue("CMakeRunConfiguration.UseTerminal").toBool() ? Console : Gui; + m_title = reader.restoreValue("CMakeRunConfiguation.Title").toString(); } QWidget *CMakeRunConfiguration::configurationWidget() @@ -148,12 +165,13 @@ QSharedPointer<ProjectExplorer::RunConfiguration> CMakeRunConfigurationFactory:: Q_ASSERT(pro); if (type == Constants::CMAKERUNCONFIGURATION) { // Restoring, filename will be added by restoreSettings - QSharedPointer<ProjectExplorer::RunConfiguration> rc(new CMakeRunConfiguration(pro, QString::null, QString::null)); + QSharedPointer<ProjectExplorer::RunConfiguration> rc(new CMakeRunConfiguration(pro, QString::null, QString::null, QString::null)); return rc; } else { // Adding new + // TODO extract target from type QString file = type.mid(QString(Constants::CMAKERUNCONFIGURATION).length()); - QSharedPointer<ProjectExplorer::RunConfiguration> rc(new CMakeRunConfiguration(pro, file, QString::null)); + QSharedPointer<ProjectExplorer::RunConfiguration> rc(new CMakeRunConfiguration(pro, file, QString::null, QString::null)); return rc; } } diff --git a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h index 77bbbc7b920..d2a142ff9f4 100644 --- a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h @@ -42,7 +42,7 @@ class CMakeProject; class CMakeRunConfiguration : public ProjectExplorer::ApplicationRunConfiguration { public: - CMakeRunConfiguration(CMakeProject *pro, const QString &target, const QString &workingDirectory); + CMakeRunConfiguration(CMakeProject *pro, const QString &target, const QString &workingDirectory, const QString &title); virtual ~CMakeRunConfiguration(); virtual QString type() const; virtual QString executable() const; @@ -52,12 +52,18 @@ public: virtual ProjectExplorer::Environment environment() const; virtual QWidget *configurationWidget(); + void setExecutable(const QString &executable); + void setWorkingDirectory(const QString &workingDirectory); + + QString title() const; + virtual void save(ProjectExplorer::PersistentSettingsWriter &writer) const; virtual void restore(const ProjectExplorer::PersistentSettingsReader &reader); private: RunMode m_runMode; QString m_target; QString m_workingDirectory; + QString m_title; }; /* The run configuration factory is used for restoring run configurations from diff --git a/src/plugins/qt4projectmanager/qt4project.cpp b/src/plugins/qt4projectmanager/qt4project.cpp index 3549df23a6e..3018da15cce 100644 --- a/src/plugins/qt4projectmanager/qt4project.cpp +++ b/src/plugins/qt4projectmanager/qt4project.cpp @@ -256,6 +256,7 @@ Qt4Project::~Qt4Project() m_manager->unregisterProject(this); delete m_projectFiles; delete m_toolChain; + m_toolChain = 0; } void Qt4Project::defaultQtVersionChanged() -- GitLab