actionmanager.cpp 20.7 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
hjk's avatar
hjk committed
3
4
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
hjk's avatar
hjk committed
29

Eike Ziller's avatar
Eike Ziller committed
30
#include "actionmanager.h"
31
#include "actionmanager_p.h"
con's avatar
con committed
32
#include "mainwindow.h"
33
#include "actioncontainer_p.h"
con's avatar
con committed
34
#include "command_p.h"
35
#include "id.h"
con's avatar
con committed
36
37

#include <coreplugin/coreconstants.h>
38
#include <coreplugin/icore.h>
39
#include <utils/qtcassert.h>
con's avatar
con committed
40

41
42
43
44
45
46
47
48
#include <QDebug>
#include <QSettings>
#include <QDesktopWidget>
#include <QLabel>
#include <QMenu>
#include <QAction>
#include <QShortcut>
#include <QMenuBar>
con's avatar
con committed
49
50
51
52
53

namespace {
    enum { warnAboutFindFailures = 0 };
}

Eike Ziller's avatar
Eike Ziller committed
54
55
56
using namespace Core;
using namespace Core::Internal;

con's avatar
con committed
57
/*!
58
    \class Core::ActionManager
con's avatar
con committed
59
60
    \mainclass

61
62
    \brief The action manager is responsible for registration of menus and
    menu items and keyboard shortcuts.
con's avatar
con committed
63

64
    The ActionManager is the central bookkeeper of actions and their shortcuts and layout.
Eike Ziller's avatar
Eike Ziller committed
65
66
    It is a singleton containing mostly static methods. If you need access to the instance,
    e.g. for connecting to signals, is its ActionManager::instance() method.
con's avatar
con committed
67
68
69
70
71

    The main reasons for the need of this class is to provide a central place where the user
    can specify all his keyboard shortcuts, and to provide a solution for actions that should
    behave differently in different contexts (like the copy/replace/undo/redo actions).

72
73
    \section1 Contexts

Eike Ziller's avatar
Eike Ziller committed
74
    All actions that are registered with the same Id (but different context lists)
75
    are considered to be overloads of the same command, represented by an instance
con's avatar
con committed
76
    of the Command class.
77
78
79
80
81
82
83
84
85
86
87
88
    Exactly only one of the registered actions with the same ID is active at any time.
    Which action this is, is defined by the context list that the actions were registered
    with:

    If the current focus widget was registered via \l{ICore::addContextObject()},
    all the contexts returned by its IContext object are active. In addition all
    contexts set via \l{ICore::addAdditionalContext()} are active as well. If one
    of the actions was registered for one of these active contexts, it is the one
    active action, and receives \c triggered and \c toggled signals. Also the
    appearance of the visible action for this ID might be adapted to this
    active action (depending on the settings of the corresponding \l{Command} object).

con's avatar
con committed
89
    The action that is visible to the user is the one returned by Command::action().
90
    If you provide yourself a user visible representation of your action you need
con's avatar
con committed
91
    to use Command::action() for this.
92
93
94
    When this action is invoked by the user,
    the signal is forwarded to the registered action that is valid for the current context.

95
96
97
    \section1 Registering Actions

    To register a globally active action "My Action"
98
99
100
    put the following in your plugin's IPlugin::initialize method:
    \code
        QAction *myAction = new QAction(tr("My Action"), this);
Eike Ziller's avatar
Eike Ziller committed
101
        Core::Command *cmd = Core::ActionManager::registerAction(myAction,
102
                                                 "myplugin.myaction",
103
                                                 Core::Context(C_GLOBAL));
104
105
106
107
108
109
        cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+u")));
        connect(myAction, SIGNAL(triggered()), this, SLOT(performMyAction()));
    \endcode

    So the \c connect is done to your own QAction instance. If you create e.g.
    a tool button that should represent the action you add the action
con's avatar
con committed
110
    from Command::action() to it:
111
112
113
114
115
116
117
118
    \code
        QToolButton *myButton = new QToolButton(someParentWidget);
        myButton->setDefaultAction(cmd->action());
    \endcode

    Also use the ActionManager to add items to registered
    action containers like the applications menu bar or menus in that menu bar.
    To do this, you register your action via the
119
    registerAction methods, get the action container for a specific ID (like specified in
120
    the Core::Constants namespace) with a call of
121
    actionContainer(const Id&) and add your command to this container.
con's avatar
con committed
122

123
124
    Following the example adding "My Action" to the "Tools" menu would be done by
    \code
Eike Ziller's avatar
Eike Ziller committed
125
        Core::ActionManager::actionContainer(Core::M_TOOLS)->addAction(cmd);
126
127
    \endcode

128
    \section1 Important Guidelines:
con's avatar
con committed
129
130
    \list
    \o Always register your actions and shortcuts!
131
132
    \o Register your actions and shortcuts during your plugin's \l{ExtensionSystem::IPlugin::initialize()}
       or \l{ExtensionSystem::IPlugin::extensionsInitialized()} methods, otherwise the shortcuts won't appear
133
       in the keyboard settings dialog from the beginning.
134
135
136
    \o When registering an action with \c{cmd=registerAction(action, id, contexts)} be sure to connect
       your own action \c{connect(action, SIGNAL...)} but make \c{cmd->action()} visible to the user, i.e.
       \c{widget->addAction(cmd->action())}.
con's avatar
con committed
137
138
139
    \o Use this class to add actions to the applications menus
    \endlist

140
    \sa Core::ICore
con's avatar
con committed
141
    \sa Core::Command
142
    \sa Core::ActionContainer
143
    \sa Core::IContext
con's avatar
con committed
144
145
*/

Eike Ziller's avatar
Eike Ziller committed
146
147
static ActionManager *m_instance = 0;

con's avatar
con committed
148
/*!
Eike Ziller's avatar
Eike Ziller committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
    \internal
*/
ActionManager::ActionManager(QObject *parent)
    : QObject(parent),
      d(new ActionManagerPrivate())
{
    m_instance = this;
}

/*!
    \internal
*/
ActionManager::~ActionManager()
{
    delete d;
}

/*!
 * \return Singleton action manager instance
 */
ActionManager *ActionManager::instance()
{
    return m_instance;
}

/*!
    \brief Creates a new menu with the given \a id.
con's avatar
con committed
176

177
    Returns a new ActionContainer that you can use to get the QMenu instance
178
    or to add menu items to the menu. The ActionManager owns
179
    the returned ActionContainer.
180
    Add your menu to some other menu or a menu bar via the
181
    ActionManager::actionContainer and ActionContainer::addMenu methods.
con's avatar
con committed
182
*/
Eike Ziller's avatar
Eike Ziller committed
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
ActionContainer *ActionManager::createMenu(const Id &id)
{
    const ActionManagerPrivate::IdContainerMap::const_iterator it = m_instance->d->m_idContainerMap.constFind(id);
    if (it !=  m_instance->d->m_idContainerMap.constEnd())
        return it.value();

    QMenu *m = new QMenu(ICore::mainWindow());
    m->setObjectName(QLatin1String(id.name()));

    MenuActionContainer *mc = new MenuActionContainer(id);
    mc->setMenu(m);

    m_instance->d->m_idContainerMap.insert(id, mc);
    connect(mc, SIGNAL(destroyed()), m_instance->d, SLOT(containerDestroyed()));

    return mc;
}
con's avatar
con committed
200
201

/*!
Eike Ziller's avatar
Eike Ziller committed
202
    \brief Creates a new menu bar with the given \a id.
con's avatar
con committed
203

204
    Returns a new ActionContainer that you can use to get the QMenuBar instance
205
    or to add menus to the menu bar. The ActionManager owns
206
    the returned ActionContainer.
con's avatar
con committed
207
*/
Eike Ziller's avatar
Eike Ziller committed
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
ActionContainer *ActionManager::createMenuBar(const Id &id)
{
    const ActionManagerPrivate::IdContainerMap::const_iterator it = m_instance->d->m_idContainerMap.constFind(id);
    if (it !=  m_instance->d->m_idContainerMap.constEnd())
        return it.value();

    QMenuBar *mb = new QMenuBar; // No parent (System menu bar on Mac OS X)
    mb->setObjectName(id.toString());

    MenuBarActionContainer *mbc = new MenuBarActionContainer(id);
    mbc->setMenuBar(mb);

    m_instance->d->m_idContainerMap.insert(id, mbc);
    connect(mbc, SIGNAL(destroyed()), m_instance->d, SLOT(containerDestroyed()));

    return mbc;
}
con's avatar
con committed
225
226

/*!
Eike Ziller's avatar
Eike Ziller committed
227
    \brief Makes an \a action known to the system under the specified \a id.
228
229

    Returns a command object that represents the action in the application and is
230
    owned by the ActionManager. You can register several actions with the
231
232
233
    same \a id as long as the \a context is different. In this case
    a trigger of the actual action is forwarded to the registered QAction
    for the currently active context.
234
235
    A scriptable action can be called from a script without the need for the user
    to interact with it.
con's avatar
con committed
236
*/
Eike Ziller's avatar
Eike Ziller committed
237
238
239
240
241
242
243
244
245
246
Command *ActionManager::registerAction(QAction *action, const Id &id, const Context &context, bool scriptable)
{
    Action *a = m_instance->d->overridableAction(id);
    if (a) {
        a->addOverrideAction(action, context, scriptable);
        emit m_instance->commandListChanged();
        emit m_instance->commandAdded(id.toString());
    }
    return a;
}
con's avatar
con committed
247
248

/*!
Eike Ziller's avatar
Eike Ziller committed
249
    \brief Makes a \a shortcut known to the system under the specified \a id.
250
251
252
253
254
255

    Returns a command object that represents the shortcut in the application and is
    owned by the ActionManager. You can registered several shortcuts with the
    same \a id as long as the \a context is different. In this case
    a trigger of the actual shortcut is forwarded to the registered QShortcut
    for the currently active context.
256
257
    A scriptable shortcut can be called from a script without the need for the user
    to interact with it.
con's avatar
con committed
258
*/
Eike Ziller's avatar
Eike Ziller committed
259
260
Command *ActionManager::registerShortcut(QShortcut *shortcut, const Id &id, const Context &context, bool scriptable)
{
261
    QTC_CHECK(!context.isEmpty());
Eike Ziller's avatar
Eike Ziller committed
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
    Shortcut *sc = 0;
    if (CommandPrivate *c = m_instance->d->m_idCmdMap.value(id, 0)) {
        sc = qobject_cast<Shortcut *>(c);
        if (!sc) {
            qWarning() << "registerShortcut: id" << id.name()
                       << "is registered with a different command type.";
            return c;
        }
    } else {
        sc = new Shortcut(id);
        m_instance->d->m_idCmdMap.insert(id, sc);
    }

    if (sc->shortcut()) {
        qWarning() << "registerShortcut: action already registered, id" << id.name() << ".";
        return sc;
    }

    if (!m_instance->d->hasContext(context))
        shortcut->setEnabled(false);
    shortcut->setObjectName(id.toString());
    shortcut->setParent(ICore::mainWindow());
    sc->setShortcut(shortcut);
    sc->setScriptable(scriptable);
286
    sc->setContext(context);
Eike Ziller's avatar
Eike Ziller committed
287
288
289
290
291
292
293
294

    emit m_instance->commandListChanged();
    emit m_instance->commandAdded(id.toString());

    if (isPresentationModeEnabled())
        connect(sc->shortcut(), SIGNAL(activated()), m_instance->d, SLOT(shortcutTriggered()));
    return sc;
}
con's avatar
con committed
295
296

/*!
con's avatar
con committed
297
    \brief Returns the Command object that is known to the system
Eike Ziller's avatar
Eike Ziller committed
298
    under the given \a id.
299
300

    \sa ActionManager::registerAction()
con's avatar
con committed
301
*/
Eike Ziller's avatar
Eike Ziller committed
302
303
304
305
306
307
308
309
310
311
312
Command *ActionManager::command(const Id &id)
{
    const ActionManagerPrivate::IdCmdMap::const_iterator it = m_instance->d->m_idCmdMap.constFind(id);
    if (it == m_instance->d->m_idCmdMap.constEnd()) {
        if (warnAboutFindFailures)
            qWarning() << "ActionManagerPrivate::command(): failed to find :"
                       << id.name();
        return 0;
    }
    return it.value();
}
con's avatar
con committed
313
314

/*!
315
    \brief Returns the IActionContainter object that is know to the system
Eike Ziller's avatar
Eike Ziller committed
316
    under the given \a id.
con's avatar
con committed
317

318
319
320
    \sa ActionManager::createMenu()
    \sa ActionManager::createMenuBar()
*/
Eike Ziller's avatar
Eike Ziller committed
321
322
323
324
325
326
327
328
329
330
331
ActionContainer *ActionManager::actionContainer(const Id &id)
{
    const ActionManagerPrivate::IdContainerMap::const_iterator it = m_instance->d->m_idContainerMap.constFind(id);
    if (it == m_instance->d->m_idContainerMap.constEnd()) {
        if (warnAboutFindFailures)
            qWarning() << "ActionManagerPrivate::actionContainer(): failed to find :"
                       << id.name();
        return 0;
    }
    return it.value();
}
332
333

/*!
Eike Ziller's avatar
Eike Ziller committed
334
335
336
337
338
339
340
341
342
343
344
345
346
 * \brief Returns all commands that have been registered.
 */
QList<Command *> ActionManager::commands()
{
    // transform list of CommandPrivate into list of Command
    QList<Command *> result;
    foreach (Command *cmd, m_instance->d->m_idCmdMap.values())
        result << cmd;
    return result;
}

/*!
    \brief Removes the knowledge about an \a action under the specified \a id.
347
348
349
350
351
352

    Usually you do not need to unregister actions. The only valid use case for unregistering
    actions, is for actions that represent user definable actions, like for the custom Locator
    filters. If the user removes such an action, it also has to be unregistered from the action manager,
    to make it disappear from shortcut settings etc.
*/
Eike Ziller's avatar
Eike Ziller committed
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
void ActionManager::unregisterAction(QAction *action, const Id &id)
{
    Action *a = 0;
    CommandPrivate *c = m_instance->d->m_idCmdMap.value(id, 0);
    QTC_ASSERT(c, return);
    a = qobject_cast<Action *>(c);
    if (!a) {
        qWarning() << "unregisterAction: id" << id.name()
                   << "is registered with a different command type.";
        return;
    }
    a->removeOverrideAction(action);
    if (a->isEmpty()) {
        // clean up
        // ActionContainers listen to the commands' destroyed signals
        ICore::mainWindow()->removeAction(a->action());
        delete a->action();
        m_instance->d->m_idCmdMap.remove(id);
        delete a;
    }
    emit m_instance->commandListChanged();
}
375

con's avatar
con committed
376
/*!
Eike Ziller's avatar
Eike Ziller committed
377
378
379
380
381
382
    \brief Removes the knowledge about a shortcut under the specified \a id.

    Usually you do not need to unregister shortcuts. The only valid use case for unregistering
    shortcuts, is for shortcuts that represent user definable actions. If the user removes such an action,
    a corresponding shortcut also has to be unregistered from the action manager,
    to make it disappear from shortcut settings etc.
con's avatar
con committed
383
*/
Eike Ziller's avatar
Eike Ziller committed
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
void ActionManager::unregisterShortcut(const Core::Id &id)
{
    Shortcut *sc = 0;
    CommandPrivate *c = m_instance->d->m_idCmdMap.value(id, 0);
    QTC_ASSERT(c, return);
    sc = qobject_cast<Shortcut *>(c);
    if (!sc) {
        qWarning() << "unregisterShortcut: id" << id.name()
                   << "is registered with a different command type.";
        return;
    }
    delete sc->shortcut();
    m_instance->d->m_idCmdMap.remove(id);
    delete sc;
    emit m_instance->commandListChanged();
}
con's avatar
con committed
400
401


Eike Ziller's avatar
Eike Ziller committed
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
void ActionManager::setPresentationModeEnabled(bool enabled)
{
    if (enabled == isPresentationModeEnabled())
        return;

    // Signal/slots to commands:
    foreach (Command *c, commands()) {
        if (c->action()) {
            if (enabled)
                connect(c->action(), SIGNAL(triggered()), m_instance->d, SLOT(actionTriggered()));
            else
                disconnect(c->action(), SIGNAL(triggered()), m_instance->d, SLOT(actionTriggered()));
        }
        if (c->shortcut()) {
            if (enabled)
                connect(c->shortcut(), SIGNAL(activated()), m_instance->d, SLOT(shortcutTriggered()));
            else
                disconnect(c->shortcut(), SIGNAL(activated()), m_instance->d, SLOT(shortcutTriggered()));
        }
    }

    // The label for the shortcuts:
    if (!m_instance->d->m_presentationLabel) {
        m_instance->d->m_presentationLabel = new QLabel(0, Qt::ToolTip | Qt::WindowStaysOnTopHint);
        QFont font = m_instance->d->m_presentationLabel->font();
        font.setPixelSize(45);
        m_instance->d->m_presentationLabel->setFont(font);
        m_instance->d->m_presentationLabel->setAlignment(Qt::AlignCenter);
        m_instance->d->m_presentationLabel->setMargin(5);

        connect(&m_instance->d->m_presentationLabelTimer, SIGNAL(timeout()), m_instance->d->m_presentationLabel, SLOT(hide()));
    } else {
        m_instance->d->m_presentationLabelTimer.stop();
        delete m_instance->d->m_presentationLabel;
        m_instance->d->m_presentationLabel = 0;
    }
}

bool ActionManager::isPresentationModeEnabled()
{
    return m_instance->d->m_presentationLabel;
}

con's avatar
con committed
445
/*!
446
447
448
    \class ActionManagerPrivate
    \inheaderfile actionmanager_p.h
    \internal
con's avatar
con committed
449
450
*/

Eike Ziller's avatar
Eike Ziller committed
451
452
ActionManagerPrivate::ActionManagerPrivate()
  : m_presentationLabel(0)
con's avatar
con committed
453
{
Tobias Hunger's avatar
Tobias Hunger committed
454
    m_presentationLabelTimer.setInterval(1000);
con's avatar
con committed
455
456
}

457
ActionManagerPrivate::~ActionManagerPrivate()
con's avatar
con committed
458
{
459
    // first delete containers to avoid them reacting to command deletion
460
461
    foreach (ActionContainerPrivate *container, m_idContainerMap)
        disconnect(container, SIGNAL(destroyed()), this, SLOT(containerDestroyed()));
con's avatar
con committed
462
    qDeleteAll(m_idContainerMap.values());
463
    qDeleteAll(m_idCmdMap.values());
con's avatar
con committed
464
465
}

466
QDebug operator<<(QDebug d, const Context &context)
467
{
468
469
470
471
    d << "CONTEXT: ";
    foreach (Id id, context)
        d << "   " << id.uniqueIdentifier() << " " << id.toString();
    return d;
472
473
}

474
void ActionManagerPrivate::setContext(const Context &context)
con's avatar
con committed
475
476
477
478
479
480
481
482
483
484
{
    // here are possibilities for speed optimization if necessary:
    // let commands (de-)register themselves for contexts
    // and only update commands that are either in old or new contexts
    m_context = context;
    const IdCmdMap::const_iterator cmdcend = m_idCmdMap.constEnd();
    for (IdCmdMap::const_iterator it = m_idCmdMap.constBegin(); it != cmdcend; ++it)
        it.value()->setCurrentContext(m_context);
}

485
bool ActionManagerPrivate::hasContext(const Context &context) const
con's avatar
con committed
486
{
hjk's avatar
hjk committed
487
488
    for (int i = 0; i < m_context.size(); ++i) {
        if (context.contains(m_context.at(i)))
con's avatar
con committed
489
490
491
492
493
            return true;
    }
    return false;
}

494
495
496
497
498
499
void ActionManagerPrivate::containerDestroyed()
{
    ActionContainerPrivate *container = static_cast<ActionContainerPrivate *>(sender());
    m_idContainerMap.remove(m_idContainerMap.key(container));
}

Tobias Hunger's avatar
Tobias Hunger committed
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
void ActionManagerPrivate::actionTriggered()
{
    QAction *action = qobject_cast<QAction *>(QObject::sender());
    if (action)
        showShortcutPopup(action->shortcut().toString());
}

void ActionManagerPrivate::shortcutTriggered()
{
    QShortcut *sc = qobject_cast<QShortcut *>(QObject::sender());
    if (sc)
        showShortcutPopup(sc->key().toString());
}

void ActionManagerPrivate::showShortcutPopup(const QString &shortcut)
{
Eike Ziller's avatar
Eike Ziller committed
516
    if (shortcut.isEmpty() || !ActionManager::isPresentationModeEnabled())
Tobias Hunger's avatar
Tobias Hunger committed
517
518
519
520
521
        return;

    m_presentationLabel->setText(shortcut);
    m_presentationLabel->adjustSize();

Eike Ziller's avatar
Eike Ziller committed
522
    QPoint p = ICore::mainWindow()->mapToGlobal(ICore::mainWindow()->rect().center() - m_presentationLabel->rect().center());
Tobias Hunger's avatar
Tobias Hunger committed
523
524
525
526
527
528
529
    m_presentationLabel->move(p);

    m_presentationLabel->show();
    m_presentationLabel->raise();
    m_presentationLabelTimer.start();
}

530
Action *ActionManagerPrivate::overridableAction(const Id &id)
con's avatar
con committed
531
{
532
    Action *a = 0;
533
    if (CommandPrivate *c = m_idCmdMap.value(id, 0)) {
534
        a = qobject_cast<Action *>(c);
con's avatar
con committed
535
        if (!a) {
536
537
            qWarning() << "registerAction: id" << id.name()
                       << "is registered with a different command type.";
538
            return 0;
con's avatar
con committed
539
        }
con's avatar
con committed
540
    } else {
541
542
        a = new Action(id);
        m_idCmdMap.insert(id, a);
Eike Ziller's avatar
Eike Ziller committed
543
        ICore::mainWindow()->addAction(a->action());
544
        a->action()->setObjectName(id.toString());
545
        a->action()->setShortcutContext(Qt::ApplicationShortcut);
546
        a->setCurrentContext(m_context);
Tobias Hunger's avatar
Tobias Hunger committed
547

Eike Ziller's avatar
Eike Ziller committed
548
        if (ActionManager::isPresentationModeEnabled())
Tobias Hunger's avatar
Tobias Hunger committed
549
            connect(a->action(), SIGNAL(triggered()), this, SLOT(actionTriggered()));
con's avatar
con committed
550
551
552
553
554
    }

    return a;
}

Friedemann Kleint's avatar
Friedemann Kleint committed
555
556
557
static const char settingsGroup[] = "KeyBindings";
static const char idKey[] = "ID";
static const char sequenceKey[] = "Keysequence";
con's avatar
con committed
558

559
void ActionManagerPrivate::initialize()
con's avatar
con committed
560
{
hjk's avatar
hjk committed
561
    QSettings *settings = Core::ICore::settings();
con's avatar
con committed
562
    const int shortcuts = settings->beginReadArray(QLatin1String(settingsGroup));
563
    for (int i = 0; i < shortcuts; ++i) {
con's avatar
con committed
564
565
        settings->setArrayIndex(i);
        const QKeySequence key(settings->value(QLatin1String(sequenceKey)).toString());
566
        const Id id = Id::fromSetting(settings->value(QLatin1String(idKey)));
con's avatar
con committed
567

Eike Ziller's avatar
Eike Ziller committed
568
        Command *cmd = ActionManager::command(id);
con's avatar
con committed
569
570
571
572
573
574
        if (cmd)
            cmd->setKeySequence(key);
    }
    settings->endArray();
}

575
void ActionManagerPrivate::saveSettings(QSettings *settings)
con's avatar
con committed
576
577
578
579
580
581
{
    settings->beginWriteArray(QLatin1String(settingsGroup));
    int count = 0;

    const IdCmdMap::const_iterator cmdcend = m_idCmdMap.constEnd();
    for (IdCmdMap::const_iterator j = m_idCmdMap.constBegin(); j != cmdcend; ++j) {
582
        const Id id = j.key();
con's avatar
con committed
583
        CommandPrivate *cmd = j.value();
con's avatar
con committed
584
585
586
        QKeySequence key = cmd->keySequence();
        if (key != cmd->defaultKeySequence()) {
            settings->setArrayIndex(count);
587
            settings->setValue(QLatin1String(idKey), id.toString());
con's avatar
con committed
588
589
590
591
592
593
594
            settings->setValue(QLatin1String(sequenceKey), key.toString());
            count++;
        }
    }

    settings->endArray();
}