diff options
author | Tobias Hunger <tobias.hunger@digia.com> | 2013-08-13 10:52:57 +0200 |
---|---|---|
committer | Tobias Hunger <tobias.hunger@digia.com> | 2013-09-27 14:34:43 +0200 |
commit | 921f86dfa748468a8d7e6bb7787aed8fb8b53da9 (patch) | |
tree | 717cc0cd5052ff7a75f27f11e5abb9143fd35447 /src/plugins/projectexplorer | |
parent | 95828d4691a993e552843738114507a5a30efe2a (diff) | |
download | qt-creator-921f86dfa748468a8d7e6bb7787aed8fb8b53da9.tar.gz |
TargetSetupPage: Generalize the page
Generalize the target setup page and move it into projectexplorer
Move the qmake specific code into a projectimporter class with
a specialization for qmake projects in the qt4projectmanager.
This change depends heavily on the BuildConfigurationFactory cleanups
done earlier and completes that change in such a way that generic
build configuration factories are now in theory possible. The
remaining problem is how to select the best factory of several that
claim to be able to handle a kit and that is left for the next patch.
Change-Id: I47134cb1938c52adebcdc1ddfe8dbf26abbbbeee
Reviewed-by: Daniel Teske <daniel.teske@digia.com>
Diffstat (limited to 'src/plugins/projectexplorer')
21 files changed, 1863 insertions, 9 deletions
diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 84cb07b285..8366ff00f0 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -341,6 +341,18 @@ IBuildConfigurationFactory *IBuildConfigurationFactory::find(Target *parent, con return 0; } +// setup +IBuildConfigurationFactory *IBuildConfigurationFactory::find(Kit *k, const QString &projectPath) +{ + QList<IBuildConfigurationFactory *> factories + = ExtensionSystem::PluginManager::instance()->getObjects<IBuildConfigurationFactory>(); + foreach (IBuildConfigurationFactory *factory, factories) { + if (factory->canSetup(k, projectPath)) + return factory; + } + return 0; +} + // create IBuildConfigurationFactory * IBuildConfigurationFactory::find(Target *parent) { diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h index 69842fba64..52bca21090 100644 --- a/src/plugins/projectexplorer/buildconfiguration.h +++ b/src/plugins/projectexplorer/buildconfiguration.h @@ -133,6 +133,13 @@ public: // List of build information that can be used to create a new build configuration via // "Add Build Configuration" button. virtual QList<BuildInfo *> availableBuilds(const Target *parent) const = 0; + + // Used to see whether this factory can produce any BuildConfigurations for a kit when + // setting up the given project. + virtual bool canSetup(const Kit *k, const QString &projectPath) const = 0; + // List of build information that can be used to initially set up a new build configuration. + virtual QList<BuildInfo *> availableSetups(const Kit *k, const QString &projectPath) const = 0; + virtual BuildConfiguration *create(Target *parent, const BuildInfo *info) const = 0; // used to recreate the runConfigurations when restoring settings diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp index 15a661d828..ced35e0b85 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp @@ -98,7 +98,7 @@ PropertiesPanel *BuildSettingsPanelFactory::createPanel(Target *target) BuildSettingsWidget::~BuildSettingsWidget() { - clear(); + clearWidgets(); qDeleteAll(m_buildInfoList); } @@ -195,7 +195,7 @@ void BuildSettingsWidget::addSubWidget(NamedWidget *widget) m_subWidgets.append(widget); } -void BuildSettingsWidget::clear() +void BuildSettingsWidget::clearWidgets() { qDeleteAll(m_subWidgets); m_subWidgets.clear(); @@ -232,7 +232,7 @@ void BuildSettingsWidget::updateAddButtonMenu() void BuildSettingsWidget::updateBuildSettings() { - clear(); + clearWidgets(); // update buttons m_removeButton->setEnabled(m_target->buildConfigurations().size() > 1); diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.h b/src/plugins/projectexplorer/buildsettingspropertiespage.h index d75b701d94..67e84a67a7 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.h +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.h @@ -72,7 +72,7 @@ public: BuildSettingsWidget(Target *target); ~BuildSettingsWidget(); - void clear(); + void clearWidgets(); void addSubWidget(ProjectExplorer::NamedWidget *widget); QList<ProjectExplorer::NamedWidget *> subWidgets() const; diff --git a/src/plugins/projectexplorer/importwidget.cpp b/src/plugins/projectexplorer/importwidget.cpp new file mode 100644 index 0000000000..01d0cb3880 --- /dev/null +++ b/src/plugins/projectexplorer/importwidget.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "importwidget.h" + +#include <utils/detailswidget.h> +#include <utils/pathchooser.h> + +#include <QPushButton> +#include <QVBoxLayout> + +namespace ProjectExplorer { +namespace Internal { + +ImportWidget::ImportWidget(QWidget *parent) : + QWidget(parent), + m_pathChooser(new Utils::PathChooser) +{ + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + QVBoxLayout *vboxLayout = new QVBoxLayout(); + setLayout(vboxLayout); + vboxLayout->setContentsMargins(0, 0, 0, 0); + Utils::DetailsWidget *detailsWidget = new Utils::DetailsWidget(this); + detailsWidget->setUseCheckBox(false); + detailsWidget->setSummaryText(tr("Import Build from...")); + detailsWidget->setSummaryFontBold(true); + // m_detailsWidget->setIcon(); // FIXME: Set icon! + vboxLayout->addWidget(detailsWidget); + + QWidget *widget = new QWidget; + QVBoxLayout *layout = new QVBoxLayout(widget); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(m_pathChooser); + + m_pathChooser->setExpectedKind(Utils::PathChooser::ExistingDirectory); + QPushButton *importButton = new QPushButton(tr("Import"), widget); + layout->addWidget(importButton); + + connect(importButton, SIGNAL(clicked()), this, SLOT(handleImportRequest())); + + detailsWidget->setWidget(widget); +} + +ImportWidget::~ImportWidget() +{ } + +void ImportWidget::setCurrentDirectory(const Utils::FileName &dir) +{ + m_pathChooser->setBaseFileName(dir); + m_pathChooser->setFileName(dir); +} + +void ImportWidget::handleImportRequest() +{ + Utils::FileName dir = m_pathChooser->fileName(); + emit importFrom(dir); + + m_pathChooser->setFileName(m_pathChooser->baseFileName()); +} + +} // namespace Internal +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/importwidget.h b/src/plugins/projectexplorer/importwidget.h new file mode 100644 index 0000000000..5eb88350da --- /dev/null +++ b/src/plugins/projectexplorer/importwidget.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef IMPORTWIDGET_H +#define IMPORTWIDGET_H + +#include <QWidget> + +namespace Utils { +class PathChooser; +class FileName; +} // namespace Utils + +namespace ProjectExplorer { +namespace Internal { + +class ImportWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ImportWidget(QWidget *parent = 0); + ~ImportWidget(); + + void setCurrentDirectory(const Utils::FileName &dir); + +signals: + void importFrom(const Utils::FileName &dir); + +private slots: + void handleImportRequest(); + +private: + Utils::PathChooser *m_pathChooser; +}; + +} // namespace Internal +} // namespace ProjectExplorer + +#endif // IMPORTWIDGET_H diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 54838549cd..7dc2ddac01 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -282,6 +282,7 @@ Target *Project::restoreTarget(const QVariantMap &data) delete t; return 0; } + return t; } @@ -505,8 +506,16 @@ void Project::setup(QList<const BuildInfo *> infoList) continue; t->addBuildConfiguration(bc); } - foreach (Target *t, toRegister) + foreach (Target *t, toRegister) { + t->updateDefaultDeployConfigurations(); + t->updateDefaultRunConfigurations(); addTarget(t); + } +} + +ProjectImporter *Project::createProjectImporter() const +{ + return 0; } void Project::onBuildDirectoryChanged() diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index 84be549966..962512c7b1 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -47,8 +47,10 @@ namespace ProjectExplorer { class BuildInfo; class IProjectManager; class EditorConfiguration; +class ProjectImporter; class ProjectNode; class Kit; +class KitMatcher; class NamedWidget; class Target; class ProjectPrivate; @@ -125,6 +127,9 @@ public: virtual void configureAsExampleProject(const QStringList &platforms); virtual bool supportsNoTargetPanel() const; + virtual ProjectImporter *createProjectImporter() const; + virtual KitMatcher *createRequiredKitMatcher() const { return 0; } + virtual KitMatcher *createPreferredKitMatcher() const { return 0; } virtual bool needsSpecialDeployment() const; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index ed3aa3739c..16c2033117 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -37,6 +37,7 @@ #include "projectexplorersettings.h" #include "projectmacroexpander.h" #include "removetaskhandler.h" +#include "unconfiguredprojectpanel.h" #include "kitmanager.h" #include "kitoptionspage.h" #include "target.h" @@ -429,6 +430,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er addAutoReleasedObject(new DependenciesPanelFactory); addAutoReleasedObject(new ProcessStepFactory); + addAutoReleasedObject(new UnconfiguredProjectPanel); addAutoReleasedObject(new AllProjectsFind); addAutoReleasedObject(new CurrentProjectFind); @@ -1653,7 +1655,7 @@ void ProjectExplorerPlugin::buildStateChanged(Project * pro) { if (debug) { qDebug() << "buildStateChanged"; - qDebug() << pro->document()->filePath() << "isBuilding()" << BuildManager::isBuilding(pro); + qDebug() << pro->projectFilePath() << "isBuilding()" << BuildManager::isBuilding(pro); } Q_UNUSED(pro) updateActions(); diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index 44009c2c53..425920fc17 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -11,12 +11,17 @@ HEADERS += projectexplorer.h \ environmentaspect.h \ environmentaspectwidget.h \ gcctoolchain.h \ + importwidget.h \ localapplicationrunconfiguration.h \ localenvironmentaspect.h \ osparser.h \ projectexplorer_export.h \ + projectimporter.h \ projectwindow.h \ removetaskhandler.h \ + targetsetuppage.h \ + targetsetupwidget.h \ + unconfiguredprojectpanel.h \ kit.h \ kitchooser.h \ kitconfigwidget.h \ @@ -147,11 +152,16 @@ SOURCES += projectexplorer.cpp \ environmentaspect.cpp \ environmentaspectwidget.cpp \ gcctoolchain.cpp \ + importwidget.cpp \ localapplicationrunconfiguration.cpp \ localenvironmentaspect.cpp \ osparser.cpp \ + projectimporter.cpp \ projectwindow.cpp \ removetaskhandler.cpp \ + targetsetuppage.cpp \ + targetsetupwidget.cpp \ + unconfiguredprojectpanel.cpp \ kit.cpp \ kitchooser.cpp \ kitconfigwidget.cpp \ diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 18ff08a8ea..3772f33c08 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -72,6 +72,7 @@ QtcPlugin { "gcctoolchainfactories.h", "gnumakeparser.cpp", "gnumakeparser.h", "headerpath.h", + "importwidget.cpp", "importwidget.h", "ioutputparser.cpp", "ioutputparser.h", "iprojectmanager.h", "iprojectproperties.h", @@ -108,6 +109,7 @@ QtcPlugin { "projectexplorersettings.h", "projectexplorersettingspage.cpp", "projectexplorersettingspage.h", "projectexplorersettingspage.ui", "projectfilewizardextension.cpp", "projectfilewizardextension.h", + "projectimporter.cpp", "projectimporter.h", "projectmacroexpander.cpp", "projectmacroexpander.h", "projectmodels.cpp", "projectmodels.h", "projectnodes.cpp", "projectnodes.h", @@ -126,8 +128,9 @@ QtcPlugin { "target.cpp", "target.h", "targetselector.cpp", "targetselector.h", "targetsettingspanel.cpp", "targetsettingspanel.h", - "targetsettingswidget.cpp", "targetsettingswidget.h", - "targetsettingswidget.ui", + "targetsettingswidget.cpp", "targetsettingswidget.h", "targetsettingswidget.ui", + "targetsetuppage.cpp", "targetsetuppage.h", + "targetsetupwidget.cpp", "targetsetupwidget.h", "task.cpp", "task.h", "taskhub.cpp", "taskhub.h", "taskmodel.cpp", "taskmodel.h", @@ -136,6 +139,7 @@ QtcPlugin { "toolchainconfigwidget.cpp", "toolchainconfigwidget.h", "toolchainmanager.cpp", "toolchainmanager.h", "toolchainoptionspage.cpp", "toolchainoptionspage.h", + "unconfiguredprojectpanel.cpp", "unconfiguredprojectpanel.h", "vcsannotatetaskhandler.cpp", "vcsannotatetaskhandler.h", ] } diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 4275912b14..0acabbf38e 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -246,6 +246,9 @@ const char VAR_CURRENTKIT_ID[] = "CurrentKit:Id"; const char VAR_CURRENTBUILD_NAME[] = "CurrentBuild:Name"; const char VAR_CURRENTBUILD_TYPE[] = "CurrentBuild:Type"; +// Unconfigured Panel +const char UNCONFIGURED_PANEL_PAGE_ID[] = "UnconfiguredPanel"; + } // namespace Constants // Run modes diff --git a/src/plugins/projectexplorer/projectimporter.cpp b/src/plugins/projectexplorer/projectimporter.cpp new file mode 100644 index 0000000000..6c8378dc06 --- /dev/null +++ b/src/plugins/projectexplorer/projectimporter.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "projectimporter.h" + +#include "kit.h" +#include "kitmanager.h" +#include "project.h" + +#include <coreplugin/idocument.h> + +#include <utils/qtcassert.h> + +namespace ProjectExplorer { + +static const Core::Id KIT_IS_TEMPORARY("PE.TempKit"); +static const Core::Id KIT_TEMPORARY_NAME("PE.TempName"); +static const Core::Id KIT_FINAL_NAME("PE.FinalName"); +static const Core::Id TEMPORARY_OF_PROJECTS("PE.TempProject"); + +ProjectImporter::ProjectImporter(const QString &path) : m_projectPath(path), m_isUpdating(false) +{ } + +ProjectImporter::~ProjectImporter() +{ + foreach (Kit *k, KitManager::kits()) + removeProject(k, m_projectPath); +} + +void ProjectImporter::markTemporary(Kit *k) +{ + QTC_ASSERT(!k->hasValue(KIT_IS_TEMPORARY), return); + + setIsUpdating(true); + + const QString name = k->displayName(); + k->setDisplayName(QCoreApplication::translate("ProjectExplorer::ProjectImporter", + "%1 - temporary").arg(name)); + + k->setValue(KIT_TEMPORARY_NAME, k->displayName()); + k->setValue(KIT_FINAL_NAME, name); + k->setValue(KIT_IS_TEMPORARY, true); + + setIsUpdating(false); +} + +void ProjectImporter::makePermanent(Kit *k) +{ + if (!k->hasValue(KIT_IS_TEMPORARY)) + return; + + setIsUpdating(true); + + k->removeKey(KIT_IS_TEMPORARY); + k->removeKey(TEMPORARY_OF_PROJECTS); + const QString tempName = k->value(KIT_TEMPORARY_NAME).toString(); + if (!tempName.isNull() && k->displayName() == tempName) + k->setDisplayName(k->value(KIT_FINAL_NAME).toString()); + k->removeKey(KIT_TEMPORARY_NAME); + k->removeKey(KIT_FINAL_NAME); + + setIsUpdating(false); +} + +void ProjectImporter::cleanupKit(Kit *k) +{ + Q_UNUSED(k); +} + +void ProjectImporter::addProject(Kit *k) +{ + if (!k->hasValue(KIT_IS_TEMPORARY)) + return; + + QStringList projects = k->value(TEMPORARY_OF_PROJECTS, QStringList()).toStringList(); + + projects.append(m_projectPath); // note: There can be more than one instance of the project added! + + setIsUpdating(true); + + k->setValue(TEMPORARY_OF_PROJECTS, projects); + + setIsUpdating(false); +} + +void ProjectImporter::removeProject(Kit *k, const QString &path) +{ + if (!k->hasValue(KIT_IS_TEMPORARY)) + return; + + QStringList projects = k->value(TEMPORARY_OF_PROJECTS, QStringList()).toStringList(); + projects.removeOne(path); + + setIsUpdating(true); + + if (projects.isEmpty()) + ProjectExplorer::KitManager::deregisterKit(k); + else + k->setValue(TEMPORARY_OF_PROJECTS, projects); + + setIsUpdating(false); +} + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectimporter.h b/src/plugins/projectexplorer/projectimporter.h new file mode 100644 index 0000000000..1bd5243dc1 --- /dev/null +++ b/src/plugins/projectexplorer/projectimporter.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef PROJECTIMPORTER_H +#define PROJECTIMPORTER_H + +#include "projectexplorer_export.h" + +#include <utils/fileutils.h> + +namespace ProjectExplorer { + +class BuildInfo; +class Kit; +class Project; +class Target; + +// Documentation inside. +class PROJECTEXPLORER_EXPORT ProjectImporter +{ +public: + ProjectImporter(const QString &path); + virtual ~ProjectImporter(); + + const QString projectFilePath() const { return m_projectPath; } + + virtual QList<BuildInfo *> import(const Utils::FileName &importPath, bool silent = false) = 0; + virtual QStringList importCandidates(const Utils::FileName &projectFilePath) = 0; + virtual Target *preferredTarget(const QList<Target *> &possibleTargets) = 0; + + bool isUpdating() const { return m_isUpdating; } + + virtual void markTemporary(Kit *k); + virtual void makePermanent(Kit *k); + + // Additional cleanup that has to happen when kits are removed + virtual void cleanupKit(Kit *k); + + void addProject(Kit *k); + void removeProject(Kit *k, const QString &path); + +protected: + void setIsUpdating(bool b) { m_isUpdating = b; } + +private: + const QString m_projectPath; + bool m_isUpdating; +}; + +} // namespace ProjectExplorer + +#endif // PROJECTIMPORTER_H diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index 58149141fe..b867943518 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -528,7 +528,7 @@ void Target::updateDefaultBuildConfigurations() qWarning("No build configuration factory found for target id '%s'.", qPrintable(id().toString())); return; } - QList<BuildInfo *> infoList = bcFactory->availableBuilds(this); + QList<BuildInfo *> infoList = bcFactory->availableSetups(this->kit(), project()->projectFilePath()); foreach (BuildInfo *info, infoList) { BuildConfiguration *bc = bcFactory->create(this, info); if (!bc) diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp new file mode 100644 index 0000000000..ddbf1911e0 --- /dev/null +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -0,0 +1,531 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "targetsetuppage.h" +#include "buildconfiguration.h" +#include "buildinfo.h" +#include "kit.h" +#include "kitmanager.h" +#include "importwidget.h" +#include "project.h" +#include "projectexplorerconstants.h" +#include "target.h" +#include "targetsetupwidget.h" + +#include <coreplugin/icore.h> +#include <utils/qtcassert.h> +#include <utils/qtcprocess.h> + +#include <QFileInfo> +#include <QLabel> +#include <QMessageBox> +#include <QScrollArea> +#include <QVBoxLayout> + +namespace ProjectExplorer { +namespace Internal { + +class TargetSetupPageUi +{ +public: + QWidget *centralWidget; + QWidget *scrollAreaWidget; + QScrollArea *scrollArea; + QLabel *headerLabel; + QLabel *descriptionLabel; + QLabel *noValidKitLabel; + QLabel *optionHintLabel; + + void setupUi(QWidget *q) + { + QWidget *setupTargetPage = new QWidget(q); + descriptionLabel = new QLabel(setupTargetPage); + descriptionLabel->setWordWrap(true); + descriptionLabel->setVisible(false); + + headerLabel = new QLabel(setupTargetPage); + headerLabel->setWordWrap(true); + headerLabel->setVisible(false); + + noValidKitLabel = new QLabel(setupTargetPage); + noValidKitLabel->setWordWrap(true); + noValidKitLabel->setText(TargetSetupPage::tr("<span style=\" font-weight:600;\">No valid kits found.</span>")); + + + optionHintLabel = new QLabel(setupTargetPage); + optionHintLabel->setWordWrap(true); + optionHintLabel->setText(TargetSetupPage::tr( + "Please add a kit in the <a href=\"buildandrun\">options</a> " + "or via the maintenance tool of the SDK.")); + optionHintLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + optionHintLabel->setVisible(false); + + centralWidget = new QWidget(setupTargetPage); + QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Fixed); + policy.setHorizontalStretch(0); + policy.setVerticalStretch(0); + policy.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth()); + centralWidget->setSizePolicy(policy); + + scrollAreaWidget = new QWidget(setupTargetPage); + scrollArea = new QScrollArea(scrollAreaWidget); + scrollArea->setWidgetResizable(true); + + QWidget *scrollAreaWidgetContents; + scrollAreaWidgetContents = new QWidget(); + scrollAreaWidgetContents->setGeometry(QRect(0, 0, 230, 81)); + scrollArea->setWidget(scrollAreaWidgetContents); + + QVBoxLayout *verticalLayout = new QVBoxLayout(scrollAreaWidget); + verticalLayout->setSpacing(0); + verticalLayout->setContentsMargins(0, 0, 0, 0); + verticalLayout->addWidget(scrollArea); + + QVBoxLayout *verticalLayout_2 = new QVBoxLayout(setupTargetPage); + verticalLayout_2->addWidget(headerLabel); + verticalLayout_2->addWidget(noValidKitLabel); + verticalLayout_2->addWidget(descriptionLabel); + verticalLayout_2->addWidget(optionHintLabel); + verticalLayout_2->addWidget(centralWidget); + verticalLayout_2->addWidget(scrollAreaWidget); + + QVBoxLayout *verticalLayout_3 = new QVBoxLayout(q); + verticalLayout_3->setContentsMargins(0, 0, 0, -1); + verticalLayout_3->addWidget(setupTargetPage); + + QObject::connect(optionHintLabel, SIGNAL(linkActivated(QString)), + q, SLOT(openOptions())); + } +}; + +} // namespace Internal + +using namespace Internal; + +TargetSetupPage::TargetSetupPage(QWidget *parent) : + QWizardPage(parent), + m_requiredMatcher(0), + m_preferredMatcher(0), + m_importer(0), + m_baseLayout(0), + m_importSearch(false), + m_firstWidget(0), + m_ui(new TargetSetupPageUi), + m_importWidget(new Internal::ImportWidget(this)), + m_spacer(new QSpacerItem(0,0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding)), + m_forceOptionHint(false) +{ + setObjectName(QLatin1String("TargetSetupPage")); + setWindowTitle(tr("Select Kits for Your Project")); + m_ui->setupUi(this); + + QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred); + policy.setHorizontalStretch(0); + policy.setVerticalStretch(0); + policy.setHeightForWidth(sizePolicy().hasHeightForWidth()); + setSizePolicy(policy); + + QWidget *centralWidget = new QWidget(this); + m_ui->scrollArea->setWidget(centralWidget); + centralWidget->setLayout(new QVBoxLayout); + m_ui->centralWidget->setLayout(new QVBoxLayout); + m_ui->centralWidget->layout()->setMargin(0); + + setUseScrollArea(true); + setImportSearch(false); + + setTitle(tr("Kit Selection")); + + QObject *km = KitManager::instance(); + connect(km, SIGNAL(kitAdded(ProjectExplorer::Kit*)), + this, SLOT(handleKitAddition(ProjectExplorer::Kit*))); + connect(km, SIGNAL(kitRemoved(ProjectExplorer::Kit*)), + this, SLOT(handleKitRemoval(ProjectExplorer::Kit*))); + connect(km, SIGNAL(kitUpdated(ProjectExplorer::Kit*)), + this, SLOT(handleKitUpdate(ProjectExplorer::Kit*))); + connect(m_importWidget, SIGNAL(importFrom(Utils::FileName)), + this, SLOT(import(Utils::FileName))); +} + +void TargetSetupPage::initializePage() +{ + reset(); + + setupWidgets(); + setupImports(); + selectAtLeastOneKit(); +} + +void TargetSetupPage::setRequiredKitMatcher(KitMatcher *matcher) +{ + m_requiredMatcher = matcher; +} + +QList<Core::Id> TargetSetupPage::selectedKits() const +{ + QList<Core::Id> result; + QMap<Core::Id, Internal::TargetSetupWidget *>::const_iterator it, end; + it = m_widgets.constBegin(); + end = m_widgets.constEnd(); + + for ( ; it != end; ++it) { + if (isKitSelected(it.key())) + result << it.key(); + } + return result; +} + +void TargetSetupPage::setPreferredKitMatcher(KitMatcher *matcher) +{ + m_preferredMatcher = matcher; +} + +TargetSetupPage::~TargetSetupPage() +{ + reset(); + delete m_ui; + delete m_preferredMatcher; + delete m_requiredMatcher; + delete m_importer; +} + +bool TargetSetupPage::isKitSelected(Core::Id id) const +{ + TargetSetupWidget *widget = m_widgets.value(id); + return widget && widget->isKitSelected(); +} + +void TargetSetupPage::setKitSelected(Core::Id id, bool selected) +{ + TargetSetupWidget *widget = m_widgets.value(id); + if (widget) + widget->setKitSelected(selected); +} + +bool TargetSetupPage::isComplete() const +{ + foreach (TargetSetupWidget *widget, m_widgets.values()) + if (widget->isKitSelected()) + return true; + return false; +} + +void TargetSetupPage::setImportSearch(bool b) +{ + m_importSearch = b; + m_importWidget->setVisible(b); +} + +void TargetSetupPage::setupWidgets() +{ + QList<Kit *> kitList; + // Known profiles: + if (m_requiredMatcher) + kitList = KitManager::matchingKits(*m_requiredMatcher); + else + kitList = KitManager::kits(); + + foreach (Kit *k, kitList) + addWidget(k); + + // Setup import widget: + m_baseLayout->addWidget(m_importWidget); + Utils::FileName path = Utils::FileName::fromString(m_projectPath); + path = path.parentDir(); // base dir + path = path.parentDir(); // parent dir + m_importWidget->setCurrentDirectory(path); + + updateVisibility(); +} + +void TargetSetupPage::reset() +{ + foreach (TargetSetupWidget *widget, m_widgets.values()) { + Kit *k = widget->kit(); + if (!k) + continue; + if (m_importer) + m_importer->removeProject(k, m_projectPath); + delete widget; + } + + m_widgets.clear(); + m_firstWidget = 0; +} + +void TargetSetupPage::setProjectPath(const QString &path) +{ + m_projectPath = path; + if (!m_projectPath.isEmpty()) + m_ui->headerLabel->setText(tr("Qt Creator can use the following kits for project <b>%1</b>:", + "%1: Project name").arg(QFileInfo(m_projectPath).baseName())); + m_ui->headerLabel->setVisible(!m_projectPath.isEmpty()); + + if (m_widgets.isEmpty()) + return; + + reset(); + setupWidgets(); +} + +void TargetSetupPage::setProjectImporter(ProjectImporter *importer) +{ + if (m_importer) + delete m_importer; + m_importer = importer; + + reset(); + setupWidgets(); +} + +void TargetSetupPage::setNoteText(const QString &text) +{ + m_ui->descriptionLabel->setText(text); + m_ui->descriptionLabel->setVisible(!text.isEmpty()); +} + +void TargetSetupPage::showOptionsHint(bool show) +{ + m_forceOptionHint = show; + updateVisibility(); +} + +void TargetSetupPage::setupImports() +{ + if (!m_importer || !m_importSearch || m_projectPath.isEmpty()) + return; + + QStringList toImport = m_importer->importCandidates(Utils::FileName::fromString(m_projectPath)); + foreach (const QString &path, toImport) + import(Utils::FileName::fromString(path), true); +} + +void TargetSetupPage::handleKitAddition(Kit *k) +{ + if (isUpdating()) + return; + + Q_ASSERT(!m_widgets.contains(k->id())); + addWidget(k); + updateVisibility(); +} + +void TargetSetupPage::handleKitRemoval(Kit *k) +{ + if (m_importer) + m_importer->cleanupKit(k); + + if (isUpdating()) + return; + + removeWidget(k); + updateVisibility(); +} + +void TargetSetupPage::handleKitUpdate(Kit *k) +{ + if (isUpdating()) + return; + + if (m_importer) + m_importer->makePermanent(k); + + TargetSetupWidget *widget = m_widgets.value(k->id()); + + bool acceptable = true; + if (m_requiredMatcher && !m_requiredMatcher->matches(k)) + acceptable = false; + + if (widget && !acceptable) + removeWidget(k); + else if (!widget && acceptable) + addWidget(k); + + updateVisibility(); +} + +void TargetSetupPage::selectAtLeastOneKit() +{ + bool atLeastOneKitSelected = false; + foreach (TargetSetupWidget *w, m_widgets.values()) { + if (w->isKitSelected()) { + atLeastOneKitSelected = true; + break; + } + } + + if (!atLeastOneKitSelected) { + TargetSetupWidget *widget = m_firstWidget; + Kit *defaultKit = KitManager::defaultKit(); + if (defaultKit) + widget = m_widgets.value(defaultKit->id(), m_firstWidget); + if (widget) + widget->setKitSelected(true); + m_firstWidget = 0; + } + emit completeChanged(); // Is this necessary? +} + +void TargetSetupPage::updateVisibility() +{ + // Always show the widgets, the import widget always makes sense to show. + m_ui->scrollAreaWidget->setVisible(m_baseLayout == m_ui->scrollArea->widget()->layout()); + m_ui->centralWidget->setVisible(m_baseLayout == m_ui->centralWidget->layout()); + + bool hasKits = !m_widgets.isEmpty(); + m_ui->noValidKitLabel->setVisible(!hasKits); + m_ui->optionHintLabel->setVisible(m_forceOptionHint || !hasKits); + + emit completeChanged(); +} + +void TargetSetupPage::openOptions() +{ + Core::ICore::instance()->showOptionsDialog(Constants::PROJECTEXPLORER_SETTINGS_CATEGORY, + Constants::KITS_SETTINGS_PAGE_ID, + this); +} + +void TargetSetupPage::import(const Utils::FileName &path) +{ + import(path, false); +} + +bool TargetSetupPage::isUpdating() const +{ + if (m_importer) + return m_importer->isUpdating(); + return false; +} + +void TargetSetupPage::import(const Utils::FileName &path, bool silent) +{ + if (!m_importer) + return; + + QList<BuildInfo *> toImport = m_importer->import(path, silent); + foreach (BuildInfo *info, toImport) { + TargetSetupWidget *widget = m_widgets.value(info->kitId, 0); + if (!widget) { + Kit *k = KitManager::find(info->kitId); + Q_ASSERT(k); + addWidget(k); + } + widget = m_widgets.value(info->kitId, 0); + if (!widget) { + delete info; + continue; + } + + widget->addBuildInfo(info, true); + widget->setKitSelected(true); + } +} + +void TargetSetupPage::removeWidget(Kit *k) +{ + TargetSetupWidget *widget = m_widgets.value(k->id()); + if (!widget) + return; + if (widget == m_firstWidget) + m_firstWidget = 0; + widget->deleteLater(); + m_widgets.remove(k->id()); +} + +TargetSetupWidget *TargetSetupPage::addWidget(Kit *k) +{ + if (!k || (m_requiredMatcher && !m_requiredMatcher->matches(k))) + return 0; + + IBuildConfigurationFactory *factory + = IBuildConfigurationFactory::find(k, m_projectPath); + if (!factory) + return 0; + + QList<BuildInfo *> infoList = factory->availableSetups(k, m_projectPath); + TargetSetupWidget *widget = infoList.isEmpty() ? 0 : new TargetSetupWidget(k, m_projectPath, infoList); + if (!widget) + return 0; + + m_baseLayout->removeWidget(m_importWidget); + m_baseLayout->removeItem(m_spacer); + + widget->setKitSelected(m_preferredMatcher && m_preferredMatcher->matches(k)); + m_widgets.insert(k->id(), widget); + m_baseLayout->addWidget(widget); + + m_baseLayout->addWidget(m_importWidget); + m_baseLayout->addItem(m_spacer); + + connect(widget, SIGNAL(selectedToggled()), + this, SIGNAL(completeChanged())); + + if (!m_firstWidget) + m_firstWidget = widget; + + return widget; +} + +bool TargetSetupPage::setupProject(Project *project) +{ + QList<const BuildInfo *> toSetUp; // Pointers are managed by the widgets! + foreach (TargetSetupWidget *widget, m_widgets.values()) { + if (!widget->isKitSelected()) + continue; + + Kit *k = widget->kit(); + if (m_importer) + m_importer->makePermanent(k); + toSetUp << widget->selectedBuildInfoList(); + widget->clearKit(); + } + + project->setup(toSetUp); + + reset(); // This will delete the pointers held in toSetUp! + toSetUp.clear(); + + Target *activeTarget = 0; + if (m_importer) + activeTarget = m_importer->preferredTarget(project->targets()); + if (activeTarget) + project->setActiveTarget(activeTarget); + + return true; +} + +void TargetSetupPage::setUseScrollArea(bool b) +{ + m_baseLayout = b ? m_ui->scrollArea->widget()->layout() : m_ui->centralWidget->layout(); + m_ui->scrollAreaWidget->setVisible(b); + m_ui->centralWidget->setVisible(!b); +} + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/targetsetuppage.h b/src/plugins/projectexplorer/targetsetuppage.h new file mode 100644 index 0000000000..7018b5a7b0 --- /dev/null +++ b/src/plugins/projectexplorer/targetsetuppage.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef TARGETSETUPPAGE_H +#define TARGETSETUPPAGE_H + +#include "projectexplorer_export.h" + +#include "projectimporter.h" + +#include <QString> +#include <QWizardPage> +#include <QMap> + +QT_FORWARD_DECLARE_CLASS(QSpacerItem) + +namespace Core { class Id; } +namespace Utils { class FileName; } + +namespace ProjectExplorer { +class Kit; +class KitMatcher; +class Project; + +namespace Internal { +class ImportWidget; +class TargetSetupPageUi; +class TargetSetupWidget; +} // namespace Internal + +/// \internal +class PROJECTEXPLORER_EXPORT TargetSetupPage : public QWizardPage +{ + Q_OBJECT + +public: + explicit TargetSetupPage(QWidget *parent = 0); + ~TargetSetupPage(); + + /// Initializes the TargetSetupPage + /// \note The import information is gathered in initializePage(), make sure that the right projectPath is set before + void initializePage(); + + // Call these before initializePage! + void setRequiredKitMatcher(KitMatcher *matcher); + void setPreferredKitMatcher(KitMatcher *matcher); + void setImportSearch(bool b); + + /// Sets whether the targetsetupage uses a scrollarea + /// to host the widgets from the factories + /// call this before \sa initializePage() + void setUseScrollArea(bool b); + + bool isComplete() const; + bool setupProject(Project *project); + bool isKitSelected(Core::Id id) const; + void setKitSelected(Core::Id id, bool selected); + QList<Core::Id> selectedKits() const; + void setProjectPath(const QString &dir); + void setProjectImporter(ProjectImporter *importer); + + /// Overrides the summary text of the targetsetuppage + void setNoteText(const QString &text); + void showOptionsHint(bool show); + +private slots: + void handleKitAddition(ProjectExplorer::Kit *k); + void handleKitRemoval(ProjectExplorer::Kit *k); + void handleKitUpdate(ProjectExplorer::Kit *k); + void updateVisibility(); + void openOptions(); + void import(const Utils::FileName &path); + +private: + bool isUpdating() const; + void selectAtLeastOneKit(); + void removeWidget(Kit *k); + Internal::TargetSetupWidget *addWidget(Kit *k); + + void setupImports(); + void import(const Utils::FileName &path, bool silent); + + void setupWidgets(); + void reset(); + + KitMatcher *m_requiredMatcher; + KitMatcher *m_preferredMatcher; + ProjectImporter *m_importer; + QLayout *m_baseLayout; + bool m_importSearch; + QString m_projectPath; + QString m_defaultShadowBuildLocation; + QMap<Core::Id, Internal::TargetSetupWidget *> m_widgets; + Internal::TargetSetupWidget *m_firstWidget; + + Internal::TargetSetupPageUi *m_ui; + + Internal::ImportWidget *m_importWidget; + QSpacerItem *m_spacer; + + bool m_forceOptionHint; +}; + +} // namespace ProjectExplorer + +#endif // TARGETSETUPPAGE_H diff --git a/src/plugins/projectexplorer/targetsetupwidget.cpp b/src/plugins/projectexplorer/targetsetupwidget.cpp new file mode 100644 index 0000000000..8cd7ea6750 --- /dev/null +++ b/src/plugins/projectexplorer/targetsetupwidget.cpp @@ -0,0 +1,366 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "targetsetupwidget.h" + +#include "buildconfiguration.h" +#include "buildinfo.h" +#include "projectexplorerconstants.h" +#include "kit.h" +#include "kitmanager.h" +#include "kitoptionspage.h" + +#include <coreplugin/icore.h> +#include <extensionsystem/pluginmanager.h> +#include <utils/detailsbutton.h> +#include <utils/detailswidget.h> +#include <utils/hostosinfo.h> +#include <utils/pathchooser.h> + +#include <QCheckBox> +#include <QHBoxLayout> +#include <QGridLayout> +#include <QLabel> +#include <QPushButton> + +namespace ProjectExplorer { +namespace Internal { + +// ------------------------------------------------------------------------- +// TargetSetupWidget +// ------------------------------------------------------------------------- + +TargetSetupWidget::TargetSetupWidget(Kit *k, + const QString &projectPath, + const QList<BuildInfo *> &infoList) : + m_kit(k), + m_haveImported(false), + m_ignoreChange(false), + m_selected(0) +{ + Q_ASSERT(m_kit); + + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + QVBoxLayout *vboxLayout = new QVBoxLayout(); + setLayout(vboxLayout); + vboxLayout->setContentsMargins(0, 0, 0, 0); + m_detailsWidget = new Utils::DetailsWidget(this); + m_detailsWidget->setUseCheckBox(true); + m_detailsWidget->setChecked(false); + m_detailsWidget->setSummaryFontBold(true); + m_detailsWidget->setToolTip(m_kit->toHtml()); + vboxLayout->addWidget(m_detailsWidget); + + Utils::FadingWidget *panel = new Utils::FadingWidget(m_detailsWidget); + QHBoxLayout *panelLayout = new QHBoxLayout(panel); + m_manageButton = new QPushButton(tr("Manage...")); + panelLayout->addWidget(m_manageButton); + m_detailsWidget->setToolWidget(panel); + + handleKitUpdate(m_kit); + + QWidget *widget = new QWidget; + QVBoxLayout *layout = new QVBoxLayout; + widget->setLayout(layout); + layout->setContentsMargins(0, 0, 0, 0); + + QWidget *w = new QWidget; + m_newBuildsLayout = new QGridLayout; + m_newBuildsLayout->setMargin(0); + if (Utils::HostOsInfo::isMacHost()) + m_newBuildsLayout->setSpacing(0); + w->setLayout(m_newBuildsLayout); + layout->addWidget(w); + + widget->setEnabled(false); + m_detailsWidget->setWidget(widget); + + foreach (BuildInfo *info, infoList) + addBuildInfo(info, false); + + setProjectPath(projectPath); + + connect(m_detailsWidget, SIGNAL(checked(bool)), + this, SLOT(targetCheckBoxToggled(bool))); + + connect(KitManager::instance(), SIGNAL(kitUpdated(ProjectExplorer::Kit*)), + this, SLOT(handleKitUpdate(ProjectExplorer::Kit*))); + + connect(m_manageButton, SIGNAL(clicked()), this, SLOT(manageKit())); +} + +TargetSetupWidget::~TargetSetupWidget() +{ + qDeleteAll(m_infoList); + m_infoList.clear(); +} + +Kit *TargetSetupWidget::kit() +{ + return m_kit; +} + +void TargetSetupWidget::clearKit() +{ + m_kit = 0; +} + +bool TargetSetupWidget::isKitSelected() const +{ + if (!m_detailsWidget->isChecked()) + return false; + + return !selectedBuildInfoList().isEmpty(); +} + +void TargetSetupWidget::setKitSelected(bool b) +{ + // Only check target if there are build configurations possible + b &= !selectedBuildInfoList().isEmpty(); + m_ignoreChange = true; + m_detailsWidget->setChecked(b); + m_detailsWidget->widget()->setEnabled(b); + m_ignoreChange = false; + + m_detailsWidget->setState(b ? Utils::DetailsWidget::Expanded : Utils::DetailsWidget::Collapsed); +} + +void TargetSetupWidget::addBuildInfo(BuildInfo *info, bool isImport) +{ + if (isImport && !m_haveImported) { + // disable everything on first import + for (int i = 0; i < m_enabled.count(); ++i) { + m_enabled[i] = false; + m_checkboxes[i]->setChecked(false); + } + m_selected = 0; + + m_haveImported = true; + } + + int pos = m_pathChoosers.count(); + m_enabled.append(true); + ++m_selected; + + m_infoList << info; + + QCheckBox *checkbox = new QCheckBox; + checkbox->setText(info->displayName); + checkbox->setChecked(m_enabled.at(pos)); + checkbox->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_newBuildsLayout->addWidget(checkbox, pos * 2, 0); + + Utils::PathChooser *pathChooser = new Utils::PathChooser(); + pathChooser->setExpectedKind(Utils::PathChooser::Directory); + pathChooser->setFileName(info->buildDirectory); + pathChooser->setEnabled(info->supportsShadowBuild); + pathChooser->setReadOnly(!info->supportsShadowBuild || isImport); + m_newBuildsLayout->addWidget(pathChooser, pos * 2, 1); + + QLabel *reportIssuesLabel = new QLabel; + reportIssuesLabel->setIndent(32); + m_newBuildsLayout->addWidget(reportIssuesLabel, pos * 2 + 1, 0, 1, 2); + reportIssuesLabel->setVisible(false); + + connect(checkbox, SIGNAL(toggled(bool)), + this, SLOT(checkBoxToggled(bool))); + + connect(pathChooser, SIGNAL(changed(QString)), + this, SLOT(pathChanged())); + + m_checkboxes.append(checkbox); + m_pathChoosers.append(pathChooser); + m_reportIssuesLabels.append(reportIssuesLabel); + + m_issues.append(false); + reportIssues(pos); + + emit selectedToggled(); +} + +void TargetSetupWidget::targetCheckBoxToggled(bool b) +{ + if (m_ignoreChange) + return; + m_detailsWidget->widget()->setEnabled(b); + if (b) { + foreach (bool error, m_issues) { + if (error) { + m_detailsWidget->setState(Utils::DetailsWidget::Expanded); + break; + } + } + } + emit selectedToggled(); +} + +void TargetSetupWidget::manageKit() +{ + ProjectExplorer::KitOptionsPage *page = + ExtensionSystem::PluginManager::getObject<ProjectExplorer::KitOptionsPage>(); + if (!page || !m_kit) + return; + + page->showKit(m_kit); + Core::ICore::showOptionsDialog(Constants::PROJECTEXPLORER_SETTINGS_CATEGORY, + Constants::KITS_SETTINGS_PAGE_ID); +} + +void TargetSetupWidget::setProjectPath(const QString &projectPath) +{ + if (!m_kit) + return; + + m_projectPath = projectPath; + clear(); + + IBuildConfigurationFactory *factory + = IBuildConfigurationFactory::find(m_kit, projectPath); + + if (!factory) + return; + + QList<BuildInfo *> infoList + = factory->availableSetups(m_kit, projectPath); + foreach (BuildInfo *info, infoList) + addBuildInfo(info, false); +} + +void TargetSetupWidget::handleKitUpdate(Kit *k) +{ + if (k != m_kit) + return; + + m_detailsWidget->setIcon(k->icon()); + m_detailsWidget->setSummaryText(k->displayName()); +} + +QList<const BuildInfo *> TargetSetupWidget::selectedBuildInfoList() const +{ + QList<const BuildInfo *> result; + for (int i = 0; i < m_infoList.count(); ++i) { + if (m_enabled.at(i)) + result.append(m_infoList.at(i)); + } + return result; +} + +void TargetSetupWidget::clear() +{ + qDeleteAll(m_checkboxes); + m_checkboxes.clear(); + qDeleteAll(m_pathChoosers); + m_pathChoosers.clear(); + qDeleteAll(m_reportIssuesLabels); + m_reportIssuesLabels.clear(); + qDeleteAll(m_infoList); + m_infoList.clear(); + + m_issues.clear(); + m_enabled.clear(); + m_selected = 0; + m_haveImported = false; + + emit selectedToggled(); +} + +void TargetSetupWidget::checkBoxToggled(bool b) +{ + QCheckBox *box = qobject_cast<QCheckBox *>(sender()); + if (!box) + return; + int index = m_checkboxes.indexOf(box); + if (index == -1) + return; + if (m_enabled[index] == b) + return; + m_selected += b ? 1 : -1; + m_enabled[index] = b; + if ((m_selected == 0 && !b) || (m_selected == 1 && b)) { + emit selectedToggled(); + m_detailsWidget->setChecked(b); + } +} + +void TargetSetupWidget::pathChanged() +{ + if (m_ignoreChange) + return; + Utils::PathChooser *pathChooser = qobject_cast<Utils::PathChooser *>(sender()); + if (!pathChooser) + return; + int index = m_pathChoosers.indexOf(pathChooser); + if (index == -1) + return; + m_infoList[index]->buildDirectory = pathChooser->fileName(); + reportIssues(index); +} + +void TargetSetupWidget::reportIssues(int index) +{ + QPair<Task::TaskType, QString> issues = findIssues(m_infoList.at(index)); + QLabel *reportIssuesLabel = m_reportIssuesLabels.at(index); + reportIssuesLabel->setText(issues.second); + bool error = issues.first != Task::Unknown; + reportIssuesLabel->setVisible(error); + m_issues[index] = error; +} + +QPair<Task::TaskType, QString> TargetSetupWidget::findIssues(const BuildInfo *info) +{ + if (m_projectPath.isEmpty()) + return qMakePair(Task::Unknown, QString()); + + QString buildDir = info->buildDirectory.toString(); + QList<Task> issues = info->reportIssues(m_projectPath, buildDir); + + QString text; + Task::TaskType highestType = Task::Unknown; + foreach (const Task &t, issues) { + if (!text.isEmpty()) + text.append(QLatin1String("<br>")); + // set severity: + QString severity; + if (t.type == Task::Error) { + highestType = Task::Error; + severity = tr("<b>Error:</b> ", "Severity is Task::Error"); + } else if (t.type == Task::Warning) { + if (highestType == Task::Unknown) + highestType = Task::Warning; + severity = tr("<b>Warning:</b> ", "Severity is Task::Warning"); + } + text.append(severity + t.description); + } + if (!text.isEmpty()) + text = QLatin1String("<nobr>") + text; + return qMakePair(highestType, text); +} + +} // namespace Internal +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/targetsetupwidget.h b/src/plugins/projectexplorer/targetsetupwidget.h new file mode 100644 index 0000000000..0c67e86167 --- /dev/null +++ b/src/plugins/projectexplorer/targetsetupwidget.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef TARGETSETUPWIDGET_H +#define TARGETSETUPWIDGET_H + +#include "projectexplorer_export.h" + +#include "buildinfo.h" +#include "task.h" + +#include <QWidget> + +QT_BEGIN_NAMESPACE +class QCheckBox; +class QHBoxLayout; +class QGridLayout; +class QLabel; +class QPushButton; +class QSpacerItem; +QT_END_NAMESPACE + +namespace Utils { +class DetailsWidget; +class PathChooser; +} // namespace Utils + +namespace ProjectExplorer { +class BuildInfo; +class Kit; + +namespace Internal { + +class TargetSetupWidget : public QWidget +{ + Q_OBJECT +public: + TargetSetupWidget(Kit *k, + const QString &projectPath, + const QList<BuildInfo *> &infoList); + ~TargetSetupWidget(); + + Kit *kit(); + void clearKit(); + + bool isKitSelected() const; + void setKitSelected(bool b); + + void addBuildInfo(BuildInfo *info, bool isImport); + + QList<const BuildInfo *> selectedBuildInfoList() const; + void setProjectPath(const QString &projectPath); + +signals: + void selectedToggled() const; + +private slots: + void handleKitUpdate(ProjectExplorer::Kit *k); + + void checkBoxToggled(bool b); + void pathChanged(); + void targetCheckBoxToggled(bool b); + void manageKit(); + +private: + void reportIssues(int index); + QPair<Task::TaskType, QString> findIssues(const BuildInfo *info); + void clear(); + + Kit *m_kit; + QString m_projectPath; + bool m_haveImported; + Utils::DetailsWidget *m_detailsWidget; + QPushButton *m_manageButton; + QGridLayout *m_newBuildsLayout; + QList<QCheckBox *> m_checkboxes; + QList<Utils::PathChooser *> m_pathChoosers; + QList<BuildInfo *> m_infoList; + QList<bool> m_enabled; + QList<QLabel *> m_reportIssuesLabels; + QList<bool> m_issues; + bool m_ignoreChange; + int m_selected; // Number of selected buildconfiguartions +}; + +} // namespace Internal +} // namespace ProjectExplorer + +#endif // TARGETSETUPWIDGET_H diff --git a/src/plugins/projectexplorer/unconfiguredprojectpanel.cpp b/src/plugins/projectexplorer/unconfiguredprojectpanel.cpp new file mode 100644 index 0000000000..0e38fa6f29 --- /dev/null +++ b/src/plugins/projectexplorer/unconfiguredprojectpanel.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "unconfiguredprojectpanel.h" + +#include "kit.h" +#include "kitmanager.h" +#include "project.h" +#include "projectexplorer.h" +#include "projectexplorerconstants.h" +#include "session.h" +#include "targetsetuppage.h" + +#include <coreplugin/icore.h> +#include <coreplugin/modemanager.h> +#include <coreplugin/coreconstants.h> + +#include <QVBoxLayout> +#include <QPushButton> +#include <QDialogButtonBox> + +namespace ProjectExplorer { +namespace Internal { + +UnconfiguredProjectPanel::UnconfiguredProjectPanel() +{ +} + +QString UnconfiguredProjectPanel::id() const +{ + return QLatin1String(Constants::UNCONFIGURED_PANEL_PAGE_ID); +} + +QString UnconfiguredProjectPanel::displayName() const +{ + return tr("Configure Project"); +} + +int UnconfiguredProjectPanel::priority() const +{ + return -10; +} + +bool UnconfiguredProjectPanel::supports(Project *project) +{ + return project->targets().isEmpty() && project->supportsNoTargetPanel(); +} + +PropertiesPanel *UnconfiguredProjectPanel::createPanel(Project *project) +{ + PropertiesPanel *panel = new PropertiesPanel; + panel->setDisplayName(displayName()); + panel->setIcon(QIcon(QLatin1String(":/projectexplorer/images/unconfigured.png"))); + + TargetSetupPageWrapper *w = new TargetSetupPageWrapper(project); + panel->setWidget(w); + return panel; +} + +///////// +/// TargetSetupPageWrapper +//////// + +TargetSetupPageWrapper::TargetSetupPageWrapper(Project *project) : + QWidget(), m_project(project) +{ + QVBoxLayout *layout = new QVBoxLayout(); + layout->setMargin(0); + setLayout(layout); + + m_targetSetupPage = new TargetSetupPage(this); + m_targetSetupPage->setProjectImporter(project->createProjectImporter()); + m_targetSetupPage->setUseScrollArea(false); + m_targetSetupPage->setImportSearch(true); + m_targetSetupPage->setProjectPath(project->projectFilePath()); + m_targetSetupPage->initializePage(); + m_targetSetupPage->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + m_targetSetupPage->setRequiredKitMatcher(project->createRequiredKitMatcher()); + m_targetSetupPage->setPreferredKitMatcher(project->createPreferredKitMatcher()); + updateNoteText(); + + layout->addWidget(m_targetSetupPage); + + // Apply row + QHBoxLayout *hbox = new QHBoxLayout(); + layout->addLayout(hbox); + layout->setMargin(0); + hbox->addStretch(); + + QDialogButtonBox *box = new QDialogButtonBox(this); + + m_configureButton = new QPushButton(this); + m_configureButton->setText(tr("Configure Project")); + box->addButton(m_configureButton, QDialogButtonBox::AcceptRole); + + m_cancelButton = new QPushButton(this); + m_cancelButton->setText(tr("Cancel")); + box->addButton(m_cancelButton, QDialogButtonBox::RejectRole); + + hbox->addWidget(box); + + layout->addStretch(10); + + completeChanged(); + + connect(m_configureButton, SIGNAL(clicked()), + this, SLOT(done())); + connect(m_cancelButton, SIGNAL(clicked()), + this, SLOT(cancel())); + connect(m_targetSetupPage, SIGNAL(completeChanged()), + this, SLOT(completeChanged())); + connect(KitManager::instance(), SIGNAL(defaultkitChanged()), + this, SLOT(updateNoteText())); + connect(KitManager::instance(), SIGNAL(kitUpdated(ProjectExplorer::Kit*)), + this, SLOT(kitUpdated(ProjectExplorer::Kit*))); +} + +void TargetSetupPageWrapper::kitUpdated(Kit *k) +{ + if (k == KitManager::defaultKit()) + updateNoteText(); +} + +void TargetSetupPageWrapper::updateNoteText() +{ + Kit *k = KitManager::defaultKit(); + + QString text; + bool showHint = false; + if (!k) { + text = tr("The project <b>%1</b> is not yet configured.<br/>" + "Qt Creator cannot parse the project, because no kit " + "has been set up.") + .arg(m_project->displayName()); + showHint = true; + } else if (k->isValid()) { + text = tr("The project <b>%1</b> is not yet configured.<br/>" + "Qt Creator uses the kit <b>%2</b> to parse the project.") + .arg(m_project->displayName()) + .arg(k->displayName()); + showHint = false; + } else { + text = tr("The project <b>%1</b> is not yet configured.<br/>" + "Qt Creator uses the <b>invalid</b> kit <b>%2</b> to parse the project.") + .arg(m_project->displayName()) + .arg(k->displayName()); + showHint = true; + } + + m_targetSetupPage->setNoteText(text); + m_targetSetupPage->showOptionsHint(showHint); +} + +void TargetSetupPageWrapper::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { + event->accept(); + done(); + } +} + +void TargetSetupPageWrapper::keyReleaseEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) + event->accept(); +} + +void TargetSetupPageWrapper::cancel() +{ + ProjectExplorerPlugin::instance()->unloadProject(m_project); + if (!SessionManager::hasProjects()) + Core::ModeManager::activateMode(Core::Constants::MODE_WELCOME); +} + +void TargetSetupPageWrapper::done() +{ + m_targetSetupPage->setupProject(m_project); + ProjectExplorerPlugin::instance()->requestProjectModeUpdate(m_project); + Core::ModeManager::activateMode(Core::Constants::MODE_EDIT); +} + +void TargetSetupPageWrapper::completeChanged() +{ + m_configureButton->setEnabled(m_targetSetupPage->isComplete()); +} + +} // namespace Internal +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/unconfiguredprojectpanel.h b/src/plugins/projectexplorer/unconfiguredprojectpanel.h new file mode 100644 index 0000000000..4e13fe4391 --- /dev/null +++ b/src/plugins/projectexplorer/unconfiguredprojectpanel.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef UNCONFIGUREDPROJECTPANEL_H +#define UNCONFIGUREDPROJECTPANEL_H + +#include "iprojectproperties.h" + +#include <QString> + +QT_FORWARD_DECLARE_CLASS(QPushButton) + +namespace ProjectExplorer { +class Kit; +class TargetSetupPage; + +namespace Internal { + +class UnconfiguredProjectPanel : public IProjectPanelFactory +{ + Q_OBJECT +public: + UnconfiguredProjectPanel(); + virtual QString id() const; + virtual QString displayName() const; + int priority() const; + virtual bool supports(Project *project); + virtual PropertiesPanel *createPanel(Project *project); +}; + +class TargetSetupPageWrapper : public QWidget +{ + Q_OBJECT +public: + TargetSetupPageWrapper(Project *project); +protected: + void keyReleaseEvent(QKeyEvent *event); + void keyPressEvent(QKeyEvent *event); +private slots: + void done(); + void cancel(); + void kitUpdated(ProjectExplorer::Kit *k); + void updateNoteText(); + void completeChanged(); + +private: + Project *m_project; + TargetSetupPage *m_targetSetupPage; + QPushButton *m_configureButton; + QPushButton *m_cancelButton; +}; + +} // namespace Internal +} // namespace ProjectExplorer + +#endif // UNCONFIGUREDPROJECTPANEL_H |