diff --git a/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.cpp b/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.cpp index 55918a7107..e181208629 100644 --- a/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.cpp +++ b/Plugins/org.blueberry.ui.qt/src/actions/berryMenuManager.cpp @@ -1,679 +1,679 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "berryMenuManager.h" #include "berryIContributionManagerOverrides.h" #include "berryQActionProperties.h" #include "berrySubContributionItem.h" #include #include class QMenuProxy { public: QMenu* menu; QMenuBar* menuBar; enum Type { MenuBar, Menu }; QMenuProxy(Type type, QWidget* parent = nullptr) : menu(nullptr), menuBar(nullptr) { switch (type) { - case MenuBar: menuBar = new QMenuBar(parent); - case Menu: menu = new QMenu(parent); + case MenuBar: menuBar = new QMenuBar(parent); break; + case Menu: menu = new QMenu(parent); break; } } bool isMenuBar() const { return menuBar != nullptr; } void setTitle(const QString& title) { if (menu) menu->setTitle(title); } void setIcon(const QIcon& icon) { if (menu) menu->setIcon(icon); } QList actions() const { return menu ? menu->actions() : menuBar->actions(); } void removeAction(QAction* action) { menu ? menu->removeAction(action) : menuBar->removeAction(action); } bool isEnabled() const { return menu ? menu->isEnabled() : menuBar->isEnabled(); } void setEnabled(bool enabled) { menu ? menu->setEnabled(enabled) : menuBar->setEnabled(enabled); } QAction* getParentItem() const { return menu ? menu->menuAction() : nullptr; } }; namespace berry { struct NullOverrides: public IContributionManagerOverrides { public: int GetEnabled(const IContributionItem* /*item*/) const override { return -1; } int GetVisible(const IContributionItem* /*item*/) const override { return -1; } }; void MenuManager::HandleAboutToShow() { if (this->removeAllWhenShown) { this->RemoveAll(); } emit AboutToShow(this); this->Update(false, false); } void MenuManager::HandleAboutToHide() { emit AboutToHide(this); } MenuManager::MenuManager(const QString& text, const QString& id) : id(id), menu(nullptr), menuItem(nullptr) , menuText(text), parent(nullptr) , removeAllWhenShown(false), visible(true) { } MenuManager::MenuManager(const QString& text, const QIcon& image, const QString& id) : id(id), menu(nullptr), menuItem(nullptr) , menuText(text), image(image) , parent(nullptr), removeAllWhenShown(false), visible(true) { } bool MenuManager::IsDirty() const { return ContributionManager::IsDirty(); } MenuManager::~MenuManager() { delete menu; } QMenu* MenuManager::CreateContextMenu(QWidget* parent) { if (!menu) { menu = new QMenuProxy(QMenuProxy::Menu, parent); this->InitializeMenu(); } return menu->menu; } QMenuBar* MenuManager::CreateMenuBar(QWidget* parent) { if (!menu) { menu = new QMenuProxy(QMenuProxy::MenuBar, parent); this->Update(false); } return menu->menuBar; } void MenuManager::AddMenuListener(QObject* listener) { this->connect(this, SIGNAL(AboutToShow(IMenuManager*)), listener, SLOT(MenuAboutToShow(IMenuManager*))); this->connect(this, SIGNAL(AboutToHide(IMenuManager*)), listener, SLOT(MenuAboutToHide(IMenuManager*))); } void MenuManager::RemoveMenuListener(QObject* listener) { this->disconnect(listener); } void MenuManager::Fill(QStatusBar* /*parent*/) { } void MenuManager::Fill(QToolBar* /*parent*/, QAction* /*before*/) { } void MenuManager::Fill(QMenu* parent, QAction* before) { this->FillMenu(parent, before); } void MenuManager::Fill(QMenuBar* parent, QAction* before) { this->FillMenu(parent, before); } void MenuManager::FillMenu(QWidget* parent, QAction* before) { if (!menuItem) { menuItem = new QAction(parent); if (parent) { parent->insertAction(before, menuItem); } menuItem->setText(GetMenuText()); menuItem->setIcon(image); if(!menu) { menu = new QMenuProxy(QMenuProxy::Menu, parent); } if (!menu->isMenuBar()) menuItem->setMenu(menu->menu); this->InitializeMenu(); this->SetDirty(true); } } IMenuManager::Pointer MenuManager::FindMenuUsingPath(const QString& path) const { IContributionItem::Pointer item(this->FindUsingPath(path)); if (IMenuManager::Pointer manager = item.Cast()) { return manager; } return IMenuManager::Pointer(nullptr); } IContributionItem::Pointer MenuManager::FindUsingPath(const QString& path) const { QString id(path); QString rest; int separator = path.indexOf('/'); if (separator != -1) { id = path.left(separator); rest = path.mid(separator + 1); } else { return ContributionManager::Find(path); } IContributionItem::Pointer item(ContributionManager::Find(id)); if (IMenuManager::Pointer manager = item.Cast()) { return manager->FindUsingPath(rest); } return IContributionItem::Pointer(nullptr); } QString MenuManager::GetId() const { return id; } QMenu* MenuManager::GetMenu() const { return menu->menu; } QString MenuManager::GetMenuText() const { if (definitionId == "") { return menuText; } // ExternalActionManager::ICallback callback = ExternalActionManager // .getInstance().getCallback(); // if (callback != null) // { // String shortCut = callback.getAcceleratorText(definitionId); // if (shortCut == null) // { // return menuText; // } // return menuText + "\t" + shortCut; //$NON-NLS-1$ // } return menuText; } QIcon MenuManager::GetImage() const { return image; } SmartPointer MenuManager::GetOverrides() { if (!overrides) { if (!parent) { overrides = new NullOverrides(); } else { overrides = parent->GetOverrides(); } ContributionManager::SetOverrides(overrides); } return overrides; } IContributionManager* MenuManager::GetParent() const { return parent; } bool MenuManager::GetRemoveAllWhenShown() const { return removeAllWhenShown; } bool MenuManager::IsDynamic() const { return false; } bool MenuManager::IsEnabled() const { return true; } bool MenuManager::IsGroupMarker() const { return false; } bool MenuManager::IsSeparator() const { return false; } bool MenuManager::IsVisible() const { if (!visible) { return false; // short circuit calculations in this case } if (removeAllWhenShown) { // we have no way of knowing if the menu has children return true; } // menus aren't visible if all of its children are invisible (or only contains visible separators). bool visibleChildren = false; foreach(IContributionItem::Pointer item, this->GetItems()) { if (item->IsVisible() && !item->IsSeparator()) { visibleChildren = true; break; } } return visibleChildren; } void MenuManager::MarkDirty() { ContributionManager::MarkDirty(); // Can't optimize by short-circuiting when the first dirty manager is encountered, // since non-visible children are not even processed. // That is, it's possible to have a dirty sub-menu under a non-dirty parent menu // even after the parent menu has been updated. // If items are added/removed in the sub-menu, we still need to propagate the dirty flag up, // even if the sub-menu is already dirty, since the result of isVisible() may change // due to the added/removed items. IContributionManager* p = this->GetParent(); if (p) { p->MarkDirty(); } } void MenuManager::SaveWidgetState() { } void MenuManager::SetOverrides(SmartPointer newOverrides) { overrides = newOverrides; ContributionManager::SetOverrides(overrides); } void MenuManager::SetParent(IContributionManager* manager) { parent = manager; } void MenuManager::SetRemoveAllWhenShown(bool removeAll) { this->removeAllWhenShown = removeAll; } void MenuManager::SetVisible(bool visible) { this->visible = visible; } void MenuManager::SetCommandId(const QString& definitionId) { this->definitionId = definitionId; } void MenuManager::Update() { this->UpdateMenuItem(); } void MenuManager::Update(const QString& property) { QList items = GetItems(); for (int i = 0; i < items.size(); i++) { items[i]->Update(property); } if (menu != nullptr && menu->getParentItem() != nullptr) { if (QActionProperties::TEXT == property) { QString text = GetMenuText(); if (!text.isNull()) { menu->getParentItem()->setText(text); } } else if (QActionProperties::IMAGE == property && !image.isNull()) { menu->getParentItem()->setIcon(image); } } } void MenuManager::Update(bool force) { this->Update(force, false); } void MenuManager::UpdateAll(bool force) { this->Update(force, true); } void MenuManager::InitializeMenu() { menu->setTitle(GetMenuText()); menu->setIcon(GetImage()); if (!menu->isMenuBar()) { this->connect(menu->menu, SIGNAL(aboutToShow()), SLOT(HandleAboutToShow())); this->connect(menu->menu, SIGNAL(aboutToHide()), SLOT(HandleAboutToHide())); } // Don't do an update(true) here, in case menu is never opened. // Always do it lazily in handleAboutToShow(). } void MenuManager::UpdateMenuItem() { if (menuItem && menu) { bool enabled = removeAllWhenShown || menu->actions().size() > 0; if (menu->isEnabled() != enabled) { menuItem->setEnabled(enabled); } } } void MenuManager::DoItemFill(IContributionItem::Pointer ci, QAction* before) { if (menu->isMenuBar()) { ci->Fill(menu->menuBar, before); } else { ci->Fill(menu->menu, before); } } void MenuManager::Update(bool force, bool recursive) { if (ContributionManager::IsDirty() || force) { if (menu) { // clean contains all active items without double separators QList items = this->GetItems(); QList clean; IContributionItem::Pointer separator; foreach (IContributionItem::Pointer ci, items) { if (!ci->IsVisible()) { continue; } if (ci->IsSeparator()) { // delay creation until necessary // (handles both adjacent separators, and separator at end) separator = ci; } else { if (separator) { if (clean.size() > 0) { clean.push_back(separator); } separator = nullptr; } clean.push_back(ci); } } // remove obsolete (removed or non active) QList mi = menu->actions(); for (int i = 0; i < mi.size(); i++) { Object::Pointer data = mi[i]->data().value(); if (!data || !clean.contains(data.Cast())) { menu->removeAction(mi[i]); } else if (IContributionItem::Pointer ci = data.Cast()) { if(ci->IsDynamic() && ci->IsDirty()) { menu->removeAction(mi[i]); delete mi[i]; } } } // add new mi = menu->actions(); int srcIx = 0; int destIx = 0; for (QList::Iterator e = clean.begin(); e != clean.end(); ++e) { IContributionItem::Pointer src(*e); IContributionItem::Pointer dest; // get corresponding item in widget if (srcIx < mi.size()) { dest = mi[srcIx]->data().value().Cast(); } else { dest = nullptr; } if (dest && src == dest) { srcIx++; destIx++; } else if (dest && dest->IsSeparator() && src->IsSeparator()) { mi[srcIx]->setData(QVariant::fromValue(src)); srcIx++; destIx++; } else { int start = menu->actions().size(); //qDebug() << "***** Filling item destIx = " << destIx << " (size: " << start << ")"; this->DoItemFill(src, destIx >= start ? nullptr : menu->actions().at(destIx)); int newItems = menu->actions().size() - start; //qDebug() << "***** New items: " << newItems; for (int i = 0; i < newItems; ++i) { menu->actions().at(destIx++)->setData(QVariant::fromValue(src)); } } // May be we can optimize this call. If the menu has just // been created via the call src.fill(fMenuBar, destIx) then // the menu has already been updated with update(true) // (see MenuManager). So if force is true we do it again. But // we can't set force to false since then information for the // sub sub menus is lost. if (recursive) { IContributionItem::Pointer item(src); if (SubContributionItem::Pointer subItem = item.Cast()) { item = subItem->GetInnerItem(); } if (IMenuManager::Pointer mm = item.Cast()) { mm->UpdateAll(force); } } } // remove any old menu items not accounted for for (; srcIx < mi.size(); srcIx++) { menu->removeAction(mi[srcIx]); delete mi[srcIx]; } this->SetDirty(false); } } else { // I am not dirty. Check if I must recursivly walk down the hierarchy. if (recursive) { foreach (IContributionItem::Pointer ci, this->GetItems()) { if (IMenuManager::Pointer mm = ci.Cast()) { if (mm->IsVisible()) { mm->UpdateAll(force); } } } } } this->UpdateMenuItem(); } void MenuManager::DumpActionInfo(QMenuProxy* menu) { if (menu->isMenuBar()) { //qDebug() << "QMenuBar [" << menu->menuBar << "]"; DumpActionInfo(menu->menuBar, 1); } else { //qDebug() << "QMenu [" << menu->menu << "]" << menu->menu; DumpActionInfo(menu->menu, 1); } } void MenuManager::DumpActionInfo(QWidget* widget, int level) { QString indent = " |"; for (int i = 0; i < level; ++i) indent += "--"; foreach(QAction* action, widget->actions()) { qDebug() << qPrintable(indent) << action->text() << "[" << action << "]"; if (action->menu()) { DumpActionInfo(action->menu(), level+1); } } } }