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>
This commit is contained in:
hjk
2016-07-22 15:53:01 +02:00
committed by hjk
parent d258d47b42
commit 2459652234
43 changed files with 1300 additions and 3156 deletions

View File

@@ -58,7 +58,9 @@ void addProjectPanelWidget()
auto panelFactory = new ProjectExplorer::ProjectPanelFactory(); auto panelFactory = new ProjectExplorer::ProjectPanelFactory();
panelFactory->setPriority(60); panelFactory->setPriority(60);
panelFactory->setDisplayName(ClangProjectSettingsWidget::tr("Clang Code Model")); panelFactory->setDisplayName(ClangProjectSettingsWidget::tr("Clang Code Model"));
panelFactory->setSimpleCreateWidgetFunction<ClangProjectSettingsWidget>(QIcon()); panelFactory->setCreateWidgetFunction([](ProjectExplorer::Project *project) {
return new ClangProjectSettingsWidget(project);
});
ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory);
} }

View File

@@ -54,6 +54,7 @@
#include <QtPlugin> #include <QtPlugin>
using namespace Debugger; using namespace Debugger;
using namespace ProjectExplorer;
namespace ClangStaticAnalyzer { namespace ClangStaticAnalyzer {
namespace Internal { namespace Internal {
@@ -116,11 +117,11 @@ bool ClangStaticAnalyzerPlugin::initialize(const QStringList &arguments, QString
Q_UNUSED(arguments); Q_UNUSED(arguments);
Q_UNUSED(errorString); Q_UNUSED(errorString);
auto panelFactory = new ProjectExplorer::ProjectPanelFactory(); auto panelFactory = new ProjectPanelFactory();
panelFactory->setPriority(100); panelFactory->setPriority(100);
panelFactory->setDisplayName(tr("Clang Static Analyzer")); panelFactory->setDisplayName(tr("Clang Static Analyzer"));
panelFactory->setSimpleCreateWidgetFunction<ProjectSettingsWidget>(QIcon()); panelFactory->setCreateWidgetFunction([](Project *project) { return new ProjectSettingsWidget(project); });
ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); ProjectPanelFactory::registerFactory(panelFactory);
m_analyzerTool = new ClangStaticAnalyzerTool(this); m_analyzerTool = new ClangStaticAnalyzerTool(this);
addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory(m_analyzerTool)); addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory(m_analyzerTool));

View File

@@ -1,560 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "doubletabwidget.h"
#include "ui_doubletabwidget.h"
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <utils/stylehelper.h>
#include <utils/theme/theme.h>
#include <QDir>
#include <QRect>
#include <QPainter>
#include <QMouseEvent>
#include <QMenu>
#include <QToolTip>
using namespace ProjectExplorer::Internal;
using namespace Utils;
static const int MIN_LEFT_MARGIN = 50;
static const int MARGIN = 12;
static const int OTHER_HEIGHT = 38;
static const int SELECTION_IMAGE_WIDTH = 10;
static const int SELECTION_IMAGE_HEIGHT = 20;
static const int OVERFLOW_DROPDOWN_WIDTH = StyleHelper::navigationWidgetHeight();
static void drawFirstLevelSeparator(QPainter *painter, const QPointF &top, const QPointF &bottom)
{
QLinearGradient grad(top, bottom);
if (!creatorTheme()->flag(Theme::FlatProjectsMode)) {
grad.setColorAt(0, QColor(255, 255, 255, 20));
grad.setColorAt(0.4, QColor(255, 255, 255, 60));
grad.setColorAt(0.7, QColor(255, 255, 255, 50));
grad.setColorAt(1, QColor(255, 255, 255, 40));
painter->setPen(QPen(grad, 1));
painter->drawLine(top, bottom);
grad.setColorAt(0, QColor(0, 0, 0, 30));
grad.setColorAt(0.4, QColor(0, 0, 0, 70));
grad.setColorAt(0.7, QColor(0, 0, 0, 70));
grad.setColorAt(1, QColor(0, 0, 0, 40));
painter->setPen(QPen(grad, 1));
painter->drawLine(top - QPoint(1,0), bottom - QPoint(1,0));
} else {
painter->setPen(QPen(creatorTheme()->color(Theme::DoubleTabWidget1stSeparatorColor), 0));
painter->drawLine(top, bottom);
}
}
static void drawSecondLevelSeparator(QPainter *painter, QPoint top, QPoint bottom)
{
QLinearGradient grad(top, bottom);
if (!creatorTheme()->flag(Theme::FlatProjectsMode)) {
grad.setColorAt(0, QColor(255, 255, 255, 0));
grad.setColorAt(0.4, QColor(255, 255, 255, 100));
grad.setColorAt(0.7, QColor(255, 255, 255, 100));
grad.setColorAt(1, QColor(255, 255, 255, 0));
painter->setPen(QPen(grad, 1));
painter->drawLine(top, bottom);
grad.setColorAt(0, QColor(0, 0, 0, 0));
grad.setColorAt(0.4, QColor(0, 0, 0, 100));
grad.setColorAt(0.7, QColor(0, 0, 0, 100));
grad.setColorAt(1, QColor(0, 0, 0, 0));
painter->setPen(QPen(grad, 1));
painter->drawLine(top - QPoint(1,0), bottom - QPoint(1,0));
} else {
painter->setPen(QPen(creatorTheme()->color(Theme::DoubleTabWidget2ndSeparatorColor), 0));
painter->drawLine(top, bottom);
}
}
DoubleTabWidget::DoubleTabWidget(QWidget *parent) :
QWidget(parent),
m_selection(StyleHelper::dpiSpecificImageFile(QLatin1String(":/projectexplorer/images/selection.png"))),
ui(new Ui::DoubleTabWidget)
{
ui->setupUi(this);
}
DoubleTabWidget::~DoubleTabWidget()
{
delete ui;
}
int DoubleTabWidget::currentIndex() const
{
return m_currentIndex;
}
void DoubleTabWidget::setCurrentIndex(int index)
{
Q_ASSERT(index < m_tabs.size());
if (index == m_currentIndex)
return;
m_currentIndex = index;
emit currentIndexChanged(m_currentIndex, m_tabs.at(m_currentIndex).currentSubTab);
update();
}
int DoubleTabWidget::currentSubIndex() const
{
if (m_currentIndex >= 0 && m_currentIndex < m_tabs.size())
return m_tabs.at(m_currentIndex).currentSubTab;
return -1;
}
QStringList DoubleTabWidget::subTabs(int index) const
{
if (index >= 0 && index < m_tabs.size())
return m_tabs.at(index).subTabs;
return QStringList();
}
void DoubleTabWidget::setSubTabs(int index, const QStringList &subTabs)
{
if (index >= 0 && index < m_tabs.size())
m_tabs[index].subTabs = subTabs;
update();
}
void DoubleTabWidget::setCurrentIndex(int index, int subIndex)
{
Q_ASSERT(index < m_tabs.size());
if (index == m_currentIndex
&& m_tabs.at(m_currentIndex).currentSubTab == subIndex)
return;
m_currentIndex = index;
m_tabs[m_currentIndex].currentSubTab = subIndex;
emit currentIndexChanged(m_currentIndex, m_tabs.at(m_currentIndex).currentSubTab);
update();
}
void DoubleTabWidget::setTitle(const QString &title)
{
m_title = title;
update();
}
QSize DoubleTabWidget::minimumSizeHint() const
{
return QSize(0, StyleHelper::navigationWidgetHeight() + OTHER_HEIGHT);
}
void DoubleTabWidget::updateNameIsUniqueAdd(Tab *tab)
{
tab->nameIsUnique = true;
for (int i = 0; i < m_tabs.size(); ++i) {
if (m_tabs.at(i).name == tab->name) {
m_tabs[i].nameIsUnique = false;
tab->nameIsUnique = false;
break;
}
}
}
void DoubleTabWidget::updateNameIsUniqueRemove(const Tab &tab)
{
if (tab.nameIsUnique)
return;
int index = -1;
int count = 0;
for (int i = 0; i < m_tabs.size(); ++i) {
if (m_tabs.at(i).name == tab.name) {
++count;
index = i;
}
}
QTC_ASSERT(index >= 0, return);
if (count == 1)
m_tabs[index].nameIsUnique = true;
}
void DoubleTabWidget::addTab(const QString &name, const QString &fullName, const QStringList &subTabs)
{
Tab tab;
tab.name = name;
tab.fullName = fullName;
tab.subTabs = subTabs;
tab.currentSubTab = tab.subTabs.isEmpty() ? -1 : 0;
updateNameIsUniqueAdd(&tab);
m_tabs.append(tab);
update();
}
void DoubleTabWidget::insertTab(int index, const QString &name, const QString &fullName, const QStringList &subTabs)
{
Tab tab;
tab.name = name;
tab.fullName = fullName;
tab.subTabs = subTabs;
tab.currentSubTab = tab.subTabs.isEmpty() ? -1 : 0;
updateNameIsUniqueAdd(&tab);
m_tabs.insert(index, tab);
if (m_currentIndex >= index) {
++m_currentIndex;
emit currentIndexChanged(m_currentIndex, m_tabs.at(m_currentIndex).currentSubTab);
}
update();
}
void DoubleTabWidget::removeTab(int index)
{
Tab t = m_tabs.takeAt(index);
updateNameIsUniqueRemove(t);
if (index <= m_currentIndex) {
--m_currentIndex;
if (m_currentIndex < 0 && m_tabs.size() > 0)
m_currentIndex = 0;
if (m_currentIndex < 0)
emit currentIndexChanged(-1, -1);
else
emit currentIndexChanged(m_currentIndex, m_tabs.at(m_currentIndex).currentSubTab);
}
update();
}
int DoubleTabWidget::tabCount() const
{
return m_tabs.size();
}
/// Converts a position to the tab/subtab that is undeneath
/// If HitArea is tab or subtab, then the second part of the pair
/// is the tab or subtab number
QPair<DoubleTabWidget::HitArea, int> DoubleTabWidget::convertPosToTab(QPoint pos)
{
if (pos.y() < StyleHelper::navigationWidgetHeight()) {
// on the top level part of the bar
int eventX = pos.x();
QFontMetrics fm(font());
int x = m_title.isEmpty() ? 0 :
2 * MARGIN + qMax(fm.width(m_title), MIN_LEFT_MARGIN);
if (eventX <= x)
return qMakePair(HITNOTHING, -1);
int i;
for (i = 0; i <= m_lastVisibleIndex; ++i) {
int otherX = x + 2 * MARGIN + fm.width(m_tabs.at(
m_currentTabIndices.at(i)).displayName());
if (eventX > x && eventX < otherX)
break;
x = otherX;
}
if (i <= m_lastVisibleIndex) {
return qMakePair(HITTAB, i);
} else if (m_lastVisibleIndex < m_tabs.size() - 1) {
// handle overflow menu
if (eventX > x && eventX < x + OVERFLOW_DROPDOWN_WIDTH)
return qMakePair(HITOVERFLOW, -1);
}
} else if (pos.y() < StyleHelper::navigationWidgetHeight() + OTHER_HEIGHT) {
int diff = (OTHER_HEIGHT - SELECTION_IMAGE_HEIGHT) / 2;
if (pos.y() < StyleHelper::navigationWidgetHeight() + diff
|| pos.y() > StyleHelper::navigationWidgetHeight() + OTHER_HEIGHT - diff)
return qMakePair(HITNOTHING, -1);
// on the lower level part of the bar
if (m_currentIndex == -1)
return qMakePair(HITNOTHING, -1);
Tab currentTab = m_tabs.at(m_currentIndex);
QStringList subTabs = currentTab.subTabs;
if (subTabs.isEmpty())
return qMakePair(HITNOTHING, -1);
int eventX = pos.x();
QFontMetrics fm(font());
int x = MARGIN;
int i;
for (i = 0; i < subTabs.size(); ++i) {
int otherX = x + 2 * SELECTION_IMAGE_WIDTH + fm.width(subTabs.at(i));
if (eventX > x && eventX < otherX)
break;
x = otherX + 2 * MARGIN;
}
if (i < subTabs.size())
return qMakePair(HITSUBTAB, i);
}
return qMakePair(HITNOTHING, -1);
}
void DoubleTabWidget::mousePressEvent(QMouseEvent *event)
{
// todo:
// the even wasn't accepted/ignored in a consistent way
// now the event is accepted everywhere were it hitted something interesting
// and otherwise ignored
// should not make any difference
QPair<HitArea, int> hit = convertPosToTab(event->pos());
if (hit.first == HITTAB) {
if (m_currentIndex != m_currentTabIndices.at(hit.second)) {
m_currentIndex = m_currentTabIndices.at(hit.second);
update();
event->accept();
emit currentIndexChanged(m_currentIndex, m_tabs.at(m_currentIndex).currentSubTab);
return;
}
} else if (hit.first == HITOVERFLOW) {
QMenu overflowMenu;
QList<QAction *> actions;
for (int i = m_lastVisibleIndex + 1; i < m_tabs.size(); ++i) {
actions << overflowMenu.addAction(m_tabs.at(m_currentTabIndices.at(i)).displayName());
}
if (QAction *action = overflowMenu.exec(event->globalPos())) { // todo used different position before
int index = m_currentTabIndices.at(actions.indexOf(action) + m_lastVisibleIndex + 1);
if (m_currentIndex != index) {
m_currentIndex = index;
update();
event->accept();
emit currentIndexChanged(m_currentIndex, m_tabs.at(m_currentIndex).currentSubTab);
return;
}
}
} else if (hit.first == HITSUBTAB) {
if (m_tabs[m_currentIndex].currentSubTab != hit.second) {
m_tabs[m_currentIndex].currentSubTab = hit.second;
update();
// todo next two lines were outside the if leading to
// unnecessary (?) signal emissions?
event->accept();
emit currentIndexChanged(m_currentIndex, m_tabs.at(m_currentIndex).currentSubTab);
return;
}
}
event->ignore();
}
void DoubleTabWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
QPainter painter(this);
QRect r = rect();
// draw top level tab bar
r.setHeight(StyleHelper::navigationWidgetHeight());
{
QStyleOptionToolBar option;
option.rect = r;
option.state = QStyle::State_Horizontal;
setProperty("panelwidget", true);
QApplication::style()->drawControl(QStyle::CE_ToolBar, &option, &painter, this);
setProperty("panelwidget", false);
}
QFontMetrics fm(font());
int baseline = (r.height() + fm.ascent()) / 2 - 1;
// top level title
if (!m_title.isEmpty()) {
painter.setPen(StyleHelper::panelTextColor());
painter.drawText(MARGIN, baseline, m_title);
}
QLinearGradient grad(QPoint(0, 0), QPoint(0, r.height() + OTHER_HEIGHT));
if (creatorTheme()->flag(Theme::FlatProjectsMode)) {
grad.setColorAt(0, creatorTheme()->color(Theme::DoubleTabWidget1stTabBackgroundColor));
} else {
grad.setColorAt(0, QColor(247, 247, 247));
grad.setColorAt(1, QColor(205, 205, 205));
}
// draw background of second bar
painter.fillRect(QRect(0, r.height(), r.width(), OTHER_HEIGHT), grad);
if (!creatorTheme()->flag(Theme::FlatProjectsMode)) {
painter.setPen(QColor(0x505050));
painter.drawLine(QPointF(0.5, r.height() + OTHER_HEIGHT - 0.5),
QPointF(r.width() - 0.5, r.height() + OTHER_HEIGHT - 0.5));
}
// top level tabs
int x = m_title.isEmpty() ? 0 :
2 * MARGIN + qMax(fm.width(m_title), MIN_LEFT_MARGIN);
// calculate sizes
QList<int> nameWidth;
int width = x;
int indexSmallerThanOverflow = -1;
int indexSmallerThanWidth = -1;
for (int i = 0; i < m_tabs.size(); ++i) {
const Tab &tab = m_tabs.at(i);
int w = fm.width(tab.displayName());
nameWidth << w;
width += 2 * MARGIN + w;
if (width < r.width())
indexSmallerThanWidth = i;
if (width < r.width() - OVERFLOW_DROPDOWN_WIDTH)
indexSmallerThanOverflow = i;
}
m_lastVisibleIndex = -1;
m_currentTabIndices.resize(m_tabs.size());
if (indexSmallerThanWidth == m_tabs.size() - 1) {
// => everything fits
for (int i = 0; i < m_tabs.size(); ++i)
m_currentTabIndices[i] = i;
m_lastVisibleIndex = m_tabs.size()-1;
} else {
// => we need the overflow thingy
if (m_currentIndex <= indexSmallerThanOverflow) {
// easy going, simply draw everything that fits
for (int i = 0; i < m_tabs.size(); ++i)
m_currentTabIndices[i] = i;
m_lastVisibleIndex = indexSmallerThanOverflow;
} else {
// now we need to put the current tab into
// visible range. for that we need to find the place
// to put it, so it fits
width = x;
int index = 0;
bool handledCurrentIndex = false;
for (int i = 0; i < m_tabs.size(); ++i) {
if (index != m_currentIndex) {
if (!handledCurrentIndex) {
// check if enough room for current tab after this one
if (width + 2 * MARGIN + nameWidth.at(index)
+ 2 * MARGIN + nameWidth.at(m_currentIndex)
< r.width() - OVERFLOW_DROPDOWN_WIDTH) {
m_currentTabIndices[i] = index;
++index;
width += 2 * MARGIN + nameWidth.at(index);
} else {
m_currentTabIndices[i] = m_currentIndex;
handledCurrentIndex = true;
m_lastVisibleIndex = i;
}
} else {
m_currentTabIndices[i] = index;
++index;
}
} else {
++index;
--i;
}
}
}
}
// actually draw top level tabs
for (int i = 0; i <= m_lastVisibleIndex; ++i) {
int actualIndex = m_currentTabIndices.at(i);
Tab tab = m_tabs.at(actualIndex);
if (actualIndex == m_currentIndex) {
painter.setPen(StyleHelper::borderColor());
painter.drawLine(QLineF(x - 0.5, 0.5, x - 0.5, r.height() - 1.5));
painter.fillRect(QRect(x, 0,
2 * MARGIN + fm.width(tab.displayName()),
r.height() + 1),
grad);
if (actualIndex != 0 && !creatorTheme()->flag(Theme::FlatProjectsMode)) {
painter.setPen(QColor(255, 255, 255, 170));
painter.drawLine(QLineF(x + 0.5, 0.5, x + 0.5, r.height() - 0.5));
}
x += MARGIN;
painter.setPen(creatorTheme()->color(Theme::DoubleTabWidget1stTabActiveTextColor));
painter.drawText(x, baseline, tab.displayName());
x += nameWidth.at(actualIndex);
x += MARGIN;
if (!creatorTheme()->flag(Theme::FlatProjectsMode)) {
painter.setPen(StyleHelper::borderColor());
painter.drawLine(QLineF(x + 0.5, 0.5, x + 0.5, r.height() - 0.5));
painter.setPen(QColor(0, 0, 0, 20));
painter.drawLine(QLineF(x + 1.5, 0.5, x + 1.5, r.height() - 0.5));
painter.setPen(QColor(255, 255, 255, 170));
painter.drawLine(QLineF(x - 0.5, 0.5, x - 0.5, r.height() - 0.5));
}
} else {
x += MARGIN;
painter.setPen(creatorTheme()->color(Theme::DoubleTabWidget1stTabInactiveTextColor));
painter.drawText(x + 1, baseline, tab.displayName());
x += nameWidth.at(actualIndex);
x += MARGIN;
drawFirstLevelSeparator(&painter, QPointF(x + 0.5, 0.5), QPointF(x + 0.5, r.height() - 0.5));
}
}
// draw overflow button
if (m_lastVisibleIndex < m_tabs.size() - 1) {
QStyleOption opt;
opt.rect = QRect(x, 0, OVERFLOW_DROPDOWN_WIDTH - 1, r.height() - 1);
style()->drawPrimitive(QStyle::PE_IndicatorArrowDown,
&opt, &painter, this);
drawFirstLevelSeparator(&painter, QPointF(x + OVERFLOW_DROPDOWN_WIDTH + 0.5, 0.5),
QPointF(x + OVERFLOW_DROPDOWN_WIDTH + 0.5, r.height() - 0.5));
}
// second level tabs
if (m_currentIndex != -1) {
int imageHeight = static_cast<int>(m_selection.height() / m_selection.devicePixelRatio());
int y = r.height() + (OTHER_HEIGHT - imageHeight) / 2;
Tab currentTab = m_tabs.at(m_currentIndex);
QStringList subTabs = currentTab.subTabs;
x = 0;
for (int i = 0; i < subTabs.size(); ++i) {
x += MARGIN;
int textWidth = fm.width(subTabs.at(i));
if (currentTab.currentSubTab == i) {
const QRect tabRect(x, y, 2 * SELECTION_IMAGE_WIDTH + textWidth, imageHeight);
if (!creatorTheme()->flag(Theme::FlatProjectsMode)) {
StyleHelper::drawCornerImage(m_selection, &painter, tabRect, 15, 0, 15, 0);
} else {
painter.setBrush(creatorTheme()->color(Theme::DoubleTabWidget2ndTabBackgroundColor));
painter.setPen(Qt::NoPen);
painter.drawRoundedRect(tabRect, 5, 5);
}
painter.setPen(creatorTheme()->color(Theme::DoubleTabWidget2ndTabActiveTextColor));
} else {
painter.setPen(creatorTheme()->color(Theme::DoubleTabWidget2ndTabInactiveTextColor));
}
x += SELECTION_IMAGE_WIDTH;
painter.drawText(x, y + (imageHeight + fm.ascent()) / 2. - 1,
subTabs.at(i));
x += textWidth + SELECTION_IMAGE_WIDTH + MARGIN;
drawSecondLevelSeparator(&painter, QPoint(x, y), QPoint(x, y + imageHeight));
}
}
}
bool DoubleTabWidget::event(QEvent *event)
{
if (event->type() == QEvent::ToolTip) {
auto helpevent = static_cast<QHelpEvent*>(event);
QPair<HitArea, int> hit = convertPosToTab(helpevent->pos());
if (hit.first == HITTAB && m_tabs.at(m_currentTabIndices.at(hit.second)).nameIsUnique) {
const QString &fileName = m_tabs.at(m_currentTabIndices.at(hit.second)).fullName;
QToolTip::showText(helpevent->globalPos(), FileName::fromString(fileName).toUserOutput(), this);
} else {
QToolTip::showText(helpevent->globalPos(), QString(), this);
}
}
return QWidget::event(event);
}
QString DoubleTabWidget::Tab::displayName() const
{
return nameIsUnique ? name : QDir::toNativeSeparators(fullName);
}

View File

@@ -1,98 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QVector>
#include <QWidget>
#include <QImage>
namespace ProjectExplorer {
namespace Internal {
namespace Ui { class DoubleTabWidget; }
class DoubleTabWidget : public QWidget
{
Q_OBJECT
public:
explicit DoubleTabWidget(QWidget *parent = nullptr);
~DoubleTabWidget() override;
void setTitle(const QString &title);
QString title() const { return m_title; }
void addTab(const QString &name, const QString &fullName, const QStringList &subTabs);
void insertTab(int index, const QString &name, const QString &fullName, const QStringList &subTabs);
void removeTab(int index);
int tabCount() const;
int currentIndex() const;
void setCurrentIndex(int index);
void setCurrentIndex(int index, int subIndex);
int currentSubIndex() const;
QStringList subTabs(int index) const;
void setSubTabs(int index, const QStringList &subTabs);
signals:
void currentIndexChanged(int index, int subIndex);
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
bool event(QEvent *event) override;
QSize minimumSizeHint() const override;
private:
class Tab {
public:
QString name;
QString fullName;
bool nameIsUnique;
QStringList subTabs;
int currentSubTab;
QString displayName() const;
};
void updateNameIsUniqueAdd(Tab *tab);
void updateNameIsUniqueRemove(const Tab &tab);
enum HitArea { HITNOTHING, HITOVERFLOW, HITTAB, HITSUBTAB };
QPair<DoubleTabWidget::HitArea, int> convertPosToTab(QPoint pos);
const QImage m_selection;
Ui::DoubleTabWidget *ui;
QString m_title;
QList<Tab> m_tabs;
int m_currentIndex = -1;
int m_lastVisibleIndex = -1;
QVector<int> m_currentTabIndices;
};
} // namespace Internal
} // namespace ProjectExplorer

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProjectExplorer::Internal::DoubleTabWidget</class>
<widget class="QWidget" name="ProjectExplorer::Internal::DoubleTabWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>400</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>DoubleTabWidget</string>
</property>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 931 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 B

View File

@@ -34,6 +34,7 @@
#include <utils/stylehelper.h> #include <utils/stylehelper.h>
#include <utils/theme/theme.h> #include <utils/theme/theme.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/styledbar.h>
namespace { namespace {
const int ICON_SIZE(64); const int ICON_SIZE(64);
@@ -106,14 +107,13 @@ void RootWidget::paintEvent(QPaintEvent *e)
/// ///
PanelsWidget::PanelsWidget(QWidget *parent) : PanelsWidget::PanelsWidget(QWidget *parent) :
QScrollArea(parent), QWidget(parent),
m_root(new RootWidget(this)) m_root(new RootWidget(this))
{ {
// We want a 900px wide widget with and the scrollbar at the // We want a 900px wide widget with and the scrollbar at the
// side of the screen. // side of the screen.
m_root->setMaximumWidth(900); m_root->setMaximumWidth(900);
m_root->setContentsMargins(0, 0, 40, 0); m_root->setContentsMargins(0, 0, 40, 0);
QPalette pal; QPalette pal;
QColor background = StyleHelper::mergedColors( QColor background = StyleHelper::mergedColors(
palette().window().color(), Qt::white, 85); palette().window().color(), Qt::white, 85);
@@ -122,6 +122,13 @@ PanelsWidget::PanelsWidget(QWidget *parent) :
pal.setColor(QPalette::All, QPalette::Window, background); pal.setColor(QPalette::All, QPalette::Window, background);
m_root->setPalette(pal); m_root->setPalette(pal);
m_scroller = new QScrollArea(this);
m_scroller->setWidget(m_root);
m_scroller->setFrameStyle(QFrame::NoFrame);
m_scroller->setWidgetResizable(true);
m_scroller->setFocusPolicy(Qt::NoFocus);
// The layout holding the individual panels: // The layout holding the individual panels:
auto topLayout = new QVBoxLayout(m_root); auto topLayout = new QVBoxLayout(m_root);
topLayout->setMargin(0); topLayout->setMargin(0);
@@ -130,13 +137,17 @@ PanelsWidget::PanelsWidget(QWidget *parent) :
m_layout = new QGridLayout; m_layout = new QGridLayout;
m_layout->setColumnMinimumWidth(0, ICON_SIZE + 4); m_layout->setColumnMinimumWidth(0, ICON_SIZE + 4);
m_layout->setSpacing(0); m_layout->setSpacing(0);
topLayout->addLayout(m_layout); topLayout->addLayout(m_layout);
topLayout->addStretch(100); topLayout->addStretch(100);
setWidget(m_root); auto layout = new QVBoxLayout(this);
setFrameStyle(QFrame::NoFrame); layout->setContentsMargins(0, 0, 0, 0);
setWidgetResizable(true); layout->setSpacing(0);
setFocusPolicy(Qt::NoFocus); layout->addWidget(new Utils::StyledBar(this));
layout->addWidget(m_scroller);
//layout->addWidget(new FindToolBarPlaceHolder(this));
} }
PanelsWidget::~PanelsWidget() PanelsWidget::~PanelsWidget()

View File

@@ -36,7 +36,7 @@ QT_END_NAMESPACE
namespace ProjectExplorer { namespace ProjectExplorer {
class PropertiesPanel; class PropertiesPanel;
class PROJECTEXPLORER_EXPORT PanelsWidget : public QScrollArea class PROJECTEXPLORER_EXPORT PanelsWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
@@ -51,6 +51,7 @@ private:
QList<PropertiesPanel *> m_panels; QList<PropertiesPanel *> m_panels;
QGridLayout *m_layout; QGridLayout *m_layout;
QScrollArea *m_scroller;
QWidget *m_root; QWidget *m_root;
}; };

View File

@@ -274,10 +274,9 @@ Target *Project::createTarget(Kit *k)
return t; return t;
} }
Target *Project::cloneTarget(Target *sourceTarget, Kit *k) bool Project::copySteps(Target *sourceTarget, Target *newTarget)
{ {
auto newTarget = new Target(this, k); bool fatalError = false;
QStringList buildconfigurationError; QStringList buildconfigurationError;
QStringList deployconfigurationError; QStringList deployconfigurationError;
QStringList runconfigurationError; QStringList runconfigurationError;
@@ -348,7 +347,6 @@ Target *Project::cloneTarget(Target *sourceTarget, Kit *k)
newTarget->setActiveRunConfiguration(rcs.first()); newTarget->setActiveRunConfiguration(rcs.first());
} }
bool fatalError = false;
if (buildconfigurationError.count() == sourceTarget->buildConfigurations().count()) if (buildconfigurationError.count() == sourceTarget->buildConfigurations().count())
fatalError = true; fatalError = true;
@@ -364,10 +362,7 @@ Target *Project::cloneTarget(Target *sourceTarget, Kit *k)
tr("Incompatible Kit"), tr("Incompatible Kit"),
tr("Kit %1 is incompatible with kit %2.") tr("Kit %1 is incompatible with kit %2.")
.arg(sourceTarget->kit()->displayName()) .arg(sourceTarget->kit()->displayName())
.arg(k->displayName())); .arg(newTarget->kit()->displayName()));
delete newTarget;
newTarget = nullptr;
} else if (!buildconfigurationError.isEmpty() } else if (!buildconfigurationError.isEmpty()
|| !deployconfigurationError.isEmpty() || !deployconfigurationError.isEmpty()
|| ! runconfigurationError.isEmpty()) { || ! runconfigurationError.isEmpty()) {
@@ -397,13 +392,10 @@ Target *Project::cloneTarget(Target *sourceTarget, Kit *k)
msgBox.setText(tr("Some configurations could not be copied.")); msgBox.setText(tr("Some configurations could not be copied."));
msgBox.setDetailedText(error); msgBox.setDetailedText(error);
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
if (msgBox.exec() != QDialog::Accepted) { fatalError = msgBox.exec() != QDialog::Accepted;
delete newTarget;
newTarget = nullptr;
}
} }
return newTarget; return !fatalError;
} }
bool Project::setupTarget(Target *t) bool Project::setupTarget(Target *t)

View File

@@ -101,7 +101,7 @@ public:
virtual bool supportsKit(Kit *k, QString *errorMessage = nullptr) const; virtual bool supportsKit(Kit *k, QString *errorMessage = nullptr) const;
Target *createTarget(Kit *k); Target *createTarget(Kit *k);
Target *cloneTarget(Target *sourceTarget, Kit *k); static bool copySteps(Target *sourceTarget, Target *newTarget);
Target *restoreTarget(const QVariantMap &data); Target *restoreTarget(const QVariantMap &data);
void saveSettings(); void saveSettings();

View File

@@ -42,7 +42,6 @@
#include "projectexplorersettings.h" #include "projectexplorersettings.h"
#include "projectexplorersettingspage.h" #include "projectexplorersettingspage.h"
#include "removetaskhandler.h" #include "removetaskhandler.h"
#include "unconfiguredprojectpanel.h"
#include "kitfeatureprovider.h" #include "kitfeatureprovider.h"
#include "kitmanager.h" #include "kitmanager.h"
#include "kitoptionspage.h" #include "kitoptionspage.h"
@@ -529,7 +528,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
dd->m_projectsMode = new ProjectsMode(dd->m_proWindow); dd->m_projectsMode = new ProjectsMode(dd->m_proWindow);
dd->m_projectsMode->setEnabled(false); dd->m_projectsMode->setEnabled(false);
addAutoReleasedObject(dd->m_projectsMode); addAutoReleasedObject(dd->m_projectsMode);
dd->m_proWindow->layout()->addWidget(new FindToolBarPlaceHolder(dd->m_proWindow));
addAutoReleasedObject(new CopyTaskHandler); addAutoReleasedObject(new CopyTaskHandler);
addAutoReleasedObject(new ShowInEditorTaskHandler); addAutoReleasedObject(new ShowInEditorTaskHandler);
@@ -556,51 +554,35 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
addAutoReleasedObject(new CurrentProjectFilter); addAutoReleasedObject(new CurrentProjectFilter);
// ProjectPanelFactories // ProjectPanelFactories
auto editorSettingsPanelFactory = new ProjectPanelFactory; auto panelFactory = new ProjectPanelFactory;
editorSettingsPanelFactory->setPriority(30); panelFactory->setPriority(30);
QString displayName = QCoreApplication::translate("EditorSettingsPanelFactory", "Editor"); panelFactory->setDisplayName(QCoreApplication::translate("EditorSettingsPanelFactory", "Editor"));
editorSettingsPanelFactory->setDisplayName(displayName); panelFactory->setIcon(":/projectexplorer/images/EditorSettings.png");
QIcon icon = QIcon(QLatin1String(":/projectexplorer/images/EditorSettings.png")); panelFactory->setCreateWidgetFunction([](Project *project) { return new EditorSettingsWidget(project); });
editorSettingsPanelFactory->setSimpleCreateWidgetFunction<EditorSettingsWidget>(icon); ProjectPanelFactory::registerFactory(panelFactory);
ProjectPanelFactory::registerFactory(editorSettingsPanelFactory);
auto codeStyleSettingsPanelFactory = new ProjectPanelFactory; panelFactory = new ProjectPanelFactory;
codeStyleSettingsPanelFactory->setPriority(40); panelFactory->setPriority(40);
displayName = QCoreApplication::translate("CodeStyleSettingsPanelFactory", "Code Style"); panelFactory->setDisplayName(QCoreApplication::translate("CodeStyleSettingsPanelFactory", "Code Style"));
codeStyleSettingsPanelFactory->setDisplayName(displayName); panelFactory->setIcon(":/projectexplorer/images/CodeStyleSettings.png");
icon = QIcon(QLatin1String(":/projectexplorer/images/CodeStyleSettings.png")); panelFactory->setCreateWidgetFunction([](Project *project) { return new CodeStyleSettingsWidget(project); });
codeStyleSettingsPanelFactory->setSimpleCreateWidgetFunction<CodeStyleSettingsWidget>(icon); ProjectPanelFactory::registerFactory(panelFactory);
ProjectPanelFactory::registerFactory(codeStyleSettingsPanelFactory);
auto dependenciesPanelFactory = new ProjectPanelFactory; panelFactory = new ProjectPanelFactory;
dependenciesPanelFactory->setPriority(50); panelFactory->setPriority(50);
displayName = QCoreApplication::translate("DependenciesPanelFactory", "Dependencies"); panelFactory->setDisplayName(QCoreApplication::translate("DependenciesPanelFactory", "Dependencies"));
dependenciesPanelFactory->setDisplayName(displayName); panelFactory->setIcon(":/projectexplorer/images/ProjectDependencies.png");
icon = QIcon(QLatin1String(":/projectexplorer/images/ProjectDependencies.png")); panelFactory->setCreateWidgetFunction([](Project *project) { return new DependenciesWidget(project); });
dependenciesPanelFactory->setSimpleCreateWidgetFunction<DependenciesWidget>(icon); ProjectPanelFactory::registerFactory(panelFactory);
ProjectPanelFactory::registerFactory(dependenciesPanelFactory);
auto unconfiguredProjectPanel = new ProjectPanelFactory; panelFactory = new ProjectPanelFactory;
unconfiguredProjectPanel->setPriority(-10); panelFactory->setPriority(-10);
unconfiguredProjectPanel->setDisplayName(tr("Configure Project")); panelFactory->setDisplayName(QCoreApplication::translate("TargetSettingsPanelFactory", "Build & Run"));
unconfiguredProjectPanel->setSupportsFunction([](Project *project){ panelFactory->setSupportsFunction([](Project *project) { return project->requiresTargetPanel() || project->needsConfiguration(); });
return project->needsConfiguration(); panelFactory->setSelectorItemCreator([panelFactory](Project *project) {
return new TargetSettingsPanelItem(panelFactory, project);
}); });
icon = QIcon(QLatin1String(":/projectexplorer/images/unconfigured.png")); ProjectPanelFactory::registerFactory(panelFactory);
unconfiguredProjectPanel->setSimpleCreateWidgetFunction<TargetSetupPageWrapper>(icon);
ProjectPanelFactory::registerFactory(unconfiguredProjectPanel);
auto targetSettingsPanelFactory = new ProjectPanelFactory;
targetSettingsPanelFactory->setPriority(-10);
displayName = QCoreApplication::translate("TargetSettingsPanelFactory", "Build & Run");
targetSettingsPanelFactory->setDisplayName(displayName);
targetSettingsPanelFactory->setSupportsFunction([](Project *project) {
return project->requiresTargetPanel();
});
targetSettingsPanelFactory->setCreateWidgetFunction([](Project *project) {
return new TargetSettingsPanelWidget(project);
});
ProjectPanelFactory::registerFactory(targetSettingsPanelFactory);
addAutoReleasedObject(new ProcessStepFactory); addAutoReleasedObject(new ProcessStepFactory);
@@ -1524,7 +1506,6 @@ ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown()
disconnect(ModeManager::instance(), &ModeManager::currentModeChanged, disconnect(ModeManager::instance(), &ModeManager::currentModeChanged,
dd, &ProjectExplorerPluginPrivate::currentModeChanged); dd, &ProjectExplorerPluginPrivate::currentModeChanged);
ProjectTree::aboutToShutDown(); ProjectTree::aboutToShutDown();
dd->m_proWindow->aboutToShutdown(); // disconnect from session
SessionManager::closeAllProjects(); SessionManager::closeAllProjects();
dd->m_projectsMode = nullptr; dd->m_projectsMode = nullptr;
dd->m_shuttingDown = true; dd->m_shuttingDown = true;
@@ -2333,11 +2314,6 @@ void ProjectExplorerPlugin::buildProject(Project *p)
QList<Id>() << Id(Constants::BUILDSTEPS_BUILD)); QList<Id>() << Id(Constants::BUILDSTEPS_BUILD));
} }
void ProjectExplorerPlugin::requestProjectModeUpdate(Project *p)
{
dd->m_proWindow->projectUpdated(p);
}
void ProjectExplorerPluginPrivate::handleBuildProject() void ProjectExplorerPluginPrivate::handleBuildProject()
{ {
queue(SessionManager::projectOrder(SessionManager::startupProject()), queue(SessionManager::projectOrder(SessionManager::startupProject()),

View File

@@ -143,9 +143,6 @@ public:
static void addExistingFiles(FolderNode *folderNode, const QStringList &filePaths); static void addExistingFiles(FolderNode *folderNode, const QStringList &filePaths);
static void buildProject(Project *p); static void buildProject(Project *p);
/// Normally there's no need to call this function.
/// This function needs to be called, only if the pages that support a project changed.
static void requestProjectModeUpdate(Project *p);
static void initiateInlineRenaming(); static void initiateInlineRenaming();

View File

@@ -23,7 +23,6 @@ HEADERS += projectexplorer.h \
removetaskhandler.h \ removetaskhandler.h \
targetsetuppage.h \ targetsetuppage.h \
targetsetupwidget.h \ targetsetupwidget.h \
unconfiguredprojectpanel.h \
kit.h \ kit.h \
kitchooser.h \ kitchooser.h \
kitconfigwidget.h \ kitconfigwidget.h \
@@ -92,9 +91,6 @@ HEADERS += projectexplorer.h \
projectexplorersettingspage.h \ projectexplorersettingspage.h \
baseprojectwizarddialog.h \ baseprojectwizarddialog.h \
miniprojecttargetselector.h \ miniprojecttargetselector.h \
targetselector.h \
targetsettingswidget.h \
doubletabwidget.h \
buildenvironmentwidget.h \ buildenvironmentwidget.h \
ldparser.h \ ldparser.h \
linuxiccparser.h \ linuxiccparser.h \
@@ -177,7 +173,6 @@ SOURCES += projectexplorer.cpp \
removetaskhandler.cpp \ removetaskhandler.cpp \
targetsetuppage.cpp \ targetsetuppage.cpp \
targetsetupwidget.cpp \ targetsetupwidget.cpp \
unconfiguredprojectpanel.cpp \
kit.cpp \ kit.cpp \
kitchooser.cpp \ kitchooser.cpp \
kitconfigwidget.cpp \ kitconfigwidget.cpp \
@@ -242,9 +237,6 @@ SOURCES += projectexplorer.cpp \
projectexplorersettingspage.cpp \ projectexplorersettingspage.cpp \
baseprojectwizarddialog.cpp \ baseprojectwizarddialog.cpp \
miniprojecttargetselector.cpp \ miniprojecttargetselector.cpp \
targetselector.cpp \
targetsettingswidget.cpp \
doubletabwidget.cpp \
buildenvironmentwidget.cpp \ buildenvironmentwidget.cpp \
ldparser.cpp \ ldparser.cpp \
linuxiccparser.cpp \ linuxiccparser.cpp \
@@ -305,7 +297,6 @@ FORMS += processstep.ui \
sessiondialog.ui \ sessiondialog.ui \
projectwizardpage.ui \ projectwizardpage.ui \
projectexplorersettingspage.ui \ projectexplorersettingspage.ui \
doubletabwidget.ui \
deploymentdataview.ui \ deploymentdataview.ui \
codestylesettingspropertiespage.ui \ codestylesettingspropertiespage.ui \
devicesupport/devicefactoryselectiondialog.ui \ devicesupport/devicefactoryselectiondialog.ui \

View File

@@ -67,7 +67,6 @@ Project {
"deploymentdataview.ui", "deploymentdataview.ui",
"deploymentdatamodel.cpp", "deploymentdatamodel.cpp",
"deploymentdatamodel.h", "deploymentdatamodel.h",
"doubletabwidget.cpp", "doubletabwidget.h", "doubletabwidget.ui",
"editorconfiguration.cpp", "editorconfiguration.h", "editorconfiguration.cpp", "editorconfiguration.h",
"editorsettingspropertiespage.cpp", "editorsettingspropertiespage.h", "editorsettingspropertiespage.ui", "editorsettingspropertiespage.cpp", "editorsettingspropertiespage.h", "editorsettingspropertiespage.ui",
"environmentaspect.cpp", "environmentaspect.h", "environmentaspect.cpp", "environmentaspect.h",
@@ -142,9 +141,7 @@ Project {
"showineditortaskhandler.cpp", "showineditortaskhandler.h", "showineditortaskhandler.cpp", "showineditortaskhandler.h",
"showoutputtaskhandler.cpp", "showoutputtaskhandler.h", "showoutputtaskhandler.cpp", "showoutputtaskhandler.h",
"target.cpp", "target.h", "target.cpp", "target.h",
"targetselector.cpp", "targetselector.h",
"targetsettingspanel.cpp", "targetsettingspanel.h", "targetsettingspanel.cpp", "targetsettingspanel.h",
"targetsettingswidget.cpp", "targetsettingswidget.h",
"targetsetuppage.cpp", "targetsetuppage.h", "targetsetuppage.cpp", "targetsetuppage.h",
"targetsetupwidget.cpp", "targetsetupwidget.h", "targetsetupwidget.cpp", "targetsetupwidget.h",
"task.cpp", "task.h", "task.cpp", "task.h",
@@ -155,7 +152,6 @@ Project {
"toolchainconfigwidget.cpp", "toolchainconfigwidget.h", "toolchainconfigwidget.cpp", "toolchainconfigwidget.h",
"toolchainmanager.cpp", "toolchainmanager.h", "toolchainmanager.cpp", "toolchainmanager.h",
"toolchainoptionspage.cpp", "toolchainoptionspage.h", "toolchainoptionspage.cpp", "toolchainoptionspage.h",
"unconfiguredprojectpanel.cpp", "unconfiguredprojectpanel.h",
"vcsannotatetaskhandler.cpp", "vcsannotatetaskhandler.h", "vcsannotatetaskhandler.cpp", "vcsannotatetaskhandler.h",
"waitforstopdialog.cpp", "waitforstopdialog.h", "waitforstopdialog.cpp", "waitforstopdialog.h",
"xcodebuildparser.cpp", "xcodebuildparser.h" "xcodebuildparser.cpp", "xcodebuildparser.h"

View File

@@ -25,13 +25,6 @@
<file>images/analyzer_overlay_small.png</file> <file>images/analyzer_overlay_small.png</file>
<file>images/analyzer_overlay_small@2x.png</file> <file>images/analyzer_overlay_small@2x.png</file>
<file>images/session.png</file> <file>images/session.png</file>
<file>images/targetrunselected.png</file>
<file>images/targetrunselected@2x.png</file>
<file>images/targetseparatorbackground.png</file>
<file>images/targetseparatorbackground@2x.png</file>
<file>images/targetunselected.png</file>
<file>images/selection.png</file>
<file>images/selection@2x.png</file>
<file>images/BuildSettings.png</file> <file>images/BuildSettings.png</file>
<file>images/CodeStyleSettings.png</file> <file>images/CodeStyleSettings.png</file>
<file>images/RunSettings.png</file> <file>images/RunSettings.png</file>
@@ -49,7 +42,6 @@
<file>images/build_hammerhead_mask.png</file> <file>images/build_hammerhead_mask.png</file>
<file>images/build_hammerhead_mask@2x.png</file> <file>images/build_hammerhead_mask@2x.png</file>
<file>images/targetpanel_bottom.png</file> <file>images/targetpanel_bottom.png</file>
<file>images/targetpanel_gradient.png</file>
<file>images/window.png</file> <file>images/window.png</file>
<file>images/continue_1_small.png</file> <file>images/continue_1_small.png</file>
<file>images/continue_1_small@2x.png</file> <file>images/continue_1_small@2x.png</file>
@@ -64,12 +56,6 @@
<file>images/buildstepremove.png</file> <file>images/buildstepremove.png</file>
<file>images/buildstepremove@2x.png</file> <file>images/buildstepremove@2x.png</file>
<file>images/unconfigured.png</file> <file>images/unconfigured.png</file>
<file>images/targetrightbutton.png</file>
<file>images/targetrightbutton@2x.png</file>
<file>images/targetchangebutton.png</file>
<file>images/targetchangebutton@2x.png</file>
<file>images/targetchangebutton2.png</file>
<file>images/targetchangebutton2@2x.png</file>
<file>images/desktopdevice.png</file> <file>images/desktopdevice.png</file>
<file>images/desktopdevice@2x.png</file> <file>images/desktopdevice@2x.png</file>
<file>images/fileoverlay_qml.png</file> <file>images/fileoverlay_qml.png</file>

View File

@@ -25,12 +25,101 @@
#include "projectpanelfactory.h" #include "projectpanelfactory.h"
#include "project.h"
#include "projectwindow.h"
#include "propertiespanel.h"
using namespace ProjectExplorer::Internal;
using namespace Utils;
namespace ProjectExplorer { namespace ProjectExplorer {
namespace Internal {
static QList<ProjectPanelFactory *> s_factories; static QList<ProjectPanelFactory *> s_factories;
ProjectPanelFactory::ProjectPanelFactory() : // Standard second level for the generic case: i.e. all except for the Build/Run page
m_supportsFunction([] (Project *) { return true; }) class ProjectPanelItem : public TreeItem
{
public:
using WidgetCreator = std::function<QWidget *(Project *Project)>;
ProjectPanelItem(ProjectPanelFactory *factory, Project *project,
const WidgetCreator &widgetCreator)
: m_factory(factory), m_project(project), m_widgetCreator(widgetCreator)
{}
~ProjectPanelItem() { delete m_widget; }
QVariant data(int column, int role) const override;
Qt::ItemFlags flags(int column) const override;
bool setData(int column, const QVariant &, int role) override;
protected:
ProjectPanelFactory *m_factory = nullptr;
QPointer<Project> m_project;
WidgetCreator m_widgetCreator;
mutable QPointer<QWidget> m_widget = nullptr;
};
QVariant ProjectPanelItem::data(int column, int role) const
{
Q_UNUSED(column)
if (role == Qt::DisplayRole) {
if (m_factory)
return m_factory->displayName();
}
// if (role == Qt::DecorationRole) {
// if (m_factory)
// return QIcon(m_factory->icon());
// }
if (role == ActiveWidgetRole) {
if (!m_widget) {
auto panelsWidget = new PanelsWidget;
auto panel = new PropertiesPanel;
panel->setDisplayName(m_factory->displayName());
QWidget *widget = m_widgetCreator(m_project);
panel->setWidget(widget);
panel->setIcon(QIcon(m_factory->icon()));
panelsWidget->addPropertiesPanel(panel);
panelsWidget->setFocusProxy(widget);
m_widget = panelsWidget;
}
return QVariant::fromValue<QWidget *>(m_widget.data());
}
if (role == ActiveIndexRole) // We are the active one.
return QVariant::fromValue(index());
return QVariant();
}
Qt::ItemFlags ProjectPanelItem::flags(int column) const
{
if (m_factory && m_project) {
if (!m_factory->supports(m_project))
return Qt::ItemIsSelectable;
}
return TreeItem::flags(column);
}
bool ProjectPanelItem::setData(int column, const QVariant &, int role)
{
if (role == ItemActivaterRole) {
// Bubble up
return parent()->setData(column, QVariant::fromValue(static_cast<TreeItem *>(this)), role);
}
return false;
}
} // Internal
ProjectPanelFactory::ProjectPanelFactory()
: m_supportsFunction([] (Project *) { return true; })
{ } { }
int ProjectPanelFactory::priority() const int ProjectPanelFactory::priority() const
@@ -68,12 +157,39 @@ QList<ProjectPanelFactory *> ProjectPanelFactory::factories()
return s_factories; return s_factories;
} }
TreeItem *ProjectPanelFactory::createSelectorItem(Project *project)
{
if (m_selectorItemCreator)
return m_selectorItemCreator(project);
return new Internal::ProjectPanelItem(this, project, m_widgetCreator);
}
void ProjectPanelFactory::destroyFactories() void ProjectPanelFactory::destroyFactories()
{ {
qDeleteAll(s_factories); qDeleteAll(s_factories);
s_factories.clear(); s_factories.clear();
} }
QString ProjectPanelFactory::icon() const
{
return m_icon;
}
void ProjectPanelFactory::setIcon(const QString &icon)
{
m_icon = icon;
}
void ProjectPanelFactory::setCreateWidgetFunction(const WidgetCreator &createWidgetFunction)
{
m_widgetCreator = createWidgetFunction;
}
void ProjectPanelFactory::setSelectorItemCreator(const SelectorItemCreator &selectorCreator)
{
m_selectorItemCreator = selectorCreator;
}
bool ProjectPanelFactory::supports(Project *project) bool ProjectPanelFactory::supports(Project *project)
{ {
return m_supportsFunction(project); return m_supportsFunction(project);
@@ -84,9 +200,4 @@ void ProjectPanelFactory::setSupportsFunction(std::function<bool (Project *)> fu
m_supportsFunction = function; m_supportsFunction = function;
} }
QWidget *ProjectPanelFactory::createWidget(Project *project)
{
return m_createWidgetFunction(project);
}
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -26,8 +26,11 @@
#pragma once #pragma once
#include "projectexplorer_export.h" #include "projectexplorer_export.h"
#include "propertiespanel.h"
#include "panelswidget.h" #include "panelswidget.h"
#include "projectwindow.h"
#include <utils/treemodel.h>
#include <functional> #include <functional>
@@ -49,52 +52,39 @@ public:
// interface for users of ProjectPanelFactory // interface for users of ProjectPanelFactory
bool supports(Project *project); bool supports(Project *project);
QWidget *createWidget(Project *project);
using WidgetCreator = std::function<QWidget *(Project *)>;
using SelectorItemCreator = std::function<Utils::TreeItem *(Project *)>;
// interface for "implementations" of ProjectPanelFactory // interface for "implementations" of ProjectPanelFactory
// by default all projects are supported, only set a custom supports function // by default all projects are supported, only set a custom supports function
// if you need something different // if you need something different
using SupportsFunction = std::function<bool (Project *)>;
void setSupportsFunction(std::function<bool (Project *)> function); void setSupportsFunction(std::function<bool (Project *)> function);
// the simpleCreatePanelFunction creates new instance of T
// wraps that into a PropertiesPanel
// sets the passed in icon on it
// and uses displayName() for the displayname
// Note: call setDisplayName before calling this
template<typename T>
void setSimpleCreateWidgetFunction(const QIcon &icon)
{
m_createWidgetFunction = [icon, this](Project *project) -> QWidget * {
PropertiesPanel *panel = new PropertiesPanel;
panel->setDisplayName(this->displayName());
QWidget *widget = new T(project);
panel->setWidget(widget);
panel->setIcon(icon);
PanelsWidget *panelsWidget = new PanelsWidget();
panelsWidget->addPropertiesPanel(panel);
panelsWidget->setFocusProxy(widget);
return panelsWidget;
};
}
void setCreateWidgetFunction(std::function<QWidget *(Project *)> function)
{
m_createWidgetFunction = function;
}
// This takes ownership. // This takes ownership.
static void registerFactory(ProjectPanelFactory *factory); static void registerFactory(ProjectPanelFactory *factory);
static QList<ProjectPanelFactory *> factories(); static QList<ProjectPanelFactory *> factories();
Utils::TreeItem *createSelectorItem(Project *project);
void setSelectorItemCreator(const SelectorItemCreator &selectorCreator);
QString icon() const;
void setIcon(const QString &icon);
void setCreateWidgetFunction(const WidgetCreator &createWidgetFunction);
private: private:
friend class ProjectExplorerPlugin; friend class ProjectExplorerPlugin;
static void destroyFactories(); static void destroyFactories();
int m_priority = 0; int m_priority = 0;
QString m_displayName; QString m_displayName;
std::function<bool (Project *)> m_supportsFunction; SupportsFunction m_supportsFunction;
std::function<QWidget *(Project *)> m_createWidgetFunction; WidgetCreator m_widgetCreator;
SelectorItemCreator m_selectorItemCreator;
QString m_icon;
}; };
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -25,345 +25,393 @@
#include "projectwindow.h" #include "projectwindow.h"
#include "doubletabwidget.h" #include "kit.h"
#include "panelswidget.h"
#include "kitmanager.h" #include "kitmanager.h"
#include "panelswidget.h"
#include "project.h" #include "project.h"
#include "projectexplorer.h" #include "projectexplorer.h"
#include "projectpanelfactory.h" #include "projectpanelfactory.h"
#include "session.h" #include "session.h"
#include "target.h" #include "target.h"
#include "targetsettingspanel.h"
#include <coreplugin/coreicons.h>
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h> #include <coreplugin/idocument.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QStackedWidget> #include <utils/navigationtreeview.h>
#include <utils/qtcassert.h>
#include <utils/styledbar.h>
#include <utils/treemodel.h>
#include <QApplication>
#include <QComboBox>
#include <QDockWidget>
#include <QHeaderView>
#include <QMenu>
#include <QStyledItemDelegate>
#include <QTreeView>
#include <QVBoxLayout> #include <QVBoxLayout>
using namespace ProjectExplorer; using namespace Core;
using namespace ProjectExplorer::Internal; using namespace Utils;
///
// ProjectWindow
///
ProjectWindow::ProjectWindow(QWidget *parent) namespace ProjectExplorer {
: QWidget(parent), namespace Internal {
m_ignoreChange(false),
m_currentWidget(0) // The first tree level, i.e. projects.
class ProjectItem : public TreeItem
{ {
// Setup overall layout: public:
auto viewLayout = new QVBoxLayout(this); explicit ProjectItem(Project *project) : m_project(project)
viewLayout->setMargin(0); {
viewLayout->setSpacing(0); QTC_ASSERT(m_project, return);
foreach (ProjectPanelFactory *factory, ProjectPanelFactory::factories())
appendChild(factory->createSelectorItem(m_project));
}
m_tabWidget = new DoubleTabWidget(this); QVariant data(int column, int role) const override
viewLayout->addWidget(m_tabWidget); {
switch (role) {
case Qt::DisplayRole:
return m_project->displayName();
// Setup our container for the contents: case ProjectDisplayNameRole:
m_centralWidget = new QStackedWidget(this); return m_project->displayName();
viewLayout->addWidget(m_centralWidget);
// Connections case Qt::DecorationRole: {
connect(m_tabWidget, &DoubleTabWidget::currentIndexChanged, QVariant icon;
this, &ProjectWindow::showProperties); forSecondLevelChildren<TreeItem *>([this, &icon](TreeItem *item) {
QVariant sicon = item->data(0, Qt::DecorationRole);
if (sicon.isValid())
icon = sicon;
});
return icon;
}
case Qt::FontRole: {
QFont font;
font.setBold(m_project == SessionManager::startupProject());
return font;
}
case ActiveWidgetRole:
case ActiveIndexRole:
if (0 <= m_currentPanelIndex && m_currentPanelIndex < childCount())
return childAt(m_currentPanelIndex)->data(column, role);
}
return QVariant();
}
bool setData(int column, const QVariant &data, int role) override
{
Q_UNUSED(column)
if (role == ItemActivaterRole) {
// Possible called from child item.
TreeItem *item = data.value<TreeItem *>();
m_currentPanelIndex = children().indexOf(item);
SessionManager::setStartupProject(m_project);
// Bubble up.
parent()->setData(0, QVariant::fromValue(static_cast<TreeItem *>(this)), role);
return true;
}
return false;
}
Project *project() const { return m_project; }
private:
int m_currentPanelIndex = 0;
Project * const m_project;
};
class RootItem : public TypedTreeItem<ProjectItem>
{
public:
QVariant data(int column, int role) const override
{
if (role == ActiveWidgetRole) {
if (0 <= m_currentProjectIndex && m_currentProjectIndex < childCount())
return childAt(m_currentProjectIndex)->data(column, role);
}
return QVariant();
}
bool setData(int column, const QVariant &data, int role) override
{
Q_UNUSED(column)
if (role == ItemActivaterRole) {
// Possible called from child item.
if (TreeItem *t = data.value<TreeItem *>())
m_currentProjectIndex = children().indexOf(t);
updateAll();
return true;
}
return false;
}
int m_currentProjectIndex = -1;
};
//
// SelectorModel
//
class SelectorModel
: public LeveledTreeModel<RootItem, ProjectItem, TreeItem>
{
Q_OBJECT
public:
SelectorModel(QObject *parent)
: LeveledTreeModel<RootItem, ProjectItem, TreeItem>(parent)
{
setRootItem(new RootItem);
setHeader({ ProjectWindow::tr("Projects") });
}
signals:
void needPanelUpdate();
};
//
// SelectorDelegate
//
class SelectorDelegate : public QStyledItemDelegate
{
public:
SelectorDelegate() {}
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const override
{
QSize s = QStyledItemDelegate::sizeHint(option, index);
auto model = static_cast<const SelectorModel *>(index.model());
TreeItem *item = model->itemForIndex(index);
if (item && item->level() == 2)
s = QSize(s.width(), 3 * s.height());
return s;
}
void paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
auto model = static_cast<const SelectorModel *>(index.model());
TreeItem *item = model->itemForIndex(index);
QStyleOptionViewItem opt = option;
if (item && item->level() == 2) {
opt.font.setBold(true);
opt.font.setPointSizeF(opt.font.pointSizeF() * 1.2);
}
QStyledItemDelegate::paint(painter, opt, index);
}
};
//
// SelectorTree
//
class SelectorTree : public NavigationTreeView
{
public:
SelectorTree()
{
setWindowTitle("Project Kit Selector");
header()->hide();
setExpandsOnDoubleClick(false);
setHeaderHidden(true);
setItemsExpandable(false); // No user interaction.
setRootIsDecorated(false);
setUniformRowHeights(false); // sic!
setSelectionMode(QAbstractItemView::SingleSelection);
setSelectionBehavior(QAbstractItemView::SelectRows);
setEditTriggers(QAbstractItemView::NoEditTriggers);
setActivationMode(SingleClickActivation);
setObjectName("ProjectNavigation");
setContextMenuPolicy(Qt::CustomContextMenu);
}
};
//
// ProjectWindow
//
ProjectWindow::ProjectWindow()
{
setBackgroundRole(QPalette::Base);
m_selectorModel = new SelectorModel(this);
connect(m_selectorModel, &SelectorModel::needPanelUpdate,
this, &ProjectWindow::updatePanel);
m_selectorTree = new SelectorTree;
m_selectorTree->setModel(m_selectorModel);
m_selectorTree->setItemDelegate(new SelectorDelegate);
connect(m_selectorTree, &QAbstractItemView::activated,
this, &ProjectWindow::itemActivated);
m_projectSelection = new QComboBox;
m_projectSelection->setModel(m_selectorModel);
// m_projectSelection->setProperty("hideicon", true);
// m_projectSelection->setProperty("notelideasterisk", true);
// m_projectSelection->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
connect(m_projectSelection, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
this, &ProjectWindow::projectSelected, Qt::QueuedConnection);
auto styledBar = new StyledBar; // The black blob on top of the side bar
styledBar->setObjectName("ProjectModeStyledBar");
auto styledBarLayout = new QHBoxLayout(styledBar);
styledBarLayout->setContentsMargins(0, 0, 0, 0);
styledBarLayout->addWidget(m_projectSelection);
auto selectorView = new QWidget; // Black blob + Project tree + Combobox below.
selectorView->setObjectName("ProjectSelector"); // Needed for dock widget state saving
selectorView->setWindowTitle(tr("Project Selector"));
selectorView->setAutoFillBackground(true);
auto innerLayout = new QVBoxLayout;
innerLayout->setContentsMargins(14, 0, 14, 0);
//innerLayout->addWidget(m_projectSelection);
innerLayout->addWidget(m_selectorTree);
auto selectorLayout = new QVBoxLayout(selectorView);
selectorLayout->setContentsMargins(0, 0, 0, 0);
selectorLayout->addWidget(styledBar);
selectorLayout->addLayout(innerLayout);
m_selectorDock = addDockForWidget(selectorView, true);
addDockWidget(Qt::LeftDockWidgetArea, m_selectorDock);
SessionManager *sessionManager = SessionManager::instance(); SessionManager *sessionManager = SessionManager::instance();
connect(sessionManager, &SessionManager::projectAdded, connect(sessionManager, &SessionManager::projectAdded,
this, &ProjectWindow::registerProject); this, &ProjectWindow::registerProject);
connect(sessionManager, &SessionManager::aboutToRemoveProject, connect(sessionManager, &SessionManager::aboutToRemoveProject,
this, &ProjectWindow::deregisterProject); this, &ProjectWindow::deregisterProject);
connect(sessionManager, &SessionManager::startupProjectChanged, connect(sessionManager, &SessionManager::startupProjectChanged,
this, &ProjectWindow::startupProjectChanged); this, &ProjectWindow::startupProjectChanged);
connect(m_selectorTree, &QWidget::customContextMenuRequested,
connect(sessionManager, &SessionManager::projectDisplayNameChanged, this, &ProjectWindow::openContextMenu);
this, &ProjectWindow::projectDisplayNameChanged);
// Update properties to empty project for now:
showProperties(-1, -1);
} }
void ProjectWindow::aboutToShutdown() void ProjectWindow::openContextMenu(const QPoint &pos)
{ {
showProperties(-1, -1); auto menu = new QMenu;
menu->setAttribute(Qt::WA_DeleteOnClose);
QModelIndex index = m_selectorTree->indexAt(pos);
m_selectorModel->setData(index, QVariant::fromValue(menu), ContextMenuItemAdderRole);
if (menu->actions().isEmpty())
delete menu;
else
menu->popup(m_selectorTree->mapToGlobal(pos));
} }
void ProjectWindow::removedTarget(Target *) void ProjectWindow::contextMenuEvent(QContextMenuEvent *event)
{ {
auto p = qobject_cast<Project *>(sender()); Q_UNUSED(event)
QTC_ASSERT(p, return); // Do nothing to avoid creation of the dock window selection menu.
if (p->targets().isEmpty())
projectUpdated(p);
}
void ProjectWindow::projectUpdated(Project *project)
{
// Called after a project was configured
int currentIndex = m_tabWidget->currentIndex();
int oldSubIndex = m_tabWidget->currentSubIndex();
removeCurrentWidget();
int newSubIndex = m_cache.recheckFactories(project, oldSubIndex);
if (newSubIndex == -1)
newSubIndex = 0;
m_tabWidget->setSubTabs(currentIndex, m_cache.tabNames(project));
m_ignoreChange = true;
m_tabWidget->setCurrentIndex(currentIndex, newSubIndex);
m_ignoreChange = false;
QWidget *widget = m_cache.widgetFor(project, newSubIndex);
if (widget) {
m_currentWidget = widget;
m_centralWidget->addWidget(m_currentWidget);
m_centralWidget->setCurrentWidget(m_currentWidget);
m_currentWidget->show();
}
}
void ProjectWindow::projectDisplayNameChanged(Project *project)
{
int index = m_cache.indexForProject(project);
if (index < 0)
return;
m_ignoreChange = true;
bool isCurrentIndex = m_tabWidget->currentIndex() == index;
int subIndex = m_tabWidget->currentSubIndex();
QStringList subTabs = m_tabWidget->subTabs(index);
m_tabWidget->removeTab(index);
m_cache.sort();
int newIndex = m_cache.indexForProject(project);
m_tabWidget->insertTab(newIndex, project->displayName(), project->projectFilePath().toString(), subTabs);
if (isCurrentIndex)
m_tabWidget->setCurrentIndex(newIndex, subIndex);
m_ignoreChange = false;
} }
void ProjectWindow::registerProject(Project *project) void ProjectWindow::registerProject(Project *project)
{ {
if (m_cache.isRegistered(project)) QTC_ASSERT(itemForProject(project) == nullptr, return);
return;
m_cache.registerProject(project); auto newTab = new ProjectItem(project);
m_tabWidget->insertTab(m_cache.indexForProject(project),
project->displayName(),
project->projectFilePath().toString(),
m_cache.tabNames(project));
connect(project, &Project::removedTarget, this, &ProjectWindow::removedTarget); m_selectorModel->rootItem()->appendChild(newTab);
}
bool ProjectWindow::deregisterProject(Project *project) // FIXME: Add a TreeModel::insert(item, comparator)
{ m_selectorModel->rootItem()->sortChildren([this](const ProjectItem *a, const ProjectItem *b) {
int index = m_cache.indexForProject(project); Project *pa = a->project();
if (index == -1) Project *pb = b->project();
return false; QString aName = pa->displayName();
QString bName = pb->displayName();
disconnect(project, &Project::removedTarget, this, &ProjectWindow::removedTarget); if (aName != bName)
QVector<QWidget *> deletedWidgets = m_cache.deregisterProject(project);
if (deletedWidgets.contains(m_currentWidget))
m_currentWidget = 0;
m_tabWidget->removeTab(index);
return true;
}
void ProjectWindow::startupProjectChanged(Project *p)
{
int index = m_cache.indexForProject(p);
if (index != -1)
m_tabWidget->setCurrentIndex(index);
}
void ProjectWindow::showProperties(int index, int subIndex)
{
if (m_ignoreChange)
return;
removeCurrentWidget();
Project *project = m_cache.projectFor(index);
if (!project) {
return;
}
QWidget *widget = m_cache.widgetFor(project, subIndex);
if (widget) {
m_currentWidget = widget;
m_centralWidget->addWidget(m_currentWidget);
m_centralWidget->setCurrentWidget(m_currentWidget);
m_currentWidget->show();
if (hasFocus()) // we get assigned focus from setFocusToCurrentMode, pass that on
m_currentWidget->setFocus();
}
SessionManager::setStartupProject(project);
}
void ProjectWindow::removeCurrentWidget()
{
if (m_currentWidget) {
m_centralWidget->removeWidget(m_currentWidget);
m_currentWidget->hide();
m_currentWidget = 0;
}
}
// WidgetCache
void WidgetCache::registerProject(Project *project)
{
QTC_ASSERT(!isRegistered(project), return);
QList<ProjectPanelFactory *> fac = ProjectPanelFactory::factories();
int factorySize = fac.size();
ProjectInfo info;
info.project = project;
info.widgets.resize(factorySize);
info.supports.resize(factorySize);
for (int i = 0; i < factorySize; ++i)
info.supports[i] = fac.at(i)->supports(project);
m_projects.append(info);
sort();
}
QVector<QWidget *> WidgetCache::deregisterProject(Project *project)
{
QTC_ASSERT(isRegistered(project), return QVector<QWidget *>());
int index = indexForProject(project);
ProjectInfo info = m_projects.at(index);
QVector<QWidget *> deletedWidgets = info.widgets;
qDeleteAll(info.widgets);
m_projects.removeAt(index);
return deletedWidgets;
}
QStringList WidgetCache::tabNames(Project *project) const
{
int index = indexForProject(project);
if (index == -1)
return QStringList();
QList<ProjectPanelFactory *> fac = ProjectPanelFactory::factories();
ProjectInfo info = m_projects.at(index);
int end = info.supports.size();
QStringList names;
for (int i = 0; i < end; ++i)
if (info.supports.at(i))
names << fac.at(i)->displayName();
return names;
}
int WidgetCache::factoryIndex(int projectIndex, int supportsIndex) const
{
QList<ProjectPanelFactory *> fac = ProjectPanelFactory::factories();
int end = fac.size();
const ProjectInfo &info = m_projects.at(projectIndex);
for (int i = 0; i < end; ++i) {
if (info.supports.at(i)) {
if (supportsIndex == 0)
return i;
else
--supportsIndex;
}
}
return -1;
}
QWidget *WidgetCache::widgetFor(Project *project, int supportsIndex)
{
int projectIndex = indexForProject(project);
if (projectIndex == -1)
return 0;
QList<ProjectPanelFactory *> fac = ProjectPanelFactory::factories();
int factoryIdx = factoryIndex(projectIndex, supportsIndex);
if (factoryIdx < 0 ||factoryIdx >= m_projects.at(projectIndex).widgets.size())
return 0;
if (!m_projects.at(projectIndex).widgets.at(factoryIdx))
m_projects[projectIndex].widgets[factoryIdx] = fac.at(factoryIdx)->createWidget(project);
return m_projects.at(projectIndex).widgets.at(factoryIdx);
}
bool WidgetCache::isRegistered(Project *project) const
{
return Utils::anyOf(m_projects, [&project](ProjectInfo pinfo) {
return pinfo.project == project;
});
}
int WidgetCache::indexForProject(Project *project) const
{
return Utils::indexOf(m_projects, [&project](ProjectInfo pinfo) {
return pinfo.project == project;
});
}
Project *WidgetCache::projectFor(int projectIndex) const
{
if (projectIndex < 0 || projectIndex >= m_projects.size())
return nullptr;
return m_projects.at(projectIndex).project;
}
void WidgetCache::sort()
{
Utils::sort(m_projects, [](const ProjectInfo &a, const ProjectInfo &b) -> bool {
QString aName = a.project->displayName();
QString bName = b.project->displayName();
if (aName == bName) {
Utils::FileName aPath = a.project->projectFilePath();
Utils::FileName bPath = b.project->projectFilePath();
if (aPath == bPath)
return a.project < b.project;
else
return aPath < bPath;
} else {
return aName < bName; return aName < bName;
} Utils::FileName aPath = pa->projectFilePath();
Utils::FileName bPath = pb->projectFilePath();
if (aPath != bPath)
return aPath < bPath;
return pa < pb;
});
m_selectorTree->expandAll();
}
void ProjectWindow::deregisterProject(Project *project)
{
delete m_selectorModel->takeItem(itemForProject(project));
}
void ProjectWindow::startupProjectChanged(Project *project)
{
if (ProjectItem *projectItem = itemForProject(project)) {
int index = projectItem->parent()->children().indexOf(projectItem);
QTC_ASSERT(index != -1, return);
m_projectSelection->setCurrentIndex(index);
m_selectorModel->rootItem()->m_currentProjectIndex = index;
m_selectorTree->update();
m_selectorTree->setRootIndex(m_selectorModel->indexForItem(m_selectorModel->rootItem()->childAt(index)));
m_selectorTree->expandAll();
QModelIndex activeIndex = projectItem->data(0, ActiveIndexRole).value<QModelIndex>();
m_selectorTree->selectionModel()->setCurrentIndex(activeIndex, QItemSelectionModel::SelectCurrent);
updatePanel();
}
}
void ProjectWindow::projectSelected(int index)
{
auto projectItem = m_selectorModel->rootItem()->childAt(index);
QTC_ASSERT(projectItem, return);
SessionManager::setStartupProject(projectItem->project());
}
void ProjectWindow::itemActivated(const QModelIndex &index)
{
m_selectorModel->setData(index, QVariant(), ItemActivaterRole);
updatePanel();
}
void ProjectWindow::updatePanel()
{
if (QWidget *widget = centralWidget()) {
takeCentralWidget();
widget->hide(); // Don't delete.
}
RootItem *rootItem = m_selectorModel->rootItem();
if (QWidget *widget = rootItem->data(0, ActiveWidgetRole).value<QWidget *>()) {
setCentralWidget(widget);
widget->show();
if (hasFocus()) // we get assigned focus from setFocusToCurrentMode, pass that on
widget->setFocus();
}
}
ProjectItem *ProjectWindow::itemForProject(Project *project) const
{
return m_selectorModel->findFirstLevelItem([project](ProjectItem *item) {
return item->project() == project;
}); });
} }
int WidgetCache::recheckFactories(Project *project, int oldSupportsIndex) } // namespace Internal
{ } // namespace ProjectExplorer
int projectIndex = indexForProject(project);
int factoryIdx = factoryIndex(projectIndex, oldSupportsIndex);
ProjectInfo &info = m_projects[projectIndex];
QList<ProjectPanelFactory *> fac = ProjectPanelFactory::factories();
int end = fac.size();
for (int i = 0; i < end; ++i) {
info.supports[i] = fac.at(i)->supports(project);
if (!info.supports.at(i)) {
delete info.widgets.at(i);
info.widgets[i] = nullptr;
}
}
if (factoryIdx < 0)
return -1;
if (!info.supports.at(factoryIdx))
return -1;
int newIndex = 0;
for (int i = 0; i < factoryIdx; ++i) {
if (info.supports.at(i))
++newIndex;
}
return newIndex;
}
#include "projectwindow.moc"

View File

@@ -27,78 +27,59 @@
#include "projectexplorer_export.h" #include "projectexplorer_export.h"
#include <QMap> #include <QPointer>
#include <QWidget> #include <QWidget>
#include <utils/fancymainwindow.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QStackedWidget; class QComboBox;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace ProjectExplorer { namespace ProjectExplorer {
class Project; class Project;
class Target; class Target;
namespace Internal { namespace Internal {
class DoubleTabWidget; class SelectorModel;
class SelectorTree;
class ProjectItem;
class WidgetCache enum {
{ ContextMenuItemAdderRole // To augment a context menu, data has a QMenu*
public: = Qt::UserRole + 1,
void registerProject(Project *project); ItemActivaterRole, // This item got activated and is now responsible for the central widget
QVector<QWidget *> deregisterProject(Project *project); ActiveWidgetRole, // This item's widget to be shown as central widget.
ActiveIndexRole, // This is the index of the currently selected item in the tree view
bool isRegistered(Project *project) const; ProjectDisplayNameRole // Shown in the project selection combobox
int indexForProject(Project *project) const;
Project *projectFor(int projectIndex) const;
QStringList tabNames(Project *project) const;
QWidget *widgetFor(Project *project, int factoryIndex);
void sort();
int recheckFactories(Project *project, int oldSupportsIndex);
void clear();
private:
int factoryIndex(int projectIndex, int supportsIndex) const;
class ProjectInfo
{
public:
Project *project;
QVector<bool> supports;
QVector<QWidget *> widgets;
};
QList<ProjectInfo> m_projects; //ordered by displaynames of the projects
}; };
class ProjectWindow : public QWidget class ProjectWindow : public Utils::FancyMainWindow
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ProjectWindow(QWidget *parent = nullptr); ProjectWindow();
void aboutToShutdown();
void projectUpdated(Project *project);
private: private:
void projectDisplayNameChanged(Project *p); void contextMenuEvent(QContextMenuEvent *event) override;
void showProperties(int index, int subIndex);
void registerProject(Project*);
bool deregisterProject(Project*);
void startupProjectChanged(Project *);
void removedTarget(Target*);
void removeCurrentWidget(); void updatePanel();
void openContextMenu(const QPoint &pos);
void registerProject(Project *project);
void deregisterProject(Project *project);
void startupProjectChanged(Project *project);
void projectSelected(int index);
void itemActivated(const QModelIndex &index);
ProjectItem *itemForProject(Project *project) const;
bool m_ignoreChange; SelectorModel *m_selectorModel;
DoubleTabWidget *m_tabWidget; SelectorTree *m_selectorTree;
QStackedWidget *m_centralWidget; QDockWidget *m_selectorDock;
QWidget *m_currentWidget; QComboBox *m_projectSelection;
WidgetCache m_cache;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -1,490 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "targetselector.h"
#include <utils/qtcassert.h>
#include <utils/stylehelper.h>
#include <QPainter>
#include <QMenu>
#include <QMouseEvent>
#include <QFontMetrics>
#include <QPushButton>
static const int TARGET_HEIGHT = 43;
static const int NAVBUTTON_WIDTH = 27;
static const int KITNAME_MARGINS = 6;
namespace ProjectExplorer {
namespace Internal {
class QPixmapButton : public QPushButton
{
public:
QPixmapButton(QWidget *parent, const QPixmap &first, const QPixmap &second)
: QPushButton(parent), m_showFirst(true), m_first(first), m_second(second)
{
setFixedSize(m_first.size()/m_first.devicePixelRatio());
}
void paintEvent(QPaintEvent *)
{
QPainter p(this);
p.drawPixmap(0, 0, m_showFirst ? m_first : m_second);
}
void setFirst(bool f)
{
m_showFirst = f;
}
private:
bool m_showFirst;
const QPixmap m_first;
const QPixmap m_second;
};
}
}
using namespace ProjectExplorer::Internal;
TargetSelector::TargetSelector(QWidget *parent) :
QWidget(parent),
m_unselected(QLatin1String(":/projectexplorer/images/targetunselected.png")),
m_runselected(Utils::StyleHelper::dpiSpecificImageFile(QLatin1String(":/projectexplorer/images/targetrunselected.png"))),
m_buildselected(m_runselected.mirrored(true, false)),
m_targetRightButton(Utils::StyleHelper::dpiSpecificImageFile(QLatin1String(":/projectexplorer/images/targetrightbutton.png"))),
m_targetLeftButton(QPixmap::fromImage(m_targetRightButton.toImage().mirrored(true, false))),
m_targetChangePixmap(Utils::StyleHelper::dpiSpecificImageFile(QLatin1String(":/projectexplorer/images/targetchangebutton.png"))),
m_targetChangePixmap2(Utils::StyleHelper::dpiSpecificImageFile(QLatin1String(":/projectexplorer/images/targetchangebutton2.png"))),
m_currentTargetIndex(-1),
m_currentHoveredTargetIndex(-1),
m_startIndex(0),
m_menuShown(false),
m_targetWidthNeedsUpdate(true)
{
QFont f = font();
f.setPixelSize(10);
f.setBold(true);
setFont(f);
setMouseTracking(true);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_targetChangeButton = new QPixmapButton(this, m_targetChangePixmap2, m_targetChangePixmap);
m_targetChangeButton->hide();
connect(m_targetChangeButton, &QAbstractButton::pressed,
this, &TargetSelector::changeButtonPressed);
}
void TargetSelector::changeButtonPressed()
{
emit menuShown(m_currentHoveredTargetIndex);
}
void TargetSelector::menuAboutToShow()
{
m_menuShown = true;
updateButtons();
}
void TargetSelector::menuAboutToHide()
{
m_menuShown = false;
updateButtons();
}
void TargetSelector::insertTarget(int index, int subIndex, const QString &name)
{
QTC_ASSERT(index >= 0 && index <= m_targets.count(), return);
Target target;
target.name = name;
target.currentSubIndex = subIndex;
m_targets.insert(index, target);
if (m_currentTargetIndex >= index)
setCurrentIndex(m_currentTargetIndex + 1);
m_targetWidthNeedsUpdate = true;
updateGeometry();
update();
}
void TargetSelector::renameTarget(int index, const QString &name)
{
m_targets[index].name = name;
m_targetWidthNeedsUpdate = true;
updateGeometry();
update();
}
void TargetSelector::removeTarget(int index)
{
QTC_ASSERT(index >= 0 && index < m_targets.count(), return);
m_targets.removeAt(index);
if (m_currentTargetIndex > index) {
--m_currentTargetIndex;
// force a signal since the index has changed
emit currentChanged(m_currentTargetIndex, m_targets.at(m_currentTargetIndex).currentSubIndex);
}
m_targetWidthNeedsUpdate = true;
updateGeometry();
update();
}
void TargetSelector::setCurrentIndex(int index)
{
if (index < -1 ||
index >= m_targets.count() ||
index == m_currentTargetIndex)
return;
if (index == -1 && !m_targets.isEmpty())
return;
m_currentTargetIndex = index;
if (isVisible())
ensureCurrentIndexVisible();
update();
emit currentChanged(m_currentTargetIndex,
m_currentTargetIndex >= 0 ? m_targets.at(m_currentTargetIndex).currentSubIndex : -1);
}
void TargetSelector::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
ensureCurrentIndexVisible();
}
void TargetSelector::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
ensureCurrentIndexVisible();
}
void TargetSelector::ensureCurrentIndexVisible()
{
if (m_currentTargetIndex < m_startIndex)
m_startIndex = m_currentTargetIndex;
const int lastIndex = m_startIndex + maxVisibleTargets() - 1;
if (m_currentTargetIndex > lastIndex)
m_startIndex = m_currentTargetIndex - maxVisibleTargets() + 1;
}
void TargetSelector::setCurrentSubIndex(int subindex)
{
if (subindex < 0 ||
subindex >= 2 ||
m_currentTargetIndex < 0 ||
subindex == m_targets.at(m_currentTargetIndex).currentSubIndex)
return;
m_targets[m_currentTargetIndex].currentSubIndex = subindex;
update();
emit currentChanged(m_currentTargetIndex,
m_targets.at(m_currentTargetIndex).currentSubIndex);
}
TargetSelector::Target TargetSelector::targetAt(int index) const
{
return m_targets.at(index);
}
void TargetSelector::setTargetMenu(QMenu *menu)
{
if (m_targetChangeButton->menu()) {
disconnect(m_targetChangeButton->menu(), &QMenu::aboutToShow,
this, &TargetSelector::menuAboutToShow);
disconnect(m_targetChangeButton->menu(), &QMenu::aboutToHide,
this, &TargetSelector::menuAboutToHide);
}
m_targetChangeButton->setMenu(menu);
if (menu) {
connect(m_targetChangeButton->menu(), &QMenu::aboutToShow,
this, &TargetSelector::menuAboutToShow);
connect(m_targetChangeButton->menu(), &QMenu::aboutToHide,
this, &TargetSelector::menuAboutToHide);
}
}
int TargetSelector::targetWidth() const
{
static int width = -1;
if (width < 0 || m_targetWidthNeedsUpdate) {
m_targetWidthNeedsUpdate = false;
QFontMetrics fm = fontMetrics();
width = 149; // minimum
// let it grow for the kit names ...
foreach (const Target &target, m_targets)
width = qMax(width, fm.width(target.name) + KITNAME_MARGINS + 2/*safety measure*/);
width = qMin(width, 299); // ... but not too much
int buttonWidth = qMax(fm.width(runButtonString()), fm.width(buildButtonString()));
width = qMax(width, buttonWidth * 2 + 31); // run & build button strings must be fully visible
}
return width;
}
QSize TargetSelector::sizeHint() const
{
return QSize((targetWidth() + 1) * m_targets.size() + (NAVBUTTON_WIDTH + 1) * 2 + 3, TARGET_HEIGHT + 1);
}
int TargetSelector::maxVisibleTargets() const
{
return qMax((width() - ((NAVBUTTON_WIDTH + 1) * 2 + 3))/(targetWidth() + 1), 1);
}
void TargetSelector::getControlAt(int x, int y, int *buttonIndex, int *targetIndex, int *targetSubIndex)
{
if (buttonIndex)
*buttonIndex = -1;
if (targetIndex)
*targetIndex = -1;
if (targetSubIndex)
*targetSubIndex = -1;
// left button?
if (m_startIndex > 0 /* button visible */ && x >= 0 && x < NAVBUTTON_WIDTH + 2) {
if (buttonIndex)
*buttonIndex = 0;
return;
}
// right button?
int rightButtonStartX = NAVBUTTON_WIDTH + (targetWidth() + 1) * maxVisibleTargets() + 2;
if (x > rightButtonStartX) {
if (m_targets.size() > maxVisibleTargets() /* button visible */ && x <= rightButtonStartX + NAVBUTTON_WIDTH + 1) {
if (buttonIndex)
*buttonIndex = 1;
}
return;
}
// find the clicked target button
int tx = NAVBUTTON_WIDTH + 3;
int index;
for (index = m_startIndex; index < m_targets.size(); ++index) {
if (x <= tx)
break;
tx += targetWidth() + 1;
}
--index;
tx -= targetWidth() + 1;
if (index >= 0 && index < m_targets.size()) {
if (targetIndex)
*targetIndex = index;
// handle clicked target
// check if user clicked on Build or Run
if (y > TARGET_HEIGHT * 3/5) {
if ((x - tx) - 2 > targetWidth() / 2) {
if (targetSubIndex)
*targetSubIndex = 1;
} else {
if (targetSubIndex)
*targetSubIndex = 0;
}
}
}
}
void TargetSelector::mousePressEvent(QMouseEvent *event)
{
int buttonIndex;
int targetIndex;
int targetSubIndex;
getControlAt(event->x(), event->y(), &buttonIndex, &targetIndex, &targetSubIndex);
if (buttonIndex == 0) {
event->accept();
--m_startIndex;
update();
} else if (buttonIndex == 1) {
event->accept();
++m_startIndex;
update();
} else if (targetIndex != -1) {
event->accept();
bool updateNeeded = false;
if (targetIndex != m_currentTargetIndex) {
m_currentTargetIndex = targetIndex;
updateNeeded = true;
}
if (targetSubIndex != -1) {
if (targetSubIndex != m_targets[m_currentTargetIndex].currentSubIndex) {
m_targets[m_currentTargetIndex].currentSubIndex = targetSubIndex;
updateNeeded = true;
}
}
if (updateNeeded) {
update();
emit currentChanged(m_currentTargetIndex, m_targets.at(m_currentTargetIndex).currentSubIndex);
}
} else {
event->ignore();
}
}
void TargetSelector::mouseMoveEvent(QMouseEvent *event)
{
int targetIndex;
getControlAt(event->x(), event->y(), 0, &targetIndex, 0);
if (m_currentHoveredTargetIndex != targetIndex) {
m_currentHoveredTargetIndex = targetIndex;
if (targetIndex != -1)
event->accept();
updateButtons();
update();
}
}
void TargetSelector::leaveEvent(QEvent *event)
{
Q_UNUSED(event)
m_currentHoveredTargetIndex = -1;
updateButtons();
update();
}
void TargetSelector::updateButtons()
{
if (m_menuShown) {
// Do nothing while the menu is show
} else if (m_currentHoveredTargetIndex == -1) {
m_targetChangeButton->hide();
} else {
int tx = NAVBUTTON_WIDTH + 3 + (m_currentHoveredTargetIndex - m_startIndex) * (targetWidth() + 1);
const int pixmapWidth =
static_cast<int>(m_targetChangePixmap.width() / m_targetChangePixmap.devicePixelRatio());
const QPoint buttonTopLeft(tx + targetWidth() - pixmapWidth - 1, 3);
m_targetChangeButton->move(buttonTopLeft);
m_targetChangeButton->setVisible(true);
m_targetChangeButton->setFirst(m_currentHoveredTargetIndex == m_currentTargetIndex);
}
}
bool TargetSelector::event(QEvent *e)
{
if (e->type() == QEvent::ToolTip) {
auto helpEvent = static_cast<const QHelpEvent *>(e);
int targetIndex;
int subTargetIndex;
getControlAt(helpEvent->x(), helpEvent->y(), 0, &targetIndex, &subTargetIndex);
if (targetIndex >= 0 && subTargetIndex < 0) {
emit toolTipRequested(helpEvent->globalPos(), targetIndex);
e->accept();
return true;
}
}
return QWidget::event(e);
}
void TargetSelector::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
// update start index depending on available width
m_startIndex = qMax(0, qMin(m_startIndex, m_targets.size() - maxVisibleTargets()));
QPainter p(this);
QColor borderColor(89, 89, 89);
int x = 2;
QFontMetrics fm(font());
//draw left button
if (m_startIndex > 0)
p.drawPixmap(x, 1, m_targetLeftButton);
x += static_cast<int>(m_targetLeftButton.width() / m_targetLeftButton.devicePixelRatio());
if (m_startIndex == 0) {
p.setPen(borderColor);
p.drawLine(QLineF(x + 0.5, 1.5, x + 0.5, TARGET_HEIGHT + 0.5));
}
x += 1;
// draw targets
const QString runString = runButtonString();
const QString buildString = buildButtonString();
const int lastIndex = qMin(m_targets.size(), m_startIndex + maxVisibleTargets()) - 1;
for (int index = m_startIndex; index <= lastIndex; ++index) {
const Target &target = m_targets.at(index);
QImage image = m_unselected;
bool buildSelected = target.currentSubIndex == 0;
if (index == m_currentTargetIndex) {
p.setPen(QColor(255, 255, 255));
if (buildSelected)
image = m_buildselected;
else
image = m_runselected;
} else {
p.setPen(Qt::black);
}
QRect buttonRect(x, 1, targetWidth(), static_cast<int>(image.height() / image.devicePixelRatio()));
Utils::StyleHelper::drawCornerImage(image, &p, buttonRect, 13, 0, 13, 0);
const QString nameText = QFontMetrics(font()).elidedText(target.name, Qt::ElideRight,
targetWidth() - KITNAME_MARGINS);
p.drawText(x + (targetWidth()- fm.width(nameText))/2 + 1, 7 + fm.ascent(),
nameText);
// Build
int margin = 2; // position centered within the rounded buttons
QFontMetrics fm = fontMetrics();
QRect textRect(x + margin, size().height() - fm.height() - 5, targetWidth()/2, fm.height());
if (index != m_currentTargetIndex)
p.setPen(QColor(0x555555));
else
p.setPen(buildSelected ? Qt::black : Qt::white);
p.drawText(textRect, Qt::AlignHCenter, buildString);
// Run
textRect.moveLeft(x + targetWidth()/2 - 2 * margin);
if (index != m_currentTargetIndex)
p.setPen(QColor(0x555555));
else
p.setPen(buildSelected ? Qt::white: Qt::black);
p.drawText(textRect, Qt::AlignHCenter, runString);
x += targetWidth();
p.setPen(index == m_currentTargetIndex ? QColor(0x222222) : QColor(0xcccccc));
p.drawLine(QLineF(x + 0.5, 1.5, x + 0.5, TARGET_HEIGHT + 0.5));
++x;
}
// draw right button and frame (left hand part already done)
p.setPen(borderColor);
p.drawLine(QLineF(2.5 + m_targetLeftButton.width() / m_targetLeftButton.devicePixelRatio(),
0.5, x - 0.5, 0.5));
if (lastIndex < m_targets.size() - 1)
p.drawPixmap(x, 1, m_targetRightButton);
else
p.drawLine(QLineF(x - 0.5, 1.5, x - 0.5, TARGET_HEIGHT + 0.5));
}

View File

@@ -1,121 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QWidget>
#include <QPixmap>
QT_BEGIN_NAMESPACE
class QMenu;
class QPushButton;
QT_END_NAMESPACE
namespace ProjectExplorer {
namespace Internal {
class QPixmapButton;
class TargetSelector : public QWidget
{
Q_OBJECT
public:
class Target {
public:
QString name;
int currentSubIndex;
};
explicit TargetSelector(QWidget *parent = nullptr);
QSize sizeHint() const override;
int targetWidth() const;
QString runButtonString() const { return tr("Run"); }
QString buildButtonString() const { return tr("Build"); }
Target targetAt(int index) const;
int targetCount() const { return m_targets.size(); }
int currentIndex() const { return m_currentTargetIndex; }
int currentSubIndex() const {
return m_currentTargetIndex == -1 ? -1
: m_targets.at(m_currentTargetIndex).currentSubIndex;
}
void setTargetMenu(QMenu *menu);
public:
void insertTarget(int index, int subIndex, const QString &name);
void renameTarget(int index, const QString &name);
void removeTarget(int index);
void setCurrentIndex(int index);
void setCurrentSubIndex(int subindex);
signals:
// This signal is emitted whenever the target pointed to by the indices
// has changed.
void currentChanged(int targetIndex, int subIndex);
void toolTipRequested(const QPoint &globalPosition, int targetIndex);
void menuShown(int targetIndex);
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void leaveEvent(QEvent *event) override;
void showEvent(QShowEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
bool event(QEvent *e) override;
private:
void changeButtonPressed();
void updateButtons();
void menuAboutToShow();
void menuAboutToHide();
void getControlAt(int x, int y, int *buttonIndex, int *targetIndex, int *targetSubIndex);
int maxVisibleTargets() const;
void ensureCurrentIndexVisible();
const QImage m_unselected;
const QImage m_runselected;
const QImage m_buildselected;
const QPixmap m_targetRightButton;
const QPixmap m_targetLeftButton;
const QPixmap m_targetChangePixmap;
const QPixmap m_targetChangePixmap2;
QPixmapButton *m_targetChangeButton;
QList<Target> m_targets;
int m_currentTargetIndex;
int m_currentHoveredTargetIndex;
int m_startIndex;
bool m_menuShown;
mutable bool m_targetWidthNeedsUpdate;
};
} // namespace Internal
} // namespace ProjectExplorer

File diff suppressed because it is too large Load Diff

View File

@@ -25,77 +25,38 @@
#pragma once #pragma once
#include <QWidget> #include "projectpanelfactory.h"
QT_BEGIN_NAMESPACE #include <coreplugin/id.h>
class QAction;
class QMenu;
class QStackedWidget;
QT_END_NAMESPACE
namespace Utils { class FileName; } #include <QCoreApplication>
namespace ProjectExplorer { namespace ProjectExplorer {
class Target;
class Project; class Project;
class ProjectImporter; class ProjectPanelFactory;
class Kit;
class PanelsWidget;
namespace Internal { namespace Internal {
class TargetSettingsWidget; class TargetItem;
class TargetSettingsPanelItemPrivate;
class TargetSettingsPanelWidget : public QWidget // Second level: Special case for the Build & Run item (with per-kit subItems)
class TargetSettingsPanelItem : public Utils::TypedTreeItem<TargetItem>
{ {
Q_OBJECT Q_DECLARE_TR_FUNCTIONS(TargetSettingsPanelItem)
public: public:
TargetSettingsPanelWidget(Project *project); TargetSettingsPanelItem(ProjectPanelFactory *factory, Project *project);
~TargetSettingsPanelWidget() override; ~TargetSettingsPanelItem() override;
void setupUi(); QVariant data(int column, int role) const override;
bool setData(int column, const QVariant &data, int role) override;
int currentSubIndex() const; Core::Id currentKitId() const;
void setCurrentSubIndex(int subIndex);
protected:
bool event(QEvent *event) override;
private: private:
void currentTargetChanged(int targetIndex, int subIndex); TargetSettingsPanelItemPrivate *d;
void showTargetToolTip(const QPoint &globalPos, int targetIndex);
void targetAdded(ProjectExplorer::Target *target);
void removedTarget(ProjectExplorer::Target *target);
void activeTargetChanged(ProjectExplorer::Target *target);
void updateTargetButtons();
void renameTarget();
void openTargetPreferences();
void removeCurrentTarget();
void menuShown(int targetIndex);
void addActionTriggered(QAction *action);
void changeActionTriggered(QAction *action);
void duplicateActionTriggered(QAction *action);
void importTarget(const Utils::FileName &path);
void createAction(Kit *k, QMenu *menu);
Target *m_currentTarget = nullptr;
Project *m_project;
ProjectImporter *m_importer;
TargetSettingsWidget *m_selector = nullptr;
QStackedWidget *m_centralWidget = nullptr;
QWidget *m_noTargetLabel;
PanelsWidget *m_panelWidgets[2];
QList<Target *> m_targets;
QMenu *m_targetMenu;
QMenu *m_changeMenu = nullptr;
QMenu *m_duplicateMenu = nullptr;
QMenu *m_addMenu;
QAction *m_lastAction = nullptr;
QAction *m_importAction = nullptr;
int m_menuTargetIndex = -1;
static int s_targetSubIndex;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -1,203 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "targetsettingswidget.h"
#include <utils/theme/theme.h>
#include <utils/stylehelper.h>
#include <QPainter>
#include <QPaintEvent>
#include <QPushButton>
#include <QVBoxLayout>
#include <cmath>
using namespace ProjectExplorer::Internal;
class TargetSettingsWidgetHeader : public QWidget
{
public:
TargetSettingsWidgetHeader(QWidget *parent) : QWidget(parent)
{
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
setSizePolicy(sizePolicy);
setAutoFillBackground(true);
}
void paintEvent(QPaintEvent *event) override
{
if (!Utils::creatorTheme()->flag(Utils::Theme::FlatProjectsMode)) {
QPainter p(this);
static const QPixmap bg(Utils::StyleHelper::dpiSpecificImageFile(
QLatin1String(":/projectexplorer/images/targetseparatorbackground.png")));
const int tileCount = int(std::ceil(qreal(width()) / bg.width() * devicePixelRatio()));
for (int tile = 0; tile < tileCount; ++tile)
p.drawPixmap(tile * bg.width() / devicePixelRatio(), 0, bg);
}
QWidget::paintEvent(event);
}
};
TargetSettingsWidget::TargetSettingsWidget(QWidget *parent) : QWidget(parent),
m_targetSelector(new TargetSelector(this))
{
auto header = new TargetSettingsWidgetHeader(this);
auto separator = new QWidget(this);
separator->setMinimumSize(QSize(0, 1));
separator->setMaximumSize(QSize(QWIDGETSIZE_MAX, 1));
separator->setAutoFillBackground(true);
auto shadow = new QWidget(this);
shadow->setMinimumSize(QSize(0, 2));
shadow->setMaximumSize(QSize(QWIDGETSIZE_MAX, 2));
shadow->setAutoFillBackground(true);
m_scrollAreaWidgetContents = new QWidget(this);
auto scrollLayout = new QVBoxLayout(m_scrollAreaWidgetContents);
scrollLayout->setSpacing(0);
scrollLayout->setContentsMargins(0, 0, 0, 0);
auto verticalLayout = new QVBoxLayout(this);
verticalLayout->setSpacing(0);
verticalLayout->setContentsMargins(0, 0, 0, 0);
verticalLayout->addWidget(header);
verticalLayout->addWidget(separator);
verticalLayout->addWidget(shadow);
verticalLayout->addWidget(m_scrollAreaWidgetContents);
if (Utils::creatorTheme()->flag(Utils::Theme::FlatProjectsMode)) {
separator->setVisible(false);
shadow->setVisible(false);
} else {
QPalette separatorPalette;
separatorPalette.setColor(QPalette::Window, QColor(115, 115, 115, 255));
separator->setPalette(separatorPalette);
QPalette shadowPalette;
QLinearGradient shadowGradient(0, 0, 0, 2);
shadowGradient.setColorAt(0, QColor(0, 0, 0, 60));
shadowGradient.setColorAt(1, Qt::transparent);
shadowPalette.setBrush(QPalette::All, QPalette::Window, shadowGradient);
shadow->setPalette(shadowPalette);
}
auto headerLayout = new QHBoxLayout;
headerLayout->setContentsMargins(5, 2, 0, 0);
header->setLayout(headerLayout);
auto buttonWidget = new QWidget(header);
auto buttonLayout = new QVBoxLayout;
buttonLayout->setContentsMargins(0, 0, 0, 0);
buttonLayout->setSpacing(4);
buttonWidget->setLayout(buttonLayout);
m_addButton = new QPushButton(tr("Add Kit"), buttonWidget);
buttonLayout->addWidget(m_addButton);
m_manageButton = new QPushButton(tr("Manage Kits..."), buttonWidget);
connect(m_manageButton, &QAbstractButton::clicked,
this, &TargetSettingsWidget::manageButtonClicked);
buttonLayout->addWidget(m_manageButton);
headerLayout->addWidget(buttonWidget, 0, Qt::AlignVCenter);
headerLayout->addWidget(m_targetSelector, 0, Qt::AlignBottom);
headerLayout->addStretch(10);
connect(m_targetSelector, &TargetSelector::currentChanged,
this, &TargetSettingsWidget::currentChanged);
connect(m_targetSelector, &TargetSelector::toolTipRequested,
this, &TargetSettingsWidget::toolTipRequested);
connect(m_targetSelector, &TargetSelector::menuShown,
this, &TargetSettingsWidget::menuShown);
}
void TargetSettingsWidget::insertTarget(int index, int subIndex, const QString &name)
{
m_targetSelector->insertTarget(index, subIndex, name);
}
void TargetSettingsWidget::renameTarget(int index, const QString &name)
{
m_targetSelector->renameTarget(index, name);
}
void TargetSettingsWidget::removeTarget(int index)
{
m_targetSelector->removeTarget(index);
}
void TargetSettingsWidget::setCurrentIndex(int index)
{
m_targetSelector->setCurrentIndex(index);
}
void TargetSettingsWidget::setCurrentSubIndex(int index)
{
m_targetSelector->setCurrentSubIndex(index);
}
void TargetSettingsWidget::setAddButtonEnabled(bool enabled)
{
m_addButton->setEnabled(enabled);
}
void TargetSettingsWidget::setAddButtonMenu(QMenu *menu)
{
m_addButton->setMenu(menu);
}
void TargetSettingsWidget::setTargetMenu(QMenu *menu)
{
m_targetSelector->setTargetMenu(menu);
}
QString TargetSettingsWidget::targetNameAt(int index) const
{
return m_targetSelector->targetAt(index).name;
}
void TargetSettingsWidget::setCentralWidget(QWidget *widget)
{
if (m_centralWidget)
m_scrollAreaWidgetContents->layout()->removeWidget(m_centralWidget);
m_centralWidget = widget;
m_scrollAreaWidgetContents->layout()->addWidget(m_centralWidget);
}
int TargetSettingsWidget::targetCount() const
{
return m_targetSelector->targetCount();
}
int TargetSettingsWidget::currentIndex() const
{
return m_targetSelector->currentIndex();
}
int TargetSettingsWidget::currentSubIndex() const
{
return m_targetSelector->currentSubIndex();
}

View File

@@ -1,79 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "targetselector.h"
QT_BEGIN_NAMESPACE
class QMenu;
class QPushButton;
QT_END_NAMESPACE
namespace ProjectExplorer {
namespace Internal {
class TargetSettingsWidget : public QWidget
{
Q_OBJECT
public:
explicit TargetSettingsWidget(QWidget *parent = nullptr);
void setCentralWidget(QWidget *widget);
QString targetNameAt(int index) const;
int targetCount() const;
int currentIndex() const;
int currentSubIndex() const;
public:
void insertTarget(int index, int subIndex, const QString &name);
void renameTarget(int index, const QString &name);
void removeTarget(int index);
void setCurrentIndex(int index);
void setCurrentSubIndex(int index);
void setAddButtonEnabled(bool enabled);
void setAddButtonMenu(QMenu *menu);
void setTargetMenu(QMenu *menu);
signals:
void currentChanged(int targetIndex, int subIndex);
void manageButtonClicked();
void duplicateButtonClicked();
void changeKitButtonClicked();
void toolTipRequested(const QPoint &globalPosition, int targetIndex);
void menuShown(int targetIndex);
private:
TargetSelector *m_targetSelector;
QPushButton *m_addButton;
QPushButton *m_manageButton;
QWidget *m_centralWidget = nullptr;
QWidget *m_scrollAreaWidgetContents;
};
} // namespace Internal
} // namespace ProjectExplorer

View File

@@ -1,174 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#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 {
/////////
/// TargetSetupPageWrapper
////////
TargetSetupPageWrapper::TargetSetupPageWrapper(Project *project) : QWidget(),
m_project(project)
{
auto layout = new QVBoxLayout();
layout->setMargin(0);
setLayout(layout);
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();
layout->addWidget(m_targetSetupPage);
// Apply row
auto hbox = new QHBoxLayout();
layout->addLayout(hbox);
layout->setMargin(0);
hbox->addStretch();
auto 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, &QAbstractButton::clicked,
this, &TargetSetupPageWrapper::done);
connect(m_cancelButton, &QAbstractButton::clicked,
this, &TargetSetupPageWrapper::cancel);
connect(m_targetSetupPage, &QWizardPage::completeChanged,
this, &TargetSetupPageWrapper::completeChanged);
connect(KitManager::instance(), &KitManager::defaultkitChanged,
this, &TargetSetupPageWrapper::updateNoteText);
connect(KitManager::instance(), &KitManager::kitUpdated,
this, &TargetSetupPageWrapper::kitUpdated);
}
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::requestProjectModeUpdate(m_project);
Core::ModeManager::activateMode(Core::Constants::MODE_EDIT);
}
void TargetSetupPageWrapper::completeChanged()
{
m_configureButton->setEnabled(m_targetSetupPage->isComplete());
}
} // namespace Internal
} // namespace ProjectExplorer

View File

@@ -1,64 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QString>
#include <QWidget>
QT_FORWARD_DECLARE_CLASS(QPushButton)
namespace ProjectExplorer {
class Kit;
class Project;
class TargetSetupPage;
namespace Internal {
class TargetSetupPageWrapper : public QWidget
{
Q_OBJECT
public:
explicit TargetSetupPageWrapper(Project *project);
protected:
void keyReleaseEvent(QKeyEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
private:
void done();
void cancel();
void kitUpdated(ProjectExplorer::Kit *k);
void updateNoteText();
void completeChanged();
Project *m_project;
TargetSetupPage *m_targetSetupPage;
QPushButton *m_configureButton;
QPushButton *m_cancelButton;
};
} // namespace Internal
} // namespace ProjectExplorer

View File

@@ -1325,7 +1325,6 @@ void QmakeProject::configureAsExampleProject(const QSet<Core::Id> &platforms)
} }
setup(infoList); setup(infoList);
qDeleteAll(infoList); qDeleteAll(infoList);
ProjectExplorerPlugin::requestProjectModeUpdate(this);
} }
bool QmakeProject::requiresTargetPanel() const bool QmakeProject::requiresTargetPanel() const

View File

@@ -35,7 +35,9 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/ieditor.h>
#include <projectexplorer/projectpanelfactory.h> #include <projectexplorer/projectpanelfactory.h>
#include <projectexplorer/propertiespanel.h>
#include <QtPlugin> #include <QtPlugin>
#include <QFileInfo> #include <QFileInfo>
@@ -68,20 +70,14 @@ bool TodoPlugin::initialize(const QStringList& args, QString *errMsg)
createItemsProvider(); createItemsProvider();
createTodoOutputPane(); createTodoOutputPane();
auto panelFactory = new ProjectExplorer::ProjectPanelFactory(); auto panelFactory = new ProjectExplorer::ProjectPanelFactory;
panelFactory->setPriority(100); panelFactory->setPriority(100);
panelFactory->setDisplayName(TodoProjectSettingsWidget::tr("To-Do")); panelFactory->setDisplayName(TodoProjectSettingsWidget::tr("To-Do"));
panelFactory->setCreateWidgetFunction([this, panelFactory](ProjectExplorer::Project *project) -> QWidget * { panelFactory->setCreateWidgetFunction([this, panelFactory](ProjectExplorer::Project *project) {
auto *panel = new ProjectExplorer::PropertiesPanel; auto widget = new TodoProjectSettingsWidget(project);
panel->setDisplayName(panelFactory->displayName());
auto *widget = new TodoProjectSettingsWidget(project);
connect(widget, &TodoProjectSettingsWidget::projectSettingsChanged, connect(widget, &TodoProjectSettingsWidget::projectSettingsChanged,
m_todoItemsProvider, [this, project](){m_todoItemsProvider->projectSettingsChanged(project);}); m_todoItemsProvider, [this, project] { m_todoItemsProvider->projectSettingsChanged(project); });
panel->setWidget(widget); return widget;
auto *panelsWidget = new ProjectExplorer::PanelsWidget();
panelsWidget->addPropertiesPanel(panel);
panelsWidget->setFocusProxy(widget);
return panelsWidget;
}); });
ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory);

View File

@@ -18,41 +18,6 @@
sodipodi:docname="qtcreatoricons.svg"> sodipodi:docname="qtcreatoricons.svg">
<defs <defs
id="defs4"> id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4806">
<stop
style="stop-color:#646464;stop-opacity:1"
offset="0"
id="stop4808" />
<stop
style="stop-color:#424242;stop-opacity:1"
offset="1"
id="stop4810" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient6371">
<stop
style="stop-color:#f7f7f7;stop-opacity:1"
offset="0"
id="stop6373" />
<stop
style="stop-color:#c3c3c3;stop-opacity:1"
offset="1"
id="stop6375" />
</linearGradient>
<linearGradient
id="linearGradient4115-6">
<stop
id="stop4781"
offset="0"
style="stop-color:#626262;stop-opacity:1" />
<stop
id="stop4783"
offset="1"
style="stop-color:#414141;stop-opacity:1" />
</linearGradient>
<linearGradient <linearGradient
id="linearGradient4115"> id="linearGradient4115">
<stop <stop
@@ -453,108 +418,6 @@
x="329" x="329"
y="536" /> y="536" />
</clipPath> </clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4115-6"
id="linearGradient4691"
gradientUnits="userSpaceOnUse"
x1="29"
y1="383"
x2="29"
y2="424" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6371"
id="linearGradient6377"
x1="68"
y1="381"
x2="68"
y2="424"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-8,0)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4806"
id="linearGradient4812"
x1="123"
y1="384"
x2="123"
y2="404"
gradientUnits="userSpaceOnUse" />
<filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Drop Shadow"
id="filter4964">
<feFlood
flood-opacity="0.498039"
flood-color="rgb(0,0,0)"
result="flood"
id="feFlood4966" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="out"
result="composite1"
id="feComposite4968" />
<feGaussianBlur
in="composite1"
stdDeviation="1.5"
result="blur"
id="feGaussianBlur4970" />
<feOffset
dx="0"
dy="1.5"
result="offset"
id="feOffset4972" />
<feComposite
in="offset"
in2="SourceGraphic"
operator="atop"
result="composite2"
id="feComposite4974" />
</filter>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath6752">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:2.1400001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0"
id="rect6754"
width="28"
height="43"
x="-2.8722695e-007"
y="381" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath6765">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:2.1400001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0"
id="rect6767"
width="31"
height="20"
x="110"
y="384"
rx="10" />
</clipPath>
<filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Fade to Black or White"
id="filter4891">
<feColorMatrix
values="0.770833 0 0 0 0.229167 0 0.770833 0 0 0.229167 0 0 0.770833 0 0.229167 0 0 0 1 0"
id="feColorMatrix4893" />
</filter>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4901">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4903"
width="16"
height="16"
x="141"
y="408" />
</clipPath>
<clipPath <clipPath
clipPathUnits="userSpaceOnUse" clipPathUnits="userSpaceOnUse"
id="clipPath6003"> id="clipPath6003">
@@ -566,39 +429,6 @@
height="16" height="16"
id="rect6005" /> id="rect6005" />
</clipPath> </clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath5245-6">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.31991057;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect5247-8"
width="5"
height="55"
x="174"
y="382" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5097"
id="linearGradient5103"
x1="176.5"
y1="382"
x2="176.5"
y2="385"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,1.6666666,0,-254.66666)" />
<linearGradient
inkscape:collect="always"
id="linearGradient5097">
<stop
style="stop-color:#000000;stop-opacity:0.3137255"
offset="0"
id="stop5099" />
<stop
style="stop-color:#000000;stop-opacity:0"
offset="1"
id="stop5101" />
</linearGradient>
<clipPath <clipPath
clipPathUnits="userSpaceOnUse" clipPathUnits="userSpaceOnUse"
id="clipPath6127"> id="clipPath6127">
@@ -723,188 +553,6 @@
id="rect4112" id="rect4112"
style="fill:#00ff00;fill-opacity:1;stroke:none" /> style="fill:#00ff00;fill-opacity:1;stroke:none" />
</g> </g>
<g
inkscape:groupmode="layer"
id="layer7"
inkscape:label="Project mode trash">
<g
id="src/plugins/projectexplorer/images/targetbuildselected"
inkscape:export-xdpi="180"
inkscape:export-ydpi="180"
clip-path="url(#clipPath6752)">
<rect
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
transform="matrix(1.3956597,0,0,0.98599436,-17.828079,5.9497684)"
y="380.37766"
x="12.773944"
height="43.610806"
width="20.062197"
id="rect4735"
style="opacity:1;fill:url(#linearGradient4691);fill-opacity:1;stroke:none;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4964)"
clip-path="none" />
<path
sodipodi:nodetypes="cczcc"
inkscape:connector-curvature="0"
id="path4727"
d="m 14,422 -1.5,0 C 8,422 4,418 4,413 c 0,-5 4,-9 8.5,-9 l 1.5,0"
style="fill:#eeeeee;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#737373;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
d="m 14.5,421.5 1,0 c 4.5,0 8,-3.5 8,-8.5 0,-5 -3.5,-8.5 -8,-8.5 l -1,0"
id="path4729"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cczcc" />
</g>
<use
x="0"
y="0"
xlink:href="#src/plugins/projectexplorer/images/targetbuildselected"
id="src/plugins/projectexplorer/images/targetrunselected"
transform="matrix(-1,0,0,1,56,0)"
width="100%"
height="100%" />
<g
id="src/plugins/projectexplorer/images/targetrightbutton">
<path
inkscape:connector-curvature="0"
d="m 57.5,381 7,7 -6,6 6,6 -6,6 2.5,2.5 -2.5,2.5 6,6 -7,7 -1.5,0 0,-43 z"
style="opacity:1;fill:url(#linearGradient6377);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path6368" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path6379"
d="m 56.5,424 0,-43"
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196081" />
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path6381"
d="m 69.5,396.5 6.5,6.5 -6.5,6.5"
style="fill:none;fill-rule:evenodd;stroke:#606060;stroke-width:2.1400001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
y="381"
x="56"
height="43"
width="27"
id="rect6383"
style="opacity:1;fill:none;fill-opacity:1;stroke:none;stroke-width:2.1400001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<use
x="0"
y="0"
xlink:href="#src/plugins/projectexplorer/images/targetrightbutton"
id="src/plugins/projectexplorer/images/targetleftbutton"
transform="matrix(-1,0,0,1,166,0)"
width="100%"
height="100%" />
<g
id="src/plugins/projectexplorer/images/selection"
clip-path="url(#clipPath6765)"
transform="translate(0,20)">
<rect
rx="10"
y="384"
x="110"
height="20"
width="31"
id="rect4796"
style="opacity:1;fill:url(#linearGradient4812);fill-opacity:1;stroke:none;stroke-width:2.1400001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0;filter:url(#filter4964)" />
</g>
<g
id="src/plugins/projectexplorer/images/targetchangebutton">
<circle
r="7.5"
cy="416"
cx="149"
id="path4752"
style="opacity:1;fill:#686868;fill-opacity:1;stroke:#484848;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="targetchangebutton_triangle"
d="m 145,415 8,0 -4,4 -4,-4"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<use
x="0"
y="0"
xlink:href="#src/plugins/projectexplorer/images/targetchangebutton"
id="src/plugins/projectexplorer/images/targetchangebutton2"
transform="translate(16,0)"
width="100%"
height="100%"
style="filter:url(#filter4891)"
clip-path="url(#clipPath4901)" />
<g
id="src/plugins/projectexplorer/images/targetseparatorbackground"
clip-path="url(#clipPath5245-6)"
transform="translate(-1,0)">
<rect
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
y="382"
x="174"
height="55"
width="7"
id="rect5093"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#b5b5b5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
transform="translate(0,-5)"
id="g5084">
<g
id="g5074">
<g
id="g5068">
<path
style="fill:none;fill-rule:evenodd;stroke:#acacac;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 173,382 9,9"
id="path5064"
inkscape:connector-curvature="0" />
<use
x="0"
y="0"
xlink:href="#path5064"
id="use5066"
transform="translate(0,5)"
width="100%"
height="100%" />
</g>
<use
height="100%"
width="100%"
transform="translate(0,10)"
id="use5072"
xlink:href="#g5068"
y="0"
x="0" />
</g>
<use
x="0"
y="0"
xlink:href="#g5074"
id="use5080"
transform="translate(0,20)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#use5080"
id="use5082"
transform="translate(0,20)"
width="100%"
height="100%" />
</g>
<rect
y="382"
x="174"
height="5"
width="7"
id="rect5095"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient5103);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
<g <g
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer6" id="layer6"

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 186 KiB