source: trunk/src/qt3support/widgets/q3action.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 64.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the Qt3Support module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "q3action.h"
43
44#ifndef QT_NO_ACTION
45
46#include "qevent.h"
47#include "q3toolbar.h"
48#include "qlist.h"
49#include "q3popupmenu.h"
50#include "q3accel.h"
51#include "qtoolbutton.h"
52#include "qcombobox.h"
53#include "qtooltip.h"
54#include "qwhatsthis.h"
55#include "qstatusbar.h"
56#include "qaction.h"
57
58QT_BEGIN_NAMESPACE
59
60/*!
61 \class Q3Action
62 \brief The Q3Action class provides an abstract user interface
63 action that can appear both in menus and tool bars.
64
65 \compat
66
67 In GUI applications many commands can be invoked via a menu
68 option, a toolbar button and a keyboard accelerator. Since the
69 same action must be performed regardless of how the action was
70 invoked, and since the menu and toolbar should be kept in sync, it
71 is useful to represent a command as an \e action. An action can be
72 added to a menu and a toolbar and will automatically keep them in
73 sync. For example, if the user presses a Bold toolbar button the
74 Bold menu item will automatically be checked.
75
76 A Q3Action may contain an icon, a menu text, an accelerator, a
77 status text, a "What's This?" text and a tool tip. Most of these can
78 be set in the constructor. They can also be set independently with
79 setIconSet(), setText(), setMenuText(), setToolTip(),
80 setStatusTip(), setWhatsThis() and setAccel().
81
82 An action may be a toggle action e.g. a Bold toolbar button, or a
83 command action, e.g. 'Open File' to invoke an open file dialog.
84 Toggle actions emit the toggled() signal when their state changes.
85 Both command and toggle actions emit the activated() signal when
86 they are invoked. Use setToggleAction() to set an action's toggled
87 status. To see if an action is a toggle action use
88 isToggleAction(). A toggle action may be "on", isOn() returns
89 true, or "off", isOn() returns false.
90
91 Actions are added to widgets (menus or toolbars) using addTo(),
92 and removed using removeFrom(). Note that when using Q3ToolBar and
93 Q3PopupMenu, their actions must be Q3Actions.
94
95 Once a Q3Action has been created it should be added to the relevant
96 menu and toolbar and then connected to the slot which will perform
97 the action.
98
99 We recommend that actions are created as children of the window
100 that they are used in. In most cases actions will be children of
101 the application's main window.
102
103 To prevent recursion, don't create an action as a child of a
104 widget that the action is later added to.
105*/
106
107class Q3ActionPrivate
108{
109public:
110 Q3ActionPrivate(Q3Action *act);
111 ~Q3ActionPrivate();
112 QIcon *icon;
113 QString text;
114 QString menutext;
115 QString tooltip;
116 QString statustip;
117 QString whatsthis;
118#ifndef QT_NO_ACCEL
119 QKeySequence key;
120 Q3Accel* accel;
121 int accelid;
122#endif
123 uint enabled : 1;
124 uint visible : 1;
125 uint toggleaction : 1;
126 uint on : 1;
127 uint forceDisabled : 1;
128 uint forceInvisible : 1;
129 Q3ActionGroupPrivate* d_group;
130 Q3Action *action;
131
132 struct MenuItem {
133 MenuItem():popup(0),id(0){}
134 Q3PopupMenu* popup;
135 int id;
136 };
137 // ComboItem is only necessary for actions that are
138 // in dropdown/exclusive actiongroups. The actiongroup
139 // will clean this up
140 struct ComboItem {
141 ComboItem():combo(0), id(0) {}
142 QComboBox *combo;
143 int id;
144 };
145 //just bindings to the Qt4.0 widgets
146 struct Action4Item {
147 Action4Item():widget(0){}
148 QWidget* widget;
149 static QAction *action;
150 };
151 QList<Action4Item *> action4items;
152 QList<MenuItem *> menuitems;
153 QList<QToolButton *> toolbuttons;
154 QList<ComboItem *> comboitems;
155
156 enum Update { Icons = 1, Visibility = 2, State = 4, EverythingElse = 8 };
157 void update(uint upd = EverythingElse);
158
159 QString menuText() const;
160 QString toolTip() const;
161 QString statusTip() const;
162};
163QAction *Q3ActionPrivate::Action4Item::action = 0;
164
165Q3ActionPrivate::Q3ActionPrivate(Q3Action *act)
166 : icon(0),
167#ifndef QT_NO_ACCEL
168 key(0), accel(0), accelid(0),
169#endif
170 enabled(true), visible(true), toggleaction(false), on(false),
171 forceDisabled(false), forceInvisible(false)
172 , d_group(0), action(act)
173{
174}
175
176Q3ActionPrivate::~Q3ActionPrivate()
177{
178 QList<QToolButton*>::Iterator ittb(toolbuttons.begin());
179 QToolButton *tb;
180
181 while (ittb != toolbuttons.end()) {
182 tb = *ittb;
183 ++ittb;
184 delete tb;
185 }
186
187 QList<Q3ActionPrivate::MenuItem*>::Iterator itmi(menuitems.begin());
188 Q3ActionPrivate::MenuItem* mi;
189 while (itmi != menuitems.end()) {
190 mi = *itmi;
191 ++itmi;
192 Q3PopupMenu* menu = mi->popup;
193 if (menu->findItem(mi->id))
194 menu->removeItem(mi->id);
195 }
196 qDeleteAll(menuitems);
197
198 QList<Q3ActionPrivate::Action4Item*>::Iterator itmi4(action4items.begin());
199 Q3ActionPrivate::Action4Item* mi4;
200 while (itmi4 != action4items.end()) {
201 mi4 = *itmi4;
202 ++itmi4;
203 mi4->widget->removeAction(mi4->action);
204 }
205 delete Q3ActionPrivate::Action4Item::action;
206 Q3ActionPrivate::Action4Item::action = 0;
207 qDeleteAll(action4items);
208
209 QList<Q3ActionPrivate::ComboItem*>::Iterator itci(comboitems.begin());
210 Q3ActionPrivate::ComboItem* ci;
211 while (itci != comboitems.end()) {
212 ci = *itci;
213 ++itci;
214 QComboBox* combo = ci->combo;
215 combo->clear();
216 Q3ActionGroup *group = qobject_cast<Q3ActionGroup*>(action->parent());
217 if (group) {
218 QObjectList siblings = group->queryList("Q3Action");
219
220 for (int i = 0; i < siblings.size(); ++i) {
221 Q3Action *sib = qobject_cast<Q3Action*>(siblings.at(i));
222 sib->removeFrom(combo);
223 }
224 for (int i = 0; i < siblings.size(); ++i) {
225 Q3Action *sib = qobject_cast<Q3Action*>(siblings.at(i));
226 if (sib == action)
227 continue;
228 sib->addTo(combo);
229 }
230 }
231 }
232 qDeleteAll(comboitems);
233
234#ifndef QT_NO_ACCEL
235 delete accel;
236#endif
237 delete icon;
238}
239
240class Q3ActionGroupPrivate
241{
242public:
243 uint exclusive: 1;
244 uint dropdown: 1;
245 QList<Q3Action*> actions;
246 Q3Action* selected;
247 Q3Action* separatorAction;
248
249 struct MenuItem {
250 MenuItem():popup(0),id(0){}
251 Q3PopupMenu* popup;
252 int id;
253 };
254 struct Action4Item {
255 Action4Item():widget(0){}
256 QWidget* widget;
257 static QAction *action;
258 };
259 QList<Action4Item *> action4items;
260 QList<QComboBox*> comboboxes;
261 QList<QToolButton*> menubuttons;
262 QList<MenuItem*> menuitems;
263 QList<Q3PopupMenu*> popupmenus;
264
265 void update(const Q3ActionGroup *);
266};
267QAction *Q3ActionGroupPrivate::Action4Item::action = 0;
268
269void Q3ActionPrivate::update(uint upd)
270{
271 for (QList<MenuItem*>::Iterator it(menuitems.begin()); it != menuitems.end(); ++it) {
272 MenuItem* mi = *it;
273 QString t = menuText();
274#ifndef QT_NO_ACCEL
275 if (key)
276 t += QLatin1Char('\t') + (QString)QKeySequence(key);
277#endif
278 if (upd & State) {
279 mi->popup->setItemEnabled(mi->id, enabled);
280 if (toggleaction)
281 mi->popup->setItemChecked(mi->id, on);
282 }
283 if (upd & Visibility)
284 mi->popup->setItemVisible(mi->id, visible);
285
286 if (upd & Icons) {
287 if (icon)
288 mi->popup->changeItem(mi->id, *icon, t);
289 else
290 mi->popup->changeItem(mi->id, QIcon(), t);
291 }
292 if (upd & EverythingElse) {
293 mi->popup->changeItem(mi->id, t);
294 if (!whatsthis.isEmpty())
295 mi->popup->setWhatsThis(mi->id, whatsthis);
296 if (toggleaction) {
297 mi->popup->setCheckable(true);
298 mi->popup->setItemChecked(mi->id, on);
299 }
300 }
301 }
302 if(QAction *act = Action4Item::action) {
303 if (upd & Visibility)
304 act->setVisible(visible);
305 if (upd & Icons) {
306 if (icon)
307 act->setIcon(*icon);
308 else
309 act->setIcon(QIcon());
310 }
311 if (upd & EverythingElse) {
312 QString text = action->menuText();
313#ifndef QT_NO_ACCEL
314 if (key)
315 text += QLatin1Char('\t') + (QString)QKeySequence(key);
316#endif
317 act->setText(text);
318 act->setToolTip(statusTip());
319 act->setWhatsThis(whatsthis);
320 }
321 }
322 for (QList<QToolButton*>::Iterator it2(toolbuttons.begin()); it2 != toolbuttons.end(); ++it2) {
323 QToolButton* btn = *it2;
324 if (upd & State) {
325 btn->setEnabled(enabled);
326 if (toggleaction)
327 btn->setOn(on);
328 }
329 if (upd & Visibility)
330 visible ? btn->show() : btn->hide();
331 if (upd & Icons) {
332 if (icon)
333 btn->setIconSet(*icon);
334 else
335 btn->setIconSet(QIcon());
336 }
337 if (upd & EverythingElse) {
338 btn->setToggleButton(toggleaction);
339 if (!text.isEmpty())
340 btn->setTextLabel(text, false);
341#ifndef QT_NO_TOOLTIP
342 btn->setToolTip(toolTip());
343#endif
344#ifndef QT_NO_STATUSTIP
345 btn->setStatusTip(statusTip());
346#endif
347#ifndef QT_NO_WHATSTHIS
348 QWhatsThis::remove(btn);
349 if (!whatsthis.isEmpty())
350 QWhatsThis::add(btn, whatsthis);
351#endif
352 }
353 }
354#ifndef QT_NO_ACCEL
355 if (accel) {
356 accel->setEnabled(enabled && visible);
357 if (!whatsthis.isEmpty())
358 accel->setWhatsThis(accelid, whatsthis);
359 }
360#endif
361 // Only used by actiongroup
362 for (QList<ComboItem*>::Iterator it3(comboitems.begin()); it3 != comboitems.end(); ++it3) {
363 ComboItem *ci = *it3;
364 if (!ci->combo)
365 return;
366 if (ci->id == -1) {
367 ci->id = ci->combo->count();
368 if (icon)
369 ci->combo->insertItem(icon->pixmap(), text);
370 else
371 ci->combo->insertItem(text);
372 } else {
373 if (icon)
374 ci->combo->changeItem(icon->pixmap(), text, ci->id);
375 else
376 ci->combo->changeItem(text, ci->id);
377 }
378 }
379}
380
381QString Q3ActionPrivate::menuText() const
382{
383 if (menutext.isNull()) {
384 QString t(text);
385 t.replace(QLatin1Char('&'), QLatin1String("&&"));
386 return t;
387 }
388 return menutext;
389}
390
391QString Q3ActionPrivate::toolTip() const
392{
393 if (tooltip.isNull()) {
394#ifndef QT_NO_ACCEL
395 if (accel)
396 return text + QLatin1String(" (") + (QString)QKeySequence(accel->key(accelid)) + QLatin1Char(')');
397#endif
398 return text;
399 }
400 return tooltip;
401}
402
403QString Q3ActionPrivate::statusTip() const
404{
405 if (statustip.isNull())
406 return toolTip();
407 return statustip;
408}
409
410/*
411 internal: guesses a descriptive text from a menu text
412 */
413static QString qt_stripMenuText(QString s)
414{
415 s.remove(QLatin1String("..."));
416 s.remove(QLatin1Char('&'));
417 return s.trimmed();
418};
419
420/*!
421 Constructs an action called \a name with parent \a parent.
422
423 If \a parent is a Q3ActionGroup, the new action inserts itself into
424 \a parent.
425
426 For accelerators and status tips to work, \a parent must either be
427 a widget, or an action group whose parent is a widget.
428
429 \warning To prevent recursion, don't create an action as a child
430 of a widget that the action is later added to.
431*/
432Q3Action::Q3Action(QObject* parent, const char* name)
433 : QObject(parent, name)
434{
435 d = new Q3ActionPrivate(this);
436 init();
437}
438
439/*!
440 Constructs an action called \a name with parent \a parent.
441
442 If \a toggle is true the action will be a toggle action, otherwise
443 it will be a command action.
444
445 If \a parent is a Q3ActionGroup, the new action inserts itself into
446 \a parent.
447
448 For accelerators and status tips to work, \a parent must either be
449 a widget, or an action group whose parent is a widget.
450*/
451Q3Action::Q3Action(QObject* parent, const char* name, bool toggle)
452 : QObject(parent, name)
453{
454 d = new Q3ActionPrivate(this);
455 d->toggleaction = toggle;
456 init();
457}
458
459
460#ifndef QT_NO_ACCEL
461
462/*!
463 This constructor creates an action with the following properties:
464 the icon or icon \a icon, the menu text \a menuText and
465 keyboard accelerator \a accel. It is a child of \a parent and
466 called \a name.
467
468 If \a parent is a Q3ActionGroup, the action automatically becomes
469 a member of it.
470
471 For accelerators and status tips to work, \a parent must either be
472 a widget, or an action group whose parent is a widget.
473
474 The action uses a stripped version of \a menuText (e.g. "\&Menu
475 Option..." becomes "Menu Option") as descriptive text for
476 tool buttons. You can override this by setting a specific
477 description with setText(). The same text and \a accel will be
478 used for tool tips and status tips unless you provide text for
479 these using setToolTip() and setStatusTip().
480
481 Call setToggleAction(true) to make the action a toggle action.
482
483 \warning To prevent recursion, don't create an action as a child
484 of a widget that the action is later added to.
485*/
486Q3Action::Q3Action(const QIcon& icon, const QString& menuText, QKeySequence accel,
487 QObject* parent, const char* name)
488 : QObject(parent, name)
489{
490 d = new Q3ActionPrivate(this);
491 if (!icon.isNull())
492 setIconSet(icon);
493 d->text = qt_stripMenuText(menuText);
494 d->menutext = menuText;
495 setAccel(accel);
496 init();
497}
498
499/*!
500 This constructor results in an icon-less action with the the menu
501 text \a menuText and keyboard accelerator \a accel. It is a child
502 of \a parent and called \a name.
503
504 If \a parent is a Q3ActionGroup, the action automatically becomes
505 a member of it.
506
507 For accelerators and status tips to work, \a parent must either be
508 a widget, or an action group whose parent is a widget.
509
510 The action uses a stripped version of \a menuText (e.g. "\&Menu
511 Option..." becomes "Menu Option") as descriptive text for
512 tool buttons. You can override this by setting a specific
513 description with setText(). The same text and \a accel will be
514 used for tool tips and status tips unless you provide text for
515 these using setToolTip() and setStatusTip().
516
517 Call setToggleAction(true) to make the action a toggle action.
518
519 \warning To prevent recursion, don't create an action as a child
520 of a widget that the action is later added to.
521*/
522Q3Action::Q3Action(const QString& menuText, QKeySequence accel,
523 QObject* parent, const char* name)
524 : QObject(parent, name)
525{
526 d = new Q3ActionPrivate(this);
527 d->text = qt_stripMenuText(menuText);
528 d->menutext = menuText;
529 setAccel(accel);
530 init();
531}
532
533/*!
534 This constructor creates an action with the following properties:
535 the description \a text, the icon or icon \a icon, the menu
536 text \a menuText and keyboard accelerator \a accel. It is a child
537 of \a parent and called \a name. If \a toggle is true the action
538 will be a toggle action, otherwise it will be a command action.
539
540 If \a parent is a Q3ActionGroup, the action automatically becomes
541 a member of it.
542
543 For accelerators and status tips to work, \a parent must either be
544 a widget, or an action group whose parent is a widget.
545
546 The \a text and \a accel will be used for tool tips and status
547 tips unless you provide specific text for these using setToolTip()
548 and setStatusTip().
549*/
550Q3Action::Q3Action(const QString& text, const QIcon& icon, const QString& menuText, QKeySequence accel, QObject* parent, const char* name, bool toggle)
551 : QObject(parent, name)
552{
553 d = new Q3ActionPrivate(this);
554 d->toggleaction = toggle;
555 if (!icon.isNull())
556 setIconSet(icon);
557
558 d->text = text;
559 d->menutext = menuText;
560 setAccel(accel);
561 init();
562}
563
564/*!
565 This constructor results in an icon-less action with the
566 description \a text, the menu text \a menuText and the keyboard
567 accelerator \a accel. Its parent is \a parent and it is called \a
568 name. If \a toggle is true the action will be a toggle action,
569 otherwise it will be a command action.
570
571 The action automatically becomes a member of \a parent if \a
572 parent is a Q3ActionGroup.
573
574 For accelerators and status tips to work, \a parent must either be
575 a widget, or an action group whose parent is a widget.
576
577 The \a text and \a accel will be used for tool tips and status
578 tips unless you provide specific text for these using setToolTip()
579 and setStatusTip().
580*/
581Q3Action::Q3Action(const QString& text, const QString& menuText, QKeySequence accel, QObject* parent, const char* name, bool toggle)
582 : QObject(parent, name)
583{
584 d = new Q3ActionPrivate(this);
585 d->toggleaction = toggle;
586 d->text = text;
587 d->menutext = menuText;
588 setAccel(accel);
589 init();
590}
591#endif
592
593/*!
594 \internal
595*/
596void Q3Action::init()
597{
598 if (qobject_cast<Q3ActionGroup*>(parent()))
599 ((Q3ActionGroup*) parent())->add(this); // insert into action group
600}
601
602/*!
603 Destroys the object and frees allocated resources.
604*/
605
606Q3Action::~Q3Action()
607{
608 delete d;
609}
610
611/*!
612 \property Q3Action::iconSet
613 \brief the action's icon
614
615 The icon is used as the tool button icon and in the menu to the
616 left of the menu text. There is no default icon.
617
618 If a null icon (QIcon::isNull() is passed into this function,
619 the icon of the action is cleared.
620
621 (See the action/toggleaction/toggleaction.cpp example.)
622
623*/
624void Q3Action::setIconSet(const QIcon& icon)
625{
626 register QIcon *i = d->icon;
627 if (!icon.isNull())
628 d->icon = new QIcon(icon);
629 else
630 d->icon = 0;
631 delete i;
632 d->update(Q3ActionPrivate::Icons);
633}
634
635QIcon Q3Action::iconSet() const
636{
637 if (d->icon)
638 return *d->icon;
639 return QIcon();
640}
641
642/*!
643 \property Q3Action::text
644 \brief the action's descriptive text
645
646 \sa setMenuText() setToolTip() setStatusTip()
647*/
648void Q3Action::setText(const QString& text)
649{
650 d->text = text;
651 d->update();
652}
653
654QString Q3Action::text() const
655{
656 return d->text;
657}
658
659
660/*!
661 \property Q3Action::menuText
662 \brief the action's menu text
663
664 If the action is added to a menu the menu option will consist of
665 the icon (if there is one), the menu text and the accelerator (if
666 there is one). If the menu text is not explicitly set in the
667 constructor or by using setMenuText() the action's description
668 text will be used as the menu text. There is no default menu text.
669
670 \sa text
671*/
672void Q3Action::setMenuText(const QString& text)
673{
674 if (d->menutext == text)
675 return;
676
677 d->menutext = text;
678 d->update();
679}
680
681QString Q3Action::menuText() const