/* This file is part of KDDockWidgets. SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sérgio Martins SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only Contact KDAB at for commercial licensing options. */ #pragma once #include "DockWidget.h" #include "kddockwidgets/KDDockWidgets.h" #include "kddockwidgets/LayoutSaver.h" #include "kddockwidgets/QtCompat_p.h" #include "kddockwidgets/core/Controller.h" #include "kddockwidgets/core/FocusScope.h" #include "kddockwidgets/docks_export.h" class TestDocks; namespace KDDockWidgets { class WidgetResizeHandler; } namespace KDDockWidgets::Core { class LayoutingGuest; class DropArea; class MDILayout; class DockWidget; class FloatingWindow; class MainWindow; class Stack; class TabBar; class TitleBar; class Item; class DOCKS_EXPORT Group : public Controller, public FocusScope { Q_OBJECT public: typedef Vector List; explicit Group(View *parent = nullptr, FrameOptions = FrameOption_None, int userType = 0); ~Group() override; static Group *deserialize(const LayoutSaver::Group &); LayoutSaver::Group serialize() const; ///@brief Adds a widget into the Group's Stack void addTab(DockWidget *, const InitialOption & = {}); ///@overload void addTab(Group *, const InitialOption & = {}); ///@overload void addTab(FloatingWindow *floatingWindow, const InitialOption & = {}); ///@brief Inserts a widget into the Group's TabWidget at @p index void insertWidget(DockWidget *, int index, const InitialOption & = {}); ///@brief removes a dockwidget from the group void removeWidget(DockWidget *); ///@brief detaches this dock widget FloatingWindow *detachTab(DockWidget *); ///@brief returns the index of the specified dock widget int indexOfDockWidget(const DockWidget *); ///@brief returns the index of the current tab int currentIndex() const; ///@brief sets the current tab index void setCurrentTabIndex(int index); ///@brief Sets the specified dock widget to be the current tab void setCurrentDockWidget(DockWidget *); ///@brief Inserts a dock widget into the specified index void insertDockWidget(DockWidget *, int index); /// @brief Returns the dock widget at @p index DockWidget *dockWidgetAt(int index) const; ///@brief Returns the current dock widget DockWidget *currentDockWidget() const; /// @brief returns the number of dock widgets inside the group int dockWidgetCount() const; /// @brief returns the tab widget Core::Stack *stack() const; Core::TabBar *tabBar() const; void updateTitleAndIcon(); void onDockWidgetTitleChanged(DockWidget *); void updateTitleBarVisibility(); void updateFloatingActions(); bool containsMouse(Point globalPos) const; Core::TitleBar *titleBar() const; Core::TitleBar *actualTitleBar() const; QString title() const; Icon icon() const; Vector dockWidgets() const; bool isTheOnlyGroup() const; ///@brief Returns whether this group is overlayed on top of the MainWindow (auto-hide feature); bool isOverlayed() const; ///@brief clears the FrameOption_IsOverlayed flag. /// For example, if you drag a side-bar overlay, then it becomes a normal floating window void unoverlay(); /** * @brief Returns whether this group is floating. A floating group isn't attached to any other * MainWindow, and if it's attached to a FloatingWindow then it's considered floating if it's * the only group in that Window. A floating group can have multiple dock widgets (tabbed), in * which case each DockWidget::isFloating() returns false, in which case you can use * isInFloatingWindow() which would still return true */ bool isFloating() const; /** * @brief Returns whether this group is in a FloatingWindow, as opposed to MainWindow. * * After setup it's equivalent to !isInMainWindow(). */ bool isInFloatingWindow() const; /** * @brief Returns whether this group is docked inside a MainWindow. */ bool isInMainWindow() const; /** * @brief returns if this widget is the central group * MainWindow supports a mode where the middle group is persistent even if no dock widget is * there. * * @return whether this widget is the central group in a main window */ bool isCentralGroup() const; /// @brief Returns whether you can DND dock widgets over this group and tab into it bool isDockable() const; /** * @brief whether the tab widget will always show tabs, even if there's only 1 dock widget * * While technically a non-floating dock widget is always tabbed, the user won't see the tabs * as in most cases there's only 1 widget tabbed. But for the main window central group it's * often wanted to see tabs even if there's only 1 widget, where each widget represents a * "document". * * @return whether the tab widget will always show tabs, even if there's only 1 dock widget */ bool alwaysShowsTabs() const; /// @brief returns whether the dockwidget @p w is inside this group bool containsDockWidget(DockWidget *w) const; ///@brief returns the FloatingWindow this group is in, if any FloatingWindow *floatingWindow() const; /** * @brief Returns the main window this group is in. * nullptr if not inside a main window. */ MainWindow *mainWindow() const; /** * @brief Puts the Group back in its previous main window position * * Usually DockWidget::Private::restoreToPreviousPosition() is used, but * when we have a floating group with tabs we just reuse the group instead of * moving the tabbed dock widgets one by one. */ void restoreToPreviousPosition(); int currentTabIndex() const; FrameOptions options() const; bool anyNonClosable() const; bool anyNonDockable() const; ///@brief returns whether there's 0 dock widgets. If not persistent then the Frame will delete /// itself. bool isEmpty() const { return dockWidgetCount() == 0; } ///@brief returns whether there's only 1 dock widget. bool hasSingleDockWidget() const { return dockWidgetCount() == 1; } ///@brief returns the layout item that either contains this Frame in the layout or is a /// placeholder Core::Item *layoutItem() const; ///@brief For tests-only. Returns the number of Frame instances in the whole application. static int dbg_numFrames(); /** * @brief Returns whether a deleteLater has already been issued */ bool beingDeletedLater() const; /** * @brief returns true if tabs are visible * * @sa hasTabsVisibleChanged() **/ bool hasTabsVisible() const; Vector affinities() const; ///@brief sets the layout item that either contains this Group in the layout or is a placeholder void setLayoutItem(Core::Item *item); /** * Returns the drag rect in global coordinates. This is usually the title bar rect. * However, when using Config::Flag_HideTitleBarWhenTabsVisible it will be the tab bar * background. Returns global coordinates. */ virtual Rect dragRect() const; ///@brief Returns whether all dock widgets have the specified option set bool allDockWidgetsHave(DockWidgetOption) const; ///@brief Returns whether at least one dock widget has the specified option set bool anyDockWidgetsHas(DockWidgetOption) const; ///@brief Returns whether all dock widgets have the specified layout saver option set bool allDockWidgetsHave(LayoutSaverOption) const; ///@brief Returns whether at least one dock widget has the specified layout saver option set bool anyDockWidgetsHas(LayoutSaverOption) const; /// @brief To allow resizing the overlayed dock widget (auto-hide feature) void setAllowedResizeSides(CursorPositions sides); /// @brief Returns whether this group is in a MDI layout /// Usually no, unless you're using an MDI main window bool isMDI() const; /// @brief Returns whether this group was created automatically just for the purpose of /// supporting DockWidgetOption_MDINestable bool isMDIWrapper() const; /// @brief If this is an MDI wrapper group, return the DockWidget MDI wrapper /// @sa isMDIWrapper DockWidget *mdiDockWidgetWrapper() const; /// @brief If this is an MDI wrapper group, return the DropArea MDI wrapper /// @sa isMDIWrapper DropArea *mdiDropAreaWrapper() const; /// @brief If this group is an MDI wrapper, returns the MDI group. That is the group you /// actually drag inside the MDI area Group *mdiFrame() const; /// @brief Returns the MDI layout. Or nullptr if this group isn't in a MDI layout MDILayout *mdiLayout() const; /// @brief If this group is a MDI group (isMDI() == true), returns whether it contains nested /// dock widgets (DockWidgetOption_MDINestable) /// @sa isMDI() bool hasNestedMDIDockWidgets() const; /// @brief See Core::DockWidget::userType() int userType() const; /// @brief Returns the resize handler. Used mostly in MDI mode. WidgetResizeHandler *resizeHandler() const; void renameTab(int index, const QString &); void changeTabIcon(int index, const Icon &); /// @brief Sets the Layout which this group is in void setLayout(Layout *); void onDockWidgetCountChanged(); /// @brief User requested floating window flags for when this group floats FloatingWindowFlags requestedFloatingWindowFlags() const; LayoutingGuest *asLayoutingGuest() const; /// Convenience that just calls close() on all its dock widgets /// Returns whether all dock widgets accepted the close bool close() const; /// Returns the group that's in the specified item static Core::Group *fromItem(const Core::Item *); static Core::Item *s_inFloatHack; protected: void isFocusedChangedCallback() override; void focusedWidgetChangedCallback() override; void setParentView_impl(View *parent) override; public: /** * @brief Returns the minimum size of the dock widgets. * This might be slightly smaller than Frame::minSize() due to the QTabWidget having some * margins and tab bar. */ Size dockWidgetsMinSize() const; /** * @brief Returns the biggest combined maxSize of all dock widgets. * * Example: * dock 1, max=2000x1000 * dock 2, max=3000x400 * dock3, max= * result=3000,1000 * * Any widget having 16777215x16777215 is ignored (represents not having a max-size, * QWIDGETSIZE_MAX) */ Size biggestDockWidgetMaxSize() const; int nonContentsHeight() const; class Private; Private *dptr() const; private: Private *const d; bool m_inCtor = true; // Needs to be initialized early, as pointed out by UBSAN protected: bool m_inDtor = false; Core::Stack *const m_stack; Core::TabBar *const m_tabBar; Core::TitleBar *const m_titleBar; #ifdef DOCKS_DEVELOPER_MODE public: #else private: #endif KDDW_DELETE_COPY_CTOR(Group) friend class ::TestDocks; friend class KDDockWidgets::Core::Stack; void scheduleDeleteLater(); void createMDIResizeHandler(); void onCloseEvent(CloseEvent *); Layout *m_layout = nullptr; WidgetResizeHandler *m_resizeHandler = nullptr; bool m_updatingTitleBar = false; bool m_beingDeleted = false; }; }