diff --git a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp new file mode 100644 index 00000000000..e8db79ed21c --- /dev/null +++ b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp @@ -0,0 +1,234 @@ +#include "cmakeopenprojectwizard.h" +#include "cmakeprojectmanager.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace CMakeProjectManager; +using namespace CMakeProjectManager::Internal; + +/////// +// Page Flow: +// Start (No .user file) +// | +// |---> In Source Build --> Page: Tell the user about that +// |--> Already existing cbp file (and new enough) --> Page: Ready to load the project +// |--> Page: Ask for cmd options, run generator +// |---> No in source Build --> Page: Ask the user for the build directory +// |--> Already existing cbp file (and new enough) --> Page: Ready to load the project +// |--> Page: Ask for cmd options, run generator + +CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory) + : m_cmakeManager(cmakeManager), + m_sourceDirectory(sourceDirectory) +{ + int startid; + if (hasInSourceBuild()) { + startid = InSourcePageId; + m_buildDirectory = m_sourceDirectory; + } else { + startid = ShadowBuildPageId; + m_buildDirectory = m_sourceDirectory + "/qtcreator-build"; + } + + setPage(InSourcePageId, new InSourceBuildPage(this)); + setPage(ShadowBuildPageId, new ShadowBuildPage(this)); + setPage(XmlFileUpToDatePageId, new XmlFileUpToDatePage(this)); + setPage(CMakeRunPageId, new CMakeRunPage(this)); + + setStartId(startid); +} + +CMakeManager *CMakeOpenProjectWizard::cmakeManager() const +{ + return m_cmakeManager; +} + +int CMakeOpenProjectWizard::nextId() const +{ + int cid = currentId(); + if (cid == InSourcePageId) { + if (existsUpToDateXmlFile()) + return XmlFileUpToDatePageId; + else + return CMakeRunPageId; + } else if (cid == ShadowBuildPageId) { + if (existsUpToDateXmlFile()) + return XmlFileUpToDatePageId; + else + return CMakeRunPageId; + } + return -1; +} + + +bool CMakeOpenProjectWizard::hasInSourceBuild() const +{ + QFileInfo fi(m_sourceDirectory + "/CMakeCache.txt"); + if (fi.exists()) + return true; + return false; +} + +bool CMakeOpenProjectWizard::existsUpToDateXmlFile() const +{ + QString cbpFile = CMakeManager::findCbpFile(QDir(buildDirectory())); + if (!cbpFile.isEmpty()) { + // We already have a cbp file + QFileInfo cbpFileInfo(cbpFile); + QFileInfo cmakeListsFileInfo(sourceDirectory() + "/CMakeLists.txt"); + + if (cbpFileInfo.lastModified() > cmakeListsFileInfo.lastModified()) + return true; + } + return false; +} + +QString CMakeOpenProjectWizard::buildDirectory() const +{ + return m_buildDirectory; +} + +QString CMakeOpenProjectWizard::sourceDirectory() const +{ + return m_sourceDirectory; +} + +void CMakeOpenProjectWizard::setBuildDirectory(const QString &directory) +{ + m_buildDirectory = directory; +} + +QStringList CMakeOpenProjectWizard::arguments() const +{ + return m_arguments; +} + +void CMakeOpenProjectWizard::setArguments(const QStringList &args) +{ + m_arguments = args; +} + + +InSourceBuildPage::InSourceBuildPage(CMakeOpenProjectWizard *cmakeWizard) + : QWizardPage(cmakeWizard), m_cmakeWizard(cmakeWizard) +{ + setLayout(new QVBoxLayout); + QLabel *label = new QLabel(this); + label->setWordWrap(true); + label->setText(tr("Qt Creator has detected an in source build. " + "This prevents out of souce builds, Qt Creator won't allow you to change the build directory. " + "If you want a out of source build, clean your source directory and open the project again")); + layout()->addWidget(label); +} + + +XmlFileUpToDatePage::XmlFileUpToDatePage(CMakeOpenProjectWizard *cmakeWizard) + : QWizardPage(cmakeWizard), m_cmakeWizard(cmakeWizard) +{ + setLayout(new QVBoxLayout); + QLabel *label = new QLabel(this); + label->setWordWrap(true); + label->setText(tr("Qt Creator has found a recent cbp file, which Qt Creator parses to gather information about the project. " + "You can change the command line arguments used to create this file, in the project mode. " + "Click finish to load the project")); + layout()->addWidget(label); +} + +ShadowBuildPage::ShadowBuildPage(CMakeOpenProjectWizard *cmakeWizard) + : QWizardPage(cmakeWizard), m_cmakeWizard(cmakeWizard) +{ + QFormLayout *fl = new QFormLayout; + this->setLayout(fl); + + QLabel *label = new QLabel(this); + label->setWordWrap(true); + label->setText(tr("Please enter the directory in which you want to build your project. " + "Qt Creator recommends to not use the source directory for building. " + "This ensures that the source directory remains clean and enables multiple builds " + "with different settings.")); + fl->addWidget(label); + m_pc = new Core::Utils::PathChooser(this); + m_pc->setPath(m_cmakeWizard->buildDirectory()); + connect(m_pc, SIGNAL(changed()), this, SLOT(buildDirectoryChanged())); + fl->addRow("Build directory:", m_pc); +} + +void ShadowBuildPage::buildDirectoryChanged() +{ + m_cmakeWizard->setBuildDirectory(m_pc->path()); +} + +CMakeRunPage::CMakeRunPage(CMakeOpenProjectWizard *cmakeWizard) + : QWizardPage(cmakeWizard), + m_cmakeWizard(cmakeWizard), + m_complete(false) +{ + 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_argumentsLineEdit = new QLineEdit(this); + fl->addRow(tr("Arguments:"), m_argumentsLineEdit); + + + m_runCMake = new QPushButton(this); + m_runCMake->setText("Run CMake"); + connect(m_runCMake, SIGNAL(clicked()), this, SLOT(runCMake())); + fl->addWidget(m_runCMake); + + m_output = new QPlainTextEdit(this); + fl->addRow(m_output); +} + +void CMakeRunPage::runCMake() +{ + m_runCMake->setEnabled(false); + 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()); + connect(m_cmakeProcess, SIGNAL(readyRead()), this, SLOT(cmakeReadyRead())); + connect(m_cmakeProcess, SIGNAL(finished(int)), this, SLOT(cmakeFinished())); +} + +void CMakeRunPage::cmakeReadyRead() +{ + m_output->appendPlainText(m_cmakeProcess->readAll()); +} + +void CMakeRunPage::cmakeFinished() +{ + m_runCMake->setEnabled(true); + m_argumentsLineEdit->setEnabled(true); + m_cmakeProcess->deleteLater(); + m_cmakeProcess = 0; + m_cmakeWizard->setArguments(ProjectExplorer::Environment::parseCombinedArgString(m_argumentsLineEdit->text())); + //TODO Actually test that running cmake was finished, for setting this bool + m_complete = true; + emit completeChanged(); +} + +void CMakeRunPage::cleanupPage() +{ + m_output->clear(); + m_complete = false; + emit completeChanged(); +} + +bool CMakeRunPage::isComplete() const +{ + return m_complete; +} + diff --git a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h new file mode 100644 index 00000000000..0cbdc49c8e9 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h @@ -0,0 +1,103 @@ +#ifndef CMAKEOPENPROJECTWIZARD_H +#define CMAKEOPENPROJECTWIZARD_H + +#include +#include +#include +#include +#include + +namespace Core { + namespace Utils { + class PathChooser; + } +} + +namespace CMakeProjectManager { +namespace Internal { + +class CMakeManager; + +class CMakeOpenProjectWizard : public QWizard +{ + Q_OBJECT +public: + enum PageId { + InSourcePageId, + ShadowBuildPageId, + XmlFileUpToDatePageId, + CMakeRunPageId + }; + CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory); + virtual int nextId() const; + QString buildDirectory() const; + QString sourceDirectory() const; + void setBuildDirectory(const QString &directory); + CMakeManager *cmakeManager() const; + QStringList arguments() const; + void setArguments(const QStringList &args); +private: + bool existsUpToDateXmlFile() const; + bool hasInSourceBuild() const; + CMakeManager *m_cmakeManager; + QString m_buildDirectory; + QString m_sourceDirectory; + QStringList m_arguments; +}; + +class InSourceBuildPage : public QWizardPage +{ + Q_OBJECT +public: + InSourceBuildPage(CMakeOpenProjectWizard *cmakeWizard); +private: + CMakeOpenProjectWizard *m_cmakeWizard; +}; + + +class XmlFileUpToDatePage : public QWizardPage +{ + Q_OBJECT +public: + XmlFileUpToDatePage(CMakeOpenProjectWizard *cmakeWizard); +private: + CMakeOpenProjectWizard *m_cmakeWizard; +}; + + +class ShadowBuildPage : public QWizardPage +{ + Q_OBJECT +public: + ShadowBuildPage(CMakeOpenProjectWizard *cmakeWizard); +private slots: + void buildDirectoryChanged(); +private: + CMakeOpenProjectWizard *m_cmakeWizard; + Core::Utils::PathChooser *m_pc; +}; + +class CMakeRunPage : public QWizardPage +{ + Q_OBJECT +public: + CMakeRunPage(CMakeOpenProjectWizard *cmakeWizard); + virtual void cleanupPage(); + virtual bool isComplete() const; +private slots: + void runCMake(); + void cmakeFinished(); + void cmakeReadyRead(); +private: + CMakeOpenProjectWizard *m_cmakeWizard; + QPlainTextEdit *m_output; + QPushButton *m_runCMake; + QProcess *m_cmakeProcess; + QLineEdit *m_argumentsLineEdit; + bool m_complete; +}; + +} +} + +#endif // CMAKEOPENPROJECTWIZARD_H