LP-56 - Better txpid option namings, fix tabs-spaces, tooltips. headers, variable...
[librepilot.git] / ground / openpilotgcs / src / plugins / coreplugin / actionmanager / actioncontainer.cpp
blob923b772be8e9e31b6af55136e0ca36e70dc3cd8a
1 /**
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
8 * @{
9 * @addtogroup CorePlugin Core Plugin
10 * @{
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
22 * for more details.
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>
38 #include <QAction>
39 #include <QMenuBar>
41 Q_DECLARE_METATYPE(Core::Internal::MenuActionContainer *)
43 using namespace Core;
44 using namespace Core::Internal;
46 /*!
47 \class ActionContainer
48 \mainclass
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}.
69 /*!
70 \enum ActionContainer::EmptyAction
71 Defines what happens when the represented menu is empty or contains only disabled/invisible items.
72 \omitvalue EA_Mask
73 \value EA_None
74 The menu will still be visible and active.
75 \value EA_Disable
76 The menu will be visible but disabled.
77 \value EA_Hide
78 The menu will not be visible until the state of the subitems change.
81 /*!
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
88 /*!
89 \fn int ActionContainer::id() const
90 \internal
93 /*!
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.
99 /*!
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.
116 \sa addAction()
117 \sa addMenu()
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.
124 \sa appendGroup()
125 \sa addMenu()
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.
132 \sa appendGroup()
133 \sa addAction()
137 \fn bool ActionContainer::update()
138 \internal
142 \fn ActionContainer::~ActionContainer()
143 \internal
146 // ---------- ActionContainerPrivate ------------
149 \class Core::Internal::ActionContainerPrivate
150 \internal
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);
171 m_groups << gid;
174 QAction *ActionContainerPrivate::insertLocation(const QString &group) const
176 int grpid = UniqueIDManager::instance()->uniqueIdentifier(group);
177 int prevKey = 0;
178 int pos = ((grpid << 16) | 0xFFFF);
180 return beforeAction(pos, &prevKey);
183 void ActionContainerPrivate::addAction(Command *action, const QString &group)
185 if (!canAddAction(action)) {
186 return;
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()) {
207 return;
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
225 return m_id;
228 QMenu *ActionContainerPrivate::menu() const
230 return 0;
233 QMenuBar *ActionContainerPrivate::menuBar() const
235 return 0;
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);
247 int prevKey = 0;
248 QAction *ba = beforeAction(pos, &prevKey);
250 if (setpos) {
251 pos = calcPosition(pos, prevKey);
252 CommandLocation loc;
253 loc.m_container = m_id;
254 loc.m_position = pos;
255 QList<CommandLocation> locs = a->locations();
256 locs.append(loc);
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);
269 int prevKey = 0;
270 QAction *ba = beforeAction(pos, &prevKey);
272 if (setpos) {
273 pos = calcPosition(pos, prevKey);
274 CommandLocation loc;
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();
289 int baId = -1;
291 (*prevKey) = -1;
293 QMap<int, int>::const_iterator i = m_posmap.constBegin();
294 while (i != m_posmap.constEnd()) {
295 if (i.key() > pos) {
296 baId = i.value();
297 break;
299 (*prevKey) = i.key();
300 ++i;
303 if (baId == -1) {
304 return 0;
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();
316 return 0;
319 int ActionContainerPrivate::calcPosition(int pos, int prevKey) const
321 int grp = (pos & 0xFFFF0000);
323 if (prevKey == -1) {
324 return grp;
327 int prevgrp = (prevKey & 0xFFFF0000);
329 if (grp != prevgrp) {
330 return grp;
333 return grp + (prevKey & 0xFFFF) + 10;
336 // ---------- MenuActionContainer ------------
339 \class Core::Internal::MenuActionContainer
340 \internal
343 MenuActionContainer::MenuActionContainer(int id)
344 : ActionContainerPrivate(id), m_menu(0)
346 setEmptyAction(EA_Disable);
349 void MenuActionContainer::setMenu(QMenu *menu)
351 m_menu = menu;
353 QVariant v;
354 qVariantSetValue<MenuActionContainer *>(v, this);
356 m_menu->menuAction()->setData(v);
359 QMenu *MenuActionContainer::menu() const
361 return m_menu;
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
381 return m_location;
384 bool MenuActionContainer::update()
386 if (hasEmptyAction(EA_None)) {
387 return true;
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";
395 continue;
397 if (container->update()) {
398 hasitems = true;
399 break;
402 if (!hasitems) {
403 foreach(Command * command, commands()) {
404 if (command->isActive()) {
405 hasitems = true;
406 break;
411 if (hasEmptyAction(EA_Hide)) {
412 m_menu->setVisible(hasitems);
413 } else if (hasEmptyAction(EA_Disable)) {
414 m_menu->setEnabled(hasitems);
417 return hasitems;
420 bool MenuActionContainer::canBeAddedToMenu() const
422 return true;
426 // ---------- MenuBarActionContainer ------------
429 \class Core::Internal::MenuBarActionContainer
430 \internal
433 MenuBarActionContainer::MenuBarActionContainer(int id)
434 : ActionContainerPrivate(id), m_menuBar(0)
436 setEmptyAction(EA_None);
439 void MenuBarActionContainer::setMenuBar(QMenuBar *menuBar)
441 m_menuBar = menuBar;
444 QMenuBar *MenuBarActionContainer::menuBar() const
446 return m_menuBar;
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)) {
462 return true;
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()) {
469 hasitems = true;
470 break;
474 if (hasEmptyAction(EA_Hide)) {
475 m_menuBar->setVisible(hasitems);
476 } else if (hasEmptyAction(EA_Disable)) {
477 m_menuBar->setEnabled(hasitems);
480 return hasitems;
483 bool MenuBarActionContainer::canBeAddedToMenu() const
485 return false;