2 ******************************************************************************
4 * @file actioncontainer.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
7 * @addtogroup GCSPlugins GCS Plugins
9 * @addtogroup CorePlugin Core Plugin
11 * @brief The Core GCS plugin
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "actioncontainer_p.h"
30 #include "actionmanager_p.h"
32 #include "command_p.h"
34 #include "coreconstants.h"
35 #include "uniqueidmanager.h"
37 #include <QtCore/QDebug>
41 Q_DECLARE_METATYPE(Core::Internal::MenuActionContainer
*)
44 using namespace Core::Internal
;
47 \class ActionContainer
50 \brief The ActionContainer class represents a menu or menu bar in the OpenPilot GCS.
52 You don't create instances of this class directly, but instead use the
53 \l{ActionManager::createMenu()}
54 and \l{ActionManager::createMenuBar()} methods.
55 Retrieve existing action containers for an ID with
56 \l{ActionManager::actionContainer()}.
58 Within a menu or menu bar you can group menus and items together by defining groups
59 (the order of the groups is defined by the order of the \l{ActionContainer::appendGroup()} calls), and
60 adding menus/actions to these groups. If no custom groups are defined, an action container
61 has three default groups \c{Core::Constants::G_DEFAULT_ONE}, \c{Core::Constants::G_DEFAULT_TWO}
62 and \c{Core::Constants::G_DEFAULT_THREE}.
64 You can define if the menu represented by this action container should automatically disable
65 or hide whenever it only contains disabled items and submenus by setting the corresponding
66 \l{ActionContainer::setEmptyAction()}{EmptyAction}.
70 \enum ActionContainer::EmptyAction
71 Defines what happens when the represented menu is empty or contains only disabled/invisible items.
74 The menu will still be visible and active.
76 The menu will be visible but disabled.
78 The menu will not be visible until the state of the subitems change.
82 \fn ActionContainer::setEmptyAction(EmptyAction disableOrHide)
83 Defines if the menu represented by this action container should automatically \a disableOrHide
84 whenever it only contains disabled items and submenus.
85 \sa ActionContainer::EmptyAction
89 \fn int ActionContainer::id() const
94 \fn QMenu *ActionContainer::menu() const
95 Returns the QMenu instance that is represented by this action container, or
96 0 if this action container represents a menu bar.
100 \fn QMenuBar *ActionContainer::menuBar() const
101 Returns the QMenuBar instance that is represented by this action container, or
102 0 if this action container represents a menu.
106 \fn QAction *ActionContainer::insertLocation(const QString &group) const
107 Returns an action representing the \a group,
108 that could be used with \c{QWidget::insertAction}.
112 \fn void ActionContainer::appendGroup(const QString &identifier)
113 Adds a group with the given \a identifier to the action container. Using groups
114 you can segment your action container into logical parts and add actions and
115 menus directly to these parts.
121 \fn void ActionContainer::addAction(Core::Command *action, const QString &group)
122 Add the \a action as a menu item to this action container. The action is added as the
123 last item of the specified \a group.
129 \fn void ActionContainer::addMenu(Core::ActionContainer *menu, const QString &group)
130 Add the \a menu as a submenu to this action container. The menu is added as the
131 last item of the specified \a group.
137 \fn bool ActionContainer::update()
142 \fn ActionContainer::~ActionContainer()
146 // ---------- ActionContainerPrivate ------------
149 \class Core::Internal::ActionContainerPrivate
153 ActionContainerPrivate::ActionContainerPrivate(int id
)
154 : m_data(0), m_id(id
)
157 void ActionContainerPrivate::setEmptyAction(EmptyAction ea
)
159 m_data
= ((m_data
& ~EA_Mask
) | ea
);
162 bool ActionContainerPrivate::hasEmptyAction(EmptyAction ea
) const
164 return (m_data
& EA_Mask
) == ea
;
167 void ActionContainerPrivate::appendGroup(const QString
&group
)
169 int gid
= UniqueIDManager::instance()->uniqueIdentifier(group
);
174 QAction
*ActionContainerPrivate::insertLocation(const QString
&group
) const
176 int grpid
= UniqueIDManager::instance()->uniqueIdentifier(group
);
178 int pos
= ((grpid
<< 16) | 0xFFFF);
180 return beforeAction(pos
, &prevKey
);
183 void ActionContainerPrivate::addAction(Command
*action
, const QString
&group
)
185 if (!canAddAction(action
)) {
189 ActionManagerPrivate
*am
= ActionManagerPrivate::instance();
190 UniqueIDManager
*idmanager
= UniqueIDManager::instance();
191 int grpid
= idmanager
->uniqueIdentifier(Constants::G_DEFAULT_TWO
);
192 if (!group
.isEmpty()) {
193 grpid
= idmanager
->uniqueIdentifier(group
);
195 if (!m_groups
.contains(grpid
) && !am
->defaultGroups().contains(grpid
)) {
196 qWarning() << "*** addAction(): Unknown group: " << group
;
198 int pos
= ((grpid
<< 16) | 0xFFFF);
199 addAction(action
, pos
, true);
202 void ActionContainerPrivate::addMenu(ActionContainer
*menu
, const QString
&group
)
204 ActionContainerPrivate
*container
= static_cast<ActionContainerPrivate
*>(menu
);
206 if (!container
->canBeAddedToMenu()) {
210 ActionManagerPrivate
*am
= ActionManagerPrivate::instance();
211 UniqueIDManager
*idmanager
= UniqueIDManager::instance();
212 int grpid
= idmanager
->uniqueIdentifier(Constants::G_DEFAULT_TWO
);
213 if (!group
.isEmpty()) {
214 grpid
= idmanager
->uniqueIdentifier(group
);
216 if (!m_groups
.contains(grpid
) && !am
->defaultGroups().contains(grpid
)) {
217 qWarning() << "*** addMenu(): Unknown group: " << group
;
219 int pos
= ((grpid
<< 16) | 0xFFFF);
220 addMenu(menu
, pos
, true);
223 int ActionContainerPrivate::id() const
228 QMenu
*ActionContainerPrivate::menu() const
233 QMenuBar
*ActionContainerPrivate::menuBar() const
238 bool ActionContainerPrivate::canAddAction(Command
*action
) const
240 return action
->action() != 0;
243 void ActionContainerPrivate::addAction(Command
*action
, int pos
, bool setpos
)
245 Action
*a
= static_cast<Action
*>(action
);
248 QAction
*ba
= beforeAction(pos
, &prevKey
);
251 pos
= calcPosition(pos
, prevKey
);
253 loc
.m_container
= m_id
;
254 loc
.m_position
= pos
;
255 QList
<CommandLocation
> locs
= a
->locations();
257 a
->setLocations(locs
);
260 m_commands
.append(action
);
261 m_posmap
.insert(pos
, action
->id());
262 insertAction(ba
, a
->action());
265 void ActionContainerPrivate::addMenu(ActionContainer
*menu
, int pos
, bool setpos
)
267 MenuActionContainer
*mc
= static_cast<MenuActionContainer
*>(menu
);
270 QAction
*ba
= beforeAction(pos
, &prevKey
);
273 pos
= calcPosition(pos
, prevKey
);
275 loc
.m_container
= m_id
;
276 loc
.m_position
= pos
;
277 mc
->setLocation(loc
);
280 m_subContainers
.append(menu
);
281 m_posmap
.insert(pos
, menu
->id());
282 insertMenu(ba
, mc
->menu());
285 QAction
*ActionContainerPrivate::beforeAction(int pos
, int *prevKey
) const
287 ActionManagerPrivate
*am
= ActionManagerPrivate::instance();
293 QMap
<int, int>::const_iterator i
= m_posmap
.constBegin();
294 while (i
!= m_posmap
.constEnd()) {
299 (*prevKey
) = i
.key();
307 if (Command
* cmd
= am
->command(baId
)) {
308 return cmd
->action();
310 if (ActionContainer
* container
= am
->actionContainer(baId
)) {
311 if (QMenu
* menu
= container
->menu()) {
312 return menu
->menuAction();
319 int ActionContainerPrivate::calcPosition(int pos
, int prevKey
) const
321 int grp
= (pos
& 0xFFFF0000);
327 int prevgrp
= (prevKey
& 0xFFFF0000);
329 if (grp
!= prevgrp
) {
333 return grp
+ (prevKey
& 0xFFFF) + 10;
336 // ---------- MenuActionContainer ------------
339 \class Core::Internal::MenuActionContainer
343 MenuActionContainer::MenuActionContainer(int id
)
344 : ActionContainerPrivate(id
), m_menu(0)
346 setEmptyAction(EA_Disable
);
349 void MenuActionContainer::setMenu(QMenu
*menu
)
354 qVariantSetValue
<MenuActionContainer
*>(v
, this);
356 m_menu
->menuAction()->setData(v
);
359 QMenu
*MenuActionContainer::menu() const
364 void MenuActionContainer::insertAction(QAction
*before
, QAction
*action
)
366 m_menu
->insertAction(before
, action
);
369 void MenuActionContainer::insertMenu(QAction
*before
, QMenu
*menu
)
371 m_menu
->insertMenu(before
, menu
);
374 void MenuActionContainer::setLocation(const CommandLocation
&location
)
376 m_location
= location
;
379 CommandLocation
MenuActionContainer::location() const
384 bool MenuActionContainer::update()
386 if (hasEmptyAction(EA_None
)) {
390 bool hasitems
= false;
392 foreach(ActionContainer
* container
, subContainers()) {
393 if (container
== this) {
394 qWarning() << Q_FUNC_INFO
<< "container" << (this->menu() ? this->menu()->title() : "") << "contains itself as subcontainer";
397 if (container
->update()) {
403 foreach(Command
* command
, commands()) {
404 if (command
->isActive()) {
411 if (hasEmptyAction(EA_Hide
)) {
412 m_menu
->setVisible(hasitems
);
413 } else if (hasEmptyAction(EA_Disable
)) {
414 m_menu
->setEnabled(hasitems
);
420 bool MenuActionContainer::canBeAddedToMenu() const
426 // ---------- MenuBarActionContainer ------------
429 \class Core::Internal::MenuBarActionContainer
433 MenuBarActionContainer::MenuBarActionContainer(int id
)
434 : ActionContainerPrivate(id
), m_menuBar(0)
436 setEmptyAction(EA_None
);
439 void MenuBarActionContainer::setMenuBar(QMenuBar
*menuBar
)
444 QMenuBar
*MenuBarActionContainer::menuBar() const
449 void MenuBarActionContainer::insertAction(QAction
*before
, QAction
*action
)
451 m_menuBar
->insertAction(before
, action
);
454 void MenuBarActionContainer::insertMenu(QAction
*before
, QMenu
*menu
)
456 m_menuBar
->insertMenu(before
, menu
);
459 bool MenuBarActionContainer::update()
461 if (hasEmptyAction(EA_None
)) {
465 bool hasitems
= false;
466 QList
<QAction
*> actions
= m_menuBar
->actions();
467 for (int i
= 0; i
< actions
.size(); ++i
) {
468 if (actions
.at(i
)->isVisible()) {
474 if (hasEmptyAction(EA_Hide
)) {
475 m_menuBar
->setVisible(hasitems
);
476 } else if (hasEmptyAction(EA_Disable
)) {
477 m_menuBar
->setEnabled(hasitems
);
483 bool MenuBarActionContainer::canBeAddedToMenu() const