KDDockWidgets API Documentation  1.6
LayoutSaver.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KDDockWidgets.
3 
4  SPDX-FileCopyrightText: 2019-2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5  Author: SĂ©rgio Martins <sergio.martins@kdab.com>
6 
7  SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
8 
9  Contact KDAB at <info@kdab.com> for commercial licensing options.
10 */
11 
19 #include "LayoutSaver.h"
20 #include "Config.h"
21 #include "MainWindowBase.h"
22 #include "DockWidgetBase.h"
23 #include "FrameworkWidgetFactory.h"
24 
25 #include "private/multisplitter/Item_p.h"
26 #include "private/LayoutSaver_p.h"
27 #include "private/DockRegistry_p.h"
28 #include "private/DockWidgetBase_p.h"
29 #include "private/FloatingWindow_p.h"
30 #include "private/Frame_p.h"
31 #include "private/LayoutWidget_p.h"
32 #include "private/Logging_p.h"
33 #include "private/Position_p.h"
34 #include "private/Utils_p.h"
35 
36 #include <qmath.h>
37 #include <QDebug>
38 #include <QFile>
39 
60 using namespace KDDockWidgets;
61 
62 QHash<QString, LayoutSaver::DockWidget::Ptr> LayoutSaver::DockWidget::s_dockWidgets;
63 LayoutSaver::Layout *LayoutSaver::Layout::s_currentLayoutBeingRestored = nullptr;
64 
65 
66 inline InternalRestoreOptions internalRestoreOptions(RestoreOptions options)
67 {
68  if (options == RestoreOption_None) {
69  return InternalRestoreOption::None;
70  } else if (options == RestoreOption_RelativeToMainWindow) {
71  return InternalRestoreOptions(InternalRestoreOption::SkipMainWindowGeometry)
72  | InternalRestoreOption::RelativeFloatingWindowGeometry;
73  } else {
74  qWarning() << Q_FUNC_INFO << "Unknown options" << options;
75  return {};
76  }
77 }
78 
79 bool LayoutSaver::Private::s_restoreInProgress = false;
80 
81 static QVariantList stringListToVariant(const QStringList &strs)
82 {
83  QVariantList variantList;
84  variantList.reserve(strs.size());
85  for (const QString &str : strs)
86  variantList.push_back(str);
87 
88  return variantList;
89 }
90 
91 static QStringList variantToStringList(const QVariantList &variantList)
92 {
93  QStringList stringList;
94  stringList.reserve(variantList.size());
95  for (const QVariant &variant : variantList)
96  stringList.push_back(variant.toString());
97 
98  return stringList;
99 }
100 
101 LayoutSaver::LayoutSaver(RestoreOptions options)
102  : d(new Private(options))
103 {
104 }
105 
107 {
108  delete d;
109 }
110 
111 bool LayoutSaver::saveToFile(const QString &jsonFilename)
112 {
113  const QByteArray data = serializeLayout();
114 
115  QFile f(jsonFilename);
116  if (!f.open(QIODevice::WriteOnly)) {
117  qWarning() << Q_FUNC_INFO << "Failed to open" << jsonFilename << f.errorString();
118  return false;
119  }
120 
121  f.write(data);
122  return true;
123 }
124 
125 bool LayoutSaver::restoreFromFile(const QString &jsonFilename)
126 {
127  QFile f(jsonFilename);
128  if (!f.open(QIODevice::ReadOnly)) {
129  qWarning() << Q_FUNC_INFO << "Failed to open" << jsonFilename << f.errorString();
130  return false;
131  }
132 
133  const QByteArray data = f.readAll();
134  const bool result = restoreLayout(data);
135 
136  return result;
137 }
138 
140 {
141  if (!d->m_dockRegistry->isSane()) {
142  qWarning() << Q_FUNC_INFO << "Refusing to serialize this layout. Check previous warnings.";
143  return {};
144  }
145 
146  LayoutSaver::Layout layout;
147 
148  // Just a simplification. One less type of windows to handle.
149  d->m_dockRegistry->ensureAllFloatingWidgetsAreMorphed();
150 
151  const MainWindowBase::List mainWindows = d->m_dockRegistry->mainwindows();
152  layout.mainWindows.reserve(mainWindows.size());
153  for (MainWindowBase *mainWindow : mainWindows) {
154  if (d->matchesAffinity(mainWindow->affinities()))
155  layout.mainWindows.push_back(mainWindow->serialize());
156  }
157 
158  const QVector<KDDockWidgets::FloatingWindow *> floatingWindows = d->m_dockRegistry->floatingWindows();
159  layout.floatingWindows.reserve(floatingWindows.size());
160  for (KDDockWidgets::FloatingWindow *floatingWindow : floatingWindows) {
161  if (d->matchesAffinity(floatingWindow->affinities()))
162  layout.floatingWindows.push_back(floatingWindow->serialize());
163  }
164 
165  // Closed dock widgets also have interesting things to save, like geometry and placeholder info
166  const DockWidgetBase::List closedDockWidgets = d->m_dockRegistry->closedDockwidgets();
167  layout.closedDockWidgets.reserve(closedDockWidgets.size());
168  for (DockWidgetBase *dockWidget : closedDockWidgets) {
169  if (d->matchesAffinity(dockWidget->affinities()))
170  layout.closedDockWidgets.push_back(dockWidget->d->serialize());
171  }
172 
173  // Save the placeholder info. We do it last, as we also restore it last, since we need all items to be created
174  // before restoring the placeholders
175 
176  const DockWidgetBase::List dockWidgets = d->m_dockRegistry->dockwidgets();
177  layout.allDockWidgets.reserve(dockWidgets.size());
178  for (DockWidgetBase *dockWidget : dockWidgets) {
179  if (d->matchesAffinity(dockWidget->affinities())) {
180  auto dw = dockWidget->d->serialize();
181  dw->lastPosition = dockWidget->d->lastPosition()->serialize();
182  layout.allDockWidgets.push_back(dw);
183  }
184  }
185 
186  return layout.toJson();
187 }
188 
190 {
191  d->clearRestoredProperty();
192  if (data.isEmpty())
193  return true;
194 
195  struct FrameCleanup
196  {
197  FrameCleanup(LayoutSaver *saver)
198  : m_saver(saver)
199  {
200  }
201 
202  ~FrameCleanup()
203  {
204  m_saver->d->deleteEmptyFrames();
205  }
206 
207  LayoutSaver *const m_saver;
208  };
209 
210  FrameCleanup cleanup(this);
211  LayoutSaver::Layout layout;
212  if (!layout.fromJson(data)) {
213  qWarning() << Q_FUNC_INFO << "Failed to parse json data";
214  return false;
215  }
216 
217  if (!layout.isValid()) {
218  return false;
219  }
220 
221  layout.scaleSizes(d->m_restoreOptions);
222 
223  d->floatWidgetsWhichSkipRestore(layout.mainWindowNames());
224  d->floatUnknownWidgets(layout);
225 
226  Private::RAIIIsRestoring isRestoring;
227 
228  // Hide all dockwidgets and unparent them from any layout before starting restore
229  // We only close the stuff that the loaded JSON knows about. Unknown widgets might be newer.
230 
231  d->m_dockRegistry->clear(d->m_dockRegistry->dockWidgets(layout.dockWidgetsToClose()),
232  d->m_dockRegistry->mainWindows(layout.mainWindowNames()),
233  d->m_affinityNames);
234 
235  // 1. Restore main windows
236  for (const LayoutSaver::MainWindow &mw : qAsConst(layout.mainWindows)) {
237  MainWindowBase *mainWindow = d->m_dockRegistry->mainWindowByName(mw.uniqueName);
238  if (!mainWindow) {
239  if (auto mwFunc = Config::self().mainWindowFactoryFunc()) {
240  mainWindow = mwFunc(mw.uniqueName);
241  } else {
242  qWarning() << "Failed to restore layout create MainWindow with name" << mw.uniqueName << "first";
243  return false;
244  }
245  }
246 
247  if (!d->matchesAffinity(mainWindow->affinities()))
248  continue;
249 
250  if (!(d->m_restoreOptions & InternalRestoreOption::SkipMainWindowGeometry)) {
251  d->deserializeWindowGeometry(mw, mainWindow->window()); // window(), as the MainWindow can be embedded
252  if (mw.windowState != Qt::WindowNoState) {
253  if (auto w = mainWindow->windowHandle()) {
254  w->setWindowState(mw.windowState);
255  }
256  }
257  }
258 
259  if (!mainWindow->deserialize(mw))
260  return false;
261  }
262 
263  // 2. Restore FloatingWindows
264  for (LayoutSaver::FloatingWindow &fw : layout.floatingWindows) {
265  if (!d->matchesAffinity(fw.affinities) || fw.skipsRestore())
266  continue;
267 
268  MainWindowBase *parent = fw.parentIndex == -1 ? nullptr
269  : DockRegistry::self()->mainwindows().at(fw.parentIndex);
270 
271  auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(parent);
272  fw.floatingWindowInstance = floatingWindow;
273  d->deserializeWindowGeometry(fw, floatingWindow);
274  if (!floatingWindow->deserialize(fw)) {
275  qWarning() << Q_FUNC_INFO << "Failed to deserialize floating window";
276  return false;
277  }
278  }
279 
280  // 3. Restore closed dock widgets. They remain closed but acquire geometry and placeholder properties
281  for (const auto &dw : qAsConst(layout.closedDockWidgets)) {
282  if (d->matchesAffinity(dw->affinities)) {
283  DockWidgetBase::deserialize(dw);
284  }
285  }
286 
287  // 4. Restore the placeholder info, now that the Items have been created
288  for (const auto &dw : qAsConst(layout.allDockWidgets)) {
289  if (!d->matchesAffinity(dw->affinities))
290  continue;
291 
292  if (DockWidgetBase *dockWidget =
293  d->m_dockRegistry->dockByName(dw->uniqueName, DockRegistry::DockByNameFlag::ConsultRemapping)) {
294  dockWidget->d->lastPosition()->deserialize(dw->lastPosition);
295  } else {
296  qWarning() << Q_FUNC_INFO << "Couldn't find dock widget" << dw->uniqueName;
297  }
298  }
299 
300  return true;
301 }
302 
303 void LayoutSaver::setAffinityNames(const QStringList &affinityNames)
304 {
305  d->m_affinityNames = affinityNames;
306  if (affinityNames.contains(QString())) {
307  // Any window with empty affinity will also be subject to save/restore
308  d->m_affinityNames << QString();
309  }
310 }
311 
312 LayoutSaver::Private *LayoutSaver::dptr() const
313 {
314  return d;
315 }
316 
318 {
319  const DockWidgetBase::List &allDockWidgets = DockRegistry::self()->dockwidgets();
320  DockWidgetBase::List result;
321  result.reserve(allDockWidgets.size());
322  for (DockWidgetBase *dw : allDockWidgets) {
323  if (dw->property("kddockwidget_was_restored").toBool())
324  result.push_back(dw);
325  }
326 
327  return result;
328 }
329 
330 void LayoutSaver::Private::clearRestoredProperty()
331 {
332  const DockWidgetBase::List &allDockWidgets = DockRegistry::self()->dockwidgets();
333  for (DockWidgetBase *dw : allDockWidgets) {
334  dw->setProperty("kddockwidget_was_restored", QVariant());
335  }
336 }
337 
338 template<typename T>
339 void LayoutSaver::Private::deserializeWindowGeometry(const T &saved, QWidgetOrQuick *topLevel)
340 {
341  // Not simply calling QWidget::setGeometry() here.
342  // For QtQuick we need to modify the QWindow's geometry.
343 
344  QRect geometry = saved.geometry;
345  if (!isNormalWindowState(saved.windowState)) {
346  // The window will be maximized. We first set its geometry to normal
347  // Later it's maximized and will remember this value
348  geometry = saved.normalGeometry;
349  }
350 
351  ::FloatingWindow::ensureRectIsOnScreen(geometry);
352 
353  if (topLevel->isWindow()) {
354  topLevel->setGeometry(geometry);
355  } else {
356  KDDockWidgets::Private::setTopLevelGeometry(geometry, topLevel);
357  }
358 
359  topLevel->setVisible(saved.isVisible);
360 }
361 
362 LayoutSaver::Private::Private(RestoreOptions options)
363  : m_dockRegistry(DockRegistry::self())
364  , m_restoreOptions(internalRestoreOptions(options))
365 {
366 }
367 
368 bool LayoutSaver::Private::matchesAffinity(const QStringList &affinities) const
369 {
370  return m_affinityNames.isEmpty() || affinities.isEmpty()
371  || DockRegistry::self()->affinitiesMatch(m_affinityNames, affinities);
372 }
373 
374 void LayoutSaver::Private::floatWidgetsWhichSkipRestore(const QStringList &mainWindowNames)
375 {
376  // Widgets with the DockWidget::LayoutSaverOption::Skip flag skip restore completely.
377  // If they were visible before they need to remain visible now.
378  // If they were previously docked we need to float them, as the main window they were on will
379  // be loading a new layout.
380 
381  for (MainWindowBase *mw : DockRegistry::self()->mainWindows(mainWindowNames)) {
382  const KDDockWidgets::DockWidgetBase::List docks = mw->layoutWidget()->dockWidgets();
383  for (auto dw : docks) {
384  if (dw->skipsRestore()) {
385  dw->setFloating(true);
386  }
387  }
388  }
389 }
390 
391 void LayoutSaver::Private::floatUnknownWidgets(const LayoutSaver::Layout &layout)
392 {
393  // An old *.json layout file might have not know about existing dock widgets
394  // When restoring such a file, we need to float any visible dock widgets which it doesn't know about
395  // so we can restore the MainWindow layout properly
396 
397  for (MainWindowBase *mw : DockRegistry::self()->mainWindows(layout.mainWindowNames())) {
398  const KDDockWidgets::DockWidgetBase::List docks = mw->layoutWidget()->dockWidgets();
399  for (DockWidgetBase *dw : docks) {
400  if (!layout.containsDockWidget(dw->uniqueName())) {
401  dw->setFloating(true);
402  }
403  }
404  }
405 }
406 
407 void LayoutSaver::Private::deleteEmptyFrames()
408 {
409  // After a restore it can happen that some DockWidgets didn't exist, so weren't restored.
410  // Delete their frame now.
411 
412  for (auto frame : m_dockRegistry->frames()) {
413  if (!frame->beingDeletedLater() && frame->isEmpty() && !frame->isCentralFrame())
414  delete frame;
415  }
416 }
417 
418 std::unique_ptr<QSettings> LayoutSaver::Private::settings() const
419 {
420  auto settings = std::unique_ptr<QSettings>(new QSettings(qApp->organizationName(),
421  qApp->applicationName()));
422  settings->beginGroup(QStringLiteral("KDDockWidgets::LayoutSaver"));
423 
424  return settings;
425 }
426 
428 {
429  return Private::s_restoreInProgress;
430 }
431 
432 bool LayoutSaver::Layout::isValid() const
433 {
434  if (serializationVersion != KDDOCKWIDGETS_SERIALIZATION_VERSION) {
435  qWarning() << Q_FUNC_INFO << "Serialization format is too old"
436  << serializationVersion << "current=" << KDDOCKWIDGETS_SERIALIZATION_VERSION;
437  return false;
438  }
439 
440  for (auto &m : mainWindows) {
441  if (!m.isValid())
442  return false;
443  }
444 
445  for (auto &m : floatingWindows) {
446  if (!m.isValid())
447  return false;
448  }
449 
450  for (auto &m : allDockWidgets) {
451  if (!m->isValid())
452  return false;
453  }
454 
455  return true;
456 }
457 
458 QByteArray LayoutSaver::Layout::toJson() const
459 {
460  QJsonDocument doc = QJsonDocument::fromVariant(toVariantMap());
461  return doc.toJson();
462 }
463 
464 bool LayoutSaver::Layout::fromJson(const QByteArray &jsonData)
465 {
466  QJsonParseError error;
467  QJsonDocument doc = QJsonDocument::fromJson(jsonData, &error);
468  if (error.error == QJsonParseError::NoError) {
469  fromVariantMap(doc.toVariant().toMap());
470  return true;
471  }
472 
473  return false;
474 }
475 
476 QVariantMap LayoutSaver::Layout::toVariantMap() const
477 {
478  QVariantMap map;
479  map.insert(QStringLiteral("serializationVersion"), serializationVersion);
480  map.insert(QStringLiteral("mainWindows"), toVariantList<LayoutSaver::MainWindow>(mainWindows));
481  map.insert(QStringLiteral("floatingWindows"), toVariantList<LayoutSaver::FloatingWindow>(floatingWindows));
482  map.insert(QStringLiteral("closedDockWidgets"), ::dockWidgetNames(closedDockWidgets));
483  map.insert(QStringLiteral("allDockWidgets"), toVariantList(allDockWidgets));
484  map.insert(QStringLiteral("screenInfo"), toVariantList<LayoutSaver::ScreenInfo>(screenInfo));
485 
486  return map;
487 }
488 
489 void LayoutSaver::Layout::fromVariantMap(const QVariantMap &map)
490 {
491  allDockWidgets.clear();
492  const QVariantList dockWidgetsV = map.value(QStringLiteral("allDockWidgets")).toList();
493  for (const QVariant &v : dockWidgetsV) {
494  const QVariantMap dwV = v.toMap();
495  const QString name = dwV.value(QStringLiteral("uniqueName")).toString();
496  auto dw = LayoutSaver::DockWidget::dockWidgetForName(name);
497  dw->fromVariantMap(dwV);
498  allDockWidgets.push_back(dw);
499  }
500 
501  closedDockWidgets.clear();
502  const QVariantList closedDockWidgetsV = map.value(QStringLiteral("closedDockWidgets")).toList();
503  closedDockWidgets.reserve(closedDockWidgetsV.size());
504  for (const QVariant &v : closedDockWidgetsV) {
505  closedDockWidgets.push_back(LayoutSaver::DockWidget::dockWidgetForName(v.toString()));
506  }
507 
508  serializationVersion = map.value(QStringLiteral("serializationVersion")).toInt();
509  mainWindows = fromVariantList<LayoutSaver::MainWindow>(map.value(QStringLiteral("mainWindows")).toList());
510  floatingWindows = fromVariantList<LayoutSaver::FloatingWindow>(map.value(QStringLiteral("floatingWindows")).toList());
511  screenInfo = fromVariantList<LayoutSaver::ScreenInfo>(map.value(QStringLiteral("screenInfo")).toList());
512 }
513 
514 void LayoutSaver::Layout::scaleSizes(InternalRestoreOptions options)
515 {
516  if (mainWindows.isEmpty())
517  return;
518 
519  const bool skipsMainWindowGeometry = options & InternalRestoreOption::SkipMainWindowGeometry;
520  if (!skipsMainWindowGeometry) {
521  // No scaling to do. All windows will be restored with the exact size specified in the
522  // saved JSON layouts.
523  return;
524  }
525 
526  // We won't restore MainWindow's geometry, we use whatever the user has now, meaning
527  // we need to scale all dock widgets inside the layout, as the layout might not have
528  // the same size as specified in the saved JSON layout
529  for (auto &mw : mainWindows)
530  mw.scaleSizes();
531 
532 
533  // MainWindow has a different size than the one in JSON, so we also restore FloatingWindows
534  // relatively to the user set new MainWindow size
535  const bool useRelativeSizesForFloatingWidgets =
536  options & InternalRestoreOption::RelativeFloatingWindowGeometry;
537 
538  if (useRelativeSizesForFloatingWidgets) {
539  for (auto &fw : floatingWindows) {
540  LayoutSaver::MainWindow mw = mainWindowForIndex(fw.parentIndex);
541  if (mw.scalingInfo.isValid())
542  fw.scaleSizes(mw.scalingInfo);
543  }
544  }
545 
546  const ScalingInfo firstScalingInfo = mainWindows.constFirst().scalingInfo;
547  if (firstScalingInfo.isValid()) {
548  for (auto &dw : allDockWidgets) {
549  // TODO: Determine the best main window. This only interesting for closed dock
550  // widget geometry which was previously floating. But they still have some other
551  // main window as parent.
552  dw->scaleSizes(firstScalingInfo);
553  }
554  }
555 }
556 
557 LayoutSaver::MainWindow LayoutSaver::Layout::mainWindowForIndex(int index) const
558 {
559  if (index < 0 || index >= mainWindows.size())
560  return {};
561 
562  return mainWindows.at(index);
563 }
564 
565 LayoutSaver::FloatingWindow LayoutSaver::Layout::floatingWindowForIndex(int index) const
566 {
567  if (index < 0 || index >= floatingWindows.size())
568  return {};
569 
570  return floatingWindows.at(index);
571 }
572 
573 QStringList LayoutSaver::Layout::mainWindowNames() const
574 {
575  QStringList names;
576  names.reserve(mainWindows.size());
577  for (const auto &mw : mainWindows) {
578  names << mw.uniqueName;
579  }
580 
581  return names;
582 }
583 
584 QStringList LayoutSaver::Layout::dockWidgetNames() const
585 {
586  QStringList names;
587  names.reserve(allDockWidgets.size());
588  for (const auto &dw : allDockWidgets) {
589  names << dw->uniqueName;
590  }
591 
592  return names;
593 }
594 
595 QStringList LayoutSaver::Layout::dockWidgetsToClose() const
596 {
597  // Before restoring a layout we close all dock widgets, unless they're a floating window with the DontCloseBeforeRestore flag
598 
599  QStringList names;
600  names.reserve(allDockWidgets.size());
601  auto registry = DockRegistry::self();
602  for (const auto &dw : allDockWidgets) {
603  if (DockWidgetBase *dockWidget = registry->dockByName(dw->uniqueName)) {
604 
605  bool doClose = true;
606 
607  if (dockWidget->skipsRestore()) {
608  if (auto fw = dockWidget->floatingWindow()) {
609  if (fw->allDockWidgetsHave(DockWidgetBase::LayoutSaverOption::Skip)) {
610  // All dock widgets in this floating window skips float, so we can honour it for all.
611  doClose = false;
612  }
613  }
614  }
615 
616  if (doClose)
617  names << dw->uniqueName;
618  }
619  }
620 
621  return names;
622 }
623 
624 bool LayoutSaver::Layout::containsDockWidget(const QString &uniqueName) const
625 {
626  return std::find_if(allDockWidgets.cbegin(), allDockWidgets.cend(), [uniqueName](const std::shared_ptr<LayoutSaver::DockWidget> &dock) {
627  return dock->uniqueName == uniqueName;
628  })
629  != allDockWidgets.cend();
630 }
631 
632 bool LayoutSaver::Frame::isValid() const
633 {
634  if (isNull)
635  return true;
636 
637  if (!geometry.isValid()) {
638  qWarning() << Q_FUNC_INFO << "Invalid geometry";
639  return false;
640  }
641 
642  if (id.isEmpty()) {
643  qWarning() << Q_FUNC_INFO << "Invalid id";
644  return false;
645  }
646 
647  if (!dockWidgets.isEmpty()) {
648  if (currentTabIndex >= dockWidgets.size() || currentTabIndex < 0) {
649  qWarning() << Q_FUNC_INFO << "Invalid tab index" << currentTabIndex << dockWidgets.size();
650  return false;
651  }
652  }
653 
654  for (auto &dw : dockWidgets) {
655  if (!dw->isValid())
656  return false;
657  }
658 
659  return true;
660 }
661 
662 bool LayoutSaver::Frame::hasSingleDockWidget() const
663 {
664  return dockWidgets.size() == 1;
665 }
666 
667 bool LayoutSaver::Frame::skipsRestore() const
668 {
669  return std::all_of(dockWidgets.cbegin(), dockWidgets.cend(), [](LayoutSaver::DockWidget::Ptr dw) {
670  return dw->skipsRestore();
671  });
672 }
673 
674 LayoutSaver::DockWidget::Ptr LayoutSaver::Frame::singleDockWidget() const
675 {
676  if (!hasSingleDockWidget())
677  return {};
678 
679  return dockWidgets.first();
680 }
681 
682 QVariantMap LayoutSaver::Frame::toVariantMap() const
683 {
684  QVariantMap map;
685  map.insert(QStringLiteral("id"), id);
686  map.insert(QStringLiteral("isNull"), isNull);
687  map.insert(QStringLiteral("objectName"), objectName);
688  map.insert(QStringLiteral("geometry"), Layouting::rectToMap(geometry));
689  map.insert(QStringLiteral("options"), options);
690  map.insert(QStringLiteral("currentTabIndex"), currentTabIndex);
691  map.insert(QStringLiteral("mainWindowUniqueName"), mainWindowUniqueName);
692  map.insert(QStringLiteral("dockWidgets"), dockWidgetNames(dockWidgets));
693 
694  return map;
695 }
696 
697 void LayoutSaver::Frame::fromVariantMap(const QVariantMap &map)
698 {
699  if (map.isEmpty()) {
700  isNull = true;
701  dockWidgets.clear();
702  return;
703  }
704 
705  id = map.value(QStringLiteral("id")).toString();
706  isNull = map.value(QStringLiteral("isNull")).toBool();
707  objectName = map.value(QStringLiteral("objectName")).toString();
708  mainWindowUniqueName = map.value(QStringLiteral("mainWindowUniqueName")).toString();
709  geometry = Layouting::mapToRect(map.value(QStringLiteral("geometry")).toMap());
710  options = static_cast<QFlags<FrameOption>::Int>(map.value(QStringLiteral("options")).toUInt());
711  currentTabIndex = map.value(QStringLiteral("currentTabIndex")).toInt();
712 
713  const QVariantList dockWidgetsV = map.value(QStringLiteral("dockWidgets")).toList();
714 
715  dockWidgets.clear();
716  dockWidgets.reserve(dockWidgetsV.size());
717  for (const auto &variant : dockWidgetsV) {
718  DockWidget::Ptr dw = DockWidget::dockWidgetForName(variant.toString());
719  dockWidgets.push_back(dw);
720  }
721 }
722 
723 bool LayoutSaver::DockWidget::isValid() const
724 {
725  return !uniqueName.isEmpty();
726 }
727 
728 void LayoutSaver::DockWidget::scaleSizes(const ScalingInfo &scalingInfo)
729 {
730  lastPosition.scaleSizes(scalingInfo);
731 }
732 
733 bool LayoutSaver::DockWidget::skipsRestore() const
734 {
735  if (DockWidgetBase *dw = DockRegistry::self()->dockByName(uniqueName))
736  return dw->skipsRestore();
737 
738  return false;
739 }
740 
741 QVariantMap LayoutSaver::DockWidget::toVariantMap() const
742 {
743  QVariantMap map;
744  if (!affinities.isEmpty())
745  map.insert(QStringLiteral("affinities"), stringListToVariant(affinities));
746  map.insert(QStringLiteral("uniqueName"), uniqueName);
747  map.insert(QStringLiteral("lastPosition"), lastPosition.toVariantMap());
748 
749  return map;
750 }
751 
752 void LayoutSaver::DockWidget::fromVariantMap(const QVariantMap &map)
753 {
754  affinities = variantToStringList(map.value(QStringLiteral("affinities")).toList());
755 
756  // Compatibility hack. Old json format had a single "affinityName" instead of an "affinities" list:
757  const QString affinityName = map.value(QStringLiteral("affinityName")).toString();
758  if (!affinityName.isEmpty() && !affinities.contains(affinityName)) {
759  affinities.push_back(affinityName);
760  }
761 
762  uniqueName = map.value(QStringLiteral("uniqueName")).toString();
763  lastPosition.fromVariantMap(map.value(QStringLiteral("lastPosition")).toMap());
764 }
765 
766 bool LayoutSaver::FloatingWindow::isValid() const
767 {
768  if (!multiSplitterLayout.isValid())
769  return false;
770 
771  if (!geometry.isValid()) {
772  qWarning() << Q_FUNC_INFO << "Invalid geometry";
773  return false;
774  }
775 
776  return true;
777 }
778 
779 bool LayoutSaver::FloatingWindow::hasSingleDockWidget() const
780 {
781  return multiSplitterLayout.hasSingleDockWidget();
782 }
783 
784 LayoutSaver::DockWidget::Ptr LayoutSaver::FloatingWindow::singleDockWidget() const
785 {
786  return multiSplitterLayout.singleDockWidget();
787 }
788 
789 bool LayoutSaver::FloatingWindow::skipsRestore() const
790 {
791  return multiSplitterLayout.skipsRestore();
792 }
793 
794 void LayoutSaver::FloatingWindow::scaleSizes(const ScalingInfo &scalingInfo)
795 {
796  scalingInfo.applyFactorsTo(/*by-ref*/ geometry);
797 }
798 
799 QVariantMap LayoutSaver::FloatingWindow::toVariantMap() const
800 {
801  QVariantMap map;
802  map.insert(QStringLiteral("multiSplitterLayout"), multiSplitterLayout.toVariantMap());
803  map.insert(QStringLiteral("parentIndex"), parentIndex);
804  map.insert(QStringLiteral("geometry"), Layouting::rectToMap(geometry));
805  map.insert(QStringLiteral("normalGeometry"), Layouting::rectToMap(normalGeometry));
806  map.insert(QStringLiteral("screenIndex"), screenIndex);
807  map.insert(QStringLiteral("screenSize"), Layouting::sizeToMap(screenSize));
808  map.insert(QStringLiteral("isVisible"), isVisible);
809  map.insert(QStringLiteral("windowState"), windowState);
810 
811  if (!affinities.isEmpty())
812  map.insert(QStringLiteral("affinities"), stringListToVariant(affinities));
813 
814  return map;
815 }
816 
817 void LayoutSaver::FloatingWindow::fromVariantMap(const QVariantMap &map)
818 {
819  multiSplitterLayout.fromVariantMap(map.value(QStringLiteral("multiSplitterLayout")).toMap());
820  parentIndex = map.value(QStringLiteral("parentIndex")).toInt();
821  geometry = Layouting::mapToRect(map.value(QStringLiteral("geometry")).toMap());
822  normalGeometry = Layouting::mapToRect(map.value(QStringLiteral("normalGeometry")).toMap());
823  screenIndex = map.value(QStringLiteral("screenIndex")).toInt();
824  screenSize = Layouting::mapToSize(map.value(QStringLiteral("screenSize")).toMap());
825  isVisible = map.value(QStringLiteral("isVisible")).toBool();
826  affinities = variantToStringList(map.value(QStringLiteral("affinities")).toList());
827  windowState = Qt::WindowState(map.value(QStringLiteral("windowState"), Qt::WindowNoState).toInt());
828 
829  // Compatibility hack. Old json format had a single "affinityName" instead of an "affinities" list:
830  const QString affinityName = map.value(QStringLiteral("affinityName")).toString();
831  if (!affinityName.isEmpty() && !affinities.contains(affinityName)) {
832  affinities.push_back(affinityName);
833  }
834 }
835 
836 bool LayoutSaver::MainWindow::isValid() const
837 {
838  if (!multiSplitterLayout.isValid())
839  return false;
840 
841  return true;
842 }
843 
844 void LayoutSaver::MainWindow::scaleSizes()
845 {
846  if (scalingInfo.isValid()) {
847  // Doesn't happen, it's called only once
848  Q_ASSERT(false);
849  return;
850  }
851 
852  scalingInfo = ScalingInfo(uniqueName, geometry, screenIndex);
853 }
854 
855 QVariantMap LayoutSaver::MainWindow::toVariantMap() const
856 {
857  QVariantMap map;
858  map.insert(QStringLiteral("options"), int(options));
859  map.insert(QStringLiteral("multiSplitterLayout"), multiSplitterLayout.toVariantMap());
860  map.insert(QStringLiteral("uniqueName"), uniqueName);
861  map.insert(QStringLiteral("geometry"), Layouting::rectToMap(geometry));
862  map.insert(QStringLiteral("normalGeometry"), Layouting::rectToMap(normalGeometry));
863  map.insert(QStringLiteral("screenIndex"), screenIndex);
864  map.insert(QStringLiteral("screenSize"), Layouting::sizeToMap(screenSize));
865  map.insert(QStringLiteral("isVisible"), isVisible);
866  map.insert(QStringLiteral("affinities"), stringListToVariant(affinities));
867  map.insert(QStringLiteral("windowState"), windowState);
868 
870  const QStringList dockWidgets = dockWidgetsPerSideBar.value(loc);
871  if (!dockWidgets.isEmpty())
872  map.insert(QStringLiteral("sidebar-%1").arg(int(loc)), stringListToVariant(dockWidgets));
873  }
874 
875  return map;
876 }
877 
878 void LayoutSaver::MainWindow::fromVariantMap(const QVariantMap &map)
879 {
880  options = KDDockWidgets::MainWindowOptions(map.value(QStringLiteral("options")).toInt());
881  multiSplitterLayout.fromVariantMap(map.value(QStringLiteral("multiSplitterLayout")).toMap());
882  uniqueName = map.value(QStringLiteral("uniqueName")).toString();
883  geometry = Layouting::mapToRect(map.value(QStringLiteral("geometry")).toMap());
884  normalGeometry = Layouting::mapToRect(map.value(QStringLiteral("normalGeometry")).toMap());
885  screenIndex = map.value(QStringLiteral("screenIndex")).toInt();
886  screenSize = Layouting::mapToSize(map.value(QStringLiteral("screenSize")).toMap());
887  isVisible = map.value(QStringLiteral("isVisible")).toBool();
888  affinities = variantToStringList(map.value(QStringLiteral("affinities")).toList());
889  windowState = Qt::WindowState(map.value(QStringLiteral("windowState"), Qt::WindowNoState).toInt());
890 
891  // Compatibility hack. Old json format had a single "affinityName" instead of an "affinities" list:
892  const QString affinityName = map.value(QStringLiteral("affinityName")).toString();
893  if (!affinityName.isEmpty() && !affinities.contains(affinityName)) {
894  affinities.push_back(affinityName);
895  }
896 
897  // Load the SideBars:
898  dockWidgetsPerSideBar.clear();
900  const QVariantList dockWidgets = map.value(QStringLiteral("sidebar-%1").arg(int(loc))).toList();
901  if (!dockWidgets.isEmpty())
902  dockWidgetsPerSideBar.insert(loc, variantToStringList(dockWidgets));
903  }
904 }
905 
906 bool LayoutSaver::MultiSplitter::isValid() const
907 {
908  if (layout.isEmpty())
909  return false;
910 
911  /*if (!size.isValid()) {
912  qWarning() << Q_FUNC_INFO << "Invalid size";
913  return false;
914  }*/
915 
916  return true;
917 }
918 
919 bool LayoutSaver::MultiSplitter::hasSingleDockWidget() const
920 {
921  return frames.size() == 1 && frames.cbegin()->hasSingleDockWidget();
922 }
923 
924 LayoutSaver::DockWidget::Ptr LayoutSaver::MultiSplitter::singleDockWidget() const
925 {
926  if (!hasSingleDockWidget())
927  return {};
928 
929  return frames.cbegin()->singleDockWidget();
930 }
931 
932 bool LayoutSaver::MultiSplitter::skipsRestore() const
933 {
934  return std::all_of(frames.cbegin(), frames.cend(), [](const LayoutSaver::Frame &frame) {
935  return frame.skipsRestore();
936  });
937 }
938 
939 QVariantMap LayoutSaver::MultiSplitter::toVariantMap() const
940 {
941  QVariantMap result;
942  result.insert(QStringLiteral("layout"), layout);
943 
944  QVariantMap framesV;
945  for (auto &frame : frames)
946  framesV.insert(frame.id, frame.toVariantMap());
947 
948  result.insert(QStringLiteral("frames"), framesV);
949  return result;
950 }
951 
952 void LayoutSaver::MultiSplitter::fromVariantMap(const QVariantMap &map)
953 {
954  layout = map.value(QStringLiteral("layout")).toMap();
955  const QVariantMap framesV = map.value(QStringLiteral("frames")).toMap();
956  frames.clear();
957  for (const QVariant &frameV : framesV) {
958  LayoutSaver::Frame frame;
959  frame.fromVariantMap(frameV.toMap());
960  frames.insert(frame.id, frame);
961  }
962 }
963 
964 void LayoutSaver::Position::scaleSizes(const ScalingInfo &scalingInfo)
965 {
966  scalingInfo.applyFactorsTo(/*by-ref*/ lastFloatingGeometry);
967 }
968 
969 QVariantMap LayoutSaver::Position::toVariantMap() const
970 {
971  QVariantMap map;
972  map.insert(QStringLiteral("lastFloatingGeometry"), Layouting::rectToMap(lastFloatingGeometry));
973  map.insert(QStringLiteral("tabIndex"), tabIndex);
974  map.insert(QStringLiteral("wasFloating"), wasFloating);
975  map.insert(QStringLiteral("placeholders"), toVariantList<LayoutSaver::Placeholder>(placeholders));
976 
977  return map;
978 }
979 
980 void LayoutSaver::Position::fromVariantMap(const QVariantMap &map)
981 {
982  lastFloatingGeometry = Layouting::mapToRect(map.value(QStringLiteral("lastFloatingGeometry")).toMap());
983  tabIndex = map.value(QStringLiteral("tabIndex")).toInt();
984  wasFloating = map.value(QStringLiteral("wasFloating")).toBool();
985  placeholders = fromVariantList<LayoutSaver::Placeholder>(map.value(QStringLiteral("placeholders")).toList());
986 }
987 
988 QVariantMap LayoutSaver::ScreenInfo::toVariantMap() const
989 {
990  QVariantMap map;
991  map.insert(QStringLiteral("index"), index);
992  map.insert(QStringLiteral("geometry"), Layouting::rectToMap(geometry));
993  map.insert(QStringLiteral("name"), name);
994  map.insert(QStringLiteral("devicePixelRatio"), devicePixelRatio);
995 
996  return map;
997 }
998 
999 void LayoutSaver::ScreenInfo::fromVariantMap(const QVariantMap &map)
1000 {
1001  index = map.value(QStringLiteral("index")).toInt();
1002  geometry = Layouting::mapToRect(map.value(QStringLiteral("geometry")).toMap());
1003  name = map.value(QStringLiteral("name")).toString();
1004  devicePixelRatio = map.value(QStringLiteral("devicePixelRatio")).toDouble();
1005 }
1006 
1007 QVariantMap LayoutSaver::Placeholder::toVariantMap() const
1008 {
1009  QVariantMap map;
1010  map.insert(QStringLiteral("isFloatingWindow"), isFloatingWindow);
1011  map.insert(QStringLiteral("itemIndex"), itemIndex);
1012 
1013  if (isFloatingWindow)
1014  map.insert(QStringLiteral("indexOfFloatingWindow"), indexOfFloatingWindow);
1015  else
1016  map.insert(QStringLiteral("mainWindowUniqueName"), mainWindowUniqueName);
1017 
1018  return map;
1019 }
1020 
1021 void LayoutSaver::Placeholder::fromVariantMap(const QVariantMap &map)
1022 {
1023  isFloatingWindow = map.value(QStringLiteral("isFloatingWindow")).toBool();
1024  indexOfFloatingWindow = map.value(QStringLiteral("indexOfFloatingWindow"), -1).toInt();
1025  itemIndex = map.value(QStringLiteral("itemIndex")).toInt();
1026  mainWindowUniqueName = map.value(QStringLiteral("mainWindowUniqueName")).toString();
1027 }
1028 
1030 {
1031  // Workaround for 5.12 which doesn't have QWidget::screen().
1032 
1033 #ifdef KDDOCKWIDGETS_QTQUICK
1034  return mw->screen();
1035 #endif
1036 
1037 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1038  if (QWindow *window = mw->window()->windowHandle())
1039  return window->screen();
1040  return nullptr;
1041 #else
1042  return mw->screen();
1043 #endif
1044 }
1045 
1046 LayoutSaver::ScalingInfo::ScalingInfo(const QString &mainWindowId, QRect savedMainWindowGeo, int screenIndex)
1047 {
1048  auto mainWindow = DockRegistry::self()->mainWindowByName(mainWindowId);
1049  if (!mainWindow) {
1050  qWarning() << Q_FUNC_INFO << "Failed to find main window with name" << mainWindowName;
1051  return;
1052  }
1053 
1054  if (!savedMainWindowGeo.isValid() || savedMainWindowGeo.isNull()) {
1055  qWarning() << Q_FUNC_INFO << "Invalid saved main window geometry" << savedMainWindowGeo;
1056  return;
1057  }
1058 
1059  if (!mainWindow->geometry().isValid() || mainWindow->geometry().isNull()) {
1060  qWarning() << Q_FUNC_INFO << "Invalid main window geometry" << mainWindow->geometry();
1061  return;
1062  }
1063 
1064  const int currentScreenIndex = qApp->screens().indexOf(screenForMainWindow(mainWindow));
1065 
1066  this->mainWindowName = mainWindowId;
1067  this->savedMainWindowGeometry = savedMainWindowGeo;
1068  realMainWindowGeometry = mainWindow->window()->geometry(); // window() as our main window might be embedded
1069  widthFactor = double(realMainWindowGeometry.width()) / savedMainWindowGeo.width();
1070  heightFactor = double(realMainWindowGeometry.height()) / savedMainWindowGeo.height();
1071  mainWindowChangedScreen = currentScreenIndex != screenIndex;
1072 }
1073 
1074 void LayoutSaver::ScalingInfo::translatePos(QPoint &pt) const
1075 {
1076  const int deltaX = pt.x() - savedMainWindowGeometry.x();
1077  const int deltaY = pt.y() - savedMainWindowGeometry.y();
1078 
1079  const double newDeltaX = deltaX * widthFactor;
1080  const double newDeltaY = deltaY * heightFactor;
1081 
1082  pt.setX(qCeil(savedMainWindowGeometry.x() + newDeltaX));
1083  pt.setY(qCeil(savedMainWindowGeometry.y() + newDeltaY));
1084 }
1085 
1086 void LayoutSaver::ScalingInfo::applyFactorsTo(QPoint &pt) const
1087 {
1088  translatePos(pt);
1089 }
1090 
1091 void LayoutSaver::ScalingInfo::applyFactorsTo(QSize &sz) const
1092 {
1093  sz.setWidth(int(widthFactor * sz.width()));
1094  sz.setHeight(int(heightFactor * sz.height()));
1095 }
1096 
1097 void LayoutSaver::ScalingInfo::applyFactorsTo(QRect &rect) const
1098 {
1099  if (rect.isEmpty())
1100  return;
1101 
1102  QPoint pos = rect.topLeft();
1103  QSize size = rect.size();
1104 
1105  applyFactorsTo(/*by-ref*/ size);
1106 
1107 
1108  if (!mainWindowChangedScreen) {
1109  // Don't play with floating window position if the main window changed screen.
1110  // There's too many corner cases that push the floating windows out of bounds, and
1111  // we're not even considering monitors with different HDPI. We can support only the simple case.
1112  // For complex cases we'll try to guarantee the window is placed somewhere reasonable.
1113  applyFactorsTo(/*by-ref*/ pos);
1114  }
1115 
1116  rect.moveTopLeft(pos);
1117  rect.setSize(size);
1118 }
1119 
1120 LayoutSaver::Private::RAIIIsRestoring::RAIIIsRestoring()
1121 {
1122  LayoutSaver::Private::s_restoreInProgress = true;
1123 }
1124 
1125 LayoutSaver::Private::RAIIIsRestoring::~RAIIIsRestoring()
1126 {
1127  LayoutSaver::Private::s_restoreInProgress = false;
1128 }
KDDockWidgets::LayoutSaver::restoreLayout
bool restoreLayout(const QByteArray &)
restores the layout from a byte array All MainWindows and DockWidgets should have been created before...
Definition: LayoutSaver.cpp:189
KDDockWidgets::LayoutSaver::serializeLayout
QByteArray serializeLayout() const
saves the layout into a byte array
Definition: LayoutSaver.cpp:139
DockWidgetBase.h
The DockWidget base-class that's shared between QtWidgets and QtQuick stack.
QRect::setSize
void setSize(const QSize &size)
QRect::moveTopLeft
void moveTopLeft(const QPoint &position)
QIODevice::errorString
QString errorString() const const
QWidget::window
QWidget * window() const const
LayoutSaver.h
Class to save and restore dockwidget layouts.
QJsonDocument::fromJson
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QRect::topLeft
QPoint topLeft() const const
QIODevice::WriteOnly
WriteOnly
QRect::size
QSize size() const const
KDDockWidgets::DockWidgetBase::LayoutSaverOption::Skip
@ Skip
The dock widget won't participate in save/restore. Currently only available for floating windows.
QRect
QFile::open
virtual bool open(QIODevice::OpenMode mode) override
QJsonDocument::toVariant
QVariant toVariant() const const
KDDockWidgets::LayoutSaver::~LayoutSaver
~LayoutSaver()
Destructor.
Definition: LayoutSaver.cpp:106
KDDockWidgets::LayoutSaver::dptr
Private * dptr() const
Definition: LayoutSaver.cpp:312
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
QWindow
QVector::push_back
void push_back(const T &value)
QWidget
KDDockWidgets::MainWindowBase::affinities
QStringList affinities
Definition: MainWindowBase.h:58
QRect::width
int width() const const
KDDockWidgets::SideBarLocation::West
@ West
QWidget::screen
QScreen * screen() const const
QSize
QList::push_back
void push_back(const T &value)
QPoint::x
int x() const const
QPoint::y
int y() const const
QSize::width
int width() const const
QFlags
QSize::setWidth
void setWidth(int width)
QScreen
MainWindowBase.h
The MainWindow base-class that's shared between QtWidgets and QtQuick stack.
QList::reserve
void reserve(int alloc)
QJsonParseError
QWidget::setVisible
virtual void setVisible(bool visible)
QList::size
int size() const const
screenForMainWindow
static QScreen * screenForMainWindow(MainWindowBase *mw)
Definition: LayoutSaver.cpp:1029
KDDockWidgets::LayoutSaver
LayoutSaver allows to save or restore layouts.
Definition: LayoutSaver.h:55
internalRestoreOptions
InternalRestoreOptions internalRestoreOptions(RestoreOptions options)
Definition: LayoutSaver.cpp:66
KDDockWidgets::LayoutSaver::restoreInProgress
static bool restoreInProgress()
returns whether a restore (restoreLayout) is in progress
Definition: LayoutSaver.cpp:427
KDDockWidgets::LayoutSaver::LayoutSaver
LayoutSaver(RestoreOptions options=RestoreOption_None)
Constructor. Construction on the stack is suggested.
Definition: LayoutSaver.cpp:101
QSize::height
int height() const const
QString
QPoint::setX
void setX(int x)
QPoint::setY
void setY(int y)
QString::isEmpty
bool isEmpty() const const
QRect::isValid
bool isValid() const const
QJsonParseError::NoError
NoError
QString::toInt
int toInt(bool *ok, int base) const const
KDDockWidgets::LayoutSaver::restoreFromFile
bool restoreFromFile(const QString &jsonFilename)
restores the layout from a JSON file
Definition: LayoutSaver.cpp:125
QList::isEmpty
bool isEmpty() const const
Qt::WindowNoState
WindowNoState
QList::cend
QList::const_iterator cend() const const
QWidget::isWindow
bool isWindow() const const
KDDockWidgets::Config::frameworkWidgetFactory
FrameworkWidgetFactory * frameworkWidgetFactory() const
getter for the framework widget factory
Definition: Config.cpp:145
KDDockWidgets::LayoutSaver::restoredDockWidgets
QVector< DockWidgetBase * > restoredDockWidgets() const
returns a list of dock widgets which were restored since the last restoreLayout() or restoreFromFile(...
Definition: LayoutSaver.cpp:317
QRect::isNull
bool isNull() const const
KDDockWidgets::RestoreOption_None
@ RestoreOption_None
Definition: KDDockWidgets.h:184
KDDockWidgets::SideBarLocation
SideBarLocation
Each main window supports 4 sidebars.
Definition: KDDockWidgets.h:208
QVector::reserve
void reserve(int size)
QString::toDouble
double toDouble(bool *ok) const const
QVariant::toMap
QMap< QString, QVariant > toMap() const const
QJsonDocument
KDDockWidgets::FrameworkWidgetFactory::createFloatingWindow
virtual FloatingWindow * createFloatingWindow(MainWindowBase *parent=nullptr) const =0
Called internally by the framework to create a FloatingWindow Override to provide your own FloatingWi...
KDDockWidgets::SideBarLocation::East
@ East
KDDockWidgets::SideBarLocation::South
@ South
Config.h
Application-wide config to tune certain behaviours of the framework.
QWidget::setGeometry
void setGeometry(int x, int y, int w, int h)
KDDockWidgets::LayoutSaver::setAffinityNames
void setAffinityNames(const QStringList &affinityNames)
Sets the list of affinity names for which restore and save will be applied on. Allows to save/restore...
Definition: LayoutSaver.cpp:303
variantToStringList
static QStringList variantToStringList(const QVariantList &variantList)
Definition: LayoutSaver.cpp:91
QWidget::windowHandle
QWindow * windowHandle() const const
QByteArray::isEmpty
bool isEmpty() const const
QRect::height
int height() const const
QRect::isEmpty
bool isEmpty() const const
QString::insert
QString & insert(int position, QChar ch)
KDDockWidgets::SideBarLocation::North
@ North
KDDockWidgets::DockWidgetBase
The DockWidget base-class. DockWidget and DockWidgetBase are only split in two so we can share some c...
Definition: DockWidgetBase.h:61
QSettings
KDDockWidgets::RestoreOption_RelativeToMainWindow
@ RestoreOption_RelativeToMainWindow
Definition: KDDockWidgets.h:185
QJsonDocument::toJson
QByteArray toJson() const const
KDDockWidgets
Definition: Config.cpp:37
stringListToVariant
static QVariantList stringListToVariant(const QStringList &strs)
Definition: LayoutSaver.cpp:81
QVector::size
int size() const const
KDDockWidgets::LayoutSaver::saveToFile
bool saveToFile(const QString &jsonFilename)
saves the layout to JSON file
Definition: LayoutSaver.cpp:111
KDDockWidgets::MainWindowBase
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
Definition: MainWindowBase.h:56
QIODevice::readAll
QByteArray readAll()
QVector
QJsonDocument::fromVariant
QJsonDocument fromVariant(const QVariant &variant)
QVariant
QHash
QFile
QSize::setHeight
void setHeight(int height)
QList::value
T value(int i) const const
QPoint
QByteArray
QIODevice::write
qint64 write(const char *data, qint64 maxSize)
KDDockWidgets::Config::self
static Config & self()
returns the singleton Config instance
Definition: Config.cpp:84
FrameworkWidgetFactory.h
A factory class for allowing the user to customize some internal widgets.
QStringList

© 2019-2022 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated on Thu Sep 15 2022 00:16:29 for KDDockWidgets API Documentation by doxygen 1.8.20