miniprojecttargetselector.cpp 25 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
#include "miniprojecttargetselector.h"
dt's avatar
dt committed
31 32
#include "buildconfigurationmodel.h"
#include "runconfigurationmodel.h"
33
#include "target.h"
34 35 36 37 38 39

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

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

#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
55
#include <QtGui/QKeyEvent>
con's avatar
con committed
56
#include <QtGui/QPainter>
57
#include <QtGui/QAction>
58
#include <QtGui/QItemDelegate>
59
#include <QtGui/QMainWindow>
60

Tobias Hunger's avatar
Tobias Hunger committed
61
#include <QtGui/QApplication>
62

63 64 65 66 67 68 69
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);

70 71 72
    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);
73
    if (!overlay.isNull()) {
74 75 76
        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);
77 78 79 80
    }
    return QIcon(targetPixmap);
}

81 82 83
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;

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

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

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

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

145 146 147 148 149 150 151 152 153 154 155
    // 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
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
}

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)
{
176 177 178 179
    MiniTargetWidget *mtw = qobject_cast<MiniTargetWidget *>(itemWidget(item(index)));
    if (!mtw)
        return;
    m_project->setActiveTarget(mtw->target());
Tobias Hunger's avatar
Tobias Hunger committed
180 181 182 183 184 185 186 187 188
}

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

    if (hasBuildConfiguration()) {
        m_buildComboBox = new QComboBox;
189 190
        m_buildComboBox->setProperty("alignarrow", true);
        m_buildComboBox->setProperty("hideborder", true);
Tobias Hunger's avatar
Tobias Hunger committed
191
        m_buildComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
192
        m_buildComboBox->setToolTip(tr("Select active build configuration"));
dt's avatar
dt committed
193
        m_buildComboBox->setModel(new BuildConfigurationModel(m_target, this));
Tobias Hunger's avatar
Tobias Hunger committed
194 195 196 197
    } else {
        m_buildComboBox = 0;
    }
 
198
    m_runComboBox = new QComboBox;
199 200
    m_runComboBox ->setProperty("alignarrow", true);
    m_runComboBox ->setProperty("hideborder", true);
201
    m_runComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
202
    m_runComboBox->setToolTip(tr("Select active run configuration"));
dt's avatar
dt committed
203 204
    RunConfigurationModel *model = new RunConfigurationModel(m_target, this);
    m_runComboBox->setModel(model);
205
    int fontSize = font().pointSize();
206 207 208 209 210
    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));
211 212 213

    QGridLayout *gridLayout = new QGridLayout(this);

Tobias Hunger's avatar
Tobias Hunger committed
214
    m_targetName = new QLabel(m_target->displayName());
215
    m_targetName->setObjectName(QString::fromUtf8("target"));
216
    m_targetIcon = new QLabel();
con's avatar
con committed
217
    updateIcon();
Tobias Hunger's avatar
Tobias Hunger committed
218 219 220
    if (hasBuildConfiguration()) {
        Q_FOREACH(BuildConfiguration* bc, m_target->buildConfigurations())
                addBuildConfiguration(bc);
221

dt's avatar
dt committed
222 223 224
        BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
        m_buildComboBox->setCurrentIndex(model->indexFor(m_target->activeBuildConfiguration()).row());

Tobias Hunger's avatar
Tobias Hunger committed
225 226 227
        connect(m_target, SIGNAL(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
                SLOT(addBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
        connect(m_target, SIGNAL(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
228
                SLOT(removeBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
Tobias Hunger's avatar
Tobias Hunger committed
229 230 231 232 233

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

dt's avatar
dt committed
235 236
    m_runComboBox->setEnabled(m_target->runConfigurations().count() > 1);
    m_runComboBox->setCurrentIndex(model->indexFor(m_target->activeRunConfiguration()).row());
237

Tobias Hunger's avatar
Tobias Hunger committed
238
    connect(m_target, SIGNAL(addedRunConfiguration(ProjectExplorer::RunConfiguration*)),
239
            SLOT(addRunConfiguration(ProjectExplorer::RunConfiguration*)));
Tobias Hunger's avatar
Tobias Hunger committed
240
    connect(m_target, SIGNAL(removedRunConfiguration(ProjectExplorer::RunConfiguration*)),
241 242 243 244
            SLOT(removeRunConfiguration(ProjectExplorer::RunConfiguration*)));

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

Tobias Hunger's avatar
Tobias Hunger committed
245 246
    connect(m_target, SIGNAL(activeRunConfigurationChanged(ProjectExplorer::RunConfiguration*)),
            SLOT(setActiveRunConfiguration()));
con's avatar
con committed
247
    connect(m_target, SIGNAL(iconChanged()), this, SLOT(updateIcon()));
Tobias Hunger's avatar
Tobias Hunger committed
248 249 250 251 252 253 254 255

    QHBoxLayout *buildHelperLayout = 0;
    if (hasBuildConfiguration()) {
        buildHelperLayout= new QHBoxLayout;
        buildHelperLayout->setMargin(0);
        buildHelperLayout->setSpacing(0);
        buildHelperLayout->addWidget(m_buildComboBox);
    }
256 257 258 259 260 261 262

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

    QFormLayout *formLayout = new QFormLayout;
263
    formLayout->setLabelAlignment(Qt::AlignRight);
Tobias Hunger's avatar
Tobias Hunger committed
264
    QLabel *lbl;
265
    int indent = 10;
Tobias Hunger's avatar
Tobias Hunger committed
266 267
    if (hasBuildConfiguration()) {
        lbl = new QLabel(tr("Build:"));
268
        lbl->setObjectName(QString::fromUtf8("buildLabel"));
269 270 271
        lbl->setMinimumWidth(lbl->fontMetrics().width(lbl->text()) + indent + 4);
        lbl->setIndent(indent);

Tobias Hunger's avatar
Tobias Hunger committed
272 273
        formLayout->addRow(lbl, buildHelperLayout);
    }
274
    lbl = new QLabel(tr("Run:"));
275
    lbl->setObjectName(QString::fromUtf8("runLabel"));
276 277
    lbl->setMinimumWidth(lbl->fontMetrics().width(lbl->text()) + indent + 4);
    lbl->setIndent(indent);
278 279 280 281 282 283 284
    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
285 286
void MiniTargetWidget::updateIcon()
{
287
    m_targetIcon->setPixmap(createCenteredIcon(m_target->icon(), QIcon()).pixmap(Core::Constants::TARGET_ICON_SIZE));
con's avatar
con committed
288 289
}

Tobias Hunger's avatar
Tobias Hunger committed
290 291 292 293 294
ProjectExplorer::Target *MiniTargetWidget::target() const
{
    return m_target;
}

295 296
void MiniTargetWidget::setActiveBuildConfiguration(int index)
{
dt's avatar
dt committed
297 298
    BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
    m_target->setActiveBuildConfiguration(model->buildConfigurationAt(index));
299
    emit changed();
300 301 302 303
}

void MiniTargetWidget::setActiveRunConfiguration(int index)
{
dt's avatar
dt committed
304 305
    RunConfigurationModel *model = static_cast<RunConfigurationModel *>(m_runComboBox->model());
    m_target->setActiveRunConfiguration(model->runConfigurationAt(index));
con's avatar
con committed
306
    updateIcon();
307
    emit changed();
308
}
dt's avatar
dt committed
309

310 311
void MiniTargetWidget::setActiveBuildConfiguration()
{
dt's avatar
dt committed
312 313 314
    QTC_ASSERT(m_buildComboBox, return);
    BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
    m_buildComboBox->setCurrentIndex(model->indexFor(m_target->activeBuildConfiguration()).row());
315 316 317 318
}

void MiniTargetWidget::setActiveRunConfiguration()
{
dt's avatar
dt committed
319 320
    RunConfigurationModel *model = static_cast<RunConfigurationModel *>(m_runComboBox->model());
    m_runComboBox->setCurrentIndex(model->indexFor(m_target->activeRunConfiguration()).row());
321 322
}

Tobias Hunger's avatar
Tobias Hunger committed
323
void MiniTargetWidget::addRunConfiguration(ProjectExplorer::RunConfiguration* rc)
324
{
hjk's avatar
hjk committed
325 326
    Q_UNUSED(rc);
    m_runComboBox->setEnabled(m_target->runConfigurations().count()>1);
327 328
}

Tobias Hunger's avatar
Tobias Hunger committed
329
void MiniTargetWidget::removeRunConfiguration(ProjectExplorer::RunConfiguration* rc)
330
{
dt's avatar
dt committed
331 332
    Q_UNUSED(rc);
    m_runComboBox->setEnabled(m_target->runConfigurations().count()>1);
333 334
}

Tobias Hunger's avatar
Tobias Hunger committed
335
void MiniTargetWidget::addBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
336
{
dt's avatar
dt committed
337
    Q_UNUSED(bc);
hjk's avatar
hjk committed
338 339
    connect(bc, SIGNAL(displayNameChanged()), SIGNAL(changed()), Qt::UniqueConnection);
    m_buildComboBox->setEnabled(m_target->buildConfigurations().count() > 1);
340 341
}

Tobias Hunger's avatar
Tobias Hunger committed
342
void MiniTargetWidget::removeBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
343
{
dt's avatar
dt committed
344
    Q_UNUSED(bc);
Tobias Hunger's avatar
Tobias Hunger committed
345
    QTC_ASSERT(m_buildComboBox, return);
dt's avatar
dt committed
346
    m_buildComboBox->setEnabled(m_target->buildConfigurations().count() > 1);
347 348
}

Tobias Hunger's avatar
Tobias Hunger committed
349 350 351 352 353
bool MiniTargetWidget::hasBuildConfiguration() const
{
    return (m_target->buildConfigurationFactory() != 0);
}

354
MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorAction, QWidget *parent) :
355
    QWidget(parent), m_projectAction(targetSelectorAction), m_ignoreIndexChange(false)
356
{
357 358
    setProperty("panelwidget", true);
    setContentsMargins(QMargins(0, 1, 1, 8));
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
    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);
380 381 382 383 384

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

385
    m_projectsBox = new QComboBox;
386
    m_projectsBox->setToolTip(tr("Select active project"));
387
    m_projectsBox->setFocusPolicy(Qt::TabFocus);
388 389 390 391 392 393
    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"));
394 395 396 397 398 399 400
    m_projectsBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);

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

    m_widgetStack = new QStackedWidget;
401
    m_widgetStack->setFocusPolicy(Qt::NoFocus);
402 403
    layout->addWidget(m_widgetStack);

Tobias Hunger's avatar
Tobias Hunger committed
404 405
    connect(m_projectsBox, SIGNAL(activated(int)),
            SLOT(emitStartupProjectChanged(int)));
406 407 408 409 410 411 412 413 414 415 416 417
}

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
418 419
    if (m_widgetStack->currentWidget())
        m_widgetStack->currentWidget()->setFocus();
420 421

    m_projectAction->setChecked(visible);
422 423
}

424 425 426 427 428 429 430 431 432 433 434 435 436
// 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);
}

437 438 439 440
void MiniProjectTargetSelector::addProject(ProjectExplorer::Project* project)
{
    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 446 447 448 449 450 451 452 453
    m_ignoreIndexChange = true;

    int pos = 0;
    for (int i=0; i < m_projectsBox->count(); ++i)
        if (m_projectsBox->itemText(i) > project->displayName())
            pos = i;

    m_widgetStack->insertWidget(pos, targetList);

    m_projectsBox->insertItem(pos, project->displayName(), QVariant::fromValue(project));
454

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

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

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

dt's avatar
dt committed
470 471
    m_ignoreIndexChange = false;

Tobias Hunger's avatar
Tobias Hunger committed
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
    int index = indexFor(project);
    if (index < 0)
        return;
    ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
484 485 486 487

    // 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
488
    m_projectsBox->removeItem(index);
489
    m_projectsBox->setEnabled(m_projectsBox->count() > 1);
Tobias Hunger's avatar
Tobias Hunger committed
490
    delete plw;
491
    m_ignoreIndexChange = false;
492 493
}

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

    // 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
521
    MiniTargetWidget *targetWidget = new MiniTargetWidget(target);
522
    connect(targetWidget, SIGNAL(changed()), this, SLOT(updateAction()));
Tobias Hunger's avatar
Tobias Hunger committed
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
    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;
    }
551 552 553
    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
554
}
555

556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
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;
        }
    }
}

573 574 575 576
void MiniProjectTargetSelector::updateAction()
{
    Project *project = ProjectExplorerPlugin::instance()->startupProject();

577
    QString projectName;;
578
    QString targetName;
con's avatar
con committed
579
    QString targetToolTipText;
580 581
    QString buildConfig;
    QString runConfig;
582
    QIcon targetIcon = style()->standardIcon(QStyle::SP_ComputerIcon);
583

584 585 586 587
    const int extrawidth = 110; // Size of margins + icon width
    // Some fudge numbers to ensure the menu doesnt grow unbounded
    int maxLength = fontMetrics().averageCharWidth() * 140;

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

591 592 593 594 595
        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
596
                buildConfig = bc->displayName();
597 598
                int minimumWidth = fontMetrics().width(bc->displayName() + tr("Build:")) + extrawidth;
                m_widgetStack->setMinimumWidth(qMin(maxLength, qMax(minimumWidth, m_widgetStack->minimumWidth())));
599 600 601 602
            }

            if (RunConfiguration *rc = target->activeRunConfiguration()) {
                runConfig = rc->displayName();
603 604
                int minimumWidth = fontMetrics().width(rc->displayName() + tr("Run:")) + extrawidth;
                m_widgetStack->setMinimumWidth(qMin(maxLength, qMax(minimumWidth, m_widgetStack->minimumWidth())));
605
            }
con's avatar
con committed
606
            targetToolTipText = target->toolTip();
607
            targetIcon = createCenteredIcon(target->icon(), target->overlayIcon());
Tobias Hunger's avatar
Tobias Hunger committed
608
        }
609 610 611
    }
    m_projectAction->setProperty("heading", projectName);
    m_projectAction->setProperty("subtitle", buildConfig);
con's avatar
con committed
612
    m_projectAction->setIcon(targetIcon);
613
    QString toolTip = tr("<html><nobr><b>Project:</b> %1<br/>%2%3<b>Run:</b> %4%5</html>");
614 615 616 617
    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
618 619 620
    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
621 622 623 624 625 626 627 628 629 630
}

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;
631 632 633 634
}

void MiniProjectTargetSelector::emitStartupProjectChanged(int index)
{
635 636
    if (m_ignoreIndexChange)
        return;
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
    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
653

654 655 656 657 658 659 660 661 662 663 664
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);
}