modemanager.cpp 10.9 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2 3 4
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 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 "modemanager.h"
hjk's avatar
hjk committed
34

con's avatar
con committed
35 36
#include "fancytabwidget.h"
#include "fancyactionbar.h"
37
#include "icore.h"
con's avatar
con committed
38 39 40
#include "mainwindow.h"

#include <aggregation/aggregate.h>
hjk's avatar
hjk committed
41

42
#include <coreplugin/actionmanager/actionmanager.h>
con's avatar
con committed
43
#include <coreplugin/actionmanager/command.h>
con's avatar
con committed
44 45
#include <coreplugin/coreconstants.h>
#include <coreplugin/imode.h>
46
#include <coreplugin/id.h>
con's avatar
con committed
47

48 49
#include <extensionsystem/pluginmanager.h>

hjk's avatar
hjk committed
50 51
#include <utils/qtcassert.h>

con's avatar
con committed
52
#include <QtCore/QDebug>
53 54 55 56
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QVector>

con's avatar
con committed
57
#include <QtCore/QSignalMapper>
58
#include <QtGui/QShortcut>
con's avatar
con committed
59 60
#include <QtGui/QAction>

61 62
namespace Core {

63 64 65 66 67 68 69 70 71
/*!
    \class Core::ModeManager

    The mode manager handles everything related to the instances of IMode
    that were added to the plugin manager's object pool as well as their
    buttons and the tool bar with the round buttons in the lower left
    corner of Qt Creator.
*/

72 73
struct ModeManagerPrivate
{
74 75 76 77 78 79 80 81
    explicit ModeManagerPrivate(Internal::MainWindow *mainWindow,
                                Internal::FancyTabWidget *modeStack,
                                ModeManager *q);

    static ModeManager *m_instance;
    Internal::MainWindow *m_mainWindow;
    Internal::FancyTabWidget *m_modeStack;
    Internal::FancyActionBar *m_actionBar;
82
    QMap<QAction*, int> m_actions;
83 84 85
    QVector<IMode*> m_modes;
    QVector<Command*> m_modeShortcuts;
    QSignalMapper *m_signalMapper;
86
    Context m_addedContexts;
87 88 89 90 91 92 93 94
    int m_oldCurrent;
};

ModeManager *ModeManagerPrivate::m_instance = 0;

ModeManagerPrivate::ModeManagerPrivate(Internal::MainWindow *mainWindow,
                                       Internal::FancyTabWidget *modeStack,
                                       ModeManager *q) :
con's avatar
con committed
95 96
    m_mainWindow(mainWindow),
    m_modeStack(modeStack),
97
    m_signalMapper(new QSignalMapper(q)),
98
    m_oldCurrent(-1)
99 100
{
}
101

102 103 104
ModeManager::ModeManager(Internal::MainWindow *mainWindow,
                         Internal::FancyTabWidget *modeStack) :
        d(new ModeManagerPrivate(mainWindow, modeStack, this))
con's avatar
con committed
105
{
106
    ModeManagerPrivate::m_instance = this;
con's avatar
con committed
107

108 109
    d->m_actionBar = new Internal::FancyActionBar(modeStack);
    d->m_modeStack->addCornerWidget(d->m_actionBar);
con's avatar
con committed
110

111 112 113
    connect(d->m_modeStack, SIGNAL(currentAboutToShow(int)), SLOT(currentTabAboutToChange(int)));
    connect(d->m_modeStack, SIGNAL(currentChanged(int)), SLOT(currentTabChanged(int)));
    connect(d->m_signalMapper, SIGNAL(mapped(QString)), this, SLOT(activateMode(QString)));
con's avatar
con committed
114 115 116 117 118 119 120 121 122 123
}

void ModeManager::init()
{
    QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(objectAdded(QObject*)),
                     this, SLOT(objectAdded(QObject*)));
    QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(aboutToRemoveObject(QObject*)),
                     this, SLOT(aboutToRemoveObject(QObject*)));
}

124 125 126 127 128 129
ModeManager::~ModeManager()
{
    delete d;
    ModeManagerPrivate::m_instance = 0;
}

con's avatar
con committed
130 131 132
void ModeManager::addWidget(QWidget *widget)
{
    // We want the actionbar to stay on the bottom
133
    // so d->m_modeStack->cornerWidgetCount() -1 inserts it at the position immediately above
con's avatar
con committed
134
    // the actionbar
135
    d->m_modeStack->insertCornerWidget(d->m_modeStack->cornerWidgetCount() -1, widget);
con's avatar
con committed
136 137 138 139
}

IMode *ModeManager::currentMode() const
{
140
    int currentIndex = d->m_modeStack->currentIndex();
con's avatar
con committed
141 142
    if (currentIndex < 0)
        return 0;
143
    return d->m_modes.at(currentIndex);
con's avatar
con committed
144 145 146 147
}

int ModeManager::indexOf(const QString &id) const
{
148 149
    for (int i = 0; i < d->m_modes.count(); ++i) {
        if (d->m_modes.at(i)->id() == id)
con's avatar
con committed
150 151 152 153 154 155 156 157 158 159
            return i;
    }
    qDebug() << "Warning, no such mode:" << id;
    return -1;
}

IMode *ModeManager::mode(const QString &id) const
{
    const int index = indexOf(id);
    if (index >= 0)
160
        return d->m_modes.at(index);
con's avatar
con committed
161 162 163
    return 0;
}

164 165
void ModeManager::activateModeType(const QString &type)
{
166 167
    if (currentMode() && currentMode()->type() == type)
        return;
168 169 170 171 172 173 174 175 176 177 178
    int index = -1;
    for (int i = 0; i < d->m_modes.count(); ++i) {
        if (d->m_modes.at(i)->type() == type) {
            index = i;
            break;
        }
    }
    if (index != -1)
        d->m_modeStack->setCurrentIndex(index);
}

con's avatar
con committed
179 180 181 182
void ModeManager::activateMode(const QString &id)
{
    const int index = indexOf(id);
    if (index >= 0)
183
        d->m_modeStack->setCurrentIndex(index);
con's avatar
con committed
184 185 186 187 188 189 190 191
}

void ModeManager::objectAdded(QObject *obj)
{
    IMode *mode = Aggregation::query<IMode>(obj);
    if (!mode)
        return;

192
    d->m_mainWindow->addContextObject(mode);
con's avatar
con committed
193 194 195

    // Count the number of modes with a higher priority
    int index = 0;
196
    foreach (const IMode *m, d->m_modes)
con's avatar
con committed
197 198 199
        if (m->priority() > mode->priority())
            ++index;

200 201 202
    d->m_modes.insert(index, mode);
    d->m_modeStack->insertTab(index, mode->widget(), mode->icon(), mode->displayName());
    d->m_modeStack->setTabEnabled(index, mode->isEnabled());
con's avatar
con committed
203 204

    // Register mode shortcut
205
    ActionManager *am = d->m_mainWindow->actionManager();
hjk's avatar
hjk committed
206
    const Id shortcutId(QLatin1String("QtCreator.Mode.") + mode->id());
207
    QShortcut *shortcut = new QShortcut(d->m_mainWindow);
208
    shortcut->setWhatsThis(tr("Switch to <b>%1</b> mode").arg(mode->displayName()));
209
    Command *cmd = am->registerShortcut(shortcut, shortcutId, Context(Constants::C_GLOBAL));
con's avatar
con committed
210

211
    d->m_modeShortcuts.insert(index, cmd);
con's avatar
con committed
212
    connect(cmd, SIGNAL(keySequenceChanged()), this, SLOT(updateModeToolTip()));
213 214
    for (int i = 0; i < d->m_modeShortcuts.size(); ++i) {
        Command *currentCmd = d->m_modeShortcuts.at(i);
215 216 217
        // we need this hack with currentlyHasDefaultSequence
        // because we call setDefaultShortcut multiple times on the same cmd
        // and still expect the current shortcut to change with it
con's avatar
con committed
218 219
        bool currentlyHasDefaultSequence = (currentCmd->keySequence()
                                            == currentCmd->defaultKeySequence());
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
220
#ifdef Q_WS_MAC
221
        currentCmd->setDefaultKeySequence(QKeySequence(QString::fromLatin1("Meta+%1").arg(i+1)));
con's avatar
con committed
222
#else
223
        currentCmd->setDefaultKeySequence(QKeySequence(QString::fromLatin1("Ctrl+%1").arg(i+1)));
con's avatar
con committed
224
#endif
con's avatar
con committed
225 226
        if (currentlyHasDefaultSequence)
            currentCmd->setKeySequence(currentCmd->defaultKeySequence());
con's avatar
con committed
227 228
    }

229 230
    d->m_signalMapper->setMapping(shortcut, mode->id());
    connect(shortcut, SIGNAL(activated()), d->m_signalMapper, SLOT(map()));
con's avatar
con committed
231 232
    connect(mode, SIGNAL(enabledStateChanged(bool)),
            this, SLOT(enabledStateChanged()));
con's avatar
con committed
233 234 235 236
}

void ModeManager::updateModeToolTip()
{
con's avatar
con committed
237
    Command *cmd = qobject_cast<Command *>(sender());
con's avatar
con committed
238
    if (cmd) {
239
        int index = d->m_modeShortcuts.indexOf(cmd);
con's avatar
con committed
240
        if (index != -1)
241
            d->m_modeStack->setTabToolTip(index, cmd->stringWithAppendedShortcut(cmd->shortcut()->whatsThis()));
con's avatar
con committed
242 243 244
    }
}

con's avatar
con committed
245 246 247 248
void ModeManager::enabledStateChanged()
{
    IMode *mode = qobject_cast<IMode *>(sender());
    QTC_ASSERT(mode, return);
249
    int index = d->m_modes.indexOf(mode);
con's avatar
con committed
250
    QTC_ASSERT(index >= 0, return);
251
    d->m_modeStack->setTabEnabled(index, mode->isEnabled());
252 253 254 255 256 257 258 259 260 261 262 263

    // Make sure we leave any disabled mode to prevent possible crashes:
    if (mode == currentMode() && !mode->isEnabled()) {
        // This assumes that there is always at least one enabled mode.
        for (int i = 0; i < d->m_modes.count(); ++i) {
            if (d->m_modes.at(i) != mode &&
                d->m_modes.at(i)->isEnabled()) {
                activateMode(d->m_modes.at(i)->id());
                break;
            }
        }
    }
con's avatar
con committed
264 265
}

con's avatar
con committed
266 267 268 269 270 271
void ModeManager::aboutToRemoveObject(QObject *obj)
{
    IMode *mode = Aggregation::query<IMode>(obj);
    if (!mode)
        return;

272 273 274 275
    const int index = d->m_modes.indexOf(mode);
    d->m_modes.remove(index);
    d->m_modeShortcuts.remove(index);
    d->m_modeStack->removeTab(index);
con's avatar
con committed
276

277
    d->m_mainWindow->removeContextObject(mode);
con's avatar
con committed
278 279
}

280
void ModeManager::addAction(QAction *action, int priority)
con's avatar
con committed
281
{
282
    d->m_actions.insert(action, priority);
con's avatar
con committed
283 284 285

    // Count the number of commands with a higher priority
    int index = 0;
286
    foreach (int p, d->m_actions) {
con's avatar
con committed
287 288
        if (p > priority)
            ++index;
con's avatar
con committed
289
    }
con's avatar
con committed
290

291
    d->m_actionBar->insertAction(index, action);
con's avatar
con committed
292 293
}

294 295
void ModeManager::addProjectSelector(QAction *action)
{
296
    d->m_actionBar->addProjectSelector(action);
297
    d->m_actions.insert(0, INT_MAX);
298 299
}

con's avatar
con committed
300 301 302
void ModeManager::currentTabAboutToChange(int index)
{
    if (index >= 0) {
303
        IMode *mode = d->m_modes.at(index);
con's avatar
con committed
304 305 306 307 308 309 310 311 312
        if (mode)
            emit currentModeAboutToChange(mode);
    }
}

void ModeManager::currentTabChanged(int index)
{
    // Tab index changes to -1 when there is no tab left.
    if (index >= 0) {
313
        IMode *mode = d->m_modes.at(index);
con's avatar
con committed
314 315 316 317

        // FIXME: This hardcoded context update is required for the Debug and Edit modes, since
        // they use the editor widget, which is already a context widget so the main window won't
        // go further up the parent tree to find the mode context.
318
        ICore::instance()->updateAdditionalContexts(d->m_addedContexts, mode->context());
319
        d->m_addedContexts = mode->context();
320

321
        IMode *oldMode = 0;
322 323 324
        if (d->m_oldCurrent >= 0)
            oldMode = d->m_modes.at(d->m_oldCurrent);
        d->m_oldCurrent = index;
325
        emit currentModeChanged(mode, oldMode);
con's avatar
con committed
326 327 328 329 330 331
    }
}

void ModeManager::setFocusToCurrentMode()
{
    IMode *mode = currentMode();
hjk's avatar
hjk committed
332
    QTC_ASSERT(mode, return);
con's avatar
con committed
333 334 335 336 337 338 339 340 341
    QWidget *widget = mode->widget();
    if (widget) {
        QWidget *focusWidget = widget->focusWidget();
        if (focusWidget)
            focusWidget->setFocus();
        else
            widget->setFocus();
    }
}
342

343 344 345 346 347
void ModeManager::setModeBarHidden(bool hidden)
{
    d->m_modeStack->setSelectionWidgetHidden(hidden);
}

348 349 350 351 352 353
ModeManager *ModeManager::instance()
{
    return ModeManagerPrivate::m_instance;
}

} // namespace Core