miniprojecttargetselector.cpp 26 KB
Newer Older
Tobias Hunger's avatar
Tobias Hunger committed
1 2 3 4
/**************************************************************************
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
Tobias Hunger's avatar
Tobias Hunger committed
6
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
Tobias Hunger's avatar
Tobias Hunger committed
8 9 10 11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
Tobias Hunger's avatar
Tobias Hunger committed
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
Tobias Hunger's avatar
Tobias Hunger committed
29
** Nokia at info@qt.nokia.com.
Tobias Hunger's avatar
Tobias Hunger committed
30 31 32
**
**************************************************************************/

33
#include "miniprojecttargetselector.h"
dt's avatar
dt committed
34 35
#include "buildconfigurationmodel.h"
#include "runconfigurationmodel.h"
36
#include "target.h"
37 38 39 40 41

#include <utils/qtcassert.h>
#include <utils/styledbar.h>
#include <utils/stylehelper.h>

42
#include <coreplugin/ifile.h>
43
#include <coreplugin/icore.h>
con's avatar
con committed
44
#include <coreplugin/coreconstants.h>
45 46 47 48 49 50 51 52 53 54 55 56 57 58

#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <projectexplorer/project.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/buildconfiguration.h>

#include <QtGui/QLayout>
#include <QtGui/QFormLayout>
#include <QtGui/QLabel>
#include <QtGui/QComboBox>
#include <QtGui/QListWidget>
#include <QtGui/QStatusBar>
#include <QtGui/QStackedWidget>
Tobias Hunger's avatar
Tobias Hunger committed
59
#include <QtGui/QKeyEvent>
con's avatar
con committed
60
#include <QtGui/QPainter>
61
#include <QtGui/QAction>
62
#include <QtGui/QItemDelegate>
63
#include <QtGui/QMainWindow>
64

Tobias Hunger's avatar
Tobias Hunger committed
65
#include <QtGui/QApplication>
66

67 68 69 70 71 72 73
static QIcon createCenteredIcon(const QIcon &icon, const QIcon &overlay)
{
    QPixmap targetPixmap;
    targetPixmap = QPixmap(Core::Constants::TARGET_ICON_SIZE, Core::Constants::TARGET_ICON_SIZE);
    targetPixmap.fill(Qt::transparent);
    QPainter painter(&targetPixmap);

74 75 76
    QPixmap pixmap = icon.pixmap(Core::Constants::TARGET_ICON_SIZE);
    painter.drawPixmap((Core::Constants::TARGET_ICON_SIZE - pixmap.width())/2,
                       (Core::Constants::TARGET_ICON_SIZE - pixmap.height())/2, pixmap);
77
    if (!overlay.isNull()) {
78 79 80
        pixmap = overlay.pixmap(Core::Constants::TARGET_ICON_SIZE);
        painter.drawPixmap((Core::Constants::TARGET_ICON_SIZE - pixmap.width())/2,
                           (Core::Constants::TARGET_ICON_SIZE - pixmap.height())/2, pixmap);
81 82 83 84
    }
    return QIcon(targetPixmap);
}

85 86 87
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
class TargetSelectorDelegate : public QItemDelegate
{
public:
    TargetSelectorDelegate(QObject *parent) : QItemDelegate(parent) { }
private:
    void paint(QPainter *painter,
               const QStyleOptionViewItem &option,
               const QModelIndex &index) const;
    mutable QImage selectionGradient;
};

void TargetSelectorDelegate::paint(QPainter *painter,
                                   const QStyleOptionViewItem &option,
                                   const QModelIndex &) const
{
    painter->save();
    painter->setClipping(false);

    if (selectionGradient.isNull())
        selectionGradient.load(QLatin1String(":/projectexplorer/images/targetpanel_gradient.png"));

    if (option.state & QStyle::State_Selected) {
110 111 112 113
        QColor color =(option.state & QStyle::State_HasFocus) ?
                      option.palette.highlight().color() :
                      option.palette.dark().color();
        painter->fillRect(option.rect, color.darker(140));
114 115 116 117 118 119 120 121 122 123 124
        Utils::StyleHelper::drawCornerImage(selectionGradient, painter, option.rect.adjusted(0, 0, 0, -1), 5, 5, 5, 5);
        painter->setPen(QColor(255, 255, 255, 60));
        painter->drawLine(option.rect.topLeft(), option.rect.topRight());
        painter->setPen(QColor(255, 255, 255, 30));
        painter->drawLine(option.rect.bottomLeft() - QPoint(0,1), option.rect.bottomRight() -  QPoint(0,1));
        painter->setPen(QColor(0, 0, 0, 80));
        painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
    }
    painter->restore();
}

Tobias Hunger's avatar
Tobias Hunger committed
125 126 127 128 129 130 131
ProjectListWidget::ProjectListWidget(ProjectExplorer::Project *project, QWidget *parent)
    : QListWidget(parent), m_project(project)
{
    setFocusPolicy(Qt::NoFocus);
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setAlternatingRowColors(false);
    setFocusPolicy(Qt::WheelFocus);
132
    setItemDelegate(new TargetSelectorDelegate(this));
133
    setAttribute(Qt::WA_MacShowFocusRect, false);
Tobias Hunger's avatar
Tobias Hunger committed
134 135 136 137 138

    connect(this, SIGNAL(currentRowChanged(int)), SLOT(setTarget(int)));
}

ProjectExplorer::Project *ProjectListWidget::project() const
139
{
Tobias Hunger's avatar
Tobias Hunger committed
140 141 142 143 144 145
    return m_project;
}

QSize ProjectListWidget::sizeHint() const
{
    int height = 0;
146 147
    int width = 0;
    for (int itemPos = 0; itemPos < count(); ++itemPos) {
Tobias Hunger's avatar
Tobias Hunger committed
148
        height += item(itemPos)->sizeHint().height();
149 150
        width = qMax(width, item(itemPos)->sizeHint().width());
    }
Tobias Hunger's avatar
Tobias Hunger committed
151

152
    // We try to keep the height of the popup equal to the actionbar
153
    QSize size(width, height);
154 155 156 157 158 159 160 161 162
    static QStatusBar *statusBar = Core::ICore::instance()->statusBar();
    static QWidget *actionBar = Core::ICore::instance()->mainWindow()->findChild<QWidget*>("actionbar");
    Q_ASSERT(actionBar);

    QMargins popupMargins = window()->contentsMargins();
    if (actionBar)
        size.setHeight(qMax(actionBar->height() - statusBar->height() -
                            (popupMargins.top() + popupMargins.bottom()), height));
    return size;
Tobias Hunger's avatar
Tobias Hunger committed
163 164 165 166
}

void ProjectListWidget::setTarget(int index)
{
167 168 169 170
    MiniTargetWidget *mtw = qobject_cast<MiniTargetWidget *>(itemWidget(item(index)));
    if (!mtw)
        return;
    m_project->setActiveTarget(mtw->target());
Tobias Hunger's avatar
Tobias Hunger committed
171 172 173 174 175 176 177 178 179
}

MiniTargetWidget::MiniTargetWidget(Target *target, QWidget *parent) :
    QWidget(parent), m_target(target)
{
    Q_ASSERT(m_target);

    if (hasBuildConfiguration()) {
        m_buildComboBox = new QComboBox;
180 181
        m_buildComboBox->setProperty("alignarrow", true);
        m_buildComboBox->setProperty("hideborder", true);
Tobias Hunger's avatar
Tobias Hunger committed
182
        m_buildComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
183
        m_buildComboBox->setToolTip(tr("Select active build configuration"));
dt's avatar
dt committed
184
        m_buildComboBox->setModel(new BuildConfigurationModel(m_target, this));
Tobias Hunger's avatar
Tobias Hunger committed
185 186 187 188
    } else {
        m_buildComboBox = 0;
    }
 
189
    m_runComboBox = new QComboBox;
190 191
    m_runComboBox ->setProperty("alignarrow", true);
    m_runComboBox ->setProperty("hideborder", true);
192
    m_runComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
193
    m_runComboBox->setToolTip(tr("Select active run configuration"));
dt's avatar
dt committed
194 195
    RunConfigurationModel *model = new RunConfigurationModel(m_target, this);
    m_runComboBox->setModel(model);
196
    int fontSize = font().pointSize();
197 198 199 200 201
    setStyleSheet(QString::fromLatin1("QLabel { font-size: %2pt; color: white; } "
                                      "#target { font: bold %1pt;} "
                                      "#buildLabel{ font: bold; color: rgba(255, 255, 255, 160)} "
                                      "#runLabel { font: bold ; color: rgba(255, 255, 255, 160)} "
                                      ).arg(fontSize).arg(fontSize - 2));
202 203 204

    QGridLayout *gridLayout = new QGridLayout(this);

Tobias Hunger's avatar
Tobias Hunger committed
205
    m_targetName = new QLabel(m_target->displayName());
206
    m_targetName->setObjectName(QString::fromUtf8("target"));
207
    m_targetIcon = new QLabel();
con's avatar
con committed
208
    updateIcon();
Tobias Hunger's avatar
Tobias Hunger committed
209 210 211
    if (hasBuildConfiguration()) {
        Q_FOREACH(BuildConfiguration* bc, m_target->buildConfigurations())
                addBuildConfiguration(bc);
212

dt's avatar
dt committed
213 214 215
        BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
        m_buildComboBox->setCurrentIndex(model->indexFor(m_target->activeBuildConfiguration()).row());

Tobias Hunger's avatar
Tobias Hunger committed
216 217 218
        connect(m_target, SIGNAL(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
                SLOT(addBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
        connect(m_target, SIGNAL(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
219
                SLOT(removeBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
Tobias Hunger's avatar
Tobias Hunger committed
220 221 222 223 224

        connect(m_target, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
                SLOT(setActiveBuildConfiguration()));
        connect(m_buildComboBox, SIGNAL(currentIndexChanged(int)), SLOT(setActiveBuildConfiguration(int)));
    }
225

dt's avatar
dt committed
226 227
    m_runComboBox->setEnabled(m_target->runConfigurations().count() > 1);
    m_runComboBox->setCurrentIndex(model->indexFor(m_target->activeRunConfiguration()).row());
228

Tobias Hunger's avatar
Tobias Hunger committed
229
    connect(m_target, SIGNAL(addedRunConfiguration(ProjectExplorer::RunConfiguration*)),
230
            SLOT(addRunConfiguration(ProjectExplorer::RunConfiguration*)));
Tobias Hunger's avatar
Tobias Hunger committed
231
    connect(m_target, SIGNAL(removedRunConfiguration(ProjectExplorer::RunConfiguration*)),
232 233 234 235
            SLOT(removeRunConfiguration(ProjectExplorer::RunConfiguration*)));

    connect(m_runComboBox, SIGNAL(currentIndexChanged(int)), SLOT(setActiveRunConfiguration(int)));

Tobias Hunger's avatar
Tobias Hunger committed
236 237
    connect(m_target, SIGNAL(activeRunConfigurationChanged(ProjectExplorer::RunConfiguration*)),
            SLOT(setActiveRunConfiguration()));
con's avatar
con committed
238
    connect(m_target, SIGNAL(iconChanged()), this, SLOT(updateIcon()));
Tobias Hunger's avatar
Tobias Hunger committed
239 240 241 242 243 244 245 246

    QHBoxLayout *buildHelperLayout = 0;
    if (hasBuildConfiguration()) {
        buildHelperLayout= new QHBoxLayout;
        buildHelperLayout->setMargin(0);
        buildHelperLayout->setSpacing(0);
        buildHelperLayout->addWidget(m_buildComboBox);
    }
247 248 249 250 251 252 253

    QHBoxLayout *runHelperLayout = new QHBoxLayout;
    runHelperLayout->setMargin(0);
    runHelperLayout->setSpacing(0);
    runHelperLayout->addWidget(m_runComboBox);

    QFormLayout *formLayout = new QFormLayout;
254
    formLayout->setLabelAlignment(Qt::AlignRight);
Tobias Hunger's avatar
Tobias Hunger committed
255
    QLabel *lbl;
256
    int indent = 10;
Tobias Hunger's avatar
Tobias Hunger committed
257 258
    if (hasBuildConfiguration()) {
        lbl = new QLabel(tr("Build:"));
259
        lbl->setObjectName(QString::fromUtf8("buildLabel"));
260 261 262
        lbl->setMinimumWidth(lbl->fontMetrics().width(lbl->text()) + indent + 4);
        lbl->setIndent(indent);

Tobias Hunger's avatar
Tobias Hunger committed
263 264
        formLayout->addRow(lbl, buildHelperLayout);
    }
265
    lbl = new QLabel(tr("Run:"));
266
    lbl->setObjectName(QString::fromUtf8("runLabel"));
267 268
    lbl->setMinimumWidth(lbl->fontMetrics().width(lbl->text()) + indent + 4);
    lbl->setIndent(indent);
269 270 271 272 273 274 275
    formLayout->addRow(lbl, runHelperLayout);

    gridLayout->addWidget(m_targetName, 0, 0);
    gridLayout->addWidget(m_targetIcon, 0, 1, 2, 1, Qt::AlignTop|Qt::AlignHCenter);
    gridLayout->addLayout(formLayout, 1, 0);
}

con's avatar
con committed
276 277
void MiniTargetWidget::updateIcon()
{
278
    m_targetIcon->setPixmap(createCenteredIcon(m_target->icon(), QIcon()).pixmap(Core::Constants::TARGET_ICON_SIZE));
con's avatar
con committed
279 280
}

Tobias Hunger's avatar
Tobias Hunger committed
281 282 283 284 285
ProjectExplorer::Target *MiniTargetWidget::target() const
{
    return m_target;
}

286 287
void MiniTargetWidget::setActiveBuildConfiguration(int index)
{
dt's avatar
dt committed
288 289
    BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
    m_target->setActiveBuildConfiguration(model->buildConfigurationAt(index));
290
    emit changed();
291 292 293 294
}

void MiniTargetWidget::setActiveRunConfiguration(int index)
{
dt's avatar
dt committed
295 296
    RunConfigurationModel *model = static_cast<RunConfigurationModel *>(m_runComboBox->model());
    m_target->setActiveRunConfiguration(model->runConfigurationAt(index));
con's avatar
con committed
297
    updateIcon();
298
    emit changed();
299
}
dt's avatar
dt committed
300

301 302
void MiniTargetWidget::setActiveBuildConfiguration()
{
dt's avatar
dt committed
303 304 305
    QTC_ASSERT(m_buildComboBox, return);
    BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
    m_buildComboBox->setCurrentIndex(model->indexFor(m_target->activeBuildConfiguration()).row());
306 307 308 309
}

void MiniTargetWidget::setActiveRunConfiguration()
{
dt's avatar
dt committed
310 311
    RunConfigurationModel *model = static_cast<RunConfigurationModel *>(m_runComboBox->model());
    m_runComboBox->setCurrentIndex(model->indexFor(m_target->activeRunConfiguration()).row());
312 313
}

Tobias Hunger's avatar
Tobias Hunger committed
314
void MiniTargetWidget::addRunConfiguration(ProjectExplorer::RunConfiguration* rc)
315
{
hjk's avatar
hjk committed
316 317
    Q_UNUSED(rc);
    m_runComboBox->setEnabled(m_target->runConfigurations().count()>1);
318 319
}

Tobias Hunger's avatar
Tobias Hunger committed
320
void MiniTargetWidget::removeRunConfiguration(ProjectExplorer::RunConfiguration* rc)
321
{
dt's avatar
dt committed
322 323
    Q_UNUSED(rc);
    m_runComboBox->setEnabled(m_target->runConfigurations().count()>1);
324 325
}

Tobias Hunger's avatar
Tobias Hunger committed
326
void MiniTargetWidget::addBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
327
{
dt's avatar
dt committed
328
    Q_UNUSED(bc);
hjk's avatar
hjk committed
329 330
    connect(bc, SIGNAL(displayNameChanged()), SIGNAL(changed()), Qt::UniqueConnection);
    m_buildComboBox->setEnabled(m_target->buildConfigurations().count() > 1);
331 332
}

Tobias Hunger's avatar
Tobias Hunger committed
333
void MiniTargetWidget::removeBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
334
{
dt's avatar
dt committed
335
    Q_UNUSED(bc);
Tobias Hunger's avatar
Tobias Hunger committed
336
    QTC_ASSERT(m_buildComboBox, return);
dt's avatar
dt committed
337
    m_buildComboBox->setEnabled(m_target->buildConfigurations().count() > 1);
338 339
}

Tobias Hunger's avatar
Tobias Hunger committed
340 341 342 343 344
bool MiniTargetWidget::hasBuildConfiguration() const
{
    return (m_target->buildConfigurationFactory() != 0);
}

345
MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorAction, QWidget *parent) :
346
    QWidget(parent), m_projectAction(targetSelectorAction), m_ignoreIndexChange(false)
347
{
348 349
    setProperty("panelwidget", true);
    setContentsMargins(QMargins(0, 1, 1, 8));
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
    setWindowFlags(Qt::Popup);

    targetSelectorAction->setIcon(style()->standardIcon(QStyle::SP_ComputerIcon));
    targetSelectorAction->setProperty("titledAction", true);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setMargin(0);
    layout->setSpacing(0);

    Utils::StyledBar *bar = new Utils::StyledBar;
    bar->setSingleRow(true);
    layout->addWidget(bar);
    QHBoxLayout *toolLayout = new QHBoxLayout(bar);
    toolLayout->setMargin(0);
    toolLayout->setSpacing(0);

    QLabel *lbl = new QLabel(tr("Project"));
    lbl->setIndent(6);
    QFont f = lbl->font();
    f.setBold(true);
    lbl->setFont(f);
371 372 373 374 375

    int panelHeight = lbl->fontMetrics().height() + 12;
    bar->ensurePolished(); // Required since manhattanstyle overrides height
    bar->setFixedHeight(panelHeight);

376
    m_projectsBox = new QComboBox;
377
    m_projectsBox->setToolTip(tr("Select active project"));
378
    m_projectsBox->setFocusPolicy(Qt::TabFocus);
379 380 381 382 383 384
    f.setBold(false);
    m_projectsBox->setFont(f);
    m_projectsBox->ensurePolished();
    m_projectsBox->setFixedHeight(panelHeight);
    m_projectsBox->setProperty("hideborder", true);
    m_projectsBox->setObjectName(QString::fromUtf8("ProjectsBox"));
385 386
    m_projectsBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    m_projectsBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
387 388 389 390 391 392

    toolLayout->addWidget(lbl);
    toolLayout->addWidget(new Utils::StyledSeparator);
    toolLayout->addWidget(m_projectsBox);

    m_widgetStack = new QStackedWidget;
393
    m_widgetStack->setFocusPolicy(Qt::NoFocus);
394 395
    layout->addWidget(m_widgetStack);

Tobias Hunger's avatar
Tobias Hunger committed
396 397
    connect(m_projectsBox, SIGNAL(activated(int)),
            SLOT(emitStartupProjectChanged(int)));
398 399 400 401 402
}

void MiniProjectTargetSelector::setVisible(bool visible)
{
    if (visible) {
403 404
        QSize sh = sizeHint();
        resize(sh);
405 406
        QStatusBar *statusBar = Core::ICore::instance()->statusBar();
        QPoint moveTo = statusBar->mapToGlobal(QPoint(0,0));
407
        moveTo -= QPoint(0, sh.height());
408 409
        move(moveTo);
    }
410

411
    QWidget::setVisible(visible);
412

Tobias Hunger's avatar
Tobias Hunger committed
413 414
    if (m_widgetStack->currentWidget())
        m_widgetStack->currentWidget()->setFocus();
415 416

    m_projectAction->setChecked(visible);
417 418
}

419 420 421 422 423 424 425 426 427 428 429 430 431
// This is a workaround for the problem that Windows
// will let the mouse events through when you click
// outside a popup to close it. This causes the popup
// to open on mouse release if you hit the button, which
//
//
// A similar case can be found in QComboBox
void MiniProjectTargetSelector::mousePressEvent(QMouseEvent *e)
{
    setAttribute(Qt::WA_NoMouseReplay);
    QWidget::mousePressEvent(e);
}

432 433
QString MiniProjectTargetSelector::fullName(ProjectExplorer::Project *project)
{
434
    return project->displayName() + " (" + project->file()->fileName() + QLatin1Char(')');
435 436 437
}

void MiniProjectTargetSelector::addProject(ProjectExplorer::Project *project)
438 439 440
{
    QTC_ASSERT(project, return);
    ProjectListWidget *targetList = new ProjectListWidget(project);
441
    targetList->setStyleSheet(QString::fromLatin1("QListWidget { background: %1; border: none; }")
442
                              .arg(QColor(70, 70, 70).name()));
443

dt's avatar
dt committed
444 445
    m_ignoreIndexChange = true;

446
    QString sortName = fullName(project);
dt's avatar
dt committed
447
    int pos = 0;
448 449 450 451
    for (int i=0; i < m_projectsBox->count(); ++i) {
        Project *p = m_projectsBox->itemData(i).value<Project*>();
        QString itemSortName = fullName(p);
        if (itemSortName > sortName)
dt's avatar
dt committed
452
            pos = i;
453
    }
dt's avatar
dt committed
454 455 456

    m_widgetStack->insertWidget(pos, targetList);

457 458 459 460 461 462 463 464 465 466 467
    bool useFullName = false;
    for (int i = 0; i < m_projectsBox->count(); ++i) {
        Project *p = m_projectsBox->itemData(i).value<Project*>();
        if (p->displayName() == project->displayName()) {
            useFullName = true;
            m_projectsBox->setItemText(i, fullName(p));
        }
    }

    QString displayName = useFullName ? fullName(project) : project->displayName();
    m_projectsBox->insertItem(pos, displayName, QVariant::fromValue(project));
468

Tobias Hunger's avatar
Tobias Hunger committed
469 470
    connect(project, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
            SLOT(updateAction()));
471

Tobias Hunger's avatar
Tobias Hunger committed
472 473 474 475
    connect(project, SIGNAL(addedTarget(ProjectExplorer::Target*)),
            SLOT(addTarget(ProjectExplorer::Target*)));
    connect(project, SIGNAL(removedTarget(ProjectExplorer::Target*)),
            SLOT(removeTarget(ProjectExplorer::Target*)));
476 477
    connect(project, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
            SLOT(changeActiveTarget(ProjectExplorer::Target*)));
478 479 480 481 482

    if (project == ProjectExplorerPlugin::instance()->startupProject()) {
        m_projectsBox->setCurrentIndex(pos);
        m_widgetStack->setCurrentIndex(pos);
    }
Tobias Hunger's avatar
Tobias Hunger committed
483

dt's avatar
dt committed
484 485
    m_ignoreIndexChange = false;

Tobias Hunger's avatar
Tobias Hunger committed
486 487
    foreach (Target *t, project->targets())
        addTarget(t, t == project->activeTarget());
488 489

    m_projectsBox->setEnabled(m_projectsBox->count() > 1);
490
    m_projectsBox->parentWidget()->layout()->activate();
491 492 493 494
}

void MiniProjectTargetSelector::removeProject(ProjectExplorer::Project* project)
{
Tobias Hunger's avatar
Tobias Hunger committed
495 496 497 498
    int index = indexFor(project);
    if (index < 0)
        return;
    ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
499 500 501 502

    // We don't want to emit a startUpProject changed, even if we remove the current startup project
    // The ProjectExplorer takes care of setting a new startup project.
    m_ignoreIndexChange = true;
Tobias Hunger's avatar
Tobias Hunger committed
503
    m_projectsBox->removeItem(index);
504
    m_projectsBox->setEnabled(m_projectsBox->count() > 1);
Tobias Hunger's avatar
Tobias Hunger committed
505
    delete plw;
506 507 508 509

    // Update display names
    QString name = project->displayName();
    int count = 0;
510
    int otherIndex = -1;
511 512 513 514 515 516 517 518 519 520 521 522
    for (int i = 0; i < m_projectsBox->count(); ++i) {
        Project *p = m_projectsBox->itemData(i).value<Project*>();
        if (p->displayName() == name) {
            ++count;
            otherIndex = i;
        }
    }
    if (count == 1) {
        Project *p = m_projectsBox->itemData(otherIndex).value<Project*>();
        m_projectsBox->setItemText(otherIndex, p->displayName());
    }

523
    m_ignoreIndexChange = false;
524
    m_projectsBox->parentWidget()->layout()->activate();
525 526
}

Tobias Hunger's avatar
Tobias Hunger committed
527 528 529 530 531 532 533 534
void MiniProjectTargetSelector::addTarget(ProjectExplorer::Target *target, bool activeTarget)
{
    QTC_ASSERT(target, return);

    int index = indexFor(target->project());
    if (index < 0)
        return;

con's avatar
con committed
535 536
    connect(target, SIGNAL(toolTipChanged()), this, SLOT(updateAction()));
    connect(target, SIGNAL(iconChanged()), this, SLOT(updateAction()));
537
    connect(target, SIGNAL(overlayIconChanged()), this, SLOT(updateAction()));
Tobias Hunger's avatar
Tobias Hunger committed
538 539
    ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
    QListWidgetItem *lwi = new QListWidgetItem();
540 541 542 543 544 545 546 547 548 549 550 551 552 553

    // Sort on insert:
    for (int idx = 0; idx <= plw->count(); ++idx) {
        QListWidgetItem *itm(plw->item(idx));
        MiniTargetWidget *mtw(qobject_cast<MiniTargetWidget *>(plw->itemWidget(itm)));
        if (!mtw && idx < plw->count())
            continue;
        if (idx == plw->count() ||
            mtw->target()->displayName() > target->displayName()) {
            plw->insertItem(idx, lwi);
            break;
        }
    }

Tobias Hunger's avatar
Tobias Hunger committed
554
    MiniTargetWidget *targetWidget = new MiniTargetWidget(target);
555
    connect(targetWidget, SIGNAL(changed()), this, SLOT(updateAction()));
Tobias Hunger's avatar
Tobias Hunger committed
556
    targetWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
557
    lwi->setSizeHint(targetWidget->sizeHint());
Tobias Hunger's avatar
Tobias Hunger committed
558 559 560 561
    plw->setItemWidget(lwi, targetWidget);

    if (activeTarget)
        plw->setCurrentItem(lwi, QItemSelectionModel::SelectCurrent);
562 563

    m_widgetStack->updateGeometry();
Tobias Hunger's avatar
Tobias Hunger committed
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
}

void MiniProjectTargetSelector::removeTarget(ProjectExplorer::Target *target)
{
    QTC_ASSERT(target, return);

    int index = indexFor(target->project());
    if (index < 0)
        return;

    ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
    for (int i = 0; i < plw->count(); ++i) {
        QListWidgetItem *itm(plw->item(i));
        MiniTargetWidget *mtw(qobject_cast<MiniTargetWidget *>(plw->itemWidget(itm)));
        if (!mtw)
            continue;
        if (target != mtw->target())
            continue;
        delete plw->takeItem(i);
        delete mtw;
    }
585

586 587 588
    disconnect(target, SIGNAL(toolTipChanged()), this, SLOT(updateAction()));
    disconnect(target, SIGNAL(iconChanged()), this, SLOT(updateAction()));
    disconnect(target, SIGNAL(overlayIconChanged()), this, SLOT(updateAction()));
589 590

    m_widgetStack->updateGeometry();
Tobias Hunger's avatar
Tobias Hunger committed
591
}
592

593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
void MiniProjectTargetSelector::changeActiveTarget(ProjectExplorer::Target *target)
{
    int index = indexFor(target->project());
    if (index < 0)
        return;
    ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));

    for (int i = 0; i < plw->count(); ++i) {
        QListWidgetItem *itm = plw->item(i);
        MiniTargetWidget *mtw = qobject_cast<MiniTargetWidget*>(plw->itemWidget(itm));
        if (mtw->target() == target) {
            plw->setCurrentItem(itm);
            break;
        }
    }
}

610 611 612 613
void MiniProjectTargetSelector::updateAction()
{
    Project *project = ProjectExplorerPlugin::instance()->startupProject();

614
    QString projectName;;
615
    QString targetName;
con's avatar
con committed
616
    QString targetToolTipText;
617 618
    QString buildConfig;
    QString runConfig;
619
    QIcon targetIcon = style()->standardIcon(QStyle::SP_ComputerIcon);
620

621
    const int extrawidth = 110; // Size of margins + icon width
Tobias Hunger's avatar
Tobias Hunger committed
622
    // Some fudge numbers to ensure the menu does not grow unbounded
623 624
    int maxLength = fontMetrics().averageCharWidth() * 140;

625 626
    if (project) {
        projectName = project->displayName();
Tobias Hunger's avatar
Tobias Hunger committed
627

628 629 630 631 632
        if (Target *target = project->activeTarget()) {
            if (project->targets().count() > 1) {
                targetName = project->activeTarget()->displayName();
            }
            if (BuildConfiguration *bc = target->activeBuildConfiguration()) {
Tobias Hunger's avatar
Tobias Hunger committed
633
                buildConfig = bc->displayName();
634 635
                int minimumWidth = fontMetrics().width(bc->displayName() + tr("Build:")) + extrawidth;
                m_widgetStack->setMinimumWidth(qMin(maxLength, qMax(minimumWidth, m_widgetStack->minimumWidth())));
636 637 638 639
            }

            if (RunConfiguration *rc = target->activeRunConfiguration()) {
                runConfig = rc->displayName();
640 641
                int minimumWidth = fontMetrics().width(rc->displayName() + tr("Run:")) + extrawidth;
                m_widgetStack->setMinimumWidth(qMin(maxLength, qMax(minimumWidth, m_widgetStack->minimumWidth())));
642
            }
con's avatar
con committed
643
            targetToolTipText = target->toolTip();
644
            targetIcon = createCenteredIcon(target->icon(), target->overlayIcon());
Tobias Hunger's avatar
Tobias Hunger committed
645
        }
646 647 648
    }
    m_projectAction->setProperty("heading", projectName);
    m_projectAction->setProperty("subtitle", buildConfig);
con's avatar
con committed
649
    m_projectAction->setIcon(targetIcon);
650
    QString toolTip = tr("<html><nobr><b>Project:</b> %1<br/>%2%3<b>Run:</b> %4%5</html>");
651 652 653 654
    QString targetTip = targetName.isEmpty() ? QLatin1String("")
        : tr("<b>Target:</b> %1<br/>").arg(targetName);
    QString buildTip = buildConfig.isEmpty() ? QLatin1String("")
        : tr("<b>Build:</b> %2<br/>").arg(buildConfig);
con's avatar
con committed
655 656 657
    QString targetToolTip = targetToolTipText.isEmpty() ? QLatin1String("")
        : tr("<br/>%1").arg(targetToolTipText);
    m_projectAction->setToolTip(toolTip.arg(projectName, targetTip, buildTip, runConfig, targetToolTip));
Tobias Hunger's avatar
Tobias Hunger committed
658 659 660 661 662 663 664 665 666 667
}

int MiniProjectTargetSelector::indexFor(ProjectExplorer::Project *project) const
{
    for (int i = 0; i < m_widgetStack->count(); ++i) {
        ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(i));
        if (plw && plw->project() == project)
            return i;
    }
    return -1;
668 669 670 671
}

void MiniProjectTargetSelector::emitStartupProjectChanged(int index)
{
672 673
    if (m_ignoreIndexChange)
        return;
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
    Project *project = m_projectsBox->itemData(index).value<Project*>();
    QTC_ASSERT(project, return;)
    emit startupProjectChanged(project);
}

void MiniProjectTargetSelector::changeStartupProject(ProjectExplorer::Project *project)
{
    for (int i = 0; i < m_widgetStack->count(); ++i) {
        ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(i));
        if (plw && plw->project() == project) {
            m_projectsBox->setCurrentIndex(i);
            m_widgetStack->setCurrentIndex(i);
        }
    }
    updateAction();
}
Tobias Hunger's avatar
Tobias Hunger committed
690

691 692 693 694 695 696 697 698 699 700 701
void MiniProjectTargetSelector::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setPen(Utils::StyleHelper::borderColor());
    painter.drawLine(rect().topLeft(), rect().topRight());
    painter.drawLine(rect().topRight(), rect().bottomRight());

    QRect bottomRect(0, rect().height() - 8, rect().width(), 8);
    static QImage image(QLatin1String(":/projectexplorer/images/targetpanel_bottom.png"));
    Utils::StyleHelper::drawCornerImage(image, &painter, bottomRect, 1, 1, 1, 1);
}