swift
menuaction.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2016 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "gui/menus/menuaction.h"
5 
6 #include <algorithm>
7 
8 #include <QAction>
9 #include <QMap>
10 #include <QMenu>
11 #include <QStringList>
12 #include <QtGlobal>
13 
14 #include "core/webdataservices.h"
15 #include "gui/guiapplication.h"
16 #include "misc/icons.h"
17 #include "misc/slot.h"
18 
19 using namespace swift::misc;
20 
21 namespace swift::gui::menus
22 {
23  CMenuAction::CMenuAction(const QIcon &icon, const QString &title, const QString &path, bool separator)
24  : m_icon(icon), m_title(title), m_path(path.trimmed()), m_separator(separator)
25  {}
26 
27  CMenuAction::CMenuAction(const QString &path, bool separator) : m_path(path.trimmed()), m_separator(separator) {}
28 
29  CMenuAction::CMenuAction(QAction *action, const QString &path, bool separator)
30  : m_action(action), m_icon(action->icon()), m_title(action->text()), m_path(path.trimmed()),
31  m_separator(separator)
32  {}
33 
35  {
36  if (!m_action) { return false; }
37  return m_action->isCheckable();
38  }
39 
40  void CMenuAction::setActionChecked(bool checked)
41  {
42  if (m_action) { m_action->setChecked(checked); }
43  }
44 
46  {
47  if (!m_action) { return false; }
48  return m_action->isEnabled();
49  }
50 
51  void CMenuAction::setActionEnabled(bool enabled)
52  {
53  if (m_action) { m_action->setEnabled(enabled); }
54  }
55 
56  bool CMenuAction::hasNoPathWithSeparator() const { return m_separator && this->hasNoPath(); }
57 
58  bool CMenuAction::hasNoPath() const { return m_path.isEmpty() || m_path == pathNone(); }
59 
60  QPixmap CMenuAction::getPixmap() const
61  {
62  if (m_icon.isNull()) { return QPixmap(); }
63  return m_icon.pixmap(m_icon.actualSize(QSize(16, 16)));
64  }
65 
66  void CMenuAction::setEnabled(bool enabled)
67  {
68  Q_ASSERT_X(m_action, Q_FUNC_INFO, "No action");
69  m_action->setEnabled(enabled);
70  }
71 
73  {
74  static const CMenuAction subdir(CIcons::appDatabase16(), "Database", CMenuAction::pathViewDatabase());
75  return subdir;
76  }
77 
79  {
80  static const CMenuAction subdir(CIcons::appModels16(), "Consolidate models",
82  return subdir;
83  }
84 
86  {
87  static const CMenuAction subdir(CIcons::appAtc16(), "COM", CMenuAction::pathClientCom());
88  return subdir;
89  }
90 
92  {
93  static const CMenuAction subdir(CIcons::appAircraft16(), "Render models",
95  return subdir;
96  }
97 
99  {
100  static const CMenuAction subdir(CIcons::appAircraft16(), "Display models",
102  return subdir;
103  }
104 
106  {
107  static const CMenuAction subdir(CIcons::appAircraft16(), "Data transfer",
109  return subdir;
110  }
111 
113  {
114  static const CMenuAction subdir(CIcons::appSimulator16(), "Simulator", CMenuAction::pathSimulator());
115  return subdir;
116  }
117 
119  {
120  if (m_path.contains('/'))
121  {
122  if (m_path.endsWith('/')) { return {}; }
123  const int i = m_path.lastIndexOf('/');
124  return m_path.mid(i + 1);
125  }
126  return {};
127  }
128 
129  void CMenuActions::splitSubMenus(const QString &key, QList<CMenuAction> &actions, QList<CMenuAction> &menus) const
130  {
131  QList<CMenuAction> myActions(m_actions.values(key));
132  QList<CMenuAction> checkableActions;
133  std::reverse(myActions.begin(), myActions.end()); // the order is reverse because of the insert multi value
134  for (const CMenuAction &action : myActions)
135  {
136  if (action.isSeparator()) { actions.append(action); }
137  else if (action.isSubMenu() || !action.getQAction()) { menus.append(action); }
138  else
139  {
140  if (action.isCheckableQAction()) { checkableActions.append(action); }
141  else { actions.append(action); }
142  }
143  }
144  actions.append(checkableActions); // checkable actions at end
145  }
146 
147  CMenuActions::CMenuActions(const QList<CMenuAction> &actions)
148  {
149  for (const CMenuAction &action : actions) { this->addAction(action); }
150  }
151 
152  QList<QAction *> CMenuActions::getQActions() const
153  {
154  QList<QAction *> qActions;
155  for (const CMenuAction &a : m_actions) { qActions.append(a.getQAction()); }
156  return qActions;
157  }
158 
159  CMenuActions CMenuActions::getMenuActions(const QString &path) const
160  {
161  if (m_actions.contains(path)) { return QList<CMenuAction>(); };
162  const QList<CMenuAction> allActions(m_actions.values(path));
163  QList<CMenuAction> menuActions;
164  for (const CMenuAction &a : allActions)
165  {
166  if (a.isSubMenu() || !a.getQAction()) { menuActions.append(a); }
167  }
168  return menuActions;
169  }
170 
171  bool CMenuActions::containsMenu(const QString &path) const
172  {
173  if (!m_actions.contains(path)) { return false; }
174  return getMenuActions(path).size() > 0;
175  }
176 
178  {
179  return this->addMenu(subdirAction.getIcon(), subdirAction.getTitle(), subdirAction.getPath());
180  }
181 
182  CMenuAction CMenuActions::addMenu(const QString &title, const QString &path)
183  {
184  return this->addMenu(QIcon(), title, path);
185  }
186 
187  void CMenuActions::addSeparator(const QString &path)
188  {
189  static const CMenuAction separatorDummy(QIcon(), "_SEP_", path);
190  this->addAction(separatorDummy);
191  }
192 
193  CMenuAction CMenuActions::addMenu(const QIcon &icon, const QString &title, const QString &path)
194  {
195  const QList<CMenuAction> exisitingMenu(this->getMenuActions(path));
196  if (!exisitingMenu.isEmpty())
197  {
198  const CMenuAction existingAction(exisitingMenu.first());
199  Q_ASSERT_X(exisitingMenu.size() > 1, Q_FUNC_INFO, "Redundant menu entries");
200  Q_ASSERT_X(existingAction.getTitle() != title, Q_FUNC_INFO, "Title mismatch");
201  if (icon.isNull() || existingAction.hasIcon()) { return existingAction.getQAction(); }
202  return existingAction;
203  }
204 
205  CMenuAction menuAction(icon, title, path);
206  menuAction.setSubMenu(true);
207  return this->addAction(menuAction);
208  }
209 
211  {
212  Q_ASSERT_X(!menuAction.getPath().isEmpty(), Q_FUNC_INFO, "Need path");
213  m_actions.insert(menuAction.getPath(), menuAction);
214  return menuAction;
215  }
216 
218  {
219  CMenuAction a;
220  CMenuActions menuActions;
221  for (const CMenuAction &action : actions.m_actions)
222  {
223  a = this->addAction(action);
224  menuActions.addAction(a);
225  }
226  return menuActions;
227  }
228 
229  CMenuAction CMenuActions::addAction(QAction *action, const QString &path)
230  {
231  return this->addAction(CMenuAction(action, path));
232  }
233 
234  CMenuActions CMenuActions::addActions(const QList<QAction *> &actions, const QString &path)
235  {
236  if (actions.isEmpty()) { return CMenuActions(); }
237  CMenuAction menuAction;
238  CMenuActions menuActions;
239  for (QAction *a : actions)
240  {
241  menuAction = this->addAction(a, path);
242  menuActions.addAction(menuAction);
243  }
244  return menuActions;
245  }
246 
247  CMenuAction CMenuActions::addAction(QAction *action, const QString &text, const QString &path,
248  const CSlot<void()> &slot, const QKeySequence &shortcut)
249  {
250  if (action) { return this->addAction(action, path); }
251  return this->addAction(text, path, slot, shortcut);
252  }
253 
254  CMenuAction CMenuActions::addAction(QAction *action, const QString &text, const QString &path, QObject *actionOwner,
255  const CSlot<void()> &slot, const QKeySequence &shortcut)
256  {
257  if (action) { return this->addAction(action, path); }
258  return this->addAction(text, path, actionOwner, slot, shortcut);
259  }
260 
261  CMenuAction CMenuActions::addAction(QAction *action, const QIcon &icon, const QString &text, const QString &path,
262  const CSlot<void()> &slot, const QKeySequence &shortcut)
263  {
264  if (action) { return this->addAction(action, path); }
265  return this->addAction(icon, text, path, slot, shortcut);
266  }
267 
268  CMenuAction CMenuActions::addAction(QAction *action, const QIcon &icon, const QString &text, const QString &path,
269  QObject *actionOwner, const CSlot<void()> &slot, const QKeySequence &shortcut)
270  {
271  if (action) { return this->addAction(action, path); }
272  Q_ASSERT_X(actionOwner, Q_FUNC_INFO, "Need action owner"); // in this case nullptr as actionOwner is not allowed
273  return this->addAction(icon, text, path, actionOwner, slot, shortcut);
274  }
275 
276  CMenuAction CMenuActions::addAction(const QString &text, const QString &path, QObject *actionOwner,
277  const QKeySequence &shortcut)
278  {
279  return this->addAction(QIcon(), text, path, actionOwner, shortcut);
280  }
281 
282  CMenuAction CMenuActions::addAction(const QIcon &actionIcon, const QString &text, const QString &path,
283  QObject *actionOwner, const QKeySequence &shortcut)
284  {
285  QAction *action =
286  actionIcon.isNull() ? new QAction(text, actionOwner) : new QAction(actionIcon, text, actionOwner);
287  action->setShortcut(shortcut);
288  const CMenuAction ma(action, path);
289  return this->addAction(ma);
290  }
291 
292  CMenuAction CMenuActions::addAction(const QIcon &actionIcon, const QString &text, const QString &path,
293  QObject *actionOwner, const CSlot<void()> &slot, const QKeySequence &shortcut)
294  {
295  CMenuAction action = this->addAction(actionIcon, text, path, actionOwner, shortcut);
296  QAction::connect(action.getQAction(), &QAction::triggered, [slot](bool checked) {
297  slot();
298  Q_UNUSED(checked);
299  });
300  return action;
301  }
302 
303  CMenuAction CMenuActions::addAction(const QIcon &actionIcon, const QString &text, const QString &path)
304  {
305  return this->addAction(actionIcon, text, path, nullptr);
306  }
307 
308  CMenuAction CMenuActions::addAction(const QIcon &actionIcon, const QString &text, const QString &path,
309  const CSlot<void()> &slot, const QKeySequence &shortcut)
310  {
311  return this->addAction(actionIcon, text, path, slot.object(), slot, shortcut);
312  }
313 
314  CMenuAction CMenuActions::addAction(const QString &text, const QString &path, const CSlot<void()> &slot,
315  const QKeySequence &shortcut)
316  {
317  return this->addAction(QIcon(), text, path, slot.object(), slot, shortcut);
318  }
319 
320  CMenuAction CMenuActions::addAction(const QString &text, const QString &path, QObject *actionOwner,
321  const CSlot<void()> &slot, const QKeySequence &shortcut)
322  {
323  return this->addAction(QIcon(), text, path, actionOwner, slot, shortcut);
324  }
325 
326  void CMenuActions::toQMenu(QMenu &menu, bool separateGroups) const
327  {
328  if (m_actions.isEmpty()) { return; }
329  const QStringList keys = m_actions.uniqueKeys(); // Sorted ascending keys, we need a menu for all those keys
330 
331  QMap<QString, QMenu *> subMenus; // all sub menus
332  QString lastKey;
333 
334  for (const QString &key : keys)
335  {
336  bool handledSeparator = false;
337  const int pathDepth = CMenuActions::pathDepth(key); // 0 based
338 
339  QList<CMenuAction> actions;
340  QList<CMenuAction> menus;
341  this->splitSubMenus(key, actions, menus); // splits actions and (sub) menus for that key
342  if (actions.isEmpty())
343  {
344  // No actions directly for that level
345  continue;
346  }
347  if (!menu.isEmpty() && separateGroups)
348  {
349  // no separator a) if there is already one b) key roots are the same (such entries belong together)
350  const bool noSeparator = (!menu.actions().isEmpty() && menu.actions().last()->isSeparator()) ||
351  (isSameKeyRoot(key, lastKey));
352  if (!noSeparator) { menu.addSeparator(); }
353  handledSeparator = true;
354  }
355 
356  int noActionsWithoutPath = 0;
357  QMenu *currentMenu = nullptr;
358 
359  // reverse iteration because same key values are inserted and have reverse order
360  for (const CMenuAction &menuAction : std::as_const(actions))
361  {
362  // create submenu if required
363  if (!currentMenu)
364  {
365  currentMenu = currentMenuForAction(menu, menuAction, menus, subMenus, key, pathDepth);
366  }
367  Q_ASSERT_X(currentMenu, Q_FUNC_INFO, "Missing menu");
368  Q_ASSERT_X(menuAction.isSubMenu() || menuAction.isSeparator() || menuAction.getQAction(), Q_FUNC_INFO,
369  "Wrong type");
370 
371  if (menuAction.isSeparator())
372  {
373  if (menu.isEmpty()) continue;
374  currentMenu->addSeparator();
375  continue;
376  }
377 
378  if (menuAction.hasNoPath())
379  {
380  noActionsWithoutPath++;
381 
382  // separator for unclassfied items
383  if ((!handledSeparator || noActionsWithoutPath > 1) && menuAction.hasNoPathWithSeparator())
384  {
385  menu.addSeparator();
386  handledSeparator = false;
387  }
388  }
389 
390  // either add to submenu or menu
391  currentMenu->addAction(menuAction.getQAction());
392 
393  // menu has ownership if there is no other parent
394  if (menuAction.getQAction() && !menuAction.getQAction()->parent())
395  {
396  menuAction.getQAction()->setParent(&menu);
397  }
398  } // actions
399 
400  // clean up empty sub menus
401  if (currentMenu && currentMenu->isEmpty()) { menu.removeAction(currentMenu->menuAction()); }
402 
403  // remember last key
404  lastKey = key;
405 
406  } // keys
407  }
408 
409  QList<CMenuAction> CMenuActions::toQList() const { return m_actions.values(); }
410 
411  CMenuActions::operator QList<QAction *>() const
412  {
413  QList<QAction *> qActions;
414  for (const CMenuAction &a : m_actions)
415  {
416  if (!a.getQAction()) { continue; }
417  qActions.append(a.getQAction());
418  }
419  return qActions;
420  }
421 
423  {
424  if (this->containsMenu(CMenuAction::pathViewOrder())) { return CMenuAction(); }
425  return this->addMenu(CIcons::arrowMediumEast16(), "Order", CMenuAction::pathViewOrder());
426  }
427 
429  {
430  if (this->containsMenu(CMenuAction::pathSimulator())) { return CMenuAction(); }
431  return this->addMenu(CIcons::appSimulator16(), "Simulator", CMenuAction::pathSimulator());
432  }
433 
435  {
436  if (this->containsMenu(CMenuAction::pathModelStash())) { return CMenuAction(); }
437  const bool canConnectDb =
439  const QString text(canConnectDb ? "Stash tools" : "Stash tools (Warning: no DB!)");
440  return this->addMenu(CIcons::appDbStash16(), text, CMenuAction::pathModelStash());
441  }
442 
444  {
446  return this->addMenu(CIcons::appDbStash16(), "Edit models", CMenuAction::pathModelStashEditor());
447  }
448 
450  {
451  if (this->containsMenu(CMenuAction::pathViewDatabase())) { return CMenuAction(); }
452  return this->addMenu(CMenuAction::subMenuDatabase());
453  }
454 
456  {
459  }
460 
462  {
463  if (this->containsMenu(CMenuAction::pathModelSet())) { return CMenuAction(); }
464  return this->addMenu(CIcons::appModels16(), "Model set", CMenuAction::pathModelSet());
465  }
466 
468  {
469  if (this->containsMenu(CMenuAction::subMenuCom().getPath())) { return CMenuAction(); }
470  return this->addAction(CMenuAction::subMenuCom());
471  }
472 
474  {
475  if (this->containsMenu(CMenuAction::subMenuDisplayModels().getPath())) { return CMenuAction(); }
477  }
478 
480  {
481  if (this->containsMenu(CMenuAction::subMenuRenderModels().getPath())) { return CMenuAction(); }
483  }
484 
486  {
487  if (this->containsMenu(CMenuAction::subMenuDataTransfer().getPath())) { return CMenuAction(); }
489  }
490 
491  QMenu *CMenuActions::currentMenuForAction(QMenu &menu, const CMenuAction &menuAction,
492  const QList<CMenuAction> &menus, QMap<QString, QMenu *> &subMenus,
493  const QString &key, int pathDepth)
494  {
495  if (pathDepth < 1) { return &menu; }
496  QMenu *parentMenu = &menu;
497  if (pathDepth > 1)
498  {
499  // find the corresponding submenu. If this is empty the next higher level will be choosen
500  // if not found at all, use top level menu
501  parentMenu = findUpwardsInMenus(key, subMenus);
502  if (!parentMenu) { parentMenu = &menu; }
503  }
504 
505  // explicity menu?
506  QMenu *subMenu = nullptr;
507  if (menus.isEmpty()) { subMenu = parentMenu->addMenu(menuAction.getLastPathPart()); }
508  else
509  {
510  const CMenuAction menuFound(menus.first());
511  subMenu = parentMenu->addMenu(menuFound.getIcon(), menuFound.getTitle());
512  }
513  Q_ASSERT_X(subMenu, Q_FUNC_INFO, "Could not create sub menu");
514 
515  if (subMenu) { subMenu->setParent(parentMenu); }
516 
517  if (pathDepth > 0 && subMenu) { subMenus.insert(key, subMenu); }
518  return subMenu;
519  }
520 
521  int CMenuActions::pathDepth(const QString &path)
522  {
523  if (path.isEmpty()) { return 0; }
524  int c = path.count('/');
525  return c > 0 ? c : 0;
526  }
527 
528  QString CMenuActions::parentPath(const QString &currentPath)
529  {
530  if (!currentPath.contains('/')) { return {}; }
531  const int i = currentPath.lastIndexOf('/');
532  return currentPath.left(i);
533  }
534 
535  QString CMenuActions::keyRoot(const QString &key)
536  {
537  const int i = key.lastIndexOf('.');
538  if (i < 0) { return {}; }
539  return key.left(i);
540  }
541 
542  bool CMenuActions::isSameKeyRoot(const QString &key1, const QString &key2)
543  {
544  const int i1 = key1.lastIndexOf('.');
545  if (i1 < 0) { return false; }
546  const int i2 = key2.lastIndexOf('.');
547  if (i2 < 0 || i1 != i2) { return false; }
548  return key1.left(i1) == key2.left(i2);
549  }
550 
551  QMenu *CMenuActions::findUpwardsInMenus(const QString &key, const QMap<QString, QMenu *> &menus)
552  {
553  QString k = key;
554  while (!k.isEmpty() && !menus.isEmpty())
555  {
556  if (menus.contains(k)) { return menus[k]; }
557  k = parentPath(k);
558  }
559  return nullptr;
560  }
561 } // namespace swift::gui::menus
CWebDataServices * getWebDataServices() const
Get the web data services.
bool hasSuccesfullyConnectedSwiftDb() const
Has already successfully connect swift DB?
Wraps a QAction with extra metadata to allow proper sorting for a QMenu.
Definition: menuaction.h:26
static const QString & pathModelSet()
Model set.
Definition: menuaction.h:150
bool hasNoPathWithSeparator() const
No path and separator wanted.
Definition: menuaction.cpp:56
void setSubMenu(bool menu)
Is menu?
Definition: menuaction.h:80
void setEnabled(bool enabled)
Set enabled / disabled (allows to gray out)
Definition: menuaction.cpp:66
QAction * getQAction() const
Action.
Definition: menuaction.h:47
static const QString & pathModelStashEditor()
Stash editor sub menu.
Definition: menuaction.h:178
static const QString & pathViewDatabase()
Database.
Definition: menuaction.h:274
static const CMenuAction & subMenuRenderModels()
Predefined sub sub menus.
Definition: menuaction.cpp:98
static const CMenuAction & subMenuConsolidateModels()
Predefined sub sub menus.
Definition: menuaction.cpp:78
CMenuAction(const QIcon &icon, const QString &title, const QString &path=pathNone(), bool separator=false)
Constructor.
Definition: menuaction.cpp:23
static const CMenuAction & subMenuDataTransfer()
Predefined sub sub menus.
Definition: menuaction.cpp:105
static const QString & pathClientCom()
Client COM related.
Definition: menuaction.h:209
static const QString & pathNone()
No key.
Definition: menuaction.h:108
static const QString & pathModelConsolidate()
Consolidate.
Definition: menuaction.h:164
const QString & getPath() const
Path.
Definition: menuaction.h:62
void setActionEnabled(bool enabled)
Enable action (allow gray out)
Definition: menuaction.cpp:51
bool hasIcon() const
Has icon?
Definition: menuaction.h:95
static const CMenuAction & subMenuSimulator()
Predefined sub sub menus.
Definition: menuaction.cpp:112
const QIcon & getIcon() const
Icon.
Definition: menuaction.h:89
static const QString & pathViewOrder()
Order submenus.
Definition: menuaction.h:295
QPixmap getPixmap() const
Icon as pixmap.
Definition: menuaction.cpp:60
const QString & getTitle() const
Title.
Definition: menuaction.h:68
bool hasNoPath() const
No path?
Definition: menuaction.cpp:58
static const CMenuAction & subMenuDatabase()
Predefined sub sub menus.
Definition: menuaction.cpp:72
static const QString & pathClientSimulationDisplay()
Client simulation/display related.
Definition: menuaction.h:237
static const CMenuAction & subMenuDisplayModels()
Predefined sub sub menus.
Definition: menuaction.cpp:91
bool isCheckableQAction() const
Checkable QAction.
Definition: menuaction.cpp:34
static const QString & pathSimulator()
Simulator sub menu.
Definition: menuaction.h:122
static const CMenuAction & subMenuCom()
Predefined sub sub menus.
Definition: menuaction.cpp:85
void setActionChecked(bool checked)
Set a checkable action, QAction::setChecked.
Definition: menuaction.cpp:40
bool isActionEnabled() const
Enabled action?
Definition: menuaction.cpp:45
static const QString & pathModelStash()
Stash sub menu.
Definition: menuaction.h:171
static const QString & pathClientSimulationTransfer()
Client simulation/display related.
Definition: menuaction.h:251
static const QString & pathClientSimulationRender()
Client simulation/display related.
Definition: menuaction.h:244
QString getLastPathPart() const
Last part of the path, e.g. "Foo/Bar" -> "Bar".
Definition: menuaction.cpp:118
Bunch of CMenuAction objects.
Definition: menuaction.h:384
CMenuAction addMenuSimulator()
Simulator menu.
Definition: menuaction.cpp:428
QList< QAction * > getQActions() const
QActions.
Definition: menuaction.cpp:152
CMenuAction addMenuConsolidateModels()
Consolidate models menu.
Definition: menuaction.cpp:455
void addSeparator(const QString &path)
Add a separator.
Definition: menuaction.cpp:187
int size() const
Elements.
Definition: menuaction.h:408
CMenuAction addMenuDisplayModels()
Add display model menu.
Definition: menuaction.cpp:473
CMenuAction addMenuStash()
Stash menu.
Definition: menuaction.cpp:434
CMenuActions getMenuActions(const QString &path) const
All menu actions.
Definition: menuaction.cpp:159
CMenuActions addActions(const CMenuActions &actions)
Add menu actions, returns last valid QAction.
Definition: menuaction.cpp:217
CMenuAction addMenuCom()
Add COM model menu.
Definition: menuaction.cpp:467
void toQMenu(QMenu &menu, bool separateGroups) const
Insert the sorted actions to the menu.
Definition: menuaction.cpp:326
CMenuAction addAction(const CMenuAction &menuAction)
Add menu action.
Definition: menuaction.cpp:210
CMenuAction addMenuStashEditor()
Stash menu.
Definition: menuaction.cpp:443
CMenuAction addMenuViewOrder()
View order menu.
Definition: menuaction.cpp:422
CMenuAction addMenu(const CMenuAction &subdirAction)
Add a sub menu.
Definition: menuaction.cpp:177
CMenuAction addMenuModelSet()
Model set menu.
Definition: menuaction.cpp:461
CMenuAction addMenuDatabase()
Database menu.
Definition: menuaction.cpp:449
QList< CMenuAction > toQList() const
To QList.
Definition: menuaction.cpp:409
CMenuAction addMenuRenderModels()
Add render model menu.
Definition: menuaction.cpp:479
bool containsMenu(const QString &path) const
Menu already available?
Definition: menuaction.cpp:171
CMenuAction addMenuDataTransfer()
Add data transfer menu.
Definition: menuaction.cpp:485
Callable wrapper for a member function with function signature F.
Definition: slot.h:62
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
Free functions in swift::misc.