From b93e723a839b288a21b92b134d5ea0f41ae45d67 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 13 Sep 2018 22:19:13 +0200 Subject: [PATCH] Fixed problem in FloatingDockContainer.cpp that caused problem when dragging a maximized window, added support for sorted insertion of toggleView actions into vieMenu --- src/DockManager.cpp | 86 ++++++++++++++++++++++++++++++++++- src/DockManager.h | 57 ++++++++++++++++++++++- src/FloatingDockContainer.cpp | 13 +++++- 3 files changed, 150 insertions(+), 6 deletions(-) diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 8abc7f4..7811986 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -31,6 +31,8 @@ #include #include "DockManager.h" +#include + #include #include @@ -43,6 +45,7 @@ #include #include #include +#include #include "FloatingDockContainer.h" #include "DockOverlay.h" @@ -51,6 +54,8 @@ #include "DockStateSerialization.h" #include "DockAreaWidget.h" +#include + namespace ads { /** @@ -65,6 +70,9 @@ struct DockManagerPrivate CDockOverlay* DockAreaOverlay; QMap DockWidgetsMap; QMap Perspectives; + QMap ViewMenuGroups; + QMenu* ViewMenu; + CDockManager::eViewMenuInsertionOrder MenuInsertionOrder = CDockManager::MenuAlphabeticallySorted; /** * Private data constructor @@ -91,6 +99,11 @@ struct DockManagerPrivate * Loads the stylesheet */ void loadStylesheet(); + + /** + * Adds action to menu - optionally in sorted order + */ + void addActionToMenu(QAction* Action, QMenu* Menu, bool InsertSorted); }; // struct DockManagerPrivate @@ -197,6 +210,35 @@ bool DockManagerPrivate::restoreState(const QByteArray &state, int version, } +//============================================================================ +void DockManagerPrivate::addActionToMenu(QAction* Action, QMenu* Menu, bool InsertSorted) +{ + if (InsertSorted) + { + auto Actions = Menu->actions(); + auto it = std::find_if(Actions.begin(), Actions.end(), + [&Action](const QAction* a) + { + return a->text().compare(Action->text(), Qt::CaseInsensitive) > 0; + }); + + if (it == Actions.end()) + { + Menu->addAction(Action); + } + else + { + Menu->insertAction(*it, Action); + } + } + else + { + Menu->addAction(Action); + } +} + + + //============================================================================ CDockManager::CDockManager(QWidget *parent) : CDockContainerWidget(this, parent), @@ -208,6 +250,7 @@ CDockManager::CDockManager(QWidget *parent) : MainWindow->setCentralWidget(this); } + d->ViewMenu = new QMenu(tr("Show View"), this); d->DockAreaOverlay = new CDockOverlay(this, CDockOverlay::ModeDockAreaOverlay); d->ContainerOverlay = new CDockOverlay(this, CDockOverlay::ModeContainerOverlay); d->Containers.append(this); @@ -294,11 +337,11 @@ unsigned int CDockManager::zOrderIndex() const //============================================================================ -QByteArray CDockManager::saveState(int version) const +QByteArray CDockManager::saveState(eXmlMode XmlMode, int version) const { QByteArray xmldata; QXmlStreamWriter s(&xmldata); - s.setAutoFormatting(true); + s.setAutoFormatting(XmlAutoFormattingEnabled == XmlMode); s.writeStartDocument(); s.writeStartElement("QtAdvancedDockingSystem"); s.writeAttribute("Version", QString::number(version)); @@ -483,6 +526,45 @@ void CDockManager::loadPerspectives(QSettings& Settings) Settings.endArray(); } + +//============================================================================ +void CDockManager::addToggleViewActionToMenu(QAction* ToggleViewAction, + const QString& Group, const QIcon& GroupIcon) +{ + bool AlphabeticallySorted = (MenuAlphabeticallySorted == d->MenuInsertionOrder); + if (!Group.isEmpty()) + { + QMenu* GroupMenu = d->ViewMenuGroups.value(Group, 0); + if (!GroupMenu) + { + GroupMenu = new QMenu(Group, this); + GroupMenu->setIcon(GroupIcon); + d->addActionToMenu(GroupMenu->menuAction(), d->ViewMenu, AlphabeticallySorted); + d->ViewMenuGroups.insert(Group, GroupMenu); + } + + d->addActionToMenu(ToggleViewAction, GroupMenu, AlphabeticallySorted); + } + else + { + d->addActionToMenu(ToggleViewAction, d->ViewMenu, AlphabeticallySorted); + } +} + + +//============================================================================ +QMenu* CDockManager::viewMenu() const +{ + return d->ViewMenu; +} + + +//============================================================================ +void CDockManager::setViewMenuInsertionOrder(eViewMenuInsertionOrder Order) +{ + d->MenuInsertionOrder = Order; +} + } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockManager.h b/src/DockManager.h index 3b14214..e4c5abe 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -31,10 +31,12 @@ // INCLUDES //============================================================================ #include "DockContainerWidget.h" +#include #include "ads_globals.h" class QSettings; +class QMenu; namespace ads { @@ -100,6 +102,18 @@ protected: CDockOverlay* dockAreaOverlay() const; public: + enum eViewMenuInsertionOrder + { + MenuSortedByInsertion, + MenuAlphabeticallySorted + }; + + enum eXmlMode + { + XmlAutoFormattingDisabled, + XmlAutoFormattingEnabled + }; + /** * Default Constructor. * If the given parent is a QMainWindow, the dock manager sets itself as the @@ -170,9 +184,13 @@ public: /** * Saves the current state of the dockmanger and all its dock widgets - * into the returned QByteArray + * into the returned QByteArray. + * The XmlMode enables / disables the auto formatting for the XmlStreamWriter. + * If auto formatting is enabled, the output is intended and line wrapped. + * The XmlMode XmlAutoFormattingDisabled is better if you would like to have + * a more compact XML output - i.e. for storage in ini files. */ - QByteArray saveState(int version = 0) const; + QByteArray saveState(eXmlMode XmlMode = XmlAutoFormattingDisabled, int version = 0) const; /** * Restores the state of this dockmanagers dockwidgets. @@ -208,6 +226,41 @@ public: */ void loadPerspectives(QSettings& Settings); + /** + * Adds a toggle view action to the the internal view menu. + * You can either manage the insertion of the toggle view actions in your + * application or you can add the actions to the internal view menu and + * then simply insert the menu object into your. + * \param[in] ToggleViewAction The action to insert. If no group is provided + * the action is directly inserted into the menu. If a group + * is provided, the action is inserted into the group and the + * group is inserted into the menu if it is not existing yet. + * \param[in] Group This is the text used for the group menu item + * \param[in] GroupIcon The icon used for grouping the workbenches in the + * view menu. I.e. if there is a workbench for each device + * like for spectrometer devices, it is good to group all these + * workbenches under a menu item + */ + void addToggleViewActionToMenu(QAction* ToggleViewAction, + const QString& Group = QString(), const QIcon& GroupIcon = QIcon()); + + /** + * This function returns the internal view menu. + * To fill the view menu, you can use the addToggleViewActionToMenu() + * function. + */ + QMenu* viewMenu() const; + + /** + * Define the insertion order for toggle view menu items. + * The order defines how the actions are added to the view menu. + * The default insertion order is MenuAlphabeticallySorted to make it + * easier for users to find the menu entry for a certain dock widget. + * You need to call this function befor you insert the first menu item + * into the view menu. + */ + void setViewMenuInsertionOrder(eViewMenuInsertionOrder Order); + public slots: /** * Opens the perspective with the given name. diff --git a/src/FloatingDockContainer.cpp b/src/FloatingDockContainer.cpp index e381db7..4e869bb 100644 --- a/src/FloatingDockContainer.cpp +++ b/src/FloatingDockContainer.cpp @@ -379,8 +379,17 @@ bool CFloatingDockContainer::event(QEvent *e) case QEvent::Resize: // If the first event after the mouse press is a resize event, then - // the user resizes the window instead of dragging it around - d->setState(StateInactive); + // the user resizes the window instead of dragging it around. + // But there is one exception. If the window is maximized, + // then dragging the window via title bar will cause the widget to + // leave the maximized state. This in turn will trigger a resize event. + // To know, if the resize event was triggered by user via moving a + // corner of the window frame or if it was caused by a windows state + // change, we check, if we are not in maximized state. + if (!isMaximized()) + { + d->setState(StateInactive); + } break; default: