4 #include "gui/menus/menuaction.h"
11 #include <QStringList>
21 namespace swift::gui::menus
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)
30 : m_action(action), m_icon(action->icon()), m_title(action->text()), m_path(path.trimmed()),
31 m_separator(separator)
36 if (!m_action) {
return false; }
37 return m_action->isCheckable();
42 if (m_action) { m_action->setChecked(checked); }
47 if (!m_action) {
return false; }
48 return m_action->isEnabled();
53 if (m_action) { m_action->setEnabled(enabled); }
62 if (m_icon.isNull()) {
return QPixmap(); }
63 return m_icon.pixmap(m_icon.actualSize(QSize(16, 16)));
68 Q_ASSERT_X(m_action, Q_FUNC_INFO,
"No action");
69 m_action->setEnabled(enabled);
80 static const CMenuAction subdir(CIcons::appModels16(),
"Consolidate models",
93 static const CMenuAction subdir(CIcons::appAircraft16(),
"Render models",
100 static const CMenuAction subdir(CIcons::appAircraft16(),
"Display models",
107 static const CMenuAction subdir(CIcons::appAircraft16(),
"Data transfer",
120 if (m_path.contains(
'/'))
122 if (m_path.endsWith(
'/')) {
return {}; }
123 const int i = m_path.lastIndexOf(
'/');
124 return m_path.mid(i + 1);
129 void CMenuActions::splitSubMenus(
const QString &key, QList<CMenuAction> &actions, QList<CMenuAction> &menus)
const
131 QList<CMenuAction> myActions(m_actions.values(key));
132 QList<CMenuAction> checkableActions;
133 std::reverse(myActions.begin(), myActions.end());
136 if (action.isSeparator()) { actions.append(action); }
137 else if (action.isSubMenu() || !action.getQAction()) { menus.append(action); }
140 if (action.isCheckableQAction()) { checkableActions.append(action); }
141 else { actions.append(action); }
144 actions.append(checkableActions);
154 QList<QAction *> qActions;
155 for (
const CMenuAction &a : m_actions) { qActions.append(a.getQAction()); }
161 if (m_actions.contains(path)) {
return QList<CMenuAction>(); };
162 const QList<CMenuAction> allActions(m_actions.values(path));
163 QList<CMenuAction> menuActions;
166 if (a.isSubMenu() || !a.getQAction()) { menuActions.append(a); }
173 if (!m_actions.contains(path)) {
return false; }
184 return this->
addMenu(QIcon(), title, path);
189 static const CMenuAction separatorDummy(QIcon(),
"_SEP_", path);
195 const QList<CMenuAction> exisitingMenu(this->
getMenuActions(path));
196 if (!exisitingMenu.isEmpty())
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;
212 Q_ASSERT_X(!menuAction.
getPath().isEmpty(), Q_FUNC_INFO,
"Need path");
213 m_actions.insert(menuAction.
getPath(), menuAction);
221 for (
const CMenuAction &action : actions.m_actions)
239 for (QAction *a : actions)
248 const CSlot<
void()> &slot,
const QKeySequence &shortcut)
250 if (action) {
return this->
addAction(action, path); }
251 return this->
addAction(text, path, slot, shortcut);
255 const CSlot<
void()> &slot,
const QKeySequence &shortcut)
257 if (action) {
return this->
addAction(action, path); }
258 return this->
addAction(text, path, actionOwner, slot, shortcut);
262 const CSlot<
void()> &slot,
const QKeySequence &shortcut)
264 if (action) {
return this->
addAction(action, path); }
265 return this->
addAction(icon, text, path, slot, shortcut);
269 QObject *actionOwner,
const CSlot<
void()> &slot,
const QKeySequence &shortcut)
271 if (action) {
return this->
addAction(action, path); }
272 Q_ASSERT_X(actionOwner, Q_FUNC_INFO,
"Need action owner");
273 return this->
addAction(icon, text, path, actionOwner, slot, shortcut);
277 const QKeySequence &shortcut)
279 return this->
addAction(QIcon(), text, path, actionOwner, shortcut);
283 QObject *actionOwner,
const QKeySequence &shortcut)
286 actionIcon.isNull() ?
new QAction(text, actionOwner) :
new QAction(actionIcon, text, actionOwner);
287 action->setShortcut(shortcut);
293 QObject *actionOwner,
const CSlot<
void()> &slot,
const QKeySequence &shortcut)
296 QAction::connect(action.
getQAction(), &QAction::triggered, [slot](
bool checked) {
305 return this->
addAction(actionIcon, text, path,
nullptr);
309 const CSlot<
void()> &slot,
const QKeySequence &shortcut)
311 return this->
addAction(actionIcon, text, path, slot.object(), slot, shortcut);
315 const QKeySequence &shortcut)
317 return this->
addAction(QIcon(), text, path, slot.object(), slot, shortcut);
321 const CSlot<
void()> &slot,
const QKeySequence &shortcut)
323 return this->
addAction(QIcon(), text, path, actionOwner, slot, shortcut);
328 if (m_actions.isEmpty()) {
return; }
329 const QStringList keys = m_actions.uniqueKeys();
334 for (
const QString &key : keys)
336 bool handledSeparator =
false;
337 const int pathDepth = CMenuActions::pathDepth(key);
339 QList<CMenuAction> actions;
340 QList<CMenuAction> menus;
341 this->splitSubMenus(key, actions, menus);
342 if (actions.isEmpty())
347 if (!menu.isEmpty() && separateGroups)
350 const bool noSeparator = (!menu.actions().isEmpty() && menu.actions().last()->isSeparator()) ||
351 (isSameKeyRoot(key, lastKey));
352 if (!noSeparator) { menu.addSeparator(); }
353 handledSeparator =
true;
356 int noActionsWithoutPath = 0;
357 QMenu *currentMenu =
nullptr;
360 for (
const CMenuAction &menuAction : std::as_const(actions))
365 currentMenu = currentMenuForAction(menu, menuAction, menus, subMenus, key, pathDepth);
367 Q_ASSERT_X(currentMenu, Q_FUNC_INFO,
"Missing menu");
368 Q_ASSERT_X(menuAction.isSubMenu() || menuAction.isSeparator() || menuAction.getQAction(), Q_FUNC_INFO,
371 if (menuAction.isSeparator())
373 if (menu.isEmpty())
continue;
374 currentMenu->addSeparator();
378 if (menuAction.hasNoPath())
380 noActionsWithoutPath++;
383 if ((!handledSeparator || noActionsWithoutPath > 1) && menuAction.hasNoPathWithSeparator())
386 handledSeparator =
false;
391 currentMenu->addAction(menuAction.getQAction());
394 if (menuAction.getQAction() && !menuAction.getQAction()->parent())
396 menuAction.getQAction()->setParent(&menu);
401 if (currentMenu && currentMenu->isEmpty()) { menu.removeAction(currentMenu->menuAction()); }
411 CMenuActions::operator QList<QAction *>()
const
413 QList<QAction *> qActions;
416 if (!a.getQAction()) {
continue; }
417 qActions.append(a.getQAction());
437 const bool canConnectDb =
439 const QString text(canConnectDb ?
"Stash tools" :
"Stash tools (Warning: no DB!)");
491 QMenu *CMenuActions::currentMenuForAction(QMenu &menu,
const CMenuAction &menuAction,
493 const QString &key,
int pathDepth)
495 if (pathDepth < 1) {
return &menu; }
496 QMenu *parentMenu = &menu;
501 parentMenu = findUpwardsInMenus(key, subMenus);
502 if (!parentMenu) { parentMenu = &menu; }
506 QMenu *subMenu =
nullptr;
507 if (menus.isEmpty()) { subMenu = parentMenu->addMenu(menuAction.
getLastPathPart()); }
510 const CMenuAction menuFound(menus.first());
511 subMenu = parentMenu->addMenu(menuFound.getIcon(), menuFound.getTitle());
513 Q_ASSERT_X(subMenu, Q_FUNC_INFO,
"Could not create sub menu");
515 if (subMenu) { subMenu->setParent(parentMenu); }
517 if (pathDepth > 0 && subMenu) { subMenus.insert(key, subMenu); }
521 int CMenuActions::pathDepth(
const QString &path)
523 if (path.isEmpty()) {
return 0; }
524 int c = path.count(
'/');
525 return c > 0 ? c : 0;
528 QString CMenuActions::parentPath(
const QString ¤tPath)
530 if (!currentPath.contains(
'/')) {
return {}; }
531 const int i = currentPath.lastIndexOf(
'/');
532 return currentPath.left(i);
535 QString CMenuActions::keyRoot(
const QString &key)
537 const int i = key.lastIndexOf(
'.');
538 if (i < 0) {
return {}; }
542 bool CMenuActions::isSameKeyRoot(
const QString &key1,
const QString &key2)
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);
554 while (!k.isEmpty() && !menus.isEmpty())
556 if (menus.contains(k)) {
return menus[k]; }
CWebDataServices * getWebDataServices() const
Get the web data services.
bool hasSuccesfullyConnectedSwiftDb() const
Has already successfully connect swift DB?
Callable wrapper for a member function with function signature F.
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
Free functions in swift::misc.