2026-04-06 00:20:51 -05:00

312 lines
9.9 KiB
C++

/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#ifndef KD_DOCKWIDGET_P_H
#define KD_DOCKWIDGET_P_H
#include "DockWidget.h"
#include "DockRegistry.h"
#include "core/Position_p.h"
#include "Action.h"
#include "core/View_p.h"
#include "QtCompat_p.h"
namespace KDDockWidgets {
namespace Core {
class SideBar;
class DOCKS_EXPORT_FOR_UNIT_TESTS DockWidget::Private
{
public:
/// RAII class to help updating actions exactly once, otherwise they can be triggered in the
/// middle of operations during reparenting
struct UpdateActions
{
explicit UpdateActions(Core::DockWidget *dock)
: dw(dock)
{
dw->d->m_willUpdateActions++;
}
~UpdateActions()
{
dw->d->m_willUpdateActions--;
// only the last one (the outer one, updates actions, in case of nesting)
if (dw->d->m_willUpdateActions == 0) {
dw->d->updateFloatAction();
if (dw->isOpen() != dw->toggleAction()->isChecked())
dw->d->updateToggleAction();
}
}
private:
KDDW_DELETE_COPY_CTOR(UpdateActions)
Core::DockWidget *const dw;
};
Private(const QString &dockName, DockWidgetOptions options_,
LayoutSaverOptions layoutSaverOptions_, DockWidget *qq);
~Private();
void init()
{
updateTitle();
q->view()->d->closeRequested.connect([this](CloseEvent *ev) { onCloseEvent(ev); });
}
/**
* @brief returns the FloatingWindow this dock widget is in. If nullptr then it's in a
* MainWindow.
*
* Note: Being in a FloatingWindow doesn't necessarily mean @ref isFloating() returns true, as
* the dock widget might be in a floating window with other dock widgets side by side.
*/
Core::FloatingWindow *floatingWindow() const
{
if (auto fw = q->view()->rootView()->asFloatingWindowController())
return fw;
return nullptr;
}
MainWindow *mainWindow() const
{
if (q->view()->isRootView())
return nullptr;
// Note: Don't simply use window(), as the MainWindow might be embedded into something else
auto p = q->view()->parentView();
while (p) {
if (auto mw = p->asMainWindowController())
return mw;
if (p->isRootView())
return nullptr;
p = p->parentView();
}
return nullptr;
}
Core::SideBar *sideBar() const
{
return DockRegistry::self()->sideBarForDockWidget(q);
}
///@brief adds the current layout item containing this dock widget
void addPlaceholderItem(Core::Item *);
///@brief returns the last position, just for tests.
Positions::Ptr &lastPosition();
void forceClose();
Point defaultCenterPosForFloating();
void onWindowActivated(std::shared_ptr<View> rootView);
void onWindowDeactivated(std::shared_ptr<View> rootView);
void updateTitle();
void toggle(bool enabled);
void updateToggleAction();
void updateFloatAction();
void close();
bool restoreToPreviousPosition();
void maybeRestoreToPreviousPosition();
int currentTabIndex() const;
void onCloseEvent(CloseEvent *);
void onParentChanged();
/**
* @brief Serializes this dock widget into an intermediate form
*/
std::shared_ptr<LayoutSaver::DockWidget> serialize() const;
/**
* @brief the Group which contains this dock widgets.
*
* A group wraps a docked DockWidget, giving it a TabWidget so it can accept other dock widgets.
* Frame is also the actual class that goes into a Layout.
*
* It's nullptr immediately after creation.
*/
Core::Group *group() const;
/**
* Returns the Layout Item this DockWidget is in.
* Can be nullptr.
*/
Core::Item *item() const;
///@brief If this dock widget is floating, then it saves its geometry
void saveLastFloatingGeometry();
/**
* Before floating a dock widget we save its position. So it can be restored when calling
* DockWidget::setFloating(false)
*/
void saveTabIndex();
/**
* @brief Creates a FloatingWindow and adds itself into it
* @return the created FloatingWindow
*/
Core::FloatingWindow *morphIntoFloatingWindow();
/// @brief calls morphIntoFloatingWindow() if the dock widget is visible and is a top-level
/// This is called delayed whenever we show a floating dock widget, so we get a FloatingWindow
void maybeMorphIntoFloatingWindow();
/// @brief Returns the mdi layout this dock widget is in, if any.
MDILayout *mdiLayout() const;
/// @brief Returns if this is an helper DockWidget created automatically to host a drop area
/// inside MDI This is only used by the DockWidgetOption_MDINestable feature
bool isMDIWrapper() const;
/// @brief If this dock widget is an MDI wrapper (isMDIWrapper()), then returns the wrapper drop
/// area
DropArea *mdiDropAreaWrapper() const;
/// @brief If this dock widget is inside a drop area nested in MDI then returns the wrapper dock
/// widget This goes up the hierarchy, while mdiDropAreaWrapper goes down.
DockWidget *mdiDockWidgetWrapper() const;
void setIsOpen(bool);
///@brief signal emitted when the icon changed
KDBindings::Signal<> iconChanged;
///@brief signal emitted when the title changed
///@param title the new title
KDBindings::Signal<QString> titleChanged;
/// @brief emitted when the hosted guest widget changed
KDBindings::Signal<> guestViewChanged;
///@brief emitted when the options change
///@sa setOptions(), options()
///@param options
KDBindings::Signal<KDDockWidgets::DockWidgetOptions> optionsChanged;
///@brief emitted when isFocused changes
///@sa isFocused
///@param isFocused
KDBindings::Signal<bool> isFocusedChanged;
///@brief emitted when isOverlayed changes
///@sa isOverlayed
///@param isOverlayed
KDBindings::Signal<bool> isOverlayedChanged;
///@brief emitted when isFloating changes
///@param isFloating
KDBindings::Signal<bool> isFloatingChanged;
/// Emitted when userData changes
KDBindings::Signal<> userDataChanged;
///@brief emitted when this dock widget is removed from a side-bar.
/// Only relevant for the auto-hide/sidebar feature
KDBindings::Signal<> removedFromSideBar;
///@brief Emitted when the top-level window this dock widget is in is activated or deactivated
/// This is convenience to replace tracking dockWidget->window(), since the window changes when
/// docking and undocking
///
/// It's called 'aboutTo' because it's done in an event filter and the target window doesn't
/// have it's 'activeWindow' property updated yet at this point.
/// @param activated
KDBindings::Signal<bool> windowActiveAboutToChange;
///@brief Emitted when the title bar that serves this dock widget changes
KDBindings::Signal<> actualTitleBarChanged;
/// @brief Emitted when this dock widget is about to be deleted due to Option_DeleteOnClose
KDBindings::Signal<> aboutToDeleteOnClose;
/// @brief Emitted when this dock widget is about to be deleted
/// @param dockWidget
KDBindings::Signal<KDDockWidgets::Core::DockWidget *> aboutToDelete;
/// @brief Emitted when a dock widget is closed
/// This is equivalent to the openedChanged(false) signal
KDBindings::Signal<> closed;
/// @brief Emitted when a dock widget is opened or closed
/// For the false case, closed() is also emitted
/// @param isOpen
KDBindings::Signal<bool> isOpenChanged;
/// @brief Emitted when a dock widget becomes current or not in its tab group
/// @param isCurrent true if it became current
KDBindings::Signal<bool> isCurrentTabChanged;
/// Each dock widget has a unique name which is used for layout save/restore
QString uniqueName() const;
/// Sets the dock widget unique name.
/// DockWidgets have their name set once (passed in ctor), therefore this method doesn't need
/// to be called, unless you know what you're doing (like reusing dock widgets during restore)
void setUniqueName(const QString &);
private:
// Go through the setter
QString m_uniqueName;
public:
Vector<QString> affinities;
QString title;
Icon titleBarIcon;
Icon tabBarIcon;
std::shared_ptr<View> guest;
DockWidget *const q;
DockWidgetOptions options;
FloatingWindowFlags m_flags = FloatingWindowFlag::FromGlobalConfig;
const LayoutSaverOptions layoutSaverOptions;
Action *const toggleAction;
Action *const floatAction;
Positions::Ptr m_lastPositions = std::make_shared<Positions>();
bool m_isPersistentCentralDockWidget = false;
bool m_processingToggleAction = false;
bool m_updatingToggleAction = false;
bool m_updatingFloatAction = false;
bool m_isForceClosing = false;
bool m_isMovingToSideBar = false;
bool m_isSettingCurrent = false;
bool m_isOpen = false;
bool m_inOpenSetter = false;
bool m_inClose = false;
bool m_inCloseEvent = false;
bool m_removingFromOverlay = false;
bool m_wasRestored = false;
Size m_lastOverlayedSize = Size(0, 0);
int m_userType = 0;
int m_willUpdateActions = 0;
KDBindings::ScopedConnection m_windowActivatedConnection;
KDBindings::ScopedConnection m_windowDeactivatedConnection;
KDBindings::ScopedConnection m_toggleActionConnection;
KDBindings::ScopedConnection m_floatActionConnection;
CloseReason m_lastCloseReason = CloseReason::Unspecified;
#if defined(KDDW_FRONTEND_QT) && QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QVariantMap m_userData;
#endif
};
}
}
#endif