OSDN Git Service

RemoteLinux: Include sysroot in incremental deployment logic.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / projectexplorer / miniprojecttargetselector.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at info@qt.nokia.com.
30 **
31 **************************************************************************/
32
33 #include "miniprojecttargetselector.h"
34 #include "buildconfigurationmodel.h"
35 #include "runconfigurationmodel.h"
36 #include "target.h"
37
38 #include <utils/qtcassert.h>
39 #include <utils/styledbar.h>
40 #include <utils/stylehelper.h>
41
42 #include <coreplugin/ifile.h>
43 #include <coreplugin/icore.h>
44 #include <coreplugin/coreconstants.h>
45
46 #include <projectexplorer/projectexplorer.h>
47 #include <projectexplorer/session.h>
48 #include <projectexplorer/project.h>
49 #include <projectexplorer/runconfiguration.h>
50 #include <projectexplorer/buildconfiguration.h>
51
52 #include <QtGui/QLayout>
53 #include <QtGui/QFormLayout>
54 #include <QtGui/QLabel>
55 #include <QtGui/QComboBox>
56 #include <QtGui/QListWidget>
57 #include <QtGui/QStatusBar>
58 #include <QtGui/QStackedWidget>
59 #include <QtGui/QKeyEvent>
60 #include <QtGui/QPainter>
61 #include <QtGui/QAction>
62 #include <QtGui/QItemDelegate>
63 #include <QtGui/QMainWindow>
64
65 #include <QtGui/QApplication>
66
67 static QIcon createCenteredIcon(const QIcon &icon, const QIcon &overlay)
68 {
69     QPixmap targetPixmap;
70     targetPixmap = QPixmap(Core::Constants::TARGET_ICON_SIZE, Core::Constants::TARGET_ICON_SIZE);
71     targetPixmap.fill(Qt::transparent);
72     QPainter painter(&targetPixmap);
73
74     QPixmap pixmap = icon.pixmap(Core::Constants::TARGET_ICON_SIZE);
75     painter.drawPixmap((Core::Constants::TARGET_ICON_SIZE - pixmap.width())/2,
76                        (Core::Constants::TARGET_ICON_SIZE - pixmap.height())/2, pixmap);
77     if (!overlay.isNull()) {
78         pixmap = overlay.pixmap(Core::Constants::TARGET_ICON_SIZE);
79         painter.drawPixmap((Core::Constants::TARGET_ICON_SIZE - pixmap.width())/2,
80                            (Core::Constants::TARGET_ICON_SIZE - pixmap.height())/2, pixmap);
81     }
82     return QIcon(targetPixmap);
83 }
84
85 using namespace ProjectExplorer;
86 using namespace ProjectExplorer::Internal;
87
88 class TargetSelectorDelegate : public QItemDelegate
89 {
90 public:
91     TargetSelectorDelegate(QObject *parent) : QItemDelegate(parent) { }
92 private:
93     void paint(QPainter *painter,
94                const QStyleOptionViewItem &option,
95                const QModelIndex &index) const;
96     mutable QImage selectionGradient;
97 };
98
99 void TargetSelectorDelegate::paint(QPainter *painter,
100                                    const QStyleOptionViewItem &option,
101                                    const QModelIndex &) const
102 {
103     painter->save();
104     painter->setClipping(false);
105
106     if (selectionGradient.isNull())
107         selectionGradient.load(QLatin1String(":/projectexplorer/images/targetpanel_gradient.png"));
108
109     if (option.state & QStyle::State_Selected) {
110         QColor color =(option.state & QStyle::State_HasFocus) ?
111                       option.palette.highlight().color() :
112                       option.palette.dark().color();
113         painter->fillRect(option.rect, color.darker(140));
114         Utils::StyleHelper::drawCornerImage(selectionGradient, painter, option.rect.adjusted(0, 0, 0, -1), 5, 5, 5, 5);
115         painter->setPen(QColor(255, 255, 255, 60));
116         painter->drawLine(option.rect.topLeft(), option.rect.topRight());
117         painter->setPen(QColor(255, 255, 255, 30));
118         painter->drawLine(option.rect.bottomLeft() - QPoint(0,1), option.rect.bottomRight() -  QPoint(0,1));
119         painter->setPen(QColor(0, 0, 0, 80));
120         painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
121     }
122     painter->restore();
123 }
124
125 ProjectListWidget::ProjectListWidget(ProjectExplorer::Project *project, QWidget *parent)
126     : QListWidget(parent), m_project(project)
127 {
128     setFocusPolicy(Qt::NoFocus);
129     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
130     setAlternatingRowColors(false);
131     setFocusPolicy(Qt::WheelFocus);
132     setItemDelegate(new TargetSelectorDelegate(this));
133     setAttribute(Qt::WA_MacShowFocusRect, false);
134
135     connect(this, SIGNAL(currentRowChanged(int)), SLOT(setTarget(int)));
136 }
137
138 ProjectExplorer::Project *ProjectListWidget::project() const
139 {
140     return m_project;
141 }
142
143 QSize ProjectListWidget::sizeHint() const
144 {
145     int height = 0;
146     int width = 0;
147     for (int itemPos = 0; itemPos < count(); ++itemPos) {
148         height += item(itemPos)->sizeHint().height();
149         width = qMax(width, item(itemPos)->sizeHint().width());
150     }
151
152     // We try to keep the height of the popup equal to the actionbar
153     QSize size(width, height);
154     static QStatusBar *statusBar = Core::ICore::instance()->statusBar();
155     static QWidget *actionBar = Core::ICore::instance()->mainWindow()->findChild<QWidget*>("actionbar");
156     Q_ASSERT(actionBar);
157
158     QMargins popupMargins = window()->contentsMargins();
159     if (actionBar)
160         size.setHeight(qMax(actionBar->height() - statusBar->height() -
161                             (popupMargins.top() + popupMargins.bottom()), height));
162     return size;
163 }
164
165 void ProjectListWidget::setRunComboPopup()
166 {
167     QWidget *w = itemWidget(currentItem());
168     MiniTargetWidget *mtw = qobject_cast<MiniTargetWidget*>(w);
169     if (mtw->runSettingsComboBox())
170         mtw->runSettingsComboBox()->showPopup();
171 }
172
173 void ProjectListWidget::setBuildComboPopup()
174 {
175     QWidget *w = itemWidget(currentItem());
176     MiniTargetWidget *mtw = qobject_cast<MiniTargetWidget*>(w);
177     if (mtw->buildSettingsComboBox())
178         mtw->buildSettingsComboBox()->showPopup();
179 }
180
181 void ProjectListWidget::setTarget(int index)
182 {
183     MiniTargetWidget *mtw = qobject_cast<MiniTargetWidget *>(itemWidget(item(index)));
184     if (!mtw)
185         return;
186     m_project->setActiveTarget(mtw->target());
187 }
188
189 MiniTargetWidget::MiniTargetWidget(Target *target, QWidget *parent) :
190     QWidget(parent), m_target(target)
191 {
192     Q_ASSERT(m_target);
193
194     if (hasBuildConfiguration()) {
195         m_buildComboBox = new QComboBox;
196         m_buildComboBox->setProperty("alignarrow", true);
197         m_buildComboBox->setProperty("hideborder", true);
198         m_buildComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
199         m_buildComboBox->setToolTip(tr("Select active build configuration"));
200         m_buildComboBox->setModel(new BuildConfigurationModel(m_target, this));
201     } else {
202         m_buildComboBox = 0;
203     }
204  
205     m_runComboBox = new QComboBox;
206     m_runComboBox ->setProperty("alignarrow", true);
207     m_runComboBox ->setProperty("hideborder", true);
208     m_runComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
209     m_runComboBox->setToolTip(tr("Select active run configuration"));
210     RunConfigurationModel *model = new RunConfigurationModel(m_target, this);
211     m_runComboBox->setModel(model);
212     int fontSize = font().pointSize();
213     setStyleSheet(QString::fromLatin1("QLabel { font-size: %2pt; color: white; } "
214                                       "#target { font: bold %1pt;} "
215                                       "#buildLabel{ font: bold; color: rgba(255, 255, 255, 160)} "
216                                       "#runLabel { font: bold ; color: rgba(255, 255, 255, 160)} "
217                                       ).arg(fontSize).arg(fontSize - 2));
218
219     QGridLayout *gridLayout = new QGridLayout(this);
220
221     m_targetName = new QLabel(m_target->displayName());
222     m_targetName->setObjectName(QString::fromUtf8("target"));
223     m_targetIcon = new QLabel();
224     updateIcon();
225     if (hasBuildConfiguration()) {
226         Q_FOREACH(BuildConfiguration* bc, m_target->buildConfigurations())
227                 addBuildConfiguration(bc);
228
229         BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
230         m_buildComboBox->setCurrentIndex(model->indexFor(m_target->activeBuildConfiguration()).row());
231
232         connect(m_target, SIGNAL(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
233                 SLOT(addBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
234         connect(m_target, SIGNAL(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
235                 SLOT(removeBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
236
237         connect(m_target, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
238                 SLOT(setActiveBuildConfiguration()));
239         connect(m_buildComboBox, SIGNAL(currentIndexChanged(int)), SLOT(setActiveBuildConfiguration(int)));
240     }
241
242     m_runComboBox->setEnabled(m_target->runConfigurations().count() > 1);
243     m_runComboBox->setCurrentIndex(model->indexFor(m_target->activeRunConfiguration()).row());
244
245     connect(m_target, SIGNAL(addedRunConfiguration(ProjectExplorer::RunConfiguration*)),
246             SLOT(addRunConfiguration(ProjectExplorer::RunConfiguration*)));
247     connect(m_target, SIGNAL(removedRunConfiguration(ProjectExplorer::RunConfiguration*)),
248             SLOT(removeRunConfiguration(ProjectExplorer::RunConfiguration*)));
249
250     connect(m_runComboBox, SIGNAL(currentIndexChanged(int)), SLOT(setActiveRunConfiguration(int)));
251
252     connect(m_target, SIGNAL(activeRunConfigurationChanged(ProjectExplorer::RunConfiguration*)),
253             SLOT(setActiveRunConfiguration()));
254     connect(m_target, SIGNAL(iconChanged()), this, SLOT(updateIcon()));
255
256     QHBoxLayout *buildHelperLayout = 0;
257     if (hasBuildConfiguration()) {
258         buildHelperLayout= new QHBoxLayout;
259         buildHelperLayout->setMargin(0);
260         buildHelperLayout->setSpacing(0);
261         buildHelperLayout->addWidget(m_buildComboBox);
262     }
263
264     QHBoxLayout *runHelperLayout = new QHBoxLayout;
265     runHelperLayout->setMargin(0);
266     runHelperLayout->setSpacing(0);
267     runHelperLayout->addWidget(m_runComboBox);
268
269     QFormLayout *formLayout = new QFormLayout;
270     formLayout->setLabelAlignment(Qt::AlignRight);
271     QLabel *lbl;
272     int indent = 10;
273     if (hasBuildConfiguration()) {
274         lbl = new QLabel(tr("Build:"));
275         lbl->setObjectName(QString::fromUtf8("buildLabel"));
276         lbl->setMinimumWidth(lbl->fontMetrics().width(lbl->text()) + indent + 4);
277         lbl->setIndent(indent);
278
279         formLayout->addRow(lbl, buildHelperLayout);
280     }
281     lbl = new QLabel(tr("Run:"));
282     lbl->setObjectName(QString::fromUtf8("runLabel"));
283     lbl->setMinimumWidth(lbl->fontMetrics().width(lbl->text()) + indent + 4);
284     lbl->setIndent(indent);
285     formLayout->addRow(lbl, runHelperLayout);
286
287     gridLayout->addWidget(m_targetName, 0, 0);
288     gridLayout->addWidget(m_targetIcon, 0, 1, 2, 1, Qt::AlignTop|Qt::AlignHCenter);
289     gridLayout->addLayout(formLayout, 1, 0);
290 }
291
292 void MiniTargetWidget::updateIcon()
293 {
294     m_targetIcon->setPixmap(createCenteredIcon(m_target->icon(), QIcon()).pixmap(Core::Constants::TARGET_ICON_SIZE));
295 }
296
297 ProjectExplorer::Target *MiniTargetWidget::target() const
298 {
299     return m_target;
300 }
301
302 void MiniTargetWidget::setActiveBuildConfiguration(int index)
303 {
304     BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
305     m_target->setActiveBuildConfiguration(model->buildConfigurationAt(index));
306     emit changed();
307 }
308
309 void MiniTargetWidget::setActiveRunConfiguration(int index)
310 {
311     RunConfigurationModel *model = static_cast<RunConfigurationModel *>(m_runComboBox->model());
312     m_target->setActiveRunConfiguration(model->runConfigurationAt(index));
313     updateIcon();
314     emit changed();
315 }
316
317 void MiniTargetWidget::setActiveBuildConfiguration()
318 {
319     QTC_ASSERT(m_buildComboBox, return);
320     BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
321     m_buildComboBox->setCurrentIndex(model->indexFor(m_target->activeBuildConfiguration()).row());
322 }
323
324 void MiniTargetWidget::setActiveRunConfiguration()
325 {
326     RunConfigurationModel *model = static_cast<RunConfigurationModel *>(m_runComboBox->model());
327     m_runComboBox->setCurrentIndex(model->indexFor(m_target->activeRunConfiguration()).row());
328 }
329
330 void MiniTargetWidget::addRunConfiguration(ProjectExplorer::RunConfiguration* rc)
331 {
332     Q_UNUSED(rc);
333     m_runComboBox->setEnabled(m_target->runConfigurations().count()>1);
334 }
335
336 void MiniTargetWidget::removeRunConfiguration(ProjectExplorer::RunConfiguration* rc)
337 {
338     Q_UNUSED(rc);
339     m_runComboBox->setEnabled(m_target->runConfigurations().count()>1);
340 }
341
342 void MiniTargetWidget::addBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
343 {
344     Q_UNUSED(bc);
345     connect(bc, SIGNAL(displayNameChanged()), SIGNAL(changed()), Qt::UniqueConnection);
346     m_buildComboBox->setEnabled(m_target->buildConfigurations().count() > 1);
347 }
348
349 void MiniTargetWidget::removeBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
350 {
351     Q_UNUSED(bc);
352     QTC_ASSERT(m_buildComboBox, return);
353     m_buildComboBox->setEnabled(m_target->buildConfigurations().count() > 1);
354 }
355
356 bool MiniTargetWidget::hasBuildConfiguration() const
357 {
358     return (m_target->buildConfigurationFactory() != 0);
359 }
360
361 MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorAction, QWidget *parent) :
362     QWidget(parent), m_projectAction(targetSelectorAction), m_ignoreIndexChange(false)
363 {
364     setProperty("panelwidget", true);
365     setContentsMargins(QMargins(0, 1, 1, 8));
366     setWindowFlags(Qt::Popup);
367
368     targetSelectorAction->setIcon(style()->standardIcon(QStyle::SP_ComputerIcon));
369     targetSelectorAction->setProperty("titledAction", true);
370
371     QVBoxLayout *layout = new QVBoxLayout(this);
372     layout->setMargin(0);
373     layout->setSpacing(0);
374
375     Utils::StyledBar *bar = new Utils::StyledBar;
376     bar->setSingleRow(true);
377     layout->addWidget(bar);
378     QHBoxLayout *toolLayout = new QHBoxLayout(bar);
379     toolLayout->setMargin(0);
380     toolLayout->setSpacing(0);
381
382     QLabel *lbl = new QLabel(tr("Project"));
383     lbl->setIndent(6);
384     QFont f = lbl->font();
385     f.setBold(true);
386     lbl->setFont(f);
387
388     int panelHeight = lbl->fontMetrics().height() + 12;
389     bar->ensurePolished(); // Required since manhattanstyle overrides height
390     bar->setFixedHeight(panelHeight);
391
392     m_projectsBox = new QComboBox;
393     m_projectsBox->setToolTip(tr("Select active project"));
394     m_projectsBox->setFocusPolicy(Qt::TabFocus);
395     f.setBold(false);
396     m_projectsBox->setFont(f);
397     m_projectsBox->ensurePolished();
398     m_projectsBox->setFixedHeight(panelHeight);
399     m_projectsBox->setProperty("hideborder", true);
400     m_projectsBox->setObjectName(QString::fromUtf8("ProjectsBox"));
401     m_projectsBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
402     m_projectsBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
403
404     toolLayout->addWidget(lbl);
405     toolLayout->addWidget(new Utils::StyledSeparator);
406     toolLayout->addWidget(m_projectsBox);
407
408     m_widgetStack = new QStackedWidget;
409     m_widgetStack->setFocusPolicy(Qt::NoFocus);
410     layout->addWidget(m_widgetStack);
411
412     connect(m_projectsBox, SIGNAL(activated(int)),
413             SLOT(emitStartupProjectChanged(int)));
414 }
415
416 void MiniProjectTargetSelector::setVisible(bool visible)
417 {
418     if (visible) {
419         QSize sh = sizeHint();
420         resize(sh);
421         QStatusBar *statusBar = Core::ICore::instance()->statusBar();
422         QPoint moveTo = statusBar->mapToGlobal(QPoint(0,0));
423         moveTo -= QPoint(0, sh.height());
424         move(moveTo);
425     }
426
427     QWidget::setVisible(visible);
428
429     if (m_widgetStack->currentWidget())
430         m_widgetStack->currentWidget()->setFocus();
431
432     m_projectAction->setChecked(visible);
433 }
434
435 // This is a workaround for the problem that Windows
436 // will let the mouse events through when you click
437 // outside a popup to close it. This causes the popup
438 // to open on mouse release if you hit the button, which
439 //
440 //
441 // A similar case can be found in QComboBox
442 void MiniProjectTargetSelector::mousePressEvent(QMouseEvent *e)
443 {
444     setAttribute(Qt::WA_NoMouseReplay);
445     QWidget::mousePressEvent(e);
446 }
447
448 QString MiniProjectTargetSelector::fullName(ProjectExplorer::Project *project)
449 {
450     return project->displayName() + " (" + project->file()->fileName() + QLatin1Char(')');
451 }
452
453 void MiniProjectTargetSelector::addProject(ProjectExplorer::Project *project)
454 {
455     QTC_ASSERT(project, return);
456     ProjectListWidget *targetList = new ProjectListWidget(project);
457     targetList->setStyleSheet(QString::fromLatin1("QListWidget { background: %1; border: none; }")
458                               .arg(QColor(70, 70, 70).name()));
459
460     m_ignoreIndexChange = true;
461
462     QString sortName = fullName(project);
463     int pos = 0;
464     for (int i=0; i < m_projectsBox->count(); ++i) {
465         Project *p = m_projectsBox->itemData(i).value<Project*>();
466         QString itemSortName = fullName(p);
467         if (itemSortName > sortName)
468             pos = i;
469     }
470
471     m_widgetStack->insertWidget(pos, targetList);
472
473     bool useFullName = false;
474     for (int i = 0; i < m_projectsBox->count(); ++i) {
475         Project *p = m_projectsBox->itemData(i).value<Project*>();
476         if (p->displayName() == project->displayName()) {
477             useFullName = true;
478             m_projectsBox->setItemText(i, fullName(p));
479         }
480     }
481
482     QString displayName = useFullName ? fullName(project) : project->displayName();
483     m_projectsBox->insertItem(pos, displayName, QVariant::fromValue(project));
484
485     connect(project, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
486             SLOT(updateAction()));
487
488     connect(project, SIGNAL(addedTarget(ProjectExplorer::Target*)),
489             SLOT(addTarget(ProjectExplorer::Target*)));
490     connect(project, SIGNAL(removedTarget(ProjectExplorer::Target*)),
491             SLOT(removeTarget(ProjectExplorer::Target*)));
492     connect(project, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
493             SLOT(changeActiveTarget(ProjectExplorer::Target*)));
494
495     if (project == ProjectExplorerPlugin::instance()->startupProject()) {
496         m_projectsBox->setCurrentIndex(pos);
497         m_widgetStack->setCurrentIndex(pos);
498     }
499
500     m_ignoreIndexChange = false;
501
502     foreach (Target *t, project->targets())
503         addTarget(t, t == project->activeTarget());
504
505     m_projectsBox->setEnabled(m_projectsBox->count() > 1);
506     m_projectsBox->parentWidget()->layout()->activate();
507 }
508
509 void MiniProjectTargetSelector::removeProject(ProjectExplorer::Project* project)
510 {
511     int index = indexFor(project);
512     if (index < 0)
513         return;
514     ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
515
516     // We don't want to emit a startUpProject changed, even if we remove the current startup project
517     // The ProjectExplorer takes care of setting a new startup project.
518     m_ignoreIndexChange = true;
519     m_projectsBox->removeItem(index);
520     m_projectsBox->setEnabled(m_projectsBox->count() > 1);
521     delete plw;
522
523     // Update display names
524     QString name = project->displayName();
525     int count = 0;
526     int otherIndex = -1;
527     for (int i = 0; i < m_projectsBox->count(); ++i) {
528         Project *p = m_projectsBox->itemData(i).value<Project*>();
529         if (p->displayName() == name) {
530             ++count;
531             otherIndex = i;
532         }
533     }
534     if (count == 1) {
535         Project *p = m_projectsBox->itemData(otherIndex).value<Project*>();
536         m_projectsBox->setItemText(otherIndex, p->displayName());
537     }
538
539     m_ignoreIndexChange = false;
540     m_projectsBox->parentWidget()->layout()->activate();
541 }
542
543 void MiniProjectTargetSelector::addTarget(ProjectExplorer::Target *target, bool activeTarget)
544 {
545     QTC_ASSERT(target, return);
546
547     int index = indexFor(target->project());
548     if (index < 0)
549         return;
550
551     connect(target, SIGNAL(toolTipChanged()), this, SLOT(updateAction()));
552     connect(target, SIGNAL(iconChanged()), this, SLOT(updateAction()));
553     connect(target, SIGNAL(overlayIconChanged()), this, SLOT(updateAction()));
554     ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
555     QListWidgetItem *lwi = new QListWidgetItem();
556
557     // Sort on insert:
558     for (int idx = 0; idx <= plw->count(); ++idx) {
559         QListWidgetItem *itm(plw->item(idx));
560         MiniTargetWidget *mtw(qobject_cast<MiniTargetWidget *>(plw->itemWidget(itm)));
561         if (!mtw && idx < plw->count())
562             continue;
563         if (idx == plw->count() ||
564             mtw->target()->displayName() > target->displayName()) {
565             plw->insertItem(idx, lwi);
566             break;
567         }
568     }
569
570     MiniTargetWidget *targetWidget = new MiniTargetWidget(target);
571     connect(targetWidget, SIGNAL(changed()), this, SLOT(updateAction()));
572     targetWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
573     lwi->setSizeHint(targetWidget->sizeHint());
574     plw->setItemWidget(lwi, targetWidget);
575
576     if (activeTarget)
577         plw->setCurrentItem(lwi, QItemSelectionModel::SelectCurrent);
578
579     m_widgetStack->updateGeometry();
580 }
581
582 void MiniProjectTargetSelector::removeTarget(ProjectExplorer::Target *target)
583 {
584     QTC_ASSERT(target, return);
585
586     int index = indexFor(target->project());
587     if (index < 0)
588         return;
589
590     ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
591     for (int i = 0; i < plw->count(); ++i) {
592         QListWidgetItem *itm(plw->item(i));
593         MiniTargetWidget *mtw(qobject_cast<MiniTargetWidget *>(plw->itemWidget(itm)));
594         if (!mtw)
595             continue;
596         if (target != mtw->target())
597             continue;
598         delete plw->takeItem(i);
599         delete mtw;
600     }
601
602     disconnect(target, SIGNAL(toolTipChanged()), this, SLOT(updateAction()));
603     disconnect(target, SIGNAL(iconChanged()), this, SLOT(updateAction()));
604     disconnect(target, SIGNAL(overlayIconChanged()), this, SLOT(updateAction()));
605
606     m_widgetStack->updateGeometry();
607 }
608
609 void MiniProjectTargetSelector::changeActiveTarget(ProjectExplorer::Target *target)
610 {
611     int index = indexFor(target->project());
612     if (index < 0)
613         return;
614     ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(index));
615
616     for (int i = 0; i < plw->count(); ++i) {
617         QListWidgetItem *itm = plw->item(i);
618         MiniTargetWidget *mtw = qobject_cast<MiniTargetWidget*>(plw->itemWidget(itm));
619         if (mtw->target() == target) {
620             plw->setCurrentItem(itm);
621             break;
622         }
623     }
624 }
625
626 void MiniProjectTargetSelector::updateAction()
627 {
628     Project *project = ProjectExplorerPlugin::instance()->startupProject();
629
630     QString projectName;;
631     QString targetName;
632     QString targetToolTipText;
633     QString buildConfig;
634     QString runConfig;
635     QIcon targetIcon = style()->standardIcon(QStyle::SP_ComputerIcon);
636
637     const int extrawidth = 110; // Size of margins + icon width
638     // Some fudge numbers to ensure the menu does not grow unbounded
639     int maxLength = fontMetrics().averageCharWidth() * 140;
640
641     if (project) {
642         projectName = project->displayName();
643
644         if (Target *target = project->activeTarget()) {
645             if (project->targets().count() > 1) {
646                 targetName = project->activeTarget()->displayName();
647             }
648             if (BuildConfiguration *bc = target->activeBuildConfiguration()) {
649                 buildConfig = bc->displayName();
650                 int minimumWidth = fontMetrics().width(bc->displayName() + tr("Build:")) + extrawidth;
651                 m_widgetStack->setMinimumWidth(qMin(maxLength, qMax(minimumWidth, m_widgetStack->minimumWidth())));
652             }
653
654             if (RunConfiguration *rc = target->activeRunConfiguration()) {
655                 runConfig = rc->displayName();
656                 int minimumWidth = fontMetrics().width(rc->displayName() + tr("Run:")) + extrawidth;
657                 m_widgetStack->setMinimumWidth(qMin(maxLength, qMax(minimumWidth, m_widgetStack->minimumWidth())));
658             }
659             targetToolTipText = target->toolTip();
660             targetIcon = createCenteredIcon(target->icon(), target->overlayIcon());
661         }
662     }
663     m_projectAction->setProperty("heading", projectName);
664     m_projectAction->setProperty("subtitle", buildConfig);
665     m_projectAction->setIcon(targetIcon);
666     QString toolTip = tr("<html><nobr><b>Project:</b> %1<br/>%2%3<b>Run:</b> %4%5</html>");
667     QString targetTip = targetName.isEmpty() ? QLatin1String("")
668         : tr("<b>Target:</b> %1<br/>").arg(targetName);
669     QString buildTip = buildConfig.isEmpty() ? QLatin1String("")
670         : tr("<b>Build:</b> %2<br/>").arg(buildConfig);
671     QString targetToolTip = targetToolTipText.isEmpty() ? QLatin1String("")
672         : tr("<br/>%1").arg(targetToolTipText);
673     m_projectAction->setToolTip(toolTip.arg(projectName, targetTip, buildTip, runConfig, targetToolTip));
674 }
675
676 int MiniProjectTargetSelector::indexFor(ProjectExplorer::Project *project) const
677 {
678     for (int i = 0; i < m_widgetStack->count(); ++i) {
679         ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(i));
680         if (plw && plw->project() == project)
681             return i;
682     }
683     return -1;
684 }
685
686 void MiniProjectTargetSelector::emitStartupProjectChanged(int index)
687 {
688     if (m_ignoreIndexChange)
689         return;
690     Project *project = m_projectsBox->itemData(index).value<Project*>();
691     QTC_ASSERT(project, return;)
692     emit startupProjectChanged(project);
693 }
694
695 void MiniProjectTargetSelector::changeStartupProject(ProjectExplorer::Project *project)
696 {
697     for (int i = 0; i < m_widgetStack->count(); ++i) {
698         ProjectListWidget *plw = qobject_cast<ProjectListWidget*>(m_widgetStack->widget(i));
699         if (plw && plw->project() == project) {
700             m_projectsBox->setCurrentIndex(i);
701             m_widgetStack->setCurrentIndex(i);
702         }
703     }
704     updateAction();
705 }
706
707 void MiniProjectTargetSelector::paintEvent(QPaintEvent *)
708 {
709     QPainter painter(this);
710     painter.setPen(Utils::StyleHelper::borderColor());
711     painter.drawLine(rect().topLeft(), rect().topRight());
712     painter.drawLine(rect().topRight(), rect().bottomRight());
713
714     QRect bottomRect(0, rect().height() - 8, rect().width(), 8);
715     static QImage image(QLatin1String(":/projectexplorer/images/targetpanel_bottom.png"));
716     Utils::StyleHelper::drawCornerImage(image, &painter, bottomRect, 1, 1, 1, 1);
717 }