actionmanager.cpp 20.7 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

Eike Ziller's avatar
Eike Ziller committed
33
#include "actionmanager.h"
34
#include "actionmanager_p.h"
con's avatar
con committed
35
#include "mainwindow.h"
36
#include "actioncontainer_p.h"
con's avatar
con committed
37
#include "command_p.h"
38
#include "id.h"
con's avatar
con committed
39 40

#include <coreplugin/coreconstants.h>
41
#include <coreplugin/icore.h>
42
#include <utils/qtcassert.h>
con's avatar
con committed
43

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

namespace {
    enum { warnAboutFindFailures = 0 };
}

Eike Ziller's avatar
Eike Ziller committed
57 58 59
using namespace Core;
using namespace Core::Internal;

con's avatar
con committed
60
/*!
61
    \class Core::ActionManager
con's avatar
con committed
62 63
    \mainclass

64 65
    \brief The action manager is responsible for registration of menus and
    menu items and keyboard shortcuts.
con's avatar
con committed
66

67
    The ActionManager is the central bookkeeper of actions and their shortcuts and layout.
Eike Ziller's avatar
Eike Ziller committed
68 69
    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
70 71 72 73 74

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

75 76
    \section1 Contexts

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

98 99 100
    \section1 Registering Actions

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

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

131
    \section1 Important Guidelines:
con's avatar
con committed
132 133
    \list
    \o Always register your actions and shortcuts!
134 135
    \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
136
       in the keyboard settings dialog from the beginning.
137 138 139
    \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
140 141 142
    \o Use this class to add actions to the applications menus
    \endlist

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

Eike Ziller's avatar
Eike Ziller committed
149 150
static ActionManager *m_instance = 0;

con's avatar
con committed
151
/*!
Eike Ziller's avatar
Eike Ziller committed
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    \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
179

180
    Returns a new ActionContainer that you can use to get the QMenu instance
181
    or to add menu items to the menu. The ActionManager owns
182
    the returned ActionContainer.
183
    Add your menu to some other menu or a menu bar via the
184
    ActionManager::actionContainer and ActionContainer::addMenu methods.
con's avatar
con committed
185
*/
Eike Ziller's avatar
Eike Ziller committed
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
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
203 204

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

207
    Returns a new ActionContainer that you can use to get the QMenuBar instance
208
    or to add menus to the menu bar. The ActionManager owns
209
    the returned ActionContainer.
con's avatar
con committed
210
*/
Eike Ziller's avatar
Eike Ziller committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
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
228 229

/*!
Eike Ziller's avatar
Eike Ziller committed
230
    \brief Makes an \a action known to the system under the specified \a id.
231 232

    Returns a command object that represents the action in the application and is
233
    owned by the ActionManager. You can register several actions with the
234 235 236
    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.
237 238
    A scriptable action can be called from a script without the need for the user
    to interact with it.
con's avatar
con committed
239
*/
Eike Ziller's avatar
Eike Ziller committed
240 241 242 243 244 245 246 247 248 249
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
250 251

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

    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.
259 260
    A scriptable shortcut can be called from a script without the need for the user
    to interact with it.
con's avatar
con committed
261
*/
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 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
Command *ActionManager::registerShortcut(QShortcut *shortcut, const Id &id, const Context &context, bool scriptable)
{
    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);

    if (context.isEmpty())
        sc->setContext(Context(0));
    else
        sc->setContext(context);

    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
301 302

/*!
con's avatar
con committed
303
    \brief Returns the Command object that is known to the system
Eike Ziller's avatar
Eike Ziller committed
304
    under the given \a id.
305 306

    \sa ActionManager::registerAction()
con's avatar
con committed
307
*/
Eike Ziller's avatar
Eike Ziller committed
308 309 310 311 312 313 314 315 316 317 318
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
319 320

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

324 325 326
    \sa ActionManager::createMenu()
    \sa ActionManager::createMenuBar()
*/
Eike Ziller's avatar
Eike Ziller committed
327 328 329 330 331 332 333 334 335 336 337
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();
}
338 339

/*!
Eike Ziller's avatar
Eike Ziller committed
340 341 342 343 344 345 346 347 348 349 350 351 352
 * \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.
353 354 355 356 357 358

    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
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
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();
}
381

con's avatar
con committed
382
/*!
Eike Ziller's avatar
Eike Ziller committed
383 384 385 386 387 388
    \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
389
*/
Eike Ziller's avatar
Eike Ziller committed
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
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
406 407


Eike Ziller's avatar
Eike Ziller committed
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 445 446 447 448 449 450 451 452 453 454
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;
}

bool ActionManager::hasContext(int context)
{
    return m_instance->d->m_context.contains(context);
}
con's avatar
con committed
455 456

/*!
457 458 459
    \class ActionManagerPrivate
    \inheaderfile actionmanager_p.h
    \internal
con's avatar
con committed
460 461
*/

Eike Ziller's avatar
Eike Ziller committed
462 463
ActionManagerPrivate::ActionManagerPrivate()
  : m_presentationLabel(0)
con's avatar
con committed
464
{
Tobias Hunger's avatar
Tobias Hunger committed
465
    m_presentationLabelTimer.setInterval(1000);
con's avatar
con committed
466 467
}

468
ActionManagerPrivate::~ActionManagerPrivate()
con's avatar
con committed
469
{
470
    // first delete containers to avoid them reacting to command deletion
471 472
    foreach (ActionContainerPrivate *container, m_idContainerMap)
        disconnect(container, SIGNAL(destroyed()), this, SLOT(containerDestroyed()));
con's avatar
con committed
473
    qDeleteAll(m_idContainerMap.values());
474
    qDeleteAll(m_idCmdMap.values());
con's avatar
con committed
475 476
}

477 478 479 480
QDebug operator<<(QDebug in, const Context &context)
{
    in << "CONTEXT: ";
    foreach (int c, context)
481
        in << "   " << c << Id::fromUniqueIdentifier(c).toString();
482 483 484
    return in;
}

485
void ActionManagerPrivate::setContext(const Context &context)
con's avatar
con committed
486 487 488 489 490 491 492 493 494 495
{
    // 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);
}

496
bool ActionManagerPrivate::hasContext(const Context &context) const
con's avatar
con committed
497
{
hjk's avatar
hjk committed
498 499
    for (int i = 0; i < m_context.size(); ++i) {
        if (context.contains(m_context.at(i)))
con's avatar
con committed
500 501 502 503 504
            return true;
    }
    return false;
}

505 506 507 508 509 510
void ActionManagerPrivate::containerDestroyed()
{
    ActionContainerPrivate *container = static_cast<ActionContainerPrivate *>(sender());
    m_idContainerMap.remove(m_idContainerMap.key(container));
}

Tobias Hunger's avatar
Tobias Hunger committed
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
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
527
    if (shortcut.isEmpty() || !ActionManager::isPresentationModeEnabled())
Tobias Hunger's avatar
Tobias Hunger committed
528 529 530 531 532
        return;

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

Eike Ziller's avatar
Eike Ziller committed
533
    QPoint p = ICore::mainWindow()->mapToGlobal(ICore::mainWindow()->rect().center() - m_presentationLabel->rect().center());
Tobias Hunger's avatar
Tobias Hunger committed
534 535 536 537 538 539 540
    m_presentationLabel->move(p);

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

541
Action *ActionManagerPrivate::overridableAction(const Id &id)
con's avatar
con committed
542
{
543
    Action *a = 0;
544
    if (CommandPrivate *c = m_idCmdMap.value(id, 0)) {
545
        a = qobject_cast<Action *>(c);
con's avatar
con committed
546
        if (!a) {
547 548
            qWarning() << "registerAction: id" << id.name()
                       << "is registered with a different command type.";
549
            return 0;
con's avatar
con committed
550
        }
con's avatar
con committed
551
    } else {
552 553
        a = new Action(id);
        m_idCmdMap.insert(id, a);
Eike Ziller's avatar
Eike Ziller committed
554
        ICore::mainWindow()->addAction(a->action());
555
        a->action()->setObjectName(id.toString());
556
        a->action()->setShortcutContext(Qt::ApplicationShortcut);
557
        a->setCurrentContext(m_context);
Tobias Hunger's avatar
Tobias Hunger committed
558

Eike Ziller's avatar
Eike Ziller committed
559
        if (ActionManager::isPresentationModeEnabled())
Tobias Hunger's avatar
Tobias Hunger committed
560
            connect(a->action(), SIGNAL(triggered()), this, SLOT(actionTriggered()));
con's avatar
con committed
561 562 563 564 565
    }

    return a;
}

Friedemann Kleint's avatar
Friedemann Kleint committed
566 567 568
static const char settingsGroup[] = "KeyBindings";
static const char idKey[] = "ID";
static const char sequenceKey[] = "Keysequence";
con's avatar
con committed
569

570
void ActionManagerPrivate::initialize()
con's avatar
con committed
571
{
hjk's avatar
hjk committed
572
    QSettings *settings = Core::ICore::settings();
con's avatar
con committed
573
    const int shortcuts = settings->beginReadArray(QLatin1String(settingsGroup));
574
    for (int i = 0; i < shortcuts; ++i) {
con's avatar
con committed
575 576
        settings->setArrayIndex(i);
        const QKeySequence key(settings->value(QLatin1String(sequenceKey)).toString());
577
        const Id id = Id(settings->value(QLatin1String(idKey)).toString());
con's avatar
con committed
578

Eike Ziller's avatar
Eike Ziller committed
579
        Command *cmd = ActionManager::command(id);
con's avatar
con committed
580 581 582 583 584 585
        if (cmd)
            cmd->setKeySequence(key);
    }
    settings->endArray();
}

586
void ActionManagerPrivate::saveSettings(QSettings *settings)
con's avatar
con committed
587 588 589 590 591 592
{
    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) {
593
        const Id id = j.key();
con's avatar
con committed
594
        CommandPrivate *cmd = j.value();
con's avatar
con committed
595 596 597
        QKeySequence key = cmd->keySequence();
        if (key != cmd->defaultKeySequence()) {
            settings->setArrayIndex(count);
598
            settings->setValue(QLatin1String(idKey), id.toString());
con's avatar
con committed
599 600 601 602 603 604 605
            settings->setValue(QLatin1String(sequenceKey), key.toString());
            count++;
        }
    }

    settings->endArray();
}