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

con's avatar
con committed
33
#include "projectwindow.h"
hjk's avatar
hjk committed
34

con's avatar
con committed
35
36
#include "doubletabwidget.h"

hjk's avatar
hjk committed
37
#include "project.h"
con's avatar
con committed
38
39
40
41
#include "projectexplorer.h"
#include "projectexplorerconstants.h"
#include "session.h"
#include "projecttreewidget.h"
42
#include "iprojectproperties.h"
Tobias Hunger's avatar
Tobias Hunger committed
43
#include "targetsettingspanel.h"
44
#include "target.h"
con's avatar
con committed
45
46

#include <coreplugin/icore.h>
47
#include <coreplugin/ifile.h>
48
#include <extensionsystem/pluginmanager.h>
Tobias Hunger's avatar
Tobias Hunger committed
49
#include <utils/qtcassert.h>
50
#include <utils/stylehelper.h>
con's avatar
con committed
51

52
53
54
55
56
#include <QApplication>
#include <QGridLayout>
#include <QLabel>
#include <QPainter>
#include <QStackedWidget>
57

con's avatar
con committed
58
59
60
61
using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;

namespace {
Tobias Hunger's avatar
Tobias Hunger committed
62
const int ICON_SIZE(64);
Tobias Hunger's avatar
Tobias Hunger committed
63
64
65
66

const int ABOVE_HEADING_MARGIN(10);
const int ABOVE_CONTENTS_MARGIN(4);
const int BELOW_CONTENTS_MARGIN(16);
Tobias Hunger's avatar
Tobias Hunger committed
67

68
} // anonymous namespace
Tobias Hunger's avatar
Tobias Hunger committed
69

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
///
// OnePixelBlackLine
///

class OnePixelBlackLine : public QWidget
{
public:
    OnePixelBlackLine(QWidget *parent)
        : QWidget(parent)
    {
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
        setMinimumHeight(1);
        setMaximumHeight(1);
    }
    void paintEvent(QPaintEvent *e)
    {
Tobias Hunger's avatar
Tobias Hunger committed
86
        Q_UNUSED(e);
87
        QPainter p(this);
88
89
90
        QColor fillColor = Utils::StyleHelper::mergedColors(
                palette().button().color(), Qt::black, 80);
        p.fillRect(contentsRect(), fillColor);
91
92
93
    }
};

Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
94
95
96
class RootWidget : public QWidget
{
public:
97
98
99
    RootWidget(QWidget *parent) : QWidget(parent) {
        setFocusPolicy(Qt::NoFocus);
    }
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
100
101
102
103
104
105
106
107
    void paintEvent(QPaintEvent *);
};

void RootWidget::paintEvent(QPaintEvent *e)
{
    QWidget::paintEvent(e);

    QPainter painter(this);
108
109
110
111
112
113
    QColor light = Utils::StyleHelper::mergedColors(
            palette().button().color(), Qt::white, 30);
    QColor dark = Utils::StyleHelper::mergedColors(
            palette().button().color(), Qt::black, 85);

    painter.setPen(light);
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
114
    painter.drawLine(rect().topRight(), rect().bottomRight());
115
    painter.setPen(dark);
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
116
117
118
    painter.drawLine(rect().topRight() - QPoint(1,0), rect().bottomRight() - QPoint(1,0));
}

119
120
121
122
///
// PanelsWidget
///

Tobias Hunger's avatar
Tobias Hunger committed
123
124
PanelsWidget::PanelsWidget(QWidget *parent) :
    QScrollArea(parent),
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
125
    m_root(new RootWidget(this))
dt's avatar
dt committed
126
{
127
    // We want a 900px wide widget with and the scrollbar at the
Tobias Hunger's avatar
Tobias Hunger committed
128
    // side of the screen.
129
    m_root->setFixedWidth(900);
130
    m_root->setContentsMargins(0, 0, 40, 0);
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
131
132
    
    QPalette pal = m_root->palette();
133
134
135
    QColor background = Utils::StyleHelper::mergedColors(
            palette().window().color(), Qt::white, 85);
    pal.setColor(QPalette::All, QPalette::Window, background.darker(102));
Jens Bache-Wiig's avatar
Jens Bache-Wiig committed
136
    setPalette(pal);
137
138
    pal.setColor(QPalette::All, QPalette::Window, background);
    m_root->setPalette(pal);
Tobias Hunger's avatar
Tobias Hunger committed
139
    // The layout holding the individual panels:
Tobias Hunger's avatar
Tobias Hunger committed
140
141
142
    m_layout = new QGridLayout(m_root);
    m_layout->setColumnMinimumWidth(0, ICON_SIZE + 4);
    m_layout->setSpacing(0);
Tobias Hunger's avatar
Tobias Hunger committed
143

144
    setWidget(m_root);
dt's avatar
dt committed
145
    setFrameStyle(QFrame::NoFrame);
dt's avatar
dt committed
146
    setWidgetResizable(true);
147
    setFocusPolicy(Qt::NoFocus);
dt's avatar
dt committed
148
149
150
151
}

PanelsWidget::~PanelsWidget()
{
con's avatar
con committed
152
    qDeleteAll(m_panels);
dt's avatar
dt committed
153
154
}

Tobias Hunger's avatar
Tobias Hunger committed
155
156
157
158
159
/*
 * Add a widget with heading information into the grid
 * layout of the PanelsWidget.
 *
 *     ...
Tobias Hunger's avatar
Tobias Hunger committed
160
 * +--------+-------------------------------------------+ ABOVE_HEADING_MARGIN
Tobias Hunger's avatar
Tobias Hunger committed
161
162
 * | icon   | name                                      |
 * +        +-------------------------------------------+
Tobias Hunger's avatar
Tobias Hunger committed
163
164
165
166
 * |        | line                                      |
 * +--------+-------------------------------------------+ ABOVE_CONTENTS_MARGIN
 * |          widget (with contentsmargins adjusted!)   |
 * +--------+-------------------------------------------+ BELOW_CONTENTS_MARGIN
Tobias Hunger's avatar
Tobias Hunger committed
167
 */
168
void PanelsWidget::addPropertiesPanel(PropertiesPanel *panel)
dt's avatar
dt committed
169
{
con's avatar
con committed
170
    QTC_ASSERT(panel, return);
Tobias Hunger's avatar
Tobias Hunger committed
171

Tobias Hunger's avatar
Tobias Hunger committed
172
173
    const int headerRow(m_layout->rowCount() - 1);

Tobias Hunger's avatar
Tobias Hunger committed
174
    // icon:
con's avatar
con committed
175
176
177
178
    if (!panel->icon().isNull()) {
        QLabel *iconLabel = new QLabel(m_root);
        iconLabel->setPixmap(panel->icon().pixmap(ICON_SIZE, ICON_SIZE));
        iconLabel->setContentsMargins(0, ABOVE_HEADING_MARGIN, 0, 0);
con's avatar
con committed
179
        m_layout->addWidget(iconLabel, headerRow, 0, 3, 1, Qt::AlignTop | Qt::AlignHCenter);
Tobias Hunger's avatar
Tobias Hunger committed
180
181
182
    }

    // name:
con's avatar
con committed
183
184
    QLabel *nameLabel = new QLabel(m_root);
    nameLabel->setText(panel->displayName());
185
186
187
    QPalette palette = nameLabel->palette();
    palette.setBrush(QPalette::All, QPalette::Foreground, QColor(0, 0, 0, 110));
    nameLabel->setPalette(palette);
con's avatar
con committed
188
189
    nameLabel->setContentsMargins(0, ABOVE_HEADING_MARGIN, 0, 0);
    QFont f = nameLabel->font();
dt's avatar
dt committed
190
    f.setBold(true);
con's avatar
con committed
191
    f.setPointSizeF(f.pointSizeF() * 1.6);
con's avatar
con committed
192
    nameLabel->setFont(f);
con's avatar
con committed
193
    m_layout->addWidget(nameLabel, headerRow, 1, 1, 1, Qt::AlignVCenter | Qt::AlignLeft);
Tobias Hunger's avatar
Tobias Hunger committed
194
195
196

    // line:
    const int lineRow(headerRow + 1);
con's avatar
con committed
197
198
    QWidget *line = new OnePixelBlackLine(m_root);
    m_layout->addWidget(line, lineRow, 1, 1, -1, Qt::AlignTop);
Tobias Hunger's avatar
Tobias Hunger committed
199

Tobias Hunger's avatar
Tobias Hunger committed
200
    // add the widget:
Tobias Hunger's avatar
Tobias Hunger committed
201
    const int widgetRow(lineRow + 1);
con's avatar
con committed
202
    addPanelWidget(panel, widgetRow);
dt's avatar
dt committed
203
204
}

205
void PanelsWidget::addPanelWidget(PropertiesPanel *panel, int row)
Tobias Hunger's avatar
Tobias Hunger committed
206
{
con's avatar
con committed
207
    QWidget *widget = panel->widget();
208
    widget->setContentsMargins(Constants::PANEL_LEFT_MARGIN,
Tobias Hunger's avatar
Tobias Hunger committed
209
210
                               ABOVE_CONTENTS_MARGIN, 0,
                               BELOW_CONTENTS_MARGIN);
con's avatar
con committed
211
212
    widget->setParent(m_root);
    m_layout->addWidget(widget, row, 0, 1, 2);
Tobias Hunger's avatar
Tobias Hunger committed
213
214
215
216

    m_panels.append(panel);
}

dt's avatar
dt committed
217
218
219
220
///
// ProjectWindow
///

dt's avatar
dt committed
221
ProjectWindow::ProjectWindow(QWidget *parent)
con's avatar
con committed
222
    : QWidget(parent),
223
224
      m_currentWidget(0),
      m_previousTargetSubIndex(-1)
con's avatar
con committed
225
{
226
    ProjectExplorer::SessionManager *session = ProjectExplorerPlugin::instance()->session();
con's avatar
con committed
227

Tobias Hunger's avatar
Tobias Hunger committed
228
229
230
231
    // Setup overall layout:
    QVBoxLayout *viewLayout = new QVBoxLayout(this);
    viewLayout->setMargin(0);
    viewLayout->setSpacing(0);
dt's avatar
dt committed
232

con's avatar
con committed
233
234
    m_tabWidget = new DoubleTabWidget(this);
    viewLayout->addWidget(m_tabWidget);
235

Tobias Hunger's avatar
Tobias Hunger committed
236
    // Setup our container for the contents:
con's avatar
con committed
237
238
    m_centralWidget = new QStackedWidget(this);
    viewLayout->addWidget(m_centralWidget);
Tobias Hunger's avatar
Tobias Hunger committed
239
240

    // connects:
con's avatar
con committed
241
242
    connect(m_tabWidget, SIGNAL(currentIndexChanged(int,int)),
            this, SLOT(showProperties(int,int)));
dt's avatar
dt committed
243

244
    connect(session, SIGNAL(sessionLoaded(QString)), this, SLOT(restoreStatus()));
245
246
247
    connect(session, SIGNAL(aboutToSaveSession()), this, SLOT(saveStatus()));

    connect(session, SIGNAL(projectAdded(ProjectExplorer::Project*)),
248
            this, SLOT(registerProject(ProjectExplorer::Project*)));
con's avatar
con committed
249
    connect(session, SIGNAL(aboutToRemoveProject(ProjectExplorer::Project*)),
250
            this, SLOT(deregisterProject(ProjectExplorer::Project*)));
251

252
253
254
    connect(session, SIGNAL(startupProjectChanged(ProjectExplorer::Project*)),
            this, SLOT(startupProjectChanged(ProjectExplorer::Project *)));

255
    // Update properties to empty project for now:
con's avatar
con committed
256
    showProperties(-1, -1);
con's avatar
con committed
257
258
259
260
261
262
}

ProjectWindow::~ProjectWindow()
{
}

263
264
265
266
267
268
void ProjectWindow::extensionsInitialized()
{
    foreach (ITargetFactory *fac, ExtensionSystem::PluginManager::instance()->getObjects<ITargetFactory>())
        connect(fac, SIGNAL(supportedTargetIdsChanged()),
                this, SLOT(targetFactoriesChanged()));

269
270
271
272
273
274
    QList<IProjectPanelFactory *> list = ExtensionSystem::PluginManager::instance()->getObjects<IProjectPanelFactory>();
    qSort(list.begin(), list.end(), &IPanelFactory::prioritySort);
    foreach (IProjectPanelFactory *fac, list)
        connect (fac, SIGNAL(projectUpdated(ProjectExplorer::Project *)),
                 this, SLOT(projectUpdated(ProjectExplorer::Project *)));

275
276
}

277
void ProjectWindow::aboutToShutdown()
278
{
con's avatar
con committed
279
280
281
    showProperties(-1, -1); // TODO that's a bit stupid, but otherwise stuff is still
                             // connected to the session
    disconnect(ProjectExplorerPlugin::instance()->session(), 0, this, 0);
282
283
}

284
285
286
287
288
289
290
291
292
void ProjectWindow::projectUpdated(Project *p)
{
    // Called after a project was configured
    int index = m_tabWidget->currentIndex();
    deregisterProject(p);
    registerProject(p);
    m_tabWidget->setCurrentIndex(index);
}

293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
void ProjectWindow::targetFactoriesChanged()
{
    bool changed = false;
    int index = m_tabWidget->currentIndex();
    QList<Project *> projects = m_tabIndexToProject;
    foreach (ProjectExplorer::Project *project, projects) {
        if (m_usesTargetPage.value(project) != useTargetPage(project)) {
            changed = true;
            deregisterProject(project);
            registerProject(project);
        }
    }
    if (changed)
        m_tabWidget->setCurrentIndex(index);
}

bool ProjectWindow::useTargetPage(ProjectExplorer::Project *project)
{
311
312
    if (project->targets().isEmpty())
        return false;
313
314
315
316
317
318
319
320
321
322
323
    if (project->targets().size() > 1)
        return true;
    QStringList tmp;
    foreach (ITargetFactory *fac, ExtensionSystem::PluginManager::instance()->getObjects<ITargetFactory>()) {
        tmp.append(fac->supportedTargetIds(project));
        if (tmp.size() > 1)
            return true;
    }
    return false;
}

324
void ProjectWindow::registerProject(ProjectExplorer::Project *project)
325
{
326
    if (!project || m_tabIndexToProject.contains(project))
Tobias Hunger's avatar
Tobias Hunger committed
327
328
        return;

329
330
331
332
333
334
335
336
337
338
    // find index to insert:
    int index = -1;
    for (int i = 0; i <= m_tabIndexToProject.count(); ++i) {
        if (i == m_tabIndexToProject.count() ||
            m_tabIndexToProject.at(i)->displayName() > project->displayName()) {
            index = i;
            break;
        }
    }

con's avatar
con committed
339
    QStringList subtabs;
340
341
342
343
344

    bool usesTargetPage = useTargetPage(project);
    m_usesTargetPage.insert(project, usesTargetPage);

    if (!usesTargetPage){
345
        // Show the target specific pages directly
346
347
348
349
350
        if (project->activeTarget()) {
            QList<ITargetPanelFactory *> factories =
                    ExtensionSystem::PluginManager::instance()->getObjects<ITargetPanelFactory>();

            qSort(factories.begin(), factories.end(), &IPanelFactory::prioritySort);
351

352
353
354
            foreach (ITargetPanelFactory *factory, factories)
                if (factory->supports(project->activeTarget()))
                    subtabs << factory->displayName();
355
356
357
358
359
360
361
362
        }
    } else {
        // Use the Targets page
        subtabs << QCoreApplication::translate("TargetSettingsPanelFactory", "Targets");
    }

    // Add the project specific pages
    QList<IProjectPanelFactory *> factories = ExtensionSystem::PluginManager::instance()->getObjects<IProjectPanelFactory>();
363
    qSort(factories.begin(), factories.end(), &IPanelFactory::prioritySort);
364
365
366
    foreach (IProjectPanelFactory *panelFactory, factories) {
        if (panelFactory->supports(project))
            subtabs << panelFactory->displayName();
367
    }
Tobias Hunger's avatar
Tobias Hunger committed
368

con's avatar
con committed
369
    m_tabIndexToProject.insert(index, project);
dt's avatar
dt committed
370
    m_tabWidget->insertTab(index, project->displayName(), project->file()->fileName(), subtabs);
con's avatar
con committed
371
372
}

373
void ProjectWindow::deregisterProject(ProjectExplorer::Project *project)
con's avatar
con committed
374
375
{
    int index = m_tabIndexToProject.indexOf(project);
376
377
    if (index < 0)
        return;
378

con's avatar
con committed
379
380
    m_tabIndexToProject.removeAt(index);
    m_tabWidget->removeTab(index);
381
382
}

con's avatar
con committed
383
384
void ProjectWindow::restoreStatus()
{
dt's avatar
dt committed
385
    // TODO
con's avatar
con committed
386
387
388
389
}

void ProjectWindow::saveStatus()
{
dt's avatar
dt committed
390
    // TODO
con's avatar
con committed
391
392
}

393
394
395
void ProjectWindow::startupProjectChanged(ProjectExplorer::Project *p)
{
    int index = m_tabIndexToProject.indexOf(p);
396
397
    if (index != -1)
        m_tabWidget->setCurrentIndex(index);
398
399
}

con's avatar
con committed
400
void ProjectWindow::showProperties(int index, int subIndex)
con's avatar
con committed
401
{
402
403
    if (index < 0 || index >= m_tabIndexToProject.count()) {
        removeCurrentWidget();
con's avatar
con committed
404
        return;
405
    }
406

con's avatar
con committed
407
    Project *project = m_tabIndexToProject.at(index);
dt's avatar
dt committed
408

409
    // Set up custom panels again:
Tobias Hunger's avatar
Tobias Hunger committed
410
    int pos = 0;
411
    IPanelFactory *fac = 0;
412
413
414
415
416
    // remember previous sub index state of target settings page
    if (TargetSettingsPanelWidget *previousPanelWidget
            = qobject_cast<TargetSettingsPanelWidget*>(m_currentWidget)) {
        m_previousTargetSubIndex = previousPanelWidget->currentSubIndex();
    }
417
418

    if (m_usesTargetPage.value(project)) {
419
420
        if (subIndex == 0) {
            // Targets page
Tobias Hunger's avatar
Tobias Hunger committed
421
            removeCurrentWidget();
422
423
424
425
            TargetSettingsPanelWidget *panelWidget = new TargetSettingsPanelWidget(project);
            if (m_previousTargetSubIndex >= 0)
                panelWidget->setCurrentSubIndex(m_previousTargetSubIndex);
            m_currentWidget = panelWidget;
Tobias Hunger's avatar
Tobias Hunger committed
426
427
            m_centralWidget->addWidget(m_currentWidget);
            m_centralWidget->setCurrentWidget(m_currentWidget);
con's avatar
con committed
428
        }
Tobias Hunger's avatar
Tobias Hunger committed
429
        ++pos;
430
    } else if (project->activeTarget()) {
431
        // No Targets page, target specific pages are first in the list
432
433
434
        QList<ITargetPanelFactory *> factories = ExtensionSystem::PluginManager::instance()->getObjects<ITargetPanelFactory>();
        qSort(factories.begin(), factories.end(), &ITargetPanelFactory::prioritySort);
        foreach (ITargetPanelFactory *panelFactory, factories) {
435
436
437
438
439
440
441
442
443
444
445
            if (panelFactory->supports(project->activeTarget())) {
                if (subIndex == pos) {
                    fac = panelFactory;
                    break;
                }
                ++pos;
            }
        }
    }

    if (!fac) {
446
447
448
        QList<IProjectPanelFactory *> factories = ExtensionSystem::PluginManager::instance()->getObjects<IProjectPanelFactory>();
        qSort(factories.begin(), factories.end(), &IPanelFactory::prioritySort);
        foreach (IProjectPanelFactory *panelFactory, factories) {
449
450
451
452
453
454
455
456
            if (panelFactory->supports(project)) {
                if (subIndex == pos) {
                    fac = panelFactory;
                    break;
                }
                ++pos;
            }
        }
con's avatar
con committed
457
    }
458
459
460
461

    if (fac) {
        removeCurrentWidget();

462
        PropertiesPanel *panel = 0;
463
464
465
466
467
468
469
470
471
472
473
474
475
476
        if (ITargetPanelFactory *ipf = qobject_cast<ITargetPanelFactory *>(fac))
            panel = ipf->createPanel(project->activeTarget());
        else if (IProjectPanelFactory *ipf = qobject_cast<IProjectPanelFactory *>(fac))
            panel = ipf->createPanel(project);
        Q_ASSERT(panel);

        PanelsWidget *panelsWidget = new PanelsWidget(m_centralWidget);
        panelsWidget->addPropertiesPanel(panel);
        m_currentWidget = panelsWidget;
        m_centralWidget->addWidget(m_currentWidget);
        m_centralWidget->setCurrentWidget(m_currentWidget);

    }

477
    ProjectExplorerPlugin::instance()->session()->setStartupProject(project);
Tobias Hunger's avatar
Tobias Hunger committed
478
479
480
481
482
483
}

void ProjectWindow::removeCurrentWidget()
{
    if (m_currentWidget) {
        m_centralWidget->removeWidget(m_currentWidget);
484
        if (m_currentWidget) {
Tobias Hunger's avatar
Tobias Hunger committed
485
486
            delete m_currentWidget;
            m_currentWidget = 0;
con's avatar
con committed
487
488
489
        }
    }
}