aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/projectexplorer/targetsettingspanel.cpp
diff options
context:
space:
mode:
authorhjk <hjk@theqtcompany.com>2016-07-22 15:53:01 +0200
committerhjk <hjk@qt.io>2016-07-26 10:00:09 +0000
commit245965223450e6936d9a6b250bff777e633bbcc6 (patch)
treed2c029881338cc3ad34046284dcbbdc73b54afba /src/plugins/projectexplorer/targetsettingspanel.cpp
parentd258d47b426dcf3e58dab8e46456bc4e396890b7 (diff)
ProjectExplorer: Rework mode main window
The existing solution with the special-style horizontal kit selector comes from a time when there was typically one, at most four targets. Today's setup can easily reach half a dozen targets with several toolchain versions each and can't be sensibly handled with the overflowing horizontal bar. This here replaces the horizontal kit selector bar as well as the top level project "tab bar" with a normal tree view. All targets are visible (but possibly disabled) at once, and can be enabled/disabled using the context menu on the tree items. Change-Id: I1ce7401ca96109bf34bc8c0ae19d265e5845aa88 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
Diffstat (limited to 'src/plugins/projectexplorer/targetsettingspanel.cpp')
-rw-r--r--src/plugins/projectexplorer/targetsettingspanel.cpp1026
1 files changed, 649 insertions, 377 deletions
diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp
index 046a4f2a46..a5bd9a4bac 100644
--- a/src/plugins/projectexplorer/targetsettingspanel.cpp
+++ b/src/plugins/projectexplorer/targetsettingspanel.cpp
@@ -25,516 +25,788 @@
#include "targetsettingspanel.h"
+#include "buildconfiguration.h"
#include "buildinfo.h"
+#include "buildmanager.h"
#include "buildsettingspropertiespage.h"
#include "ipotentialkit.h"
+#include "kit.h"
+#include "kitmanager.h"
#include "kitoptionspage.h"
#include "panelswidget.h"
#include "project.h"
+#include "projectexplorer.h"
#include "projectimporter.h"
+#include "projecttree.h"
#include "projectwindow.h"
#include "propertiespanel.h"
#include "runsettingspropertiespage.h"
#include "session.h"
#include "target.h"
-#include "targetsettingswidget.h"
+#include "targetsetuppage.h"
#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/coreicons.h>
+#include <coreplugin/modemanager.h>
+
#include <extensionsystem/pluginmanager.h>
-#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/kit.h>
-#include <projectexplorer/kitmanager.h>
-#include <projectexplorer/buildmanager.h>
-#include <projectexplorer/buildconfiguration.h>
+
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
+#include <utils/treemodel.h>
+#include <QCoreApplication>
+#include <QDialogButtonBox>
#include <QFileDialog>
#include <QLabel>
#include <QMenu>
#include <QMessageBox>
#include <QPushButton>
-#include <QStackedWidget>
#include <QToolTip>
#include <QVBoxLayout>
+#include <cmath>
using namespace Core;
+using namespace Utils;
namespace ProjectExplorer {
namespace Internal {
-int TargetSettingsPanelWidget::s_targetSubIndex = -1;
+class TargetSetupPageWrapper : public QWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(TargetSettingsPanelWidget)
-///
-// TargetSettingsWidget
-///
+public:
+ explicit TargetSetupPageWrapper(Project *project);
-TargetSettingsPanelWidget::TargetSettingsPanelWidget(Project *project) :
- m_project(project),
- m_importer(project->createProjectImporter())
-{
- Q_ASSERT(m_project);
+protected:
+ void keyReleaseEvent(QKeyEvent *event) override
+ {
+ if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
+ event->accept();
+ }
- m_panelWidgets[0] = nullptr;
- m_panelWidgets[1] = nullptr;
+ void keyPressEvent(QKeyEvent *event) override
+ {
+ if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
+ event->accept();
+ done();
+ }
+ }
- m_addMenu = new QMenu(this);
- m_targetMenu = new QMenu(this);
+private:
+ void done()
+ {
+ m_targetSetupPage->setupProject(m_project);
+ }
- if (m_importer) {
- m_importAction = new QAction(tr("Import existing build..."), this);
- connect(m_importAction, &QAction::triggered, this, [this]() {
- const QString toImport
- = QFileDialog::getExistingDirectory(this, tr("Import directory"),
- m_project->projectDirectory().toString());
- importTarget(Utils::FileName::fromString(toImport));
- });
+ void cancel()
+ {
+ ProjectExplorerPlugin::unloadProject(m_project);
}
- setFocusPolicy(Qt::NoFocus);
+ void kitUpdated(ProjectExplorer::Kit *k)
+ {
+ if (k == KitManager::defaultKit())
+ updateNoteText();
+ }
- setupUi();
+ void completeChanged()
+ {
+ m_configureButton->setEnabled(m_targetSetupPage->isComplete());
+ }
- connect(m_project, &Project::addedTarget, this, &TargetSettingsPanelWidget::targetAdded);
- connect(m_project, &Project::removedTarget, this, &TargetSettingsPanelWidget::removedTarget);
+ void updateNoteText();
- connect(m_project, &Project::activeTargetChanged,
- this, &TargetSettingsPanelWidget::activeTargetChanged);
+ Project *m_project;
+ TargetSetupPage *m_targetSetupPage;
+ QPushButton *m_configureButton;
+};
- connect(KitManager::instance(), &KitManager::kitsChanged,
- this, &TargetSettingsPanelWidget::updateTargetButtons);
+TargetSetupPageWrapper::TargetSetupPageWrapper(Project *project)
+ : m_project(project)
+{
+ m_targetSetupPage = new TargetSetupPage(this);
+ m_targetSetupPage->setProjectImporter(project->createProjectImporter());
+ m_targetSetupPage->setUseScrollArea(false);
+ m_targetSetupPage->setProjectPath(project->projectFilePath().toString());
+ m_targetSetupPage->setRequiredKitMatcher(project->requiredKitMatcher());
+ m_targetSetupPage->setPreferredKitMatcher(project->preferredKitMatcher());
+ m_targetSetupPage->initializePage();
+ m_targetSetupPage->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ updateNoteText();
+
+ auto box = new QDialogButtonBox(this);
+
+ m_configureButton = new QPushButton(this);
+ m_configureButton->setText(tr("Configure Project"));
+ box->addButton(m_configureButton, QDialogButtonBox::AcceptRole);
+
+ auto hbox = new QHBoxLayout;
+ hbox->addStretch();
+ hbox->addWidget(box);
+
+ auto layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+ layout->addWidget(m_targetSetupPage);
+ layout->addLayout(hbox);
+ layout->addStretch(10);
+
+ completeChanged();
+
+ connect(m_configureButton, &QAbstractButton::clicked,
+ this, &TargetSetupPageWrapper::done);
+ connect(m_targetSetupPage, &QWizardPage::completeChanged,
+ this, &TargetSetupPageWrapper::completeChanged);
+ connect(KitManager::instance(), &KitManager::defaultkitChanged,
+ this, &TargetSetupPageWrapper::updateNoteText);
+ connect(KitManager::instance(), &KitManager::kitUpdated,
+ this, &TargetSetupPageWrapper::kitUpdated);
}
-TargetSettingsPanelWidget::~TargetSettingsPanelWidget()
+void TargetSetupPageWrapper::updateNoteText()
{
- delete m_importer;
+ 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);
}
-bool TargetSettingsPanelWidget::event(QEvent *event)
+//
+// TargetSettingsPanelItem
+//
+
+class TargetSettingsPanelItemPrivate : public QObject
{
- if (event->type() == QEvent::StatusTip) {
- QAction *act = nullptr;
- QMenu *menu = nullptr;
- if (m_addMenu->activeAction()) {
- menu = m_addMenu;
- act = m_addMenu->activeAction();
- } else if (m_changeMenu && m_changeMenu->activeAction()) {
- menu = m_changeMenu;
- act = m_changeMenu->activeAction();
- } else if (m_duplicateMenu && m_duplicateMenu->activeAction()) {
- menu = m_duplicateMenu;
- act = m_duplicateMenu->activeAction();
- } else {
- return QWidget::event(event);
- }
+public:
+ TargetSettingsPanelItemPrivate(TargetSettingsPanelItem *q, Project *project);
+ ~TargetSettingsPanelItemPrivate() { /*delete m_importer;*/ }
- auto ev = static_cast<QStatusTipEvent *>(event);
- ev->accept();
-
- if (act != m_lastAction)
- QToolTip::showText(QPoint(), QString());
- m_lastAction = act;
- if (act) {
- QRect actionRect = menu->actionGeometry(act);
- actionRect.translate(menu->pos());
- QPoint p = QCursor::pos();
- if (!actionRect.contains(p))
- p = actionRect.center();
- p.setY(actionRect.center().y());
- QToolTip::showText(p, ev->tip(), menu, menu->actionGeometry(act));
- } else {
- QToolTip::showText(QPoint(), QString());
- }
+ void handleRemovedKit(Kit *kit);
+ void handleAddedKit(Kit *kit);
- return true;
- }
- return QWidget::event(event);
-}
+ TargetItem *currentTargetItem() const;
+
+ void importTarget(const Utils::FileName &path);
+ void ensureWidget();
+ void rebuildContents();
+ Id currentKitId() const;
+
+ TargetSettingsPanelItem *q;
+ QString m_displayName;
+ QPointer<Project> m_project;
+ ProjectImporter *m_importer;
-void TargetSettingsPanelWidget::setupUi()
+ QPointer<QWidget> m_noKitLabel;
+ QPointer<QWidget> m_configurePage;
+ QPointer<QWidget> m_configuredPage;
+};
+
+void TargetSettingsPanelItemPrivate::ensureWidget()
{
- auto viewLayout = new QVBoxLayout(this);
- viewLayout->setMargin(0);
- viewLayout->setSpacing(0);
-
- m_selector = new TargetSettingsWidget(this);
- viewLayout->addWidget(m_selector);
-
- // Setup our container for the contents:
- m_centralWidget = new QStackedWidget(this);
- m_selector->setCentralWidget(m_centralWidget);
-
- // no target label:
- m_noTargetLabel = new QWidget;
- auto noTargetLayout = new QVBoxLayout(m_noTargetLabel);
- noTargetLayout->setMargin(0);
- auto label = new QLabel(m_noTargetLabel);
- label->setText(tr("No kit defined in this project."));
- {
+ if (!m_noKitLabel) {
+ m_noKitLabel = new QWidget;
+ m_noKitLabel->setFocusPolicy(Qt::NoFocus);
+
+ auto label = new QLabel;
+ label->setText(tr("No kit defined in this project."));
QFont f = label->font();
f.setPointSizeF(f.pointSizeF() * 1.4);
f.setBold(true);
label->setFont(f);
+ label->setMargin(10);
+ label->setAlignment(Qt::AlignTop);
+
+ auto layout = new QVBoxLayout(m_noKitLabel);
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->addWidget(label);
+ layout->addStretch(10);
+ }
+
+ if (!m_configurePage) {
+ auto panelsWidget = new PanelsWidget;
+ auto panel = new PropertiesPanel;
+ panel->setDisplayName(tr("Configure Project"));
+ auto widget = new TargetSetupPageWrapper(m_project);
+ panel->setWidget(widget);
+ panel->setIcon(QIcon(":/projectexplorer/images/unconfigured.png"));
+ panelsWidget->addPropertiesPanel(panel);
+ panelsWidget->setFocusProxy(widget);
+ m_configurePage = panelsWidget;
+ }
+
+ if (!m_configuredPage) {
+ auto panelsWidget = new PanelsWidget;
+ auto panel = new PropertiesPanel;
+ panel->setDisplayName(tr("Configure Project"));
+ auto widget = new QWidget;
+ auto label = new QLabel("This project is already configured.");
+ auto layout = new QVBoxLayout(widget);
+ layout->setMargin(0);
+ layout->addWidget(label);
+ layout->addStretch(10);
+ panel->setWidget(widget);
+ panel->setIcon(QIcon(":/projectexplorer/images/unconfigured.png"));
+ panelsWidget->addPropertiesPanel(panel);
+ m_configuredPage = panelsWidget;
}
- label->setMargin(10);
- label->setAlignment(Qt::AlignTop);
- noTargetLayout->addWidget(label);
- noTargetLayout->addStretch(10);
- m_centralWidget->addWidget(m_noTargetLabel);
-
- foreach (Target *t, m_project->targets())
- targetAdded(t);
-
- // Now set the correct target
- int index = m_targets.indexOf(m_project->activeTarget());
- m_selector->setCurrentIndex(index);
- m_selector->setCurrentSubIndex(s_targetSubIndex);
- currentTargetChanged(index, m_selector->currentSubIndex());
-
- connect(m_selector, &TargetSettingsWidget::currentChanged,
- this, &TargetSettingsPanelWidget::currentTargetChanged);
- connect(m_selector, &TargetSettingsWidget::manageButtonClicked,
- this, &TargetSettingsPanelWidget::openTargetPreferences);
- connect(m_selector, &TargetSettingsWidget::toolTipRequested,
- this, &TargetSettingsPanelWidget::showTargetToolTip);
- connect(m_selector, &TargetSettingsWidget::menuShown,
- this, &TargetSettingsPanelWidget::menuShown);
-
- connect(m_addMenu, &QMenu::triggered,
- this, &TargetSettingsPanelWidget::addActionTriggered);
-
- m_selector->setAddButtonMenu(m_addMenu);
- m_selector->setTargetMenu(m_targetMenu);
-
- updateTargetButtons();
}
-void TargetSettingsPanelWidget::currentTargetChanged(int targetIndex, int subIndex)
+void TargetSettingsPanelItemPrivate::importTarget(const Utils::FileName &path)
{
- if (targetIndex < -1 || targetIndex >= m_targets.count())
- return;
- if (subIndex < -1 || subIndex >= 2)
+ if (!m_importer)
return;
- if (targetIndex == -1 || subIndex == -1) { // no more kits!
- delete m_panelWidgets[0];
- m_panelWidgets[0] = nullptr;
- delete m_panelWidgets[1];
- m_panelWidgets[1] = nullptr;
+ Target *target = nullptr;
+ BuildConfiguration *bc = nullptr;
+ QList<BuildInfo *> toImport = m_importer->import(path, false);
+ foreach (BuildInfo *info, toImport) {
+ target = m_project->target(info->kitId);
+ if (!target) {
+ target = m_project->createTarget(KitManager::find(info->kitId));
+ m_project->addTarget(target);
+ }
+ bc = info->factory()->create(target, info);
+ QTC_ASSERT(bc, continue);
+ target->addBuildConfiguration(bc);
+ }
- m_centralWidget->setCurrentWidget(m_noTargetLabel);
- return;
+ SessionManager::setActiveTarget(m_project, target, SetActive::Cascade);
+
+ if (target && bc)
+ SessionManager::setActiveBuildConfiguration(target, bc, SetActive::Cascade);
+
+ qDeleteAll(toImport);
+}
+
+//
+// Third level: The per-kit entries
+//
+
+class TargetItemPrivate : public QObject
+{
+ // QObject base needed as guard for the Project::addedTarget connection below.
+public:
+ TargetItemPrivate(TargetItem *q) : q(q) {}
+
+ void handleChangedTarget(Target *target);
+
+ TargetItem *q;
+};
+
+class TargetItem : public TypedTreeItem<TreeItem, TargetSettingsPanelItem>
+{
+ Q_DECLARE_TR_FUNCTIONS(TargetSettingsPanelWidget)
+
+public:
+ TargetItem(Project *project, Id kitId)
+ : d(new TargetItemPrivate(this)), m_project(project), m_kitId(kitId)
+ {
+ QObject::connect(m_project, &Project::addedTarget, d, &TargetItemPrivate::handleChangedTarget);
+ updateSubItems();
}
- s_targetSubIndex = subIndex;
+ ~TargetItem()
+ {
+ delete d;
+ }
- Target *target = m_targets.at(targetIndex);
+ Target *target() const
+ {
+ return m_project->target(m_kitId);
+ }
- // Target was not actually changed:
- if (m_currentTarget == target) {
- if (m_panelWidgets[subIndex])
- m_centralWidget->setCurrentWidget(m_panelWidgets[subIndex]);
- else
- m_centralWidget->setCurrentWidget(m_noTargetLabel);
- return;
+ void updateSubItems();
+
+ Qt::ItemFlags flags(int column) const override
+ {
+ Q_UNUSED(column)
+ if (isEnabled())
+ return Qt::ItemFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ return Qt::ItemIsSelectable;
}
- // Target has changed:
- m_currentTarget = target;
+ QVariant data(int column, int role) const override
+ {
+ switch (role) {
+ case Qt::DisplayRole: {
+ if (Kit *kit = KitManager::find(m_kitId))
+ return kit->displayName();
+ break;
+ }
+
+ case Qt::DecorationRole: {
+ Kit *k = KitManager::find(m_kitId);
+ QTC_ASSERT(k, return QVariant());
+ if (!k->isValid())
+ return Core::Icons::ERROR.icon();
+ if (k->hasWarning())
+ return Core::Icons::WARNING.icon();
+ break;
+ }
- auto wrapWidgetInPropertiesPanel
- = [](QWidget *widget, const QString &displayName, const QIcon &icon) -> PropertiesPanel *{
- auto panel = new PropertiesPanel;
- auto w = new QWidget();
- auto l = new QVBoxLayout(w);
- l->addWidget(widget);
- l->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
- l->setContentsMargins(QMargins());
- panel->setWidget(w);
- panel->setIcon(icon);
- panel->setDisplayName(displayName);
- return panel;
- };
+ case Qt::FontRole: {
+ QFont font = parent()->data(column, role).value<QFont>();
+ if (parent()->currentKitId() == m_kitId && m_project == SessionManager::startupProject())
+ font.setBold(true);
+ return font;
+ }
- PropertiesPanel *build = wrapWidgetInPropertiesPanel(new BuildSettingsWidget(target),
- QCoreApplication::translate("BuildSettingsPanel", "Build Settings"),
- QIcon(QLatin1String(":/projectexplorer/images/BuildSettings.png")));
- PropertiesPanel *run= wrapWidgetInPropertiesPanel(new RunSettingsWidget(target),
- RunSettingsWidget::tr("Run Settings"),
- QIcon(QLatin1String(":/projectexplorer/images/RunSettings.png")));
+ case Qt::ToolTipRole: {
+ Kit *k = KitManager::find(m_kitId);
+ QTC_ASSERT(k, return QVariant());
+ return k->toHtml();
+ }
- auto buildPanel = new PanelsWidget(m_centralWidget);
- auto runPanel = new PanelsWidget(m_centralWidget);
+ case ActiveWidgetRole:
+ case ActiveIndexRole: {
+ if (m_currentChild >= 0 && m_currentChild < childCount())
+ return childAt(m_currentChild)->data(column, role);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return QVariant();
+ }
- buildPanel->addPropertiesPanel(build);
- runPanel->addPropertiesPanel(run);
+ bool setData(int column, const QVariant &data, int role) override
+ {
+ Q_UNUSED(column)
- m_centralWidget->addWidget(buildPanel);
- m_centralWidget->addWidget(runPanel);
+ if (role == ContextMenuItemAdderRole) {
+ QMenu *menu = data.value<QMenu *>();
+ addToContextMenu(menu);
+ return true;
+ }
- m_centralWidget->setCurrentWidget(subIndex == 0 ? buildPanel : runPanel);
+ if (role == ItemActivaterRole) {
+ int child = children().indexOf(data.value<TreeItem *>());
+ if (child != -1)
+ m_currentChild = child; // Triggered from sub-item.
+ parent()->setData(column, QVariant::fromValue(static_cast<TreeItem *>(this)), role);
+ return true;
+ }
- delete m_panelWidgets[0];
- m_panelWidgets[0] = buildPanel;
- delete m_panelWidgets[1];
- m_panelWidgets[1] = runPanel;
+ return false;
+ }
- SessionManager::setActiveTarget(m_project, target, SetActive::Cascade);
-}
+ void addToContextMenu(QMenu *menu)
+ {
+ Kit *kit = KitManager::find(m_kitId);
+ QTC_ASSERT(kit, return);
+ const QString kitName = kit->displayName();
+ const QString projectName = m_project->displayName();
+
+ QAction *enableAction = menu->addAction(tr("Enable Kit \"%1\" for Project \"%2\"").arg(kitName, projectName));
+ enableAction->setEnabled(m_kitId.isValid() && !isEnabled());
+ QObject::connect(enableAction, &QAction::triggered, [this, kit] {
+ Target *t = m_project->createTarget(kit);
+ m_project->addTarget(t);
+ updateSubItems();
+ setData(0, QVariant(), ItemActivaterRole);
+ });
-void TargetSettingsPanelWidget::menuShown(int targetIndex)
-{
- m_menuTargetIndex = targetIndex;
-}
+ QAction *disableAction = menu->addAction(tr("Disable Kit \"%1\" for Project \"%2\"").arg(kitName, projectName));
+ disableAction->setEnabled(m_kitId.isValid() && isEnabled());
+ QObject::connect(disableAction, &QAction::triggered, [this, kit] {
+ Target *t = target();
+ QTC_ASSERT(t, return);
+ QString kitName = t->displayName();
+ if (BuildManager::isBuilding(t)) {
+ QMessageBox box;
+ QPushButton *closeAnyway = box.addButton(tr("Cancel Build and Disable Kit in This Project"), QMessageBox::AcceptRole);
+ QPushButton *cancelClose = box.addButton(tr("Do Not Remove"), QMessageBox::RejectRole);
+ box.setDefaultButton(cancelClose);
+ box.setWindowTitle(tr("Disable Kit %1 in This Project?").arg(kitName));
+ box.setText(tr("The kit <b>%1</b> is currently being built.").arg(kitName));
+ box.setInformativeText(tr("Do you want to cancel the build process and remove the kit anyway?"));
+ box.exec();
+ if (box.clickedButton() != closeAnyway)
+ return;
+ BuildManager::cancel();
+ }
+
+ QCoreApplication::processEvents();
+
+ if (m_project->removeTarget(t)) {
+ updateSubItems();
+ if (m_project->targets().isEmpty()) {
+ parent()->setData(0, QVariant(), ItemActivaterRole);
+ QMetaObject::invokeMethod(model(), "needPanelUpdate");
+ }
+ }
+ });
-void TargetSettingsPanelWidget::changeActionTriggered(QAction *action)
-{
- QTC_ASSERT(m_menuTargetIndex >= 0, return);
- Kit *k = KitManager::find(action->data().value<Id>());
- Target *sourceTarget = m_targets.at(m_menuTargetIndex);
- Target *newTarget = m_project->cloneTarget(sourceTarget, k);
+ QMenu *copyMenu = menu->addMenu(tr("Copy Steps From Other Kit..."));
+ if (m_kitId.isValid()) {
+ const QList<Kit *> kits = KitManager::kits();
+ for (Kit *kit : kits) {
+ QAction *copyAction = copyMenu->addAction(kit->displayName());
+ if (kit->id() == m_kitId || !m_project->target(kit->id())) {
+ copyAction->setEnabled(false);
+ } else {
+ QObject::connect(copyAction, &QAction::triggered, [this, kit] {
+ Target *sourceTarget = target();
+ Target *newTarget = m_project->target(kit->id());
+ bool success = Project::copySteps(sourceTarget, newTarget);
+ Q_UNUSED(success);
+ SessionManager::setActiveTarget(m_project, newTarget, SetActive::Cascade);
+ });
+ }
+ }
+ } else {
+ copyMenu->setEnabled(false);
+ }
+
+ menu->addSeparator();
- if (newTarget) {
- m_project->addTarget(newTarget);
- SessionManager::setActiveTarget(m_project, newTarget, SetActive::Cascade);
- m_project->removeTarget(sourceTarget);
+ QAction *manageKits = menu->addAction(tr("Manage Kits"));
+ QObject::connect(manageKits, &QAction::triggered, menu, [this] {
+ KitOptionsPage *page = ExtensionSystem::PluginManager::getObject<KitOptionsPage>();
+ if (page)
+ page->showKit(KitManager::find(m_kitId));
+ ICore::showOptionsDialog(Constants::KITS_SETTINGS_PAGE_ID, ICore::mainWindow());
+ });
}
-}
-void TargetSettingsPanelWidget::duplicateActionTriggered(QAction *action)
+ bool isEnabled() const { return target() != 0; }
+
+public:
+ TargetItemPrivate *d;
+ Project *m_project; // Not owned.
+ Id m_kitId;
+ int m_currentChild = 1; // Use run page by default.
+};
+
+//
+// Fourth level: The 'Build' and 'Run' sub-items.
+//
+
+class BuildOrRunItem : public TreeItem
{
- QTC_ASSERT(m_menuTargetIndex >= 0, return);
- Kit *k = KitManager::find(action->data().value<Id>());
- Target *newTarget = m_project->cloneTarget(m_targets.at(m_menuTargetIndex), k);
+ Q_DECLARE_TR_FUNCTIONS(TargetSettingsPanelWidget)
- if (newTarget) {
- m_project->addTarget(newTarget);
- SessionManager::setActiveTarget(m_project, newTarget, SetActive::Cascade);
+public:
+ enum SubIndex { BuildPage = 0, RunPage = 1 };
+
+ BuildOrRunItem(Project *project, Id kitId, SubIndex subIndex)
+ : m_project(project), m_kitId(kitId), m_subIndex(subIndex)
+ {
}
-}
-void TargetSettingsPanelWidget::addActionTriggered(QAction *action)
-{
- const QVariant data = action->data();
- if (data.canConvert<Id>()) { // id of kit
- Kit *k = KitManager::find(action->data().value<Id>());
- QTC_ASSERT(!m_project->target(k), return);
+ ~BuildOrRunItem()
+ {
+ delete m_panel;
+ }
- m_project->addTarget(m_project->createTarget(k));
- } else {
- QTC_ASSERT(data.canConvert<IPotentialKit *>(), return);
- IPotentialKit *potentialKit = data.value<IPotentialKit *>();
- potentialKit->executeFromMenu();
+ Target *target() const
+ {
+ return m_project->target(m_kitId);
}
-}
-void TargetSettingsPanelWidget::removeCurrentTarget()
-{
- QTC_ASSERT(m_menuTargetIndex >= 0, return);
- Target *t = m_targets.at(m_menuTargetIndex);
-
- if (BuildManager::isBuilding(t)) {
- QMessageBox box;
- QPushButton *closeAnyway = box.addButton(tr("Cancel Build && Remove Kit"), QMessageBox::AcceptRole);
- QPushButton *cancelClose = box.addButton(tr("Do Not Remove"), QMessageBox::RejectRole);
- box.setDefaultButton(cancelClose);
- box.setWindowTitle(tr("Remove Kit %1?").arg(t->displayName()));
- box.setText(tr("The kit <b>%1</b> is currently being built.").arg(t->displayName()));
- box.setInformativeText(tr("Do you want to cancel the build process and remove the kit anyway?"));
- box.exec();
- if (box.clickedButton() != closeAnyway)
- return;
- BuildManager::cancel();
- } else {
- // We don't show the generic message box on removing the target, if we showed the still building one
- int ret = QMessageBox::warning(this, tr("Qt Creator"),
- tr("Do you really want to remove the\n"
- "\"%1\" kit?").arg(t->displayName()),
- QMessageBox::Yes | QMessageBox::No,
- QMessageBox::No);
- if (ret != QMessageBox::Yes)
- return;
+ void updateSubItems()
+ {
+ static_cast<TargetItem *>(parent())->updateSubItems();
}
- m_project->removeTarget(t);
-}
+ QVariant data(int column, int role) const override
+ {
+ switch (role) {
+ case Qt::DisplayRole: {
+ switch (m_subIndex) {
+ case BuildPage:
+ return tr("Build");
+ case RunPage:
+ return tr("Run");
+ }
+ break;
+ }
-void TargetSettingsPanelWidget::showTargetToolTip(const QPoint &globalPos, int targetIndex)
-{
- QTC_ASSERT(targetIndex >= 0 && targetIndex < m_targets.count(), return);
- Target *target = m_targets.at(targetIndex);
- QToolTip::showText(globalPos, target->kit()->toHtml());
-}
+ case Qt::ToolTipRole:
+ return parent()->data(column, role);
-void TargetSettingsPanelWidget::targetAdded(Target *target)
-{
- Q_ASSERT(m_project == target->project());
- Q_ASSERT(m_selector);
+ case ActiveWidgetRole:
+ return QVariant::fromValue(panel());
- for (int pos = 0; pos <= m_targets.count(); ++pos) {
- if (m_targets.count() == pos ||
- m_targets.at(pos)->displayName() > target->displayName()) {
- m_targets.insert(pos, target);
- m_selector->insertTarget(pos, m_project->hasActiveBuildSettings() ? 0 : 1,
- target->displayName());
+ case ActiveIndexRole:
+ return QVariant::fromValue<TreeItem *>(const_cast<BuildOrRunItem *>(this));
+ default:
break;
}
+
+ return QVariant();
}
- connect(target, &ProjectConfiguration::displayNameChanged,
- this, &TargetSettingsPanelWidget::renameTarget);
- updateTargetButtons();
-}
+ Qt::ItemFlags flags(int column) const override
+ {
+ return parent()->flags(column);
+ }
+
+ bool setData(int column, const QVariant &data, int role) override
+ {
+ if (role == ItemActivaterRole) {
+ parent()->setData(column, QVariant::fromValue(static_cast<TreeItem *>(this)), role);
+ return true;
+ }
+
+ return parent()->setData(column, data, role);
+ }
+
+ static QWidget *createPanelWidget(QWidget *widget, const QString &displayName, const QString &icon)
+ {
+ auto panel = new PropertiesPanel;
+ auto w = new QWidget();
+ auto l = new QVBoxLayout(w);
+ l->addWidget(widget);
+ l->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
+ l->setContentsMargins(QMargins());
+ panel->setWidget(w);
+ panel->setIcon(QIcon(icon));
+ panel->setDisplayName(displayName);
+
+ auto result = new PanelsWidget;
+ result->addPropertiesPanel(panel);
+ return result;
+ };
+
+ QWidget *panel() const
+ {
+ if (!m_panel) {
+ m_panel = (m_subIndex == RunPage)
+ ? createPanelWidget(new RunSettingsWidget(target()),
+ RunSettingsWidget::tr("Run Settings"),
+ ":/projectexplorer/images/RunSettings.png")
+ : createPanelWidget(new BuildSettingsWidget(target()),
+ QCoreApplication::translate("BuildSettingsPanel", "Build Settings"),
+ ":/projectexplorer/images/BuildSettings.png");
+ }
+ return m_panel;
+ }
-void TargetSettingsPanelWidget::removedTarget(Target *target)
+public:
+ Project *m_project; // Not owned.
+ Id m_kitId;
+ mutable QPointer<QWidget> m_panel; // Owned.
+ const SubIndex m_subIndex;
+};
+
+//
+// Also third level:
+//
+class PotentialKitItem : public TypedTreeItem<TreeItem, TargetSettingsPanelItem>
{
- Q_ASSERT(m_project == target->project());
- Q_ASSERT(m_selector);
+ Q_DECLARE_TR_FUNCTIONS(TargetSettingsPanelWidget)
- int index(m_targets.indexOf(target));
- if (index < 0)
- return;
- m_targets.removeAt(index);
+public:
+ PotentialKitItem(Project *project, IPotentialKit *potentialKit)
+ : m_project(project), m_potentialKit(potentialKit)
+ {}
- m_selector->removeTarget(index);
+ QVariant data(int column, int role) const override
+ {
+ if (role == Qt::DisplayRole)
+ return m_potentialKit->displayName();
- updateTargetButtons();
-}
+ if (role == Qt::FontRole) {
+ QFont font = parent()->data(column, role).value<QFont>();
+ font.setItalic(true);
+ return font;
+ }
-void TargetSettingsPanelWidget::activeTargetChanged(Target *target)
-{
- Q_ASSERT(m_selector);
+ return QVariant();
+ }
- int index = m_targets.indexOf(target);
- m_selector->setCurrentIndex(index);
+ bool setData(int column, const QVariant &data, int role) override
+ {
+ Q_UNUSED(column)
+ if (role == ContextMenuItemAdderRole) {
+ QMenu *menu = data.value<QMenu *>();
+ auto enableAction = menu->addAction(tr("Enable Kit"));
+ enableAction->setEnabled(!isEnabled());
+ QObject::connect(enableAction, &QAction::triggered, [this] {
+ m_potentialKit->executeFromMenu();
+ });
+ return true;
+ }
+
+ return false;
+ }
+
+ Qt::ItemFlags flags(int column) const override
+ {
+ Q_UNUSED(column)
+ if (isEnabled())
+ return Qt::ItemFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ return Qt::ItemIsSelectable;
+ }
+
+ bool isEnabled() const { return m_potentialKit->isEnabled(); }
+
+ Project *m_project;
+ IPotentialKit *m_potentialKit;
+};
+
+TargetSettingsPanelItem::TargetSettingsPanelItem(ProjectPanelFactory *factory, Project *project)
+ : d(new TargetSettingsPanelItemPrivate(this, project))
+{
+ d->m_displayName = factory->displayName();
}
-void TargetSettingsPanelWidget::createAction(Kit *k, QMenu *menu)
+TargetSettingsPanelItem::~TargetSettingsPanelItem()
{
- auto action = new QAction(k->displayName(), menu);
- action->setData(QVariant::fromValue(k->id()));
- QString statusTip = QLatin1String("<html><body>");
- QString errorMessage;
- if (!m_project->supportsKit(k, &errorMessage)) {
- action->setEnabled(false);
- statusTip += errorMessage;
- }
- statusTip += k->toHtml();
- action->setStatusTip(statusTip);
-
- menu->addAction(action);
+ delete d;
}
-void TargetSettingsPanelWidget::updateTargetButtons()
+TargetSettingsPanelItemPrivate::TargetSettingsPanelItemPrivate(TargetSettingsPanelItem *q,
+ Project *project)
+ : q(q), m_project(project)
{
- if (!m_selector)
- return;
+ m_importer = project->createProjectImporter();
- m_addMenu->clear();
- m_targetMenu->clear();
-
- if (m_importAction)
- m_addMenu->addAction(m_importAction);
- const QList<IPotentialKit *> potentialKits
- = ExtensionSystem::PluginManager::getObjects<IPotentialKit>();
- foreach (IPotentialKit *potentialKit, potentialKits) {
- if (!potentialKit->isEnabled())
- continue;
- auto action = new QAction(potentialKit->displayName(), m_addMenu);
- action->setData(QVariant::fromValue(potentialKit));
- m_addMenu->addAction(action);
- }
- if (!m_addMenu->actions().isEmpty())
- m_addMenu->addSeparator();
-
- m_changeMenu = m_targetMenu->addMenu(tr("Change Kit"));
- m_duplicateMenu = m_targetMenu->addMenu(tr("Copy to Kit"));
- QAction *removeAction = m_targetMenu->addAction(tr("Remove Kit"));
-
- if (m_project->targets().size() < 2)
- removeAction->setEnabled(false);
-
- connect(m_changeMenu, &QMenu::triggered,
- this, &TargetSettingsPanelWidget::changeActionTriggered);
- connect(m_duplicateMenu, &QMenu::triggered,
- this, &TargetSettingsPanelWidget::duplicateActionTriggered);
- connect(removeAction, &QAction::triggered,
- this, &TargetSettingsPanelWidget::removeCurrentTarget);
-
- foreach (Kit *k, KitManager::sortKits(KitManager::kits())) {
- if (m_project->target(k))
- continue;
- createAction(k, m_addMenu);
- createAction(k, m_changeMenu);
- createAction(k, m_duplicateMenu);
- }
- if (m_changeMenu->actions().isEmpty())
- m_changeMenu->setEnabled(false);
- if (m_duplicateMenu->actions().isEmpty())
- m_duplicateMenu->setEnabled(false);
-
- m_selector->setAddButtonEnabled(!m_addMenu->actions().isEmpty());
+ if (m_importer) {
+ auto importAction = new QAction(tr("Import existing build..."), 0);
+ QObject::connect(importAction, &QAction::triggered, [this] {
+ QString dir = m_project->projectDirectory().toString();
+ QString toImport = QFileDialog::getExistingDirectory(ICore::mainWindow(), tr("Import directory"), dir);
+ importTarget(FileName::fromString(toImport));
+ });
+ }
+
+ // force a signal since the index has changed
+ connect(KitManager::instance(), &KitManager::kitAdded,
+ this, &TargetSettingsPanelItemPrivate::handleAddedKit);
+ connect(KitManager::instance(), &KitManager::kitRemoved,
+ this, &TargetSettingsPanelItemPrivate::handleRemovedKit);
+
+ rebuildContents();
}
-void TargetSettingsPanelWidget::renameTarget()
+QVariant TargetSettingsPanelItem::data(int column, int role) const
{
- auto t = qobject_cast<Target *>(sender());
- if (!t)
- return;
- const int pos = m_targets.indexOf(t);
- if (pos < 0)
- return;
- m_selector->renameTarget(pos, t->displayName());
+ if (role == Qt::DisplayRole)
+ return d->m_displayName;
+
+ if (role == ActiveIndexRole) {
+ Id needle = currentKitId();
+ TargetItem *item = findFirstLevelChild([this, needle](TargetItem *item) { return item->m_kitId == needle; });
+ return item ? item->data(column, role) : QVariant();
+ }
+
+ if (role == ActiveWidgetRole) {
+ Id needle = currentKitId();
+ TargetItem *item = findFirstLevelChild([this, needle](TargetItem *item) { return item->m_kitId == needle; });
+ if (item)
+ return item->data(column, role);
+
+ d->ensureWidget();
+ if (d->m_project->targets().isEmpty()) {
+ return QVariant::fromValue<QWidget *>(d->m_configurePage.data());
+ }
+ return QVariant::fromValue<QWidget *>(d->m_configuredPage.data());
+ }
+
+ return QVariant();
}
-void TargetSettingsPanelWidget::openTargetPreferences()
+bool TargetSettingsPanelItem::setData(int column, const QVariant &data, int role)
{
- int targetIndex = m_selector->currentIndex();
- if (targetIndex >= 0 && targetIndex < m_targets.size()) {
- if (KitOptionsPage *page = ExtensionSystem::PluginManager::getObject<KitOptionsPage>())
- page->showKit(m_targets.at(targetIndex)->kit());
+ if (role == ItemActivaterRole) {
+ // From sub item
+ if (TreeItem *subItem = data.value<TreeItem *>()) {
+ // Bubble up (i.e. set active project)
+ parent()->setData(column, QVariant::fromValue(static_cast<TreeItem *>(this)), role);
+
+ // Set selected target.
+ Id kitId = static_cast<TargetItem *>(subItem)->m_kitId;
+ Target *target = d->m_project->target(kitId);
+ SessionManager::setActiveTarget(d->m_project, target, SetActive::Cascade);
+
+ return true;
+ }
+
+ // Bubble up
+ SessionManager::setActiveTarget(d->m_project, nullptr, SetActive::Cascade);
+ return parent()->setData(column, QVariant::fromValue(static_cast<TreeItem *>(this)), role);
}
- ICore::showOptionsDialog(Constants::KITS_SETTINGS_PAGE_ID, this);
+
+ return false;
}
-void TargetSettingsPanelWidget::importTarget(const Utils::FileName &path)
+Id TargetSettingsPanelItem::currentKitId() const
{
- if (!m_importer)
- return;
+ return d->currentKitId();
+}
- Target *target = nullptr;
- BuildConfiguration *bc = nullptr;
- QList<BuildInfo *> toImport = m_importer->import(path, false);
- foreach (BuildInfo *info, toImport) {
- target = m_project->target(info->kitId);
- if (!target) {
- target = m_project->createTarget(KitManager::find(info->kitId));
- m_project->addTarget(target);
- }
- bc = info->factory()->create(target, info);
- QTC_ASSERT(bc, continue);
- target->addBuildConfiguration(bc);
- }
+Id TargetSettingsPanelItemPrivate::currentKitId() const
+{
+ Target *target = m_project->activeTarget();
+ return target ? target->id() : Id(); // Unconfigured project have no active target.
+}
- SessionManager::setActiveTarget(m_project, target, SetActive::Cascade);
+void TargetSettingsPanelItemPrivate::handleRemovedKit(Kit *kit)
+{
+ Q_UNUSED(kit);
+ rebuildContents();
+}
- if (target && bc)
- SessionManager::setActiveBuildConfiguration(target, bc, SetActive::Cascade);
+void TargetSettingsPanelItemPrivate::handleAddedKit(Kit *kit)
+{
+ q->appendChild(new TargetItem(m_project, kit->id()));
+}
- qDeleteAll(toImport);
+void TargetItem::updateSubItems()
+{
+ removeChildren();
+ if (isEnabled()) {
+ appendChild(new BuildOrRunItem(m_project, m_kitId, BuildOrRunItem::BuildPage));
+ appendChild(new BuildOrRunItem(m_project, m_kitId, BuildOrRunItem::RunPage));
+ }
}
-int TargetSettingsPanelWidget::currentSubIndex() const
+void TargetSettingsPanelItemPrivate::rebuildContents()
{
- return m_selector->currentSubIndex();
+ q->removeChildren();
+
+ foreach (Kit *kit, KitManager::sortKits(KitManager::kits()))
+ q->appendChild(new TargetItem(m_project, kit->id()));
}
-void TargetSettingsPanelWidget::setCurrentSubIndex(int subIndex)
+void TargetItemPrivate::handleChangedTarget(Target *target)
{
- m_selector->setCurrentSubIndex(subIndex);
+ if (q->m_kitId == target->id()) {
+ q->updateSubItems();
+ q->parent()->update();
+ }
}
-} // namespace Internal
-} // namespace ProjectExplorer
+} // Internal
+} // ProjectExplorer