361 lines
10 KiB
C++
361 lines
10 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_LAYOUTSAVER_P_H
|
|
#define KD_LAYOUTSAVER_P_H
|
|
|
|
#include "kddockwidgets/KDDockWidgets.h"
|
|
#include "kddockwidgets/LayoutSaver.h"
|
|
#include "kddockwidgets/core/Platform.h"
|
|
#include "core/Window_p.h"
|
|
#include "nlohmann_helpers_p.h"
|
|
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <map>
|
|
|
|
/**
|
|
* Bump whenever the format changes, so we can still load old layouts.
|
|
* version 1: Initial version
|
|
* version 2: Introduced MainWindow::screenSize and FloatingWindow::screenSize
|
|
* version 3: New layouting engine
|
|
*/
|
|
#define KDDOCKWIDGETS_SERIALIZATION_VERSION 3
|
|
|
|
|
|
namespace KDDockWidgets {
|
|
|
|
namespace Core {
|
|
class FloatingWindow;
|
|
class View;
|
|
}
|
|
|
|
class Positions;
|
|
class DockRegistry;
|
|
|
|
/// @brief A more granular version of KDDockWidgets::RestoreOption
|
|
/// There's some granularity that we don't want to expose to all users but want to allow some users
|
|
/// to use. We might make more options public once they've proven themselves, so for now they are
|
|
/// internal
|
|
enum class InternalRestoreOption {
|
|
None = 0,
|
|
SkipMainWindowGeometry = 1, ///< Don't reposition the main window's geometry when restoring.
|
|
RelativeFloatingWindowGeometry =
|
|
2 ///< FloatingWindow's are repositioned relatively to the new MainWindow's size
|
|
};
|
|
Q_DECLARE_FLAGS(InternalRestoreOptions, InternalRestoreOption)
|
|
|
|
|
|
struct LayoutSaver::Placeholder
|
|
{
|
|
typedef Vector<LayoutSaver::Placeholder> List;
|
|
|
|
bool isFloatingWindow;
|
|
int indexOfFloatingWindow;
|
|
int itemIndex;
|
|
QString mainWindowUniqueName;
|
|
};
|
|
|
|
///@brief contains info about how a main window is scaled.
|
|
/// Used for RestoreOption_RelativeToMainWindow
|
|
struct DOCKS_EXPORT LayoutSaver::ScalingInfo
|
|
{
|
|
ScalingInfo() = default;
|
|
explicit ScalingInfo(const QString &mainWindowId, Rect savedMainWindowGeo, int screenIndex);
|
|
|
|
bool isValid() const
|
|
{
|
|
return heightFactor > 0 && widthFactor > 0
|
|
&& !((fuzzyCompare(widthFactor, 1) && fuzzyCompare(heightFactor, 1)));
|
|
}
|
|
|
|
void translatePos(Point &) const;
|
|
void applyFactorsTo(Point &) const;
|
|
void applyFactorsTo(Size &) const;
|
|
void applyFactorsTo(Rect &) const;
|
|
|
|
QString mainWindowName;
|
|
Rect savedMainWindowGeometry;
|
|
Rect realMainWindowGeometry;
|
|
double heightFactor = -1;
|
|
double widthFactor = -1;
|
|
bool mainWindowChangedScreen = false;
|
|
};
|
|
|
|
struct DOCKS_EXPORT LayoutSaver::Position
|
|
{
|
|
Rect lastFloatingGeometry;
|
|
int tabIndex;
|
|
bool wasFloating;
|
|
LayoutSaver::Placeholder::List placeholders;
|
|
std::unordered_map<SideBarLocation, Rect> lastOverlayedGeometries;
|
|
|
|
/// Iterates through the layout and patches all absolute sizes. See
|
|
/// RestoreOption_RelativeToMainWindow.
|
|
void scaleSizes(const ScalingInfo &scalingInfo);
|
|
};
|
|
|
|
struct DOCKS_EXPORT LayoutSaver::DockWidget
|
|
{
|
|
// Using shared ptr, as we need to modify shared instances
|
|
typedef std::shared_ptr<LayoutSaver::DockWidget> Ptr;
|
|
typedef Vector<Ptr> List;
|
|
static std::map<QString, Ptr> s_dockWidgets;
|
|
|
|
bool isValid() const;
|
|
|
|
/// Iterates through the layout and patches all absolute sizes. See
|
|
/// RestoreOption_RelativeToMainWindow.
|
|
void scaleSizes(const ScalingInfo &scalingInfo);
|
|
|
|
static Ptr dockWidgetForName(const QString &name)
|
|
{
|
|
auto it = s_dockWidgets.find(name);
|
|
auto dw = it == s_dockWidgets.cend() ? nullptr : it->second;
|
|
if (dw)
|
|
return dw;
|
|
|
|
dw = Ptr(new LayoutSaver::DockWidget);
|
|
s_dockWidgets[name] = dw;
|
|
dw->uniqueName = name;
|
|
|
|
return dw;
|
|
}
|
|
|
|
bool skipsRestore() const;
|
|
|
|
QString uniqueName;
|
|
Vector<QString> affinities;
|
|
LayoutSaver::Position lastPosition;
|
|
CloseReason lastCloseReason;
|
|
#if defined(KDDW_FRONTEND_QT) && QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
QVariantMap userData;
|
|
#endif
|
|
|
|
private:
|
|
DockWidget()
|
|
{
|
|
}
|
|
};
|
|
|
|
inline Vector<QString> dockWidgetNames(const LayoutSaver::DockWidget::List &list)
|
|
{
|
|
Vector<QString> result;
|
|
result.reserve(list.size());
|
|
for (auto &dw : list)
|
|
result.push_back(dw->uniqueName);
|
|
|
|
return result;
|
|
}
|
|
|
|
struct DOCKS_EXPORT LayoutSaver::Group
|
|
{
|
|
bool isValid() const;
|
|
|
|
bool hasSingleDockWidget() const;
|
|
bool skipsRestore() const;
|
|
|
|
/// @brief in case this group only has one group, returns the name of that dock widget
|
|
LayoutSaver::DockWidget::Ptr singleDockWidget() const;
|
|
|
|
bool isNull = true;
|
|
QString objectName;
|
|
Rect geometry;
|
|
QFlags<FrameOption>::Int options;
|
|
int currentTabIndex;
|
|
QString id; // for coorelation purposes
|
|
|
|
/// Might be empty if not in a main window. Used so we don't create a group when restoring
|
|
/// the persistent central group, that's never deleted when restoring
|
|
QString mainWindowUniqueName;
|
|
|
|
LayoutSaver::DockWidget::List dockWidgets;
|
|
};
|
|
|
|
struct DOCKS_EXPORT LayoutSaver::MultiSplitter
|
|
{
|
|
bool isValid() const;
|
|
|
|
bool hasSingleDockWidget() const;
|
|
LayoutSaver::DockWidget::Ptr singleDockWidget() const;
|
|
bool skipsRestore() const;
|
|
|
|
nlohmann::json layout;
|
|
std::unordered_map<QString, LayoutSaver::Group> groups;
|
|
};
|
|
|
|
struct DOCKS_EXPORT LayoutSaver::FloatingWindow
|
|
{
|
|
typedef Vector<LayoutSaver::FloatingWindow> List;
|
|
|
|
bool isValid() const;
|
|
|
|
bool hasSingleDockWidget() const;
|
|
LayoutSaver::DockWidget::Ptr singleDockWidget() const;
|
|
bool skipsRestore() const;
|
|
|
|
/// Iterates through the layout and patches all absolute sizes. See
|
|
/// RestoreOption_RelativeToMainWindow.
|
|
void scaleSizes(const ScalingInfo &);
|
|
|
|
LayoutSaver::MultiSplitter multiSplitterLayout;
|
|
Vector<QString> affinities;
|
|
int parentIndex = -1;
|
|
Rect geometry;
|
|
Rect normalGeometry;
|
|
int screenIndex;
|
|
int flags = -1;
|
|
Size screenSize; // for relative-size restoring
|
|
bool isVisible = true;
|
|
|
|
// The instance that was created during a restore:
|
|
Core::FloatingWindow *floatingWindowInstance = nullptr;
|
|
KDDockWidgets::WindowState windowState = KDDockWidgets::WindowState::None;
|
|
};
|
|
|
|
struct DOCKS_EXPORT LayoutSaver::MainWindow
|
|
{
|
|
public:
|
|
typedef Vector<LayoutSaver::MainWindow> List;
|
|
|
|
bool isValid() const;
|
|
|
|
/// Iterates through the layout and patches all absolute sizes. See
|
|
/// RestoreOption_RelativeToMainWindow.
|
|
void scaleSizes();
|
|
|
|
Vector<QString> dockWidgetsForSideBar(SideBarLocation) const;
|
|
|
|
std::unordered_map<SideBarLocation, Vector<QString>> dockWidgetsPerSideBar;
|
|
KDDockWidgets::MainWindowOptions options;
|
|
LayoutSaver::MultiSplitter multiSplitterLayout;
|
|
QString uniqueName;
|
|
Vector<QString> affinities;
|
|
Rect geometry;
|
|
Rect normalGeometry;
|
|
int screenIndex;
|
|
Size screenSize; // for relative-size restoring
|
|
bool isVisible;
|
|
KDDockWidgets::WindowState windowState = KDDockWidgets::WindowState::None;
|
|
|
|
ScalingInfo scalingInfo;
|
|
};
|
|
|
|
///@brief we serialize some info about screens, so eventually we can make restore smarter when
|
|
/// switching screens
|
|
/// Not used currently, but nice to have in the json already
|
|
struct LayoutSaver::ScreenInfo
|
|
{
|
|
typedef Vector<LayoutSaver::ScreenInfo> List;
|
|
|
|
int index;
|
|
Rect geometry;
|
|
QString name;
|
|
double devicePixelRatio;
|
|
};
|
|
|
|
struct DOCKS_EXPORT LayoutSaver::Layout
|
|
{
|
|
public:
|
|
Layout()
|
|
{
|
|
assert(!s_currentLayoutBeingRestored);
|
|
s_currentLayoutBeingRestored = this;
|
|
|
|
const auto screens = Core::Platform::instance()->screens();
|
|
const auto numScreens = screens.size();
|
|
screenInfo.reserve(numScreens);
|
|
for (auto i = 0; i < numScreens; ++i) {
|
|
ScreenInfo info;
|
|
info.index = i;
|
|
info.geometry = screens[i]->geometry();
|
|
info.name = screens[i]->name();
|
|
info.devicePixelRatio = screens[i]->devicePixelRatio();
|
|
screenInfo.push_back(info);
|
|
}
|
|
}
|
|
|
|
~Layout()
|
|
{
|
|
s_currentLayoutBeingRestored = nullptr;
|
|
}
|
|
|
|
bool isValid() const;
|
|
|
|
QByteArray toJson() const;
|
|
bool fromJson(const QByteArray &jsonData);
|
|
|
|
/// Iterates through the layout and patches all absolute sizes. See
|
|
/// RestoreOption_RelativeToMainWindow.
|
|
void scaleSizes(KDDockWidgets::InternalRestoreOptions);
|
|
|
|
static LayoutSaver::Layout *s_currentLayoutBeingRestored;
|
|
|
|
LayoutSaver::MainWindow mainWindowForIndex(int index) const;
|
|
LayoutSaver::FloatingWindow floatingWindowForIndex(int index) const;
|
|
|
|
Vector<QString> mainWindowNames() const;
|
|
Vector<QString> dockWidgetNames() const;
|
|
Vector<QString> dockWidgetsToClose() const;
|
|
bool containsDockWidget(const QString &uniqueName) const;
|
|
|
|
int serializationVersion = KDDOCKWIDGETS_SERIALIZATION_VERSION;
|
|
LayoutSaver::MainWindow::List mainWindows;
|
|
LayoutSaver::FloatingWindow::List floatingWindows;
|
|
LayoutSaver::DockWidget::List closedDockWidgets;
|
|
LayoutSaver::DockWidget::List allDockWidgets;
|
|
ScreenInfo::List screenInfo;
|
|
|
|
private:
|
|
KDDW_DELETE_COPY_CTOR(Layout)
|
|
};
|
|
|
|
class DOCKS_EXPORT LayoutSaver::Private
|
|
{
|
|
public:
|
|
struct RAIIIsRestoring
|
|
{
|
|
RAIIIsRestoring();
|
|
~RAIIIsRestoring();
|
|
KDDW_DELETE_COPY_CTOR(RAIIIsRestoring)
|
|
};
|
|
|
|
explicit Private(RestoreOptions options);
|
|
|
|
static void restorePendingPositions(Core::DockWidget *);
|
|
|
|
bool matchesAffinity(const Vector<QString> &affinities) const;
|
|
void floatWidgetsWhichSkipRestore(const Vector<QString> &mainWindowNames);
|
|
void floatUnknownWidgets(const LayoutSaver::Layout &layout);
|
|
|
|
template<typename T>
|
|
void deserializeWindowGeometry(const T &saved, Core::Window::Ptr);
|
|
void deleteEmptyGroups() const;
|
|
void clearRestoredProperty();
|
|
|
|
DockRegistry *const m_dockRegistry;
|
|
InternalRestoreOptions m_restoreOptions = {};
|
|
Vector<QString> m_affinityNames;
|
|
|
|
/// If a layout is restored but the dock widget doesn't exist, we store its last position here
|
|
/// so when we create the dock widget we can finally restore
|
|
static std::unordered_map<QString, std::shared_ptr<KDDockWidgets::Positions>> s_unrestoredPositions;
|
|
|
|
/// Misc unrestored properties we might want to restore. Only CloseReason for now
|
|
/// TODO: If we keep needing to expose more stuff, we can just expose the entire LayoutSaver::Layout instead
|
|
static std::unordered_map<QString, CloseReason> s_unrestoredProperties;
|
|
|
|
static bool s_restoreInProgress;
|
|
};
|
|
}
|
|
|
|
#endif
|