miniprojecttargetselector.cpp 24.7 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 40

#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
41
#include <coreplugin/coreconstants.h>
42 43 44 45 46 47 48 49 50 51 52 53 54 55

#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
56
#include <QtGui/QKeyEvent>
con's avatar
con committed
57
#include <QtGui/QPainter>
58
#include <QtGui/QAction>
59
#include <QtGui/QItemDelegate>
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 444 445 446
    int pos = m_widgetStack->addWidget(targetList);

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

Tobias Hunger's avatar
Tobias Hunger committed
447 448
    connect(project, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
            SLOT(updateAction()));
449

Tobias Hunger's avatar
Tobias Hunger committed
450 451 452 453
    connect(project, SIGNAL(addedTarget(ProjectExplorer::Target*)),
            SLOT(addTarget(ProjectExplorer::Target*)));
    connect(project, SIGNAL(removedTarget(ProjectExplorer::Target*)),
            SLOT(removeTarget(ProjectExplorer::Target*)));
454 455
    connect(project, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
            SLOT(changeActiveTarget(ProjectExplorer::Target*)));
456 457 458 459 460

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

    foreach (Target *t, project->targets())
        addTarget(t, t == project->activeTarget());
464 465

    m_projectsBox->setEnabled(m_projectsBox->count() > 1);
466 467 468 469
}

void MiniProjectTargetSelector::removeProject(ProjectExplorer::Project* project)
{
Tobias Hunger's avatar
Tobias Hunger committed
470 471 472 473
    int index = indexFor(project);
    if (index < 0)
        return;
    ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
474 475 476 477

    // 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
478
    m_projectsBox->removeItem(index);
479
    m_projectsBox->setEnabled(m_projectsBox->count() > 1);
Tobias Hunger's avatar
Tobias Hunger committed
480
    delete plw;
481
    m_ignoreIndexChange = false;
482 483
}

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

    // 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
511
    MiniTargetWidget *targetWidget = new MiniTargetWidget(target);
512
    connect(targetWidget, SIGNAL(changed()), this, SLOT(updateAction()));
Tobias Hunger's avatar
Tobias Hunger committed
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
    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;
    }
541 542 543
    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
544
}
545

546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
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;
        }
    }
}

563 564 565 566
void MiniProjectTargetSelector::updateAction()
{
    Project *project = ProjectExplorerPlugin::instance()->startupProject();

567
    QString projectName;;
568
    QString targetName;
con's avatar
con committed
569
    QString targetToolTipText;
570 571
    QString buildConfig;
    QString runConfig;
572
    QIcon targetIcon = style()->standardIcon(QStyle::SP_ComputerIcon);
573

574 575 576 577
    const int extrawidth = 110; // Size of margins + icon width
    // Some fudge numbers to ensure the menu doesnt grow unbounded
    int maxLength = fontMetrics().averageCharWidth() * 140;

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

581 582 583 584 585
        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
586
                buildConfig = bc->displayName();
587 588
                int minimumWidth = fontMetrics().width(bc->displayName() + tr("Build:")) + extrawidth;
                m_widgetStack->setMinimumWidth(qMin(maxLength, qMax(minimumWidth, m_widgetStack->minimumWidth())));
589 590 591 592
            }

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

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;
621 622 623 624
}

void MiniProjectTargetSelector::emitStartupProjectChanged(int index)
{
625 626
    if (m_ignoreIndexChange)
        return;
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
    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
643

644 645 646 647 648 649 650 651 652 653 654
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);
}