miniprojecttargetselector.cpp 24 KB
Newer Older
Tobias Hunger's avatar
Tobias Hunger committed
1 2 3 4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
Tobias Hunger's avatar
Tobias Hunger committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

30 31 32 33 34 35 36 37
#include "miniprojecttargetselector.h"

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

#include <coreplugin/icore.h>
#include <coreplugin/mainwindow.h>
con's avatar
con committed
38
#include <coreplugin/coreconstants.h>
39 40 41 42 43 44 45 46 47 48 49 50 51 52

#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
53
#include <QtGui/QKeyEvent>
con's avatar
con committed
54
#include <QtGui/QPainter>
55
#include <QtGui/QItemDelegate>
56

Tobias Hunger's avatar
Tobias Hunger committed
57
#include <QtGui/QApplication>
58

59 60 61 62 63 64 65
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);

66 67 68
    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);
69
    if (!overlay.isNull()) {
70 71 72
        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);
73 74 75 76
    }
    return QIcon(targetPixmap);
}

77 78 79
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
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) {
102 103 104 105
        QColor color =(option.state & QStyle::State_HasFocus) ?
                      option.palette.highlight().color() :
                      option.palette.dark().color();
        painter->fillRect(option.rect, color.darker(140));
106 107 108 109 110 111 112 113 114 115 116
        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
117 118 119 120 121 122 123
ProjectListWidget::ProjectListWidget(ProjectExplorer::Project *project, QWidget *parent)
    : QListWidget(parent), m_project(project)
{
    setFocusPolicy(Qt::NoFocus);
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setAlternatingRowColors(false);
    setFocusPolicy(Qt::WheelFocus);
124
    setItemDelegate(new TargetSelectorDelegate(this));
125
    setAttribute(Qt::WA_MacShowFocusRect, false);
Tobias Hunger's avatar
Tobias Hunger committed
126 127 128 129 130

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

ProjectExplorer::Project *ProjectListWidget::project() const
131
{
Tobias Hunger's avatar
Tobias Hunger committed
132 133 134 135 136 137 138 139 140
    return m_project;
}

QSize ProjectListWidget::sizeHint() const
{
    int height = 0;
    for (int itemPos = 0; itemPos < count(); ++itemPos)
        height += item(itemPos)->sizeHint().height();

141 142 143 144 145 146 147 148 149 150 151
    // We try to keep the height of the popup equal to the actionbar
    QSize size(QListWidget::sizeHint().width(), height);
    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
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
}

void ProjectListWidget::setRunComboPopup()
{
    QWidget *w = itemWidget(currentItem());
    MiniTargetWidget *mtw = qobject_cast<MiniTargetWidget*>(w);
    if (mtw->runSettingsComboBox())
        mtw->runSettingsComboBox()->showPopup();
}

void ProjectListWidget::setBuildComboPopup()
{
    QWidget *w = itemWidget(currentItem());
    MiniTargetWidget *mtw = qobject_cast<MiniTargetWidget*>(w);
    if (mtw->buildSettingsComboBox())
        mtw->buildSettingsComboBox()->showPopup();
}

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

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

    if (hasBuildConfiguration()) {
        m_buildComboBox = new QComboBox;
185 186
        m_buildComboBox->setProperty("alignarrow", true);
        m_buildComboBox->setProperty("hideborder", true);
Tobias Hunger's avatar
Tobias Hunger committed
187
        m_buildComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
188
        m_buildComboBox->setToolTip(tr("Select active build configuration"));
Tobias Hunger's avatar
Tobias Hunger committed
189 190 191 192
    } else {
        m_buildComboBox = 0;
    }
 
193
    m_runComboBox = new QComboBox;
194 195
    m_runComboBox ->setProperty("alignarrow", true);
    m_runComboBox ->setProperty("hideborder", true);
196
    m_runComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
197
    m_runComboBox->setToolTip(tr("Select active run configuration"));
198
    int fontSize = font().pointSize();
199 200 201 202 203
    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));
204 205 206

    QGridLayout *gridLayout = new QGridLayout(this);

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

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

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

Tobias Hunger's avatar
Tobias Hunger committed
225
    Q_FOREACH(RunConfiguration* rc, m_target->runConfigurations())
226 227
            addRunConfiguration(rc);

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

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

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

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

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

    QFormLayout *formLayout = new QFormLayout;
253
    formLayout->setLabelAlignment(Qt::AlignRight);
Tobias Hunger's avatar
Tobias Hunger committed
254 255 256
    QLabel *lbl;
    if (hasBuildConfiguration()) {
        lbl = new QLabel(tr("Build:"));
257 258
        lbl->setObjectName(QString::fromUtf8("buildLabel"));
        lbl->setIndent(10);
Tobias Hunger's avatar
Tobias Hunger committed
259 260
        formLayout->addRow(lbl, buildHelperLayout);
    }
261
    lbl = new QLabel(tr("Run:"));
262 263
    lbl->setObjectName(QString::fromUtf8("runLabel"));
    lbl->setIndent(10);
264 265 266 267 268 269 270
    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
271 272
void MiniTargetWidget::updateIcon()
{
273
    m_targetIcon->setPixmap(createCenteredIcon(m_target->icon(), QIcon()).pixmap(Core::Constants::TARGET_ICON_SIZE));
con's avatar
con committed
274 275
}

Tobias Hunger's avatar
Tobias Hunger committed
276 277 278 279 280
ProjectExplorer::Target *MiniTargetWidget::target() const
{
    return m_target;
}

281 282 283 284
void MiniTargetWidget::setActiveBuildConfiguration(int index)
{
    ProjectExplorer::BuildConfiguration* bc =
            m_buildComboBox->itemData(index).value<ProjectExplorer::BuildConfiguration*>();
Tobias Hunger's avatar
Tobias Hunger committed
285
    m_target->setActiveBuildConfiguration(bc);
286
    emit changed();
287 288 289 290
}

void MiniTargetWidget::setActiveRunConfiguration(int index)
{
Tobias Hunger's avatar
Tobias Hunger committed
291
    m_target->setActiveRunConfiguration(
292
            m_runComboBox->itemData(index).value<ProjectExplorer::RunConfiguration*>());
con's avatar
con committed
293
    updateIcon();
294
    emit changed();
295 296 297
}
void MiniTargetWidget::setActiveBuildConfiguration()
{
Tobias Hunger's avatar
Tobias Hunger committed
298
    QTC_ASSERT(m_buildComboBox, return)
299
    m_buildComboBox->setCurrentIndex(m_buildComboBox->findData(
Tobias Hunger's avatar
Tobias Hunger committed
300
            QVariant::fromValue(m_target->activeBuildConfiguration())));
301 302 303 304 305
}

void MiniTargetWidget::setActiveRunConfiguration()
{
    m_runComboBox->setCurrentIndex(m_runComboBox->findData(
Tobias Hunger's avatar
Tobias Hunger committed
306
            QVariant::fromValue(m_target->activeRunConfiguration())));
307 308
}

Tobias Hunger's avatar
Tobias Hunger committed
309
void MiniTargetWidget::addRunConfiguration(ProjectExplorer::RunConfiguration* rc)
310
{
Tobias Hunger's avatar
Tobias Hunger committed
311 312 313
    connect(rc, SIGNAL(displayNameChanged()), SLOT(updateDisplayName()));
    m_runComboBox->addItem(rc->displayName(), QVariant::fromValue(rc));
    if (m_target->activeRunConfiguration() == rc)
314
        m_runComboBox->setCurrentIndex(m_runComboBox->count()-1);
315 316

    m_runComboBox->setEnabled(m_runComboBox->count()>1);
317 318
}

Tobias Hunger's avatar
Tobias Hunger committed
319
void MiniTargetWidget::removeRunConfiguration(ProjectExplorer::RunConfiguration* rc)
320
{
Tobias Hunger's avatar
Tobias Hunger committed
321
    m_runComboBox->removeItem(m_runComboBox->findData(QVariant::fromValue(rc)));
322
    m_runComboBox->setEnabled(m_runComboBox->count()>1);
323 324
}

Tobias Hunger's avatar
Tobias Hunger committed
325
void MiniTargetWidget::addBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
326
{
Tobias Hunger's avatar
Tobias Hunger committed
327 328 329 330
    QTC_ASSERT(m_buildComboBox, return);
    connect(bc, SIGNAL(displayNameChanged()), SLOT(updateDisplayName()));
    m_buildComboBox->addItem(bc->displayName(), QVariant::fromValue(bc));
    if (m_target->activeBuildConfiguration() == bc)
331
        m_buildComboBox->setCurrentIndex(m_buildComboBox->count()-1);
332 333

    m_buildComboBox->setEnabled(m_buildComboBox->count() > 1);
334 335
}

Tobias Hunger's avatar
Tobias Hunger committed
336
void MiniTargetWidget::removeBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
337
{
Tobias Hunger's avatar
Tobias Hunger committed
338 339
    QTC_ASSERT(m_buildComboBox, return);
    m_buildComboBox->removeItem(m_buildComboBox->findData(QVariant::fromValue(bc)));
340
    m_buildComboBox->setEnabled(m_buildComboBox->count() > 1);
341 342 343 344 345
}

void MiniTargetWidget::updateDisplayName()
{
    QObject *obj = sender();
Tobias Hunger's avatar
Tobias Hunger committed
346 347 348 349 350 351 352 353
    RunConfiguration *rc = qobject_cast<RunConfiguration*>(obj);
    BuildConfiguration *bc = qobject_cast<BuildConfiguration*>(obj);
    if (rc) {
        m_runComboBox->setItemText(m_runComboBox->findData(QVariant::fromValue(rc)),
                                   rc->displayName());
    } else if (bc) {
        m_buildComboBox->setItemText(m_buildComboBox->findData(QVariant::fromValue(bc)),
                                     bc->displayName());
354
    }
355
    emit changed();
356 357
}

Tobias Hunger's avatar
Tobias Hunger committed
358 359 360 361 362
bool MiniTargetWidget::hasBuildConfiguration() const
{
    return (m_target->buildConfigurationFactory() != 0);
}

363 364 365
MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorAction, QWidget *parent) :
    QWidget(parent), m_projectAction(targetSelectorAction)
{
366 367
    setProperty("panelwidget", true);
    setContentsMargins(QMargins(0, 1, 1, 8));
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
    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);
389 390 391 392 393

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

394
    m_projectsBox = new QComboBox;
395
    m_projectsBox->setToolTip(tr("Select active project"));
396
    m_projectsBox->setFocusPolicy(Qt::TabFocus);
397 398 399 400 401 402
    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"));
403 404 405 406 407 408 409 410
    m_projectsBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
    m_projectsBox->setMaximumWidth(200);

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

    m_widgetStack = new QStackedWidget;
411
    m_widgetStack->setFocusPolicy(Qt::NoFocus);
412 413
    layout->addWidget(m_widgetStack);

Tobias Hunger's avatar
Tobias Hunger committed
414 415
    connect(m_projectsBox, SIGNAL(activated(int)),
            SLOT(emitStartupProjectChanged(int)));
416 417 418 419 420 421 422 423 424 425 426 427
}

void MiniProjectTargetSelector::setVisible(bool visible)
{
    if (visible) {
        resize(sizeHint());
        QStatusBar *statusBar = Core::ICore::instance()->statusBar();
        QPoint moveTo = statusBar->mapToGlobal(QPoint(0,0));
        moveTo -= QPoint(0, sizeHint().height());
        move(moveTo);
    }
    QWidget::setVisible(visible);
Tobias Hunger's avatar
Tobias Hunger committed
428 429
    if (m_widgetStack->currentWidget())
        m_widgetStack->currentWidget()->setFocus();
430 431

    m_projectAction->setChecked(visible);
432 433
}

434 435 436 437 438 439 440 441 442 443 444 445 446
// 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);
}

447 448 449 450
void MiniProjectTargetSelector::addProject(ProjectExplorer::Project* project)
{
    QTC_ASSERT(project, return);
    ProjectListWidget *targetList = new ProjectListWidget(project);
451
    targetList->setStyleSheet(QString::fromLatin1("QListWidget { background: %1; border: none; }")
452
                              .arg(QColor(70, 70, 70).name()));
453 454 455 456
    int pos = m_widgetStack->addWidget(targetList);

    m_projectsBox->addItem(project->displayName(), QVariant::fromValue(project));

Tobias Hunger's avatar
Tobias Hunger committed
457 458
    connect(project, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
            SLOT(updateAction()));
459

Tobias Hunger's avatar
Tobias Hunger committed
460 461 462 463
    connect(project, SIGNAL(addedTarget(ProjectExplorer::Target*)),
            SLOT(addTarget(ProjectExplorer::Target*)));
    connect(project, SIGNAL(removedTarget(ProjectExplorer::Target*)),
            SLOT(removeTarget(ProjectExplorer::Target*)));
464 465
    connect(project, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
            SLOT(changeActiveTarget(ProjectExplorer::Target*)));
466 467 468 469 470

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

    foreach (Target *t, project->targets())
        addTarget(t, t == project->activeTarget());
474 475

    m_projectsBox->setEnabled(m_projectsBox->count() > 1);
476 477 478 479
}

void MiniProjectTargetSelector::removeProject(ProjectExplorer::Project* project)
{
Tobias Hunger's avatar
Tobias Hunger committed
480 481 482 483 484
    int index = indexFor(project);
    if (index < 0)
        return;
    ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
    m_projectsBox->removeItem(index);
485
    m_projectsBox->setEnabled(m_projectsBox->count() > 1);
Tobias Hunger's avatar
Tobias Hunger committed
486
    delete plw;
487 488
}

Tobias Hunger's avatar
Tobias Hunger committed
489 490 491 492 493 494 495 496
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
497 498
    connect(target, SIGNAL(toolTipChanged()), this, SLOT(updateAction()));
    connect(target, SIGNAL(iconChanged()), this, SLOT(updateAction()));
499
    connect(target, SIGNAL(overlayIconChanged()), this, SLOT(updateAction()));
Tobias Hunger's avatar
Tobias Hunger committed
500 501
    ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
    QListWidgetItem *lwi = new QListWidgetItem();
502 503 504 505 506 507 508 509 510 511 512 513 514 515

    // 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
516
    MiniTargetWidget *targetWidget = new MiniTargetWidget(target);
517
    connect(targetWidget, SIGNAL(changed()), this, SLOT(updateAction()));
Tobias Hunger's avatar
Tobias Hunger committed
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
    targetWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
    // width==0 size hint to avoid horizontal scrolling in list widget
    lwi->setSizeHint(QSize(0, targetWidget->sizeHint().height()));
    plw->setItemWidget(lwi, targetWidget);

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

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;
    }
546 547 548
    disconnect(target, SIGNAL(toolTipChanged()), this, SLOT(updateAction()));
    disconnect(target, SIGNAL(iconChanged()), this, SLOT(updateAction()));
    disconnect(target, SIGNAL(overlayIconChanged()), this, SLOT(updateAction()));
Tobias Hunger's avatar
Tobias Hunger committed
549
}
550

551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
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;
        }
    }
}

568 569 570 571
void MiniProjectTargetSelector::updateAction()
{
    Project *project = ProjectExplorerPlugin::instance()->startupProject();

572
    QString projectName;;
573
    QString targetName;
con's avatar
con committed
574
    QString targetToolTipText;
575 576
    QString buildConfig;
    QString runConfig;
577
    QIcon targetIcon = style()->standardIcon(QStyle::SP_ComputerIcon);
578 579 580

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

582 583 584 585 586
        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
587
                buildConfig = bc->displayName();
588 589 590 591 592
            }

            if (RunConfiguration *rc = target->activeRunConfiguration()) {
                runConfig = rc->displayName();
            }
con's avatar
con committed
593
            targetToolTipText = target->toolTip();
594
            targetIcon = createCenteredIcon(target->icon(), target->overlayIcon());
Tobias Hunger's avatar
Tobias Hunger committed
595
        }
596 597 598
    }
    m_projectAction->setProperty("heading", projectName);
    m_projectAction->setProperty("subtitle", buildConfig);
con's avatar
con committed
599
    m_projectAction->setIcon(targetIcon);
600
    QString toolTip = tr("<html><nobr><b>Project:</b> %1<br/>%2%3<b>Run:</b> %4%5</html>");
601 602 603 604
    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
605 606 607
    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
608 609 610 611 612 613 614 615 616 617
}

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;
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
}

void MiniProjectTargetSelector::emitStartupProjectChanged(int index)
{
    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
638

639 640 641 642 643 644 645 646 647 648 649
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);
}