actionmanager.cpp 18.9 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** 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
** 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
Eike Ziller's avatar
Eike Ziller committed
13
14
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
25
26
**
** 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
27
28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
hjk's avatar
hjk committed
30

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

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

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

namespace {
    enum { warnAboutFindFailures = 0 };
}

51
static const char kKeyboardSettingsKey[] = "KeyboardShortcuts";
52
static const char kKeyboardSettingsTransferredKey[] = "OldSettingsTransferred";
53

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
    \mainclass
Falko Arps's avatar
Falko Arps committed
60
    \inmodule Qt Creator
con's avatar
con committed
61

62
    \brief The ActionManager class is responsible for registration of menus and
63
    menu items and keyboard shortcuts.
con's avatar
con committed
64

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

    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).

73
74
    \section1 Contexts

Eike Ziller's avatar
Eike Ziller committed
75
    All actions that are registered with the same Id (but different context lists)
76
    are considered to be overloads of the same command, represented by an instance
con's avatar
con committed
77
    of the Command class.
78
79
80
81
82
83
84
85
86
87
88
89
    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
90
    The action that is visible to the user is the one returned by Command::action().
91
    If you provide yourself a user visible representation of your action you need
con's avatar
con committed
92
    to use Command::action() for this.
93
94
95
    When this action is invoked by the user,
    the signal is forwarded to the registered action that is valid for the current context.

96
97
98
    \section1 Registering Actions

    To register a globally active action "My Action"
99
    put the following in your plugin's IPlugin::initialize function:
100
101
    \code
        QAction *myAction = new QAction(tr("My Action"), this);
Eike Ziller's avatar
Eike Ziller committed
102
        Core::Command *cmd = Core::ActionManager::registerAction(myAction,
103
                                                 "myplugin.myaction",
104
                                                 Core::Context(C_GLOBAL));
105
106
107
108
109
110
        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
111
    from Command::action() to it:
112
113
114
115
116
117
118
119
    \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
120
    registerAction functions, get the action container for a specific ID (like specified in
121
    the Core::Constants namespace) with a call of
122
    actionContainer(const Id&) and add your command to this container.
con's avatar
con committed
123

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

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

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

Falko Arps's avatar
Falko Arps committed
147
148
149
150
151
152
153
154
155
156
157
158
/*!
    \fn void ActionManager::commandListChanged()

    Emitted when the command list has changed.
*/

/*!
    \fn void ActionManager::commandAdded(const QString &id)

    Emitted when a command (with the \a id) is added.
*/

Eike Ziller's avatar
Eike Ziller committed
159
static ActionManager *m_instance = 0;
160
static ActionManagerPrivate *d;
Eike Ziller's avatar
Eike Ziller committed
161

con's avatar
con committed
162
/*!
Eike Ziller's avatar
Eike Ziller committed
163
164
165
    \internal
*/
ActionManager::ActionManager(QObject *parent)
166
    : QObject(parent)
Eike Ziller's avatar
Eike Ziller committed
167
168
{
    m_instance = this;
169
    d = new ActionManagerPrivate;
Eike Ziller's avatar
Eike Ziller committed
170
171
172
173
174
175
176
177
178
179
180
}

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

/*!
Falko Arps's avatar
Falko Arps committed
181
182
    Returns the pointer to the instance, which is only used for connecting to signals.
*/
Eike Ziller's avatar
Eike Ziller committed
183
184
185
186
187
188
ActionManager *ActionManager::instance()
{
    return m_instance;
}

/*!
Leena Miettinen's avatar
Leena Miettinen committed
189
    Creates a new menu with the given \a id.
con's avatar
con committed
190

191
    Returns a new ActionContainer that you can use to get the QMenu instance
192
    or to add menu items to the menu. The ActionManager owns
193
    the returned ActionContainer.
194
    Add your menu to some other menu or a menu bar via the
195
    ActionManager::actionContainer and ActionContainer::addMenu functions.
con's avatar
con committed
196
*/
197
ActionContainer *ActionManager::createMenu(Id id)
Eike Ziller's avatar
Eike Ziller committed
198
{
199
200
    const ActionManagerPrivate::IdContainerMap::const_iterator it = d->m_idContainerMap.constFind(id);
    if (it !=  d->m_idContainerMap.constEnd())
Eike Ziller's avatar
Eike Ziller committed
201
202
203
204
205
206
207
208
        return it.value();

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

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

209
210
    d->m_idContainerMap.insert(id, mc);
    connect(mc, SIGNAL(destroyed()), d, SLOT(containerDestroyed()));
Eike Ziller's avatar
Eike Ziller committed
211
212
213

    return mc;
}
con's avatar
con committed
214
215

/*!
Leena Miettinen's avatar
Leena Miettinen committed
216
    Creates a new menu bar with the given \a id.
con's avatar
con committed
217

218
    Returns a new ActionContainer that you can use to get the QMenuBar instance
219
    or to add menus to the menu bar. The ActionManager owns
220
    the returned ActionContainer.
con's avatar
con committed
221
*/
222
ActionContainer *ActionManager::createMenuBar(Id id)
Eike Ziller's avatar
Eike Ziller committed
223
{
224
225
    const ActionManagerPrivate::IdContainerMap::const_iterator it = d->m_idContainerMap.constFind(id);
    if (it !=  d->m_idContainerMap.constEnd())
Eike Ziller's avatar
Eike Ziller committed
226
227
228
229
230
231
232
233
        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);

234
235
    d->m_idContainerMap.insert(id, mbc);
    connect(mbc, SIGNAL(destroyed()), d, SLOT(containerDestroyed()));
Eike Ziller's avatar
Eike Ziller committed
236
237
238

    return mbc;
}
con's avatar
con committed
239
240

/*!
Leena Miettinen's avatar
Leena Miettinen committed
241
    Makes an \a action known to the system under the specified \a id.
242
243

    Returns a command object that represents the action in the application and is
244
    owned by the ActionManager. You can register several actions with the
245
246
247
    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.
248
249
    A scriptable action can be called from a script without the need for the user
    to interact with it.
con's avatar
con committed
250
*/
251
Command *ActionManager::registerAction(QAction *action, Id id, const Context &context, bool scriptable)
Eike Ziller's avatar
Eike Ziller committed
252
{
253
    Action *a = d->overridableAction(id);
Eike Ziller's avatar
Eike Ziller committed
254
255
256
    if (a) {
        a->addOverrideAction(action, context, scriptable);
        emit m_instance->commandListChanged();
257
        emit m_instance->commandAdded(id);
Eike Ziller's avatar
Eike Ziller committed
258
259
260
    }
    return a;
}
con's avatar
con committed
261
262

/*!
Leena Miettinen's avatar
Leena Miettinen committed
263
    Returns the Command object that is known to the system
Eike Ziller's avatar
Eike Ziller committed
264
    under the given \a id.
265
266

    \sa ActionManager::registerAction()
con's avatar
con committed
267
*/
268
Command *ActionManager::command(Id id)
Eike Ziller's avatar
Eike Ziller committed
269
{
270
271
    const ActionManagerPrivate::IdCmdMap::const_iterator it = d->m_idCmdMap.constFind(id);
    if (it == d->m_idCmdMap.constEnd()) {
Eike Ziller's avatar
Eike Ziller committed
272
273
274
275
276
277
278
        if (warnAboutFindFailures)
            qWarning() << "ActionManagerPrivate::command(): failed to find :"
                       << id.name();
        return 0;
    }
    return it.value();
}
con's avatar
con committed
279
280

/*!
Leena Miettinen's avatar
Leena Miettinen committed
281
    Returns the IActionContainter object that is know to the system
Eike Ziller's avatar
Eike Ziller committed
282
    under the given \a id.
con's avatar
con committed
283

284
285
286
    \sa ActionManager::createMenu()
    \sa ActionManager::createMenuBar()
*/
287
ActionContainer *ActionManager::actionContainer(Id id)
Eike Ziller's avatar
Eike Ziller committed
288
{
289
290
    const ActionManagerPrivate::IdContainerMap::const_iterator it = d->m_idContainerMap.constFind(id);
    if (it == d->m_idContainerMap.constEnd()) {
Eike Ziller's avatar
Eike Ziller committed
291
292
293
294
295
296
297
        if (warnAboutFindFailures)
            qWarning() << "ActionManagerPrivate::actionContainer(): failed to find :"
                       << id.name();
        return 0;
    }
    return it.value();
}
298
299

/*!
Falko Arps's avatar
Falko Arps committed
300
301
    Returns all commands that have been registered.
*/
Eike Ziller's avatar
Eike Ziller committed
302
303
QList<Command *> ActionManager::commands()
{
304
    // transform list of Action into list of Command
Eike Ziller's avatar
Eike Ziller committed
305
    QList<Command *> result;
306
    foreach (Command *cmd, d->m_idCmdMap)
Eike Ziller's avatar
Eike Ziller committed
307
308
309
310
311
        result << cmd;
    return result;
}

/*!
Leena Miettinen's avatar
Leena Miettinen committed
312
    Removes the knowledge about an \a action under the specified \a id.
313
314
315
316
317
318

    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.
*/
319
void ActionManager::unregisterAction(QAction *action, Id id)
Eike Ziller's avatar
Eike Ziller committed
320
{
321
    Action *a = d->m_idCmdMap.value(id, 0);
Eike Ziller's avatar
Eike Ziller committed
322
323
324
325
326
327
328
329
330
331
332
    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();
333
        d->m_idCmdMap.remove(id);
Eike Ziller's avatar
Eike Ziller committed
334
335
336
337
        delete a;
    }
    emit m_instance->commandListChanged();
}
338

Falko Arps's avatar
Falko Arps committed
339
340
341
342
343
/*!
    Handles the display of the used shortcuts in the presentation mode. The presentation mode is
    enabled when starting \QC with the command line argument \c{-presentationMode}. In the
    presentation mode, \QC displays any pressed shortcut in a grey box.
*/
Eike Ziller's avatar
Eike Ziller committed
344
345
346
347
348
349
350
351
352
void ActionManager::setPresentationModeEnabled(bool enabled)
{
    if (enabled == isPresentationModeEnabled())
        return;

    // Signal/slots to commands:
    foreach (Command *c, commands()) {
        if (c->action()) {
            if (enabled)
353
                connect(c->action(), SIGNAL(triggered()), d, SLOT(actionTriggered()));
Eike Ziller's avatar
Eike Ziller committed
354
            else
355
                disconnect(c->action(), SIGNAL(triggered()), d, SLOT(actionTriggered()));
Eike Ziller's avatar
Eike Ziller committed
356
357
358
359
        }
    }

    // The label for the shortcuts:
360
361
362
    if (!d->m_presentationLabel) {
        d->m_presentationLabel = new QLabel(0, Qt::ToolTip | Qt::WindowStaysOnTopHint);
        QFont font = d->m_presentationLabel->font();
Eike Ziller's avatar
Eike Ziller committed
363
        font.setPixelSize(45);
364
365
366
        d->m_presentationLabel->setFont(font);
        d->m_presentationLabel->setAlignment(Qt::AlignCenter);
        d->m_presentationLabel->setMargin(5);
Eike Ziller's avatar
Eike Ziller committed
367

368
        connect(&d->m_presentationLabelTimer, SIGNAL(timeout()), d->m_presentationLabel, SLOT(hide()));
Eike Ziller's avatar
Eike Ziller committed
369
    } else {
370
371
372
        d->m_presentationLabelTimer.stop();
        delete d->m_presentationLabel;
        d->m_presentationLabel = 0;
Eike Ziller's avatar
Eike Ziller committed
373
374
375
376
377
    }
}

bool ActionManager::isPresentationModeEnabled()
{
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
    return d->m_presentationLabel;
}

void ActionManager::initialize()
{
    d->initialize();
}

void ActionManager::saveSettings(QSettings *settings)
{
    d->saveSettings(settings);
}

void ActionManager::setContext(const Context &context)
{
    d->setContext(context);
Eike Ziller's avatar
Eike Ziller committed
394
395
}

con's avatar
con committed
396
/*!
397
398
399
    \class ActionManagerPrivate
    \inheaderfile actionmanager_p.h
    \internal
con's avatar
con committed
400
401
*/

Eike Ziller's avatar
Eike Ziller committed
402
403
ActionManagerPrivate::ActionManagerPrivate()
  : m_presentationLabel(0)
con's avatar
con committed
404
{
Tobias Hunger's avatar
Tobias Hunger committed
405
    m_presentationLabelTimer.setInterval(1000);
con's avatar
con committed
406
407
}

408
ActionManagerPrivate::~ActionManagerPrivate()
con's avatar
con committed
409
{
410
    // first delete containers to avoid them reacting to command deletion
411
412
    foreach (ActionContainerPrivate *container, m_idContainerMap)
        disconnect(container, SIGNAL(destroyed()), this, SLOT(containerDestroyed()));
413
414
    qDeleteAll(m_idContainerMap);
    qDeleteAll(m_idCmdMap);
con's avatar
con committed
415
416
}

417
QDebug operator<<(QDebug d, const Context &context)
418
{
419
420
421
422
    d << "CONTEXT: ";
    foreach (Id id, context)
        d << "   " << id.uniqueIdentifier() << " " << id.toString();
    return d;
423
424
}

425
void ActionManagerPrivate::setContext(const Context &context)
con's avatar
con committed
426
427
428
429
430
431
432
433
434
435
{
    // 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);
}

436
bool ActionManagerPrivate::hasContext(const Context &context) const
con's avatar
con committed
437
{
hjk's avatar
hjk committed
438
439
    for (int i = 0; i < m_context.size(); ++i) {
        if (context.contains(m_context.at(i)))
con's avatar
con committed
440
441
442
443
444
            return true;
    }
    return false;
}

445
446
447
448
449
450
void ActionManagerPrivate::containerDestroyed()
{
    ActionContainerPrivate *container = static_cast<ActionContainerPrivate *>(sender());
    m_idContainerMap.remove(m_idContainerMap.key(container));
}

Tobias Hunger's avatar
Tobias Hunger committed
451
452
453
454
455
456
457
458
459
void ActionManagerPrivate::actionTriggered()
{
    QAction *action = qobject_cast<QAction *>(QObject::sender());
    if (action)
        showShortcutPopup(action->shortcut().toString());
}

void ActionManagerPrivate::showShortcutPopup(const QString &shortcut)
{
Eike Ziller's avatar
Eike Ziller committed
460
    if (shortcut.isEmpty() || !ActionManager::isPresentationModeEnabled())
Tobias Hunger's avatar
Tobias Hunger committed
461
462
463
464
465
        return;

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

Eike Ziller's avatar
Eike Ziller committed
466
    QPoint p = ICore::mainWindow()->mapToGlobal(ICore::mainWindow()->rect().center() - m_presentationLabel->rect().center());
Tobias Hunger's avatar
Tobias Hunger committed
467
468
469
470
471
472
473
    m_presentationLabel->move(p);

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

474
Action *ActionManagerPrivate::overridableAction(Id id)
con's avatar
con committed
475
{
476
477
    Action *a = m_idCmdMap.value(id, 0);
    if (!a) {
478
479
        a = new Action(id);
        m_idCmdMap.insert(id, a);
480
        readUserSettings(id, a);
Eike Ziller's avatar
Eike Ziller committed
481
        ICore::mainWindow()->addAction(a->action());
482
        a->action()->setObjectName(id.toString());
483
        a->action()->setShortcutContext(Qt::ApplicationShortcut);
484
        a->setCurrentContext(m_context);
Tobias Hunger's avatar
Tobias Hunger committed
485

Eike Ziller's avatar
Eike Ziller committed
486
        if (ActionManager::isPresentationModeEnabled())
Tobias Hunger's avatar
Tobias Hunger committed
487
            connect(a->action(), SIGNAL(triggered()), this, SLOT(actionTriggered()));
con's avatar
con committed
488
489
490
491
492
    }

    return a;
}

493
void ActionManagerPrivate::readUserSettings(Id id, Action *cmd)
494
495
496
497
498
499
500
501
502
503
504
{
    QSettings *settings = Core::ICore::settings();
    settings->beginGroup(QLatin1String(kKeyboardSettingsKey));
    if (settings->contains(id.toString()))
        cmd->setKeySequence(QKeySequence(settings->value(id.toString()).toString()));
    settings->endGroup();
}

static const char oldSettingsGroup[] = "KeyBindings";
static const char oldIdKey[] = "ID";
static const char oldSequenceKey[] = "Keysequence";
con's avatar
con committed
505

506
void ActionManagerPrivate::initialize()
con's avatar
con committed
507
{
508
    // TODO remove me after some period after 3.1
509
510
511
512
    // TODO also remove the old settings after some period after 3.1
    // settings->remove(QLatin1String(oldSettingsGroup));
    // settings->contains(QLatin1String(kKeyboardSettingsKey) + QLatin1Char('/')
    //                    + QLatin1String(kKeyboardSettingsTransferredKey))
513
    // check if settings in old style (pre 3.1) exist
hjk's avatar
hjk committed
514
    QSettings *settings = Core::ICore::settings();
515
516
    if (settings->contains(QLatin1String(kKeyboardSettingsKey) + QLatin1Char('/')
                           + QLatin1String(kKeyboardSettingsTransferredKey))) {
517
        return;
518
    }
519
520
521
    // move old settings style to new settings style
    QMap<Id, QKeySequence> shortcutMap;
    const int shortcuts = settings->beginReadArray(QLatin1String(oldSettingsGroup));
522
    for (int i = 0; i < shortcuts; ++i) {
con's avatar
con committed
523
        settings->setArrayIndex(i);
524
525
526
        const QKeySequence key(settings->value(QLatin1String(oldSequenceKey)).toString());
        const Id id = Id::fromSetting(settings->value(QLatin1String(oldIdKey)));
        shortcutMap.insert(id, key);
con's avatar
con committed
527
528
    }
    settings->endArray();
529
530
    // write settings in new style
    settings->beginGroup(QLatin1String(kKeyboardSettingsKey));
531
    settings->setValue(QLatin1String(kKeyboardSettingsTransferredKey), true);
532
533
534
535
536
537
    QMapIterator<Id, QKeySequence> it(shortcutMap);
    while (it.hasNext()) {
        it.next();
        settings->setValue(it.key().toString(), it.value().toString());
    }
    settings->endGroup();
con's avatar
con committed
538
539
}

540
void ActionManagerPrivate::saveSettings(QSettings *settings)
con's avatar
con committed
541
{
542
    settings->beginGroup(QLatin1String(kKeyboardSettingsKey));
con's avatar
con committed
543
544
    const IdCmdMap::const_iterator cmdcend = m_idCmdMap.constEnd();
    for (IdCmdMap::const_iterator j = m_idCmdMap.constBegin(); j != cmdcend; ++j) {
545
        const Id id = j.key();
546
        Action *cmd = j.value();
con's avatar
con committed
547
        QKeySequence key = cmd->keySequence();
548
549
550
551
        if (key != cmd->defaultKeySequence())
            settings->setValue(id.toString(), key.toString());
        else
            settings->remove(id.toString());
con's avatar
con committed
552
    }
553
    settings->endGroup();
con's avatar
con committed
554
}