OSDN Git Service

bc0ff900606abfd9f6b4f2edeb0dc92c4f9cc526
[qt-creator-jp/qt-creator-jp.git] / src / plugins / coreplugin / actionmanager / command.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "command_p.h"
35
36 #include "icore.h"
37 #include "icontext.h"
38 #include "uniqueidmanager.h"
39
40 #include <QtCore/QDebug>
41 #include <QtCore/QTextStream>
42
43 #include <QtGui/QAction>
44 #include <QtGui/QShortcut>
45 #include <QtGui/QMainWindow>
46
47 /*!
48     \class Core::Command
49     \mainclass
50
51     \brief The class Command represents an action like a menu item, tool button, or shortcut.
52     You don't create Command objects directly, instead use \l{ActionManager::registerAction()}
53     to register an action and retrieve a Command. The Command object represents the user visible
54     action and its properties. If multiple actions are registered with the same ID (but
55     different contexts) the returned Command is the shared one between these actions.
56
57     A Command has two basic properties: A default shortcut and a default text. The default
58     shortcut is a key sequence that the user can use to trigger the active action that
59     the Command represents. The default text is e.g. used for representing the Command
60     in the keyboard shortcut preference pane. If the default text is empty, the text
61     of the visible action is used.
62
63     The user visible action is updated to represent the state of the active action (if any).
64     For performance reasons only the enabled and visible state are considered by default though.
65     You can tell a Command to also update the actions icon and text by setting the
66     corresponding \l{Command::CommandAttribute}{attribute}.
67
68     If there is no active action, the default behavior of the visible action is to be disabled.
69     You can change that behavior to make the visible action hide instead via the Command's
70     \l{Command::CommandAttribute}{attributes}.
71 */
72
73 /*!
74     \enum Command::CommandAttribute
75     Defines how the user visible action is updated when the active action changes.
76     The default is to update the enabled and visible state, and to disable the
77     user visible action when there is no active action.
78     \omitvalue CA_Mask
79     \value CA_UpdateText
80         Also update the actions text.
81     \value CA_UpdateIcon
82         Also update the actions icon.
83     \value CA_Hide
84         When there is no active action, hide the user "visible" action, instead of just
85         disabling it.
86     \value CA_NonConfigurable
87         Flag to indicate that the keyboard shortcut of this Command should not be
88         configurable by the user.
89 */
90
91 /*!
92     \fn void Command::setDefaultKeySequence(const QKeySequence &key)
93     Set the default keyboard shortcut that can be used to activate this command to \a key.
94     This is used if the user didn't customize the shortcut, or resets the shortcut
95     to the default one.
96 */
97
98 /*!
99     \fn void Command::defaultKeySequence() const
100     Returns the default keyboard shortcut that can be used to activate this command.
101     \sa setDefaultKeySequence()
102 */
103
104 /*!
105     \fn void Command::keySequenceChanged()
106     Sent when the keyboard shortcut assigned to this Command changes, e.g.
107     when the user sets it in the keyboard shortcut settings dialog.
108 */
109
110 /*!
111     \fn QKeySequence Command::keySequence() const
112     Returns the current keyboard shortcut assigned to this Command.
113     \sa defaultKeySequence()
114 */
115
116 /*!
117     \fn void Command::setKeySequence(const QKeySequence &key)
118     \internal
119 */
120
121 /*!
122     \fn void Command::setDefaultText(const QString &text)
123     Set the \a text that is used to represent the Command in the
124     keyboard shortcut settings dialog. If you don't set this,
125     the current text from the user visible action is taken (which
126     is ok in many cases).
127 */
128
129 /*!
130     \fn QString Command::defaultText() const
131     Returns the text that is used to present this Command to the user.
132     \sa setDefaultText()
133 */
134
135 /*!
136     \fn int Command::id() const
137     \internal
138 */
139
140 /*!
141     \fn QString Command::stringWithAppendedShortcut(const QString &string) const
142     Returns the \a string with an appended representation of the keyboard shortcut
143     that is currently assigned to this Command.
144 */
145
146 /*!
147     \fn QAction *Command::action() const
148     Returns the user visible action for this Command.
149     If the Command represents a shortcut, it returns null.
150     Use this action to put it on e.g. tool buttons. The action
151     automatically forwards trigger and toggle signals to the
152     action that is currently active for this Command.
153     It also shows the current keyboard shortcut in its
154     tool tip (in addition to the tool tip of the active action)
155     and gets disabled/hidden when there is
156     no active action for the current context.
157 */
158
159 /*!
160     \fn QShortcut *Command::shortcut() const
161     Returns the shortcut for this Command.
162     If the Command represents an action, it returns null.
163 */
164
165 /*!
166     \fn void Command::setAttribute(CommandAttribute attribute)
167     Add the \a attribute to the attributes of this Command.
168     \sa CommandAttribute
169     \sa removeAttribute()
170     \sa hasAttribute()
171 */
172
173 /*!
174     \fn void Command::removeAttribute(CommandAttribute attribute)
175     Remove the \a attribute from the attributes of this Command.
176     \sa CommandAttribute
177     \sa setAttribute()
178 */
179
180 /*!
181     \fn bool Command::hasAttribute(CommandAttribute attribute) const
182     Returns if the Command has the \a attribute set.
183     \sa CommandAttribute
184     \sa removeAttribute()
185     \sa setAttribute()
186 */
187
188 /*!
189     \fn bool Command::isActive() const
190     Returns if the Command has an active action/shortcut for the current
191     context.
192 */
193
194 /*!
195     \fn bool Command::isScriptable() const
196     Returns if the Command is scriptable. A scriptable command can be called
197     from a script without the need for the user to interact with it.
198 */
199
200 /*!
201     \fn bool Command::isScriptable(const Context &) const
202     Returns if the Command is scriptable for the given context.
203     A scriptable command can be called from a script without the need for the user to
204     interact with it.
205 */
206
207 /*!
208     \fn Command::~Command()
209     \internal
210 */
211
212 using namespace Core::Internal;
213
214 /*!
215     \class CommandPrivate
216     \internal
217 */
218
219 CommandPrivate::CommandPrivate(int id)
220     : m_attributes(0), m_id(id), m_isKeyInitialized(false)
221 {
222 }
223
224 void CommandPrivate::setDefaultKeySequence(const QKeySequence &key)
225 {
226     if (!m_isKeyInitialized)
227         setKeySequence(key);
228     m_defaultKey = key;
229 }
230
231 QKeySequence CommandPrivate::defaultKeySequence() const
232 {
233     return m_defaultKey;
234 }
235
236 void CommandPrivate::setKeySequence(const QKeySequence &key)
237 {
238     Q_UNUSED(key)
239     m_isKeyInitialized = true;
240 }
241
242 void CommandPrivate::setDefaultText(const QString &text)
243 {
244     m_defaultText = text;
245 }
246
247 QString CommandPrivate::defaultText() const
248 {
249     return m_defaultText;
250 }
251
252 int CommandPrivate::id() const
253 {
254     return m_id;
255 }
256
257 QAction *CommandPrivate::action() const
258 {
259     return 0;
260 }
261
262 QShortcut *CommandPrivate::shortcut() const
263 {
264     return 0;
265 }
266
267 Core::Context CommandPrivate::context() const
268 {
269     return m_context;
270 }
271
272 void CommandPrivate::setAttribute(CommandAttribute attr)
273 {
274     m_attributes |= attr;
275 }
276
277 void CommandPrivate::removeAttribute(CommandAttribute attr)
278 {
279     m_attributes &= ~attr;
280 }
281
282 bool CommandPrivate::hasAttribute(CommandAttribute attr) const
283 {
284     return (m_attributes & attr);
285 }
286
287 QString CommandPrivate::stringWithAppendedShortcut(const QString &str) const
288 {
289     return Utils::ProxyAction::stringWithAppendedShortcut(str, keySequence());
290 }
291
292 // ---------- Shortcut ------------
293
294 /*!
295     \class Shortcut
296     \internal
297 */
298
299 Shortcut::Shortcut(int id)
300     : CommandPrivate(id), m_shortcut(0), m_scriptable(false)
301 {
302
303 }
304
305 void Shortcut::setShortcut(QShortcut *shortcut)
306 {
307     m_shortcut = shortcut;
308 }
309
310 QShortcut *Shortcut::shortcut() const
311 {
312     return m_shortcut;
313 }
314
315 void Shortcut::setContext(const Core::Context &context)
316 {
317     m_context = context;
318 }
319
320 Core::Context Shortcut::context() const
321 {
322     return m_context;
323 }
324
325 void Shortcut::setKeySequence(const QKeySequence &key)
326 {
327     CommandPrivate::setKeySequence(key);
328     m_shortcut->setKey(key);
329     emit keySequenceChanged();
330 }
331
332 QKeySequence Shortcut::keySequence() const
333 {
334     return m_shortcut->key();
335 }
336
337 void Shortcut::setDefaultText(const QString &text)
338 {
339     m_defaultText = text;
340 }
341
342 QString Shortcut::defaultText() const
343 {
344     return m_defaultText;
345 }
346
347 void Shortcut::setCurrentContext(const Core::Context &context)
348 {
349     foreach (int ctxt, m_context) {
350         if (context.contains(ctxt)) {
351             if (!m_shortcut->isEnabled()) {
352                 m_shortcut->setEnabled(true);
353                 emit activeStateChanged();
354             }
355             return;
356         }
357     }
358     if (m_shortcut->isEnabled()) {
359         m_shortcut->setEnabled(false);
360         emit activeStateChanged();
361     }
362     return;
363 }
364
365 bool Shortcut::isActive() const
366 {
367     return m_shortcut->isEnabled();
368 }
369
370 bool Shortcut::isScriptable() const
371 {
372     return m_scriptable;
373 }
374
375 bool Shortcut::isScriptable(const Core::Context &) const
376 {
377     return m_scriptable;
378 }
379
380 void Shortcut::setScriptable(bool value)
381 {
382     m_scriptable = value;
383 }
384
385 // ---------- Action ------------
386
387 /*!
388   \class Action
389   \internal
390 */
391 Action::Action(int id)
392     : CommandPrivate(id),
393     m_action(new Utils::ProxyAction(this)),
394     m_active(false),
395     m_contextInitialized(false)
396 {
397     m_action->setShortcutVisibleInToolTip(true);
398     connect(m_action, SIGNAL(changed()), this, SLOT(updateActiveState()));
399 }
400
401 QAction *Action::action() const
402 {
403     return m_action;
404 }
405
406 void Action::setKeySequence(const QKeySequence &key)
407 {
408     CommandPrivate::setKeySequence(key);
409     m_action->setShortcut(key);
410     emit keySequenceChanged();
411 }
412
413 QKeySequence Action::keySequence() const
414 {
415     return m_action->shortcut();
416 }
417
418 void Action::setCurrentContext(const Core::Context &context)
419 {
420     m_context = context;
421
422     QAction *currentAction = 0;
423     for (int i = 0; i < m_context.size(); ++i) {
424         if (QAction *a = m_contextActionMap.value(m_context.at(i), 0)) {
425             currentAction = a;
426             break;
427         }
428     }
429
430     m_action->setAction(currentAction);
431     updateActiveState();
432 }
433
434 void Action::updateActiveState()
435 {
436     setActive(m_action->isEnabled() && m_action->isVisible() && !m_action->isSeparator());
437 }
438
439 static inline QString msgActionWarning(QAction *newAction, int k, QAction *oldAction)
440 {
441     QString msg;
442     QTextStream str(&msg);
443     str << "addOverrideAction " << newAction->objectName() << '/' << newAction->text()
444          << ": Action ";
445     if (oldAction)
446         str << oldAction->objectName() << '/' << oldAction->text();
447     str << " is already registered for context " << k << ' '
448         << Core::ICore::instance()->uniqueIDManager()->stringForUniqueIdentifier(k)
449         << '.';
450     return msg;
451 }
452
453 void Action::addOverrideAction(QAction *action, const Core::Context &context, bool scriptable)
454 {
455 #ifdef Q_WS_MAC
456     action->setIconVisibleInMenu(false);
457 #endif
458     if (isEmpty())
459         m_action->initialize(action);
460     if (context.isEmpty()) {
461         m_contextActionMap.insert(0, action);
462     } else {
463         for (int i = 0; i < context.size(); ++i) {
464             int k = context.at(i);
465             if (m_contextActionMap.contains(k))
466                 qWarning("%s", qPrintable(msgActionWarning(action, k, m_contextActionMap.value(k, 0))));
467             m_contextActionMap.insert(k, action);
468         }
469     }
470     m_scriptableMap[action] = scriptable;
471     setCurrentContext(m_context);
472 }
473
474 void Action::removeOverrideAction(QAction *action)
475 {
476     QMutableMapIterator<int, QPointer<QAction> > it(m_contextActionMap);
477     while (it.hasNext()) {
478         it.next();
479         if (it.value() == 0) {
480             it.remove();
481         } else if (it.value() == action) {
482             it.remove();
483         }
484     }
485     setCurrentContext(m_context);
486 }
487
488 bool Action::isActive() const
489 {
490     return m_active;
491 }
492
493 void Action::setActive(bool state)
494 {
495     if (state != m_active) {
496         m_active = state;
497         emit activeStateChanged();
498     }
499 }
500
501 bool Action::isEmpty() const
502 {
503     return m_contextActionMap.isEmpty();
504 }
505
506 bool Action::isScriptable() const
507 {
508     return m_scriptableMap.values().contains(true);
509 }
510
511 bool Action::isScriptable(const Core::Context &context) const
512 {
513     if (context == m_context && m_scriptableMap.contains(m_action->action()))
514         return m_scriptableMap.value(m_action->action());
515
516     for (int i = 0; i < context.size(); ++i) {
517         if (QAction *a = m_contextActionMap.value(context.at(i), 0)) {
518             if (m_scriptableMap.contains(a) && m_scriptableMap.value(a))
519                 return true;
520         }
521     }
522     return false;
523 }
524
525 void Action::setAttribute(CommandAttribute attr)
526 {
527     CommandPrivate::setAttribute(attr);
528     switch (attr) {
529     case Core::Command::CA_Hide:
530         m_action->setAttribute(Utils::ProxyAction::Hide);
531         break;
532     case Core::Command::CA_UpdateText:
533         m_action->setAttribute(Utils::ProxyAction::UpdateText);
534         break;
535     case Core::Command::CA_UpdateIcon:
536         m_action->setAttribute(Utils::ProxyAction::UpdateIcon);
537         break;
538     case Core::Command::CA_NonConfigurable:
539         break;
540     }
541 }
542
543 void Action::removeAttribute(CommandAttribute attr)
544 {
545     CommandPrivate::removeAttribute(attr);
546     switch (attr) {
547     case Core::Command::CA_Hide:
548         m_action->removeAttribute(Utils::ProxyAction::Hide);
549         break;
550     case Core::Command::CA_UpdateText:
551         m_action->removeAttribute(Utils::ProxyAction::UpdateText);
552         break;
553     case Core::Command::CA_UpdateIcon:
554         m_action->removeAttribute(Utils::ProxyAction::UpdateIcon);
555         break;
556     case Core::Command::CA_NonConfigurable:
557         break;
558     }
559 }