DockContainerWidget.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 ** Qt Advanced Docking System
3 ** Copyright (C) 2017 Uwe Kindler
4 **
5 ** This library is free software; you can redistribute it and/or
6 ** modify it under the terms of the GNU Lesser General Public
7 ** License as published by the Free Software Foundation; either
8 ** version 2.1 of the License, or (at your option) any later version.
9 **
10 ** This library is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ** Lesser General Public License for more details.
14 **
15 ** You should have received a copy of the GNU Lesser General Public
16 ** License along with this library; If not, see <http://www.gnu.org/licenses/>.
17 ******************************************************************************/
18 
19 
20 //============================================================================
25 //============================================================================
26 
27 
28 //============================================================================
29 // INCLUDES
30 //============================================================================
31 #include "DockContainerWidget.h"
32 
33 #include <QEvent>
34 #include <QList>
35 #include <QGridLayout>
36 #include <QPointer>
37 #include <QVariant>
38 #include <QDebug>
39 #include <QXmlStreamWriter>
40 #include <QAbstractButton>
41 
42 #include "DockManager.h"
43 #include "DockAreaWidget.h"
44 #include "DockWidget.h"
45 #include "DockingStateReader.h"
46 #include "FloatingDockContainer.h"
47 #include "DockOverlay.h"
48 #include "ads_globals.h"
49 #include "DockSplitter.h"
50 
51 #include <functional>
52 #include <iostream>
53 
54 #if QT_VERSION < 0x050900
55 
56 inline char toHexLower(uint value)
57 {
58  return "0123456789abcdef"[value & 0xF];
59 }
60 
61 QByteArray qByteArrayToHex(const QByteArray& src, char separator)
62 {
63  if(src.size() == 0)
64  return QByteArray();
65 
66  const int length = separator ? (src.size() * 3 - 1) : (src.size() * 2);
67  QByteArray hex(length, Qt::Uninitialized);
68  char *hexData = hex.data();
69  const uchar *data = reinterpret_cast<const uchar *>(src.data());
70  for (int i = 0, o = 0; i < src.size(); ++i) {
71  hexData[o++] = toHexLower(data[i] >> 4);
72  hexData[o++] = toHexLower(data[i] & 0xf);
73 
74  if ((separator) && (o < length))
75  hexData[o++] = separator;
76  }
77  return hex;
78 }
79 #endif
80 
81 namespace ads
82 {
83 static unsigned int zOrderCounter = 0;
84 
86 {
90 };
91 
95 static int areaIdToIndex(DockWidgetArea area)
96 {
97  switch (area)
98  {
99  case LeftDockWidgetArea: return 0;
100  case RightDockWidgetArea: return 1;
101  case TopDockWidgetArea: return 2;
102  case BottomDockWidgetArea: return 3;
103  case CenterDockWidgetArea: return 4;
104  default:
105  return 4;
106  }
107 }
108 
112 static void insertWidgetIntoSplitter(QSplitter* Splitter, QWidget* widget, bool Append)
113 {
114  if (Append)
115  {
116  Splitter->addWidget(widget);
117  }
118  else
119  {
120  Splitter->insertWidget(0, widget);
121  }
122 }
123 
128 {
129 public:
131  QPointer<CDockManager> DockManager;
132  unsigned int zOrderIndex = 0;
134  QGridLayout* Layout = nullptr;
135  QSplitter* RootSplitter = nullptr;
136  bool isFloating = false;
140 
145 
151 
156  CDockAreaWidget* TargetDockArea);
157 
161  void addDockArea(CDockAreaWidget* NewDockWidget, DockWidgetArea area = CenterDockWidgetArea);
162 
166  void dropIntoContainer(CFloatingDockContainer* FloatingWidget, DockWidgetArea area);
167 
171  void dropIntoSection(CFloatingDockContainer* FloatingWidget,
172  CDockAreaWidget* TargetArea, DockWidgetArea area);
173 
178  void moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area);
179 
184  void moveToContainer(QWidget* Widgett, DockWidgetArea area);
185 
189  void dropIntoCenterOfSection(CFloatingDockContainer* FloatingWidget,
190  CDockAreaWidget* TargetArea);
191 
195  void moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea);
196 
197 
201  void addDockAreasToList(const QList<CDockAreaWidget*> NewDockAreas);
202 
207  void appendDockAreas(const QList<CDockAreaWidget*> NewDockAreas);
208 
212  void saveChildNodesState(QXmlStreamWriter& Stream, QWidget* Widget);
213 
222  bool restoreChildNodes(CDockingStateReader& Stream, QWidget*& CreatedWidget,
223  bool Testing);
224 
229  bool restoreSplitter(CDockingStateReader& Stream, QWidget*& CreatedWidget,
230  bool Testing);
231 
236  bool restoreDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget,
237  bool Testing);
238 
242  void dumpRecursive(int level, QWidget* widget);
243 
247  eDropMode getDropMode(const QPoint& TargetPos);
248 
254  {
255  if (VisibleDockAreaCount > -1)
256  {
257  return;
258  }
259 
260  VisibleDockAreaCount = 0;
261  for (auto DockArea : DockAreas)
262  {
263  VisibleDockAreaCount += DockArea->isHidden() ? 0 : 1;
264  }
265  }
266 
271  {
272  // Lazy initialisation - we initialize the VisibleDockAreaCount variable
273  // on first use
275  return VisibleDockAreaCount;
276  }
277 
283 
285  {
287  emit _this->dockAreasRemoved();
288  }
289 
291  {
293  emit _this->dockAreasAdded();
294  }
295 
299  CDockSplitter* newSplitter(Qt::Orientation orientation, QWidget* parent = nullptr)
300  {
301  CDockSplitter* s = new CDockSplitter(orientation, parent);
303  s->setChildrenCollapsible(false);
304  return s;
305  }
306 
311  void adjustSplitterSizesOnInsertion(QSplitter* Splitter, qreal LastRatio = 1.0)
312  {
313  int AreaSize = (Splitter->orientation() == Qt::Horizontal) ? Splitter->width() : Splitter->height();
314  auto SplitterSizes = Splitter->sizes();
315 
316  qreal TotRatio = SplitterSizes.size() - 1.0 + LastRatio;
317  for(int i = 0; i < SplitterSizes.size() -1; i++)
318  {
319  SplitterSizes[i] = AreaSize / TotRatio;
320  }
321  SplitterSizes.back() = AreaSize * LastRatio / TotRatio;
322  Splitter->setSizes(SplitterSizes);
323  }
324 
329  void updateSplitterHandles(QSplitter* splitter);
330 
336  bool widgetResizesWithContainer(QWidget* widget);
337 
338 // private slots: ------------------------------------------------------------
339  void onDockAreaViewToggled(bool Visible)
340  {
341  CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(_this->sender());
342  VisibleDockAreaCount += Visible ? 1 : -1;
344  emit _this->dockAreaViewToggled(DockArea, Visible);
345  }
346 }; // struct DockContainerWidgetPrivate
347 
348 
349 //============================================================================
351  _this(_public)
352 {
353  std::fill(std::begin(LastAddedAreaCache),std::end(LastAddedAreaCache), nullptr);
354 }
355 
356 
357 //============================================================================
359 {
360  CDockAreaWidget* DockArea = _this->dockAreaAt(TargetPos);
361  auto dropArea = InvalidDockWidgetArea;
362  auto ContainerDropArea = DockManager->containerOverlay()->dropAreaUnderCursor();
363 
364  if (DockArea)
365  {
366  auto dropOverlay = DockManager->dockAreaOverlay();
367  dropOverlay->setAllowedAreas(DockArea->allowedAreas());
368  dropArea = dropOverlay->showOverlay(DockArea);
369  if (ContainerDropArea != InvalidDockWidgetArea &&
370  ContainerDropArea != dropArea)
371  {
372  dropArea = InvalidDockWidgetArea;
373  }
374 
375  if (dropArea != InvalidDockWidgetArea)
376  {
377  ADS_PRINT("Dock Area Drop Content: " << dropArea);
378  return DropModeIntoArea;
379  }
380  }
381 
382  // mouse is over container
383  if (InvalidDockWidgetArea == dropArea)
384  {
385  dropArea = ContainerDropArea;
386  ADS_PRINT("Container Drop Content: " << dropArea);
387  if (dropArea != InvalidDockWidgetArea)
388  {
389  return DropModeIntoContainer;
390  }
391  }
392 
393  return DropModeInvalid;
394 }
395 
396 
397 //============================================================================
399 {
401 
402  if (TopLevelDockArea)
403  {
407  }
408  else if (this->TopLevelDockArea)
409  {
410  this->TopLevelDockArea->titleBarButton(TitleBarButtonUndock)->setVisible(true);
411  this->TopLevelDockArea->titleBarButton(TitleBarButtonClose)->setVisible(true);
412  this->TopLevelDockArea = nullptr;
413  }
414 }
415 
416 
417 //============================================================================
419  DockWidgetArea area)
420 {
421  auto InsertParam = internal::dockAreaInsertParameters(area);
422  CDockContainerWidget* FloatingDockContainer = FloatingWidget->dockContainer();
423  auto NewDockAreas = FloatingDockContainer->findChildren<CDockAreaWidget*>(
424  QString(), Qt::FindChildrenRecursively);
425  QSplitter* Splitter = RootSplitter;
426 
427  if (DockAreas.count() <= 1)
428  {
429  Splitter->setOrientation(InsertParam.orientation());
430  }
431  else if (Splitter->orientation() != InsertParam.orientation())
432  {
433  QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
434  QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
435  NewSplitter->addWidget(Splitter);
436  updateSplitterHandles(NewSplitter);
437  Splitter = NewSplitter;
438  delete li;
439  }
440 
441  // Now we can insert the floating widget content into this container
442  auto FloatingSplitter = FloatingDockContainer->rootSplitter();
443  if (FloatingSplitter->count() == 1)
444  {
445  insertWidgetIntoSplitter(Splitter, FloatingSplitter->widget(0), InsertParam.append());
446  updateSplitterHandles(Splitter);
447  }
448  else if (FloatingSplitter->orientation() == InsertParam.orientation())
449  {
450  int InsertIndex = InsertParam.append() ? Splitter->count() : 0;
451  while (FloatingSplitter->count())
452  {
453  Splitter->insertWidget(InsertIndex++, FloatingSplitter->widget(0));
454  updateSplitterHandles(Splitter);
455  }
456  }
457  else
458  {
459  insertWidgetIntoSplitter(Splitter, FloatingSplitter, InsertParam.append());
460  }
461 
462  RootSplitter = Splitter;
463  addDockAreasToList(NewDockAreas);
464 
465  // If we dropped the floating widget into the main dock container that does
466  // not contain any dock widgets, then splitter is invisible and we need to
467  // show it to display the docked widgets
468  if (!Splitter->isVisible())
469  {
470  Splitter->show();
471  }
472  _this->dumpLayout();
473 }
474 
475 
476 //============================================================================
478  CFloatingDockContainer* FloatingWidget, CDockAreaWidget* TargetArea)
479 {
480  CDockContainerWidget* FloatingContainer = FloatingWidget->dockContainer();
481  auto NewDockWidgets = FloatingContainer->dockWidgets();
482  auto TopLevelDockArea = FloatingContainer->topLevelDockArea();
483  int NewCurrentIndex = -1;
484 
485  // If the floating widget contains only one single dock are, then the
486  // current dock widget of the dock area will also be the future current
487  // dock widget in the drop area.
488  if (TopLevelDockArea)
489  {
490  NewCurrentIndex = TopLevelDockArea->currentIndex();
491  }
492 
493  for (int i = 0; i < NewDockWidgets.count(); ++i)
494  {
495  CDockWidget* DockWidget = NewDockWidgets[i];
496  TargetArea->insertDockWidget(i, DockWidget, false);
497  // If the floating widget contains multiple visible dock areas, then we
498  // simply pick the first visible open dock widget and make it
499  // the current one.
500  if (NewCurrentIndex < 0 && !DockWidget->isClosed())
501  {
502  NewCurrentIndex = i;
503  }
504  }
505  TargetArea->setCurrentIndex(NewCurrentIndex);
506  TargetArea->updateTitleBarVisibility();
507  return;
508 }
509 
510 
511 //============================================================================
513  CDockAreaWidget* TargetArea, DockWidgetArea area)
514 {
515  // Dropping into center means all dock widgets in the dropped floating
516  // widget will become tabs of the drop area
517  if (CenterDockWidgetArea == area)
518  {
519  dropIntoCenterOfSection(FloatingWidget, TargetArea);
520  return;
521  }
522 
523  auto InsertParam = internal::dockAreaInsertParameters(area);
524  auto NewDockAreas = FloatingWidget->dockContainer()->findChildren<CDockAreaWidget*>(
525  QString(), Qt::FindChildrenRecursively);
526  QSplitter* TargetAreaSplitter = internal::findParent<QSplitter*>(TargetArea);
527 
528  if (!TargetAreaSplitter)
529  {
530  QSplitter* Splitter = newSplitter(InsertParam.orientation());
531  Layout->replaceWidget(TargetArea, Splitter);
532  Splitter->addWidget(TargetArea);
533  updateSplitterHandles(Splitter);
534  TargetAreaSplitter = Splitter;
535  }
536  int AreaIndex = TargetAreaSplitter->indexOf(TargetArea);
537  auto Widget = FloatingWidget->dockContainer()->findChild<QWidget*>(QString(), Qt::FindDirectChildrenOnly);
538  auto FloatingSplitter = qobject_cast<QSplitter*>(Widget);
539 
540  if (TargetAreaSplitter->orientation() == InsertParam.orientation())
541  {
542  auto Sizes = TargetAreaSplitter->sizes();
543  int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
544  bool AdjustSplitterSizes = true;
545  if ((FloatingSplitter->orientation() != InsertParam.orientation()) && FloatingSplitter->count() > 1)
546  {
547  TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), Widget);
548  updateSplitterHandles(TargetAreaSplitter);
549  }
550  else
551  {
552  AdjustSplitterSizes = (FloatingSplitter->count() == 1);
553  int InsertIndex = AreaIndex + InsertParam.insertOffset();
554  while (FloatingSplitter->count())
555  {
556  TargetAreaSplitter->insertWidget(InsertIndex++, FloatingSplitter->widget(0));
557  updateSplitterHandles(TargetAreaSplitter);
558  }
559  }
560 
561  if (AdjustSplitterSizes)
562  {
563  int Size = (TargetAreaSize - TargetAreaSplitter->handleWidth()) / 2;
564  Sizes[AreaIndex] = Size;
565  Sizes.insert(AreaIndex, Size);
566  TargetAreaSplitter->setSizes(Sizes);
567  }
568  }
569  else
570  {
571  QList<int> NewSplitterSizes;
572  QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
573  int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
574  bool AdjustSplitterSizes = true;
575  if ((FloatingSplitter->orientation() != InsertParam.orientation()) && FloatingSplitter->count() > 1)
576  {
577  NewSplitter->addWidget(Widget);
578  updateSplitterHandles(NewSplitter);
579  }
580  else
581  {
582  AdjustSplitterSizes = (FloatingSplitter->count() == 1);
583  while (FloatingSplitter->count())
584  {
585  NewSplitter->addWidget(FloatingSplitter->widget(0));
586  updateSplitterHandles(NewSplitter);
587  }
588  }
589 
590  // Save the sizes before insertion and restore it later to prevent
591  // shrinking of existing area
592  auto Sizes = TargetAreaSplitter->sizes();
593  insertWidgetIntoSplitter(NewSplitter, TargetArea, !InsertParam.append());
594  updateSplitterHandles(NewSplitter);
595  if (AdjustSplitterSizes)
596  {
597  int Size = TargetAreaSize / 2;
598  NewSplitter->setSizes({Size, Size});
599  }
600  TargetAreaSplitter->insertWidget(AreaIndex, NewSplitter);
601  TargetAreaSplitter->setSizes(Sizes);
602  updateSplitterHandles(TargetAreaSplitter);
603  }
604 
605  addDockAreasToList(NewDockAreas);
606  _this->dumpLayout();
607 }
608 
609 
610 //============================================================================
612 {
613  auto DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
614  auto DroppedArea = qobject_cast<CDockAreaWidget*>(Widget);
615 
616  if (DroppedDockWidget)
617  {
618  CDockAreaWidget* OldDockArea = DroppedDockWidget->dockAreaWidget();
619  if (OldDockArea == TargetArea)
620  {
621  return;
622  }
623 
624  if (OldDockArea)
625  {
626  OldDockArea->removeDockWidget(DroppedDockWidget);
627  }
628  TargetArea->insertDockWidget(0, DroppedDockWidget, true);
629  }
630  else
631  {
632  QList<CDockWidget*> NewDockWidgets = DroppedArea->dockWidgets();
633  int NewCurrentIndex = DroppedArea->currentIndex();
634  for (int i = 0; i < NewDockWidgets.count(); ++i)
635  {
636  CDockWidget* DockWidget = NewDockWidgets[i];
637  TargetArea->insertDockWidget(i, DockWidget, false);
638  }
639  TargetArea->setCurrentIndex(NewCurrentIndex);
640  DroppedArea->dockContainer()->removeDockArea(DroppedArea);
641  DroppedArea->deleteLater();
642  }
643 
644  TargetArea->updateTitleBarVisibility();
645  return;
646 }
647 
648 
649 //============================================================================
651 {
652  // Dropping into center means all dock widgets in the dropped floating
653  // widget will become tabs of the drop area
654  if (CenterDockWidgetArea == area)
655  {
656  moveIntoCenterOfSection(Widget, TargetArea);
657  return;
658  }
659 
660 
661  CDockWidget* DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
662  CDockAreaWidget* DroppedDockArea = qobject_cast<CDockAreaWidget*>(Widget);
663  CDockAreaWidget* NewDockArea;
664  if (DroppedDockWidget)
665  {
666  NewDockArea = new CDockAreaWidget(DockManager, _this);
667  CDockAreaWidget* OldDockArea = DroppedDockWidget->dockAreaWidget();
668  if (OldDockArea)
669  {
670  OldDockArea->removeDockWidget(DroppedDockWidget);
671  }
672  NewDockArea->addDockWidget(DroppedDockWidget);
673  }
674  else
675  {
676  DroppedDockArea->dockContainer()->removeDockArea(DroppedDockArea);
677  NewDockArea = DroppedDockArea;
678  }
679 
680  auto InsertParam = internal::dockAreaInsertParameters(area);
681  QSplitter* TargetAreaSplitter = internal::findParent<QSplitter*>(TargetArea);
682  int AreaIndex = TargetAreaSplitter->indexOf(TargetArea);
683  auto Sizes = TargetAreaSplitter->sizes();
684  if (TargetAreaSplitter->orientation() == InsertParam.orientation())
685  {
686  int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
687  TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), NewDockArea);
688  updateSplitterHandles(TargetAreaSplitter);
689  int Size = (TargetAreaSize - TargetAreaSplitter->handleWidth()) / 2;
690  Sizes[AreaIndex] = Size;
691  Sizes.insert(AreaIndex, Size);
692  }
693  else
694  {
695  auto Sizes = TargetAreaSplitter->sizes();
696  int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
697  QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
698  NewSplitter->addWidget(TargetArea);
699  insertWidgetIntoSplitter(NewSplitter, NewDockArea, InsertParam.append());
700  updateSplitterHandles(NewSplitter);
701  int Size = TargetAreaSize / 2;
702  NewSplitter->setSizes({Size, Size});
703  TargetAreaSplitter->insertWidget(AreaIndex, NewSplitter);
704  updateSplitterHandles(TargetAreaSplitter);
705  }
706  TargetAreaSplitter->setSizes(Sizes);
707 
708  addDockAreasToList({NewDockArea});
709 }
710 
711 
712 //============================================================================
714 {
715  if (!DockManager->centralWidget() || !splitter)
716  {
717  return;
718  }
719 
720  for (int i = 0; i < splitter->count(); ++i)
721  {
722  splitter->setStretchFactor(i, widgetResizesWithContainer(splitter->widget(i)) ? 1 : 0);
723  }
724 }
725 
726 
727 //============================================================================
729 {
730  if (!DockManager->centralWidget())
731  {
732  return true;
733  }
734 
735  auto Area = qobject_cast<CDockAreaWidget*>(widget);
736  if(Area)
737  {
738  return Area->isCentralWidgetArea();
739  }
740 
741  auto innerSplitter = qobject_cast<CDockSplitter*>(widget);
742  if (innerSplitter)
743  {
744  return innerSplitter->isResizingWithContainer();
745  }
746 
747  return false;
748 }
749 
750 
751 
752 //============================================================================
754 {
755  CDockWidget* DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
756  CDockAreaWidget* DroppedDockArea = qobject_cast<CDockAreaWidget*>(Widget);
757  CDockAreaWidget* NewDockArea;
758 
759  if (DroppedDockWidget)
760  {
761  NewDockArea = new CDockAreaWidget(DockManager, _this);
762  CDockAreaWidget* OldDockArea = DroppedDockWidget->dockAreaWidget();
763  if (OldDockArea)
764  {
765  OldDockArea->removeDockWidget(DroppedDockWidget);
766  }
767  NewDockArea->addDockWidget(DroppedDockWidget);
768  }
769  else
770  {
771  // We check, if we insert the dropped widget into the same place that
772  // it already has and do nothing, if it is the same place. It would
773  // also work without this check, but it looks nicer with the check
774  // because there will be no layout updates
775  auto Splitter = internal::findParent<CDockSplitter*>(DroppedDockArea);
776  auto InsertParam = internal::dockAreaInsertParameters(area);
777  if (Splitter == RootSplitter && InsertParam.orientation() == Splitter->orientation())
778  {
779  if (InsertParam.append() && Splitter->lastWidget() == DroppedDockArea)
780  {
781  return;
782  }
783  else if (!InsertParam.append() && Splitter->firstWidget() == DroppedDockArea)
784  {
785  return;
786  }
787  }
788  DroppedDockArea->dockContainer()->removeDockArea(DroppedDockArea);
789  NewDockArea = DroppedDockArea;
790  }
791 
792  addDockArea(NewDockArea, area);
793  LastAddedAreaCache[areaIdToIndex(area)] = NewDockArea;
794 }
795 
796 
797 //============================================================================
799 {
800  int CountBefore = DockAreas.count();
801  int NewAreaCount = NewDockAreas.count();
802  appendDockAreas(NewDockAreas);
803  // If the user dropped a floating widget that contains only one single
804  // visible dock area, then its title bar button TitleBarButtonUndock is
805  // likely hidden. We need to ensure, that it is visible
806  for (auto DockArea : NewDockAreas)
807  {
808  DockArea->titleBarButton(TitleBarButtonUndock)->setVisible(true);
809  DockArea->titleBarButton(TitleBarButtonClose)->setVisible(true);
810  }
811 
812  // We need to ensure, that the dock area title bar is visible. The title bar
813  // is invisible, if the dock are is a single dock area in a floating widget.
814  if (1 == CountBefore)
815  {
816  DockAreas.at(0)->updateTitleBarVisibility();
817  }
818 
819  if (1 == NewAreaCount)
820  {
821  DockAreas.last()->updateTitleBarVisibility();
822  }
823 
825 }
826 
827 
828 //============================================================================
830 {
831  DockAreas.append(NewDockAreas);
832  for (auto DockArea : NewDockAreas)
833  {
834  QObject::connect(DockArea,
836  _this,
837  std::bind(&DockContainerWidgetPrivate::onDockAreaViewToggled, this, std::placeholders::_1));
838  }
839 }
840 
841 
842 //============================================================================
843 void DockContainerWidgetPrivate::saveChildNodesState(QXmlStreamWriter& s, QWidget* Widget)
844 {
845  QSplitter* Splitter = qobject_cast<QSplitter*>(Widget);
846  if (Splitter)
847  {
848  s.writeStartElement("Splitter");
849  s.writeAttribute("Orientation", (Splitter->orientation() == Qt::Horizontal) ? "|" : "-");
850  s.writeAttribute("Count", QString::number(Splitter->count()));
851  ADS_PRINT("NodeSplitter orient: " << Splitter->orientation()
852  << " WidgetCont: " << Splitter->count());
853  for (int i = 0; i < Splitter->count(); ++i)
854  {
855  saveChildNodesState(s, Splitter->widget(i));
856  }
857 
858  s.writeStartElement("Sizes");
859  for (auto Size : Splitter->sizes())
860  {
861  s.writeCharacters(QString::number(Size) + " ");
862  }
863  s.writeEndElement();
864  s.writeEndElement();
865  }
866  else
867  {
868  CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(Widget);
869  if (DockArea)
870  {
871  DockArea->saveState(s);
872  }
873  }
874 }
875 
876 
877 //============================================================================
879  QWidget*& CreatedWidget, bool Testing)
880 {
881  bool Ok;
882  QString OrientationStr = s.attributes().value("Orientation").toString();
883 
884  // Check if the orientation string is right
885  if (!OrientationStr.startsWith("|") && !OrientationStr.startsWith("-"))
886  {
887  return false;
888  }
889 
890  // The "|" shall indicate a vertical splitter handle which in turn means
891  // a Horizontal orientation of the splitter layout.
892  bool HorizontalSplitter = OrientationStr.startsWith("|");
893  // In version 0 we had a small bug. The "|" indicated a vertical orientation,
894  // but this is wrong, because only the splitter handle is vertical, the
895  // layout of the splitter is a horizontal layout. We fix this here
896  if (s.fileVersion() == 0)
897  {
898  HorizontalSplitter = !HorizontalSplitter;
899  }
900 
901  int Orientation = HorizontalSplitter ? Qt::Horizontal : Qt::Vertical;
902  int WidgetCount = s.attributes().value("Count").toInt(&Ok);
903  if (!Ok)
904  {
905  return false;
906  }
907  ADS_PRINT("Restore NodeSplitter Orientation: " << Orientation <<
908  " WidgetCount: " << WidgetCount);
909  QSplitter* Splitter = nullptr;
910  if (!Testing)
911  {
912  Splitter = newSplitter(static_cast<Qt::Orientation>(Orientation));
913  }
914  bool Visible = false;
915  QList<int> Sizes;
916  while (s.readNextStartElement())
917  {
918  QWidget* ChildNode = nullptr;
919  bool Result = true;
920  if (s.name() == "Splitter")
921  {
922  Result = restoreSplitter(s, ChildNode, Testing);
923  }
924  else if (s.name() == "Area")
925  {
926  Result = restoreDockArea(s, ChildNode, Testing);
927  }
928  else if (s.name() == "Sizes")
929  {
930  QString sSizes = s.readElementText().trimmed();
931  ADS_PRINT("Sizes: " << sSizes);
932  QTextStream TextStream(&sSizes);
933  while (!TextStream.atEnd())
934  {
935  int value;
936  TextStream >> value;
937  Sizes.append(value);
938  }
939  }
940  else
941  {
942  s.skipCurrentElement();
943  }
944 
945  if (!Result)
946  {
947  return false;
948  }
949 
950  if (Testing || !ChildNode)
951  {
952  continue;
953  }
954 
955  ADS_PRINT("ChildNode isVisible " << ChildNode->isVisible()
956  << " isVisibleTo " << ChildNode->isVisibleTo(Splitter));
957  Splitter->addWidget(ChildNode);
958  Visible |= ChildNode->isVisibleTo(Splitter);
959  }
960  if(!Testing)
961  {
962  updateSplitterHandles(Splitter);
963  }
964 
965  if (Sizes.count() != WidgetCount)
966  {
967  return false;
968  }
969 
970  if (!Testing)
971  {
972  if (!Splitter->count())
973  {
974  delete Splitter;
975  Splitter = nullptr;
976  }
977  else
978  {
979  Splitter->setSizes(Sizes);
980  Splitter->setVisible(Visible);
981  }
982  CreatedWidget = Splitter;
983  }
984  else
985  {
986  CreatedWidget = nullptr;
987  }
988 
989  return true;
990 }
991 
992 
993 //============================================================================
995  QWidget*& CreatedWidget, bool Testing)
996 {
997  bool Ok;
998 #ifdef ADS_DEBUG_PRINT
999  int Tabs = s.attributes().value("Tabs").toInt(&Ok);
1000  if (!Ok)
1001  {
1002  return false;
1003  }
1004 #endif
1005 
1006  QString CurrentDockWidget = s.attributes().value("Current").toString();
1007  ADS_PRINT("Restore NodeDockArea Tabs: " << Tabs << " Current: "
1008  << CurrentDockWidget);
1009 
1010  CDockAreaWidget* DockArea = nullptr;
1011  if (!Testing)
1012  {
1013  DockArea = new CDockAreaWidget(DockManager, _this);
1014  const auto AllowedAreasAttribute = s.attributes().value("AllowedAreas");
1015  if (!AllowedAreasAttribute.isEmpty())
1016  {
1017  DockArea->setAllowedAreas((DockWidgetArea)AllowedAreasAttribute.toInt(nullptr, 16));
1018  }
1019 
1020  const auto FlagsAttribute = s.attributes().value("Flags");
1021  if (!FlagsAttribute.isEmpty())
1022  {
1023  DockArea->setDockAreaFlags((CDockAreaWidget::DockAreaFlags)FlagsAttribute.toInt(nullptr, 16));
1024  }
1025  }
1026 
1027  while (s.readNextStartElement())
1028  {
1029  if (s.name() != "Widget")
1030  {
1031  continue;
1032  }
1033 
1034  auto ObjectName = s.attributes().value("Name");
1035  if (ObjectName.isEmpty())
1036  {
1037  return false;
1038  }
1039 
1040  bool Closed = s.attributes().value("Closed").toInt(&Ok);
1041  if (!Ok)
1042  {
1043  return false;
1044  }
1045 
1046  s.skipCurrentElement();
1047  CDockWidget* DockWidget = DockManager->findDockWidget(ObjectName.toString());
1048  if (!DockWidget || Testing)
1049  {
1050  continue;
1051  }
1052 
1053  ADS_PRINT("Dock Widget found - parent " << DockWidget->parent());
1054  // We hide the DockArea here to prevent the short display (the flashing)
1055  // of the dock areas during application startup
1056  DockArea->hide();
1057  DockArea->addDockWidget(DockWidget);
1058  DockWidget->setToggleViewActionChecked(!Closed);
1059  DockWidget->setClosedState(Closed);
1060  DockWidget->setProperty(internal::ClosedProperty, Closed);
1061  DockWidget->setProperty(internal::DirtyProperty, false);
1062  }
1063 
1064  if (Testing)
1065  {
1066  return true;
1067  }
1068 
1069  if (!DockArea->dockWidgetsCount())
1070  {
1071  delete DockArea;
1072  DockArea = nullptr;
1073  }
1074  else
1075  {
1076  DockArea->setProperty("currentDockWidget", CurrentDockWidget);
1077  appendDockAreas({DockArea});
1078  }
1079 
1080  CreatedWidget = DockArea;
1081  return true;
1082 }
1083 
1084 
1085 //============================================================================
1087  QWidget*& CreatedWidget, bool Testing)
1088 {
1089  bool Result = true;
1090  while (s.readNextStartElement())
1091  {
1092  if (s.name() == "Splitter")
1093  {
1094  Result = restoreSplitter(s, CreatedWidget, Testing);
1095  ADS_PRINT("Splitter");
1096  }
1097  else if (s.name() == "Area")
1098  {
1099  Result = restoreDockArea(s, CreatedWidget, Testing);
1100  ADS_PRINT("DockAreaWidget");
1101  }
1102  else
1103  {
1104  s.skipCurrentElement();
1105  ADS_PRINT("Unknown element");
1106  }
1107  }
1108 
1109  return Result;
1110 }
1111 
1112 
1113 //============================================================================
1115  CDockWidget* Dockwidget)
1116 {
1117  CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this);
1118  NewDockArea->addDockWidget(Dockwidget);
1119  addDockArea(NewDockArea, area);
1120  NewDockArea->updateTitleBarVisibility();
1121  LastAddedAreaCache[areaIdToIndex(area)] = NewDockArea;
1122  return NewDockArea;
1123 }
1124 
1125 
1126 //============================================================================
1128 {
1129  auto InsertParam = internal::dockAreaInsertParameters(area);
1130  // As long as we have only one dock area in the splitter we can adjust
1131  // its orientation
1132  if (DockAreas.count() <= 1)
1133  {
1134  RootSplitter->setOrientation(InsertParam.orientation());
1135  }
1136 
1137  QSplitter* Splitter = RootSplitter;
1138  if (Splitter->orientation() == InsertParam.orientation())
1139  {
1140  insertWidgetIntoSplitter(Splitter, NewDockArea, InsertParam.append());
1141  updateSplitterHandles(Splitter);
1142  if (Splitter->isHidden())
1143  {
1144  Splitter->show();
1145  }
1146  }
1147  else
1148  {
1149  QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
1150  if (InsertParam.append())
1151  {
1152  QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
1153  NewSplitter->addWidget(Splitter);
1154  NewSplitter->addWidget(NewDockArea);
1155  updateSplitterHandles(NewSplitter);
1156  delete li;
1157  }
1158  else
1159  {
1160  NewSplitter->addWidget(NewDockArea);
1161  QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
1162  NewSplitter->addWidget(Splitter);
1163  updateSplitterHandles(NewSplitter);
1164  delete li;
1165  }
1166  RootSplitter = NewSplitter;
1167  }
1168 
1169  addDockAreasToList({NewDockArea});
1170 }
1171 
1172 
1173 //============================================================================
1174 void DockContainerWidgetPrivate::dumpRecursive(int level, QWidget* widget)
1175 {
1176 #if defined(QT_DEBUG)
1177  QSplitter* Splitter = qobject_cast<QSplitter*>(widget);
1178  QByteArray buf;
1179  buf.fill(' ', level * 4);
1180  if (Splitter)
1181  {
1182 #ifdef ADS_DEBUG_PRINT
1183  qDebug("%sSplitter %s v: %s c: %s",
1184  (const char*)buf,
1185  (Splitter->orientation() == Qt::Vertical) ? "--" : "|",
1186  Splitter->isHidden() ? " " : "v",
1187  QString::number(Splitter->count()).toStdString().c_str());
1188  std::cout << (const char*)buf << "Splitter "
1189  << ((Splitter->orientation() == Qt::Vertical) ? "--" : "|") << " "
1190  << (Splitter->isHidden() ? " " : "v") << " "
1191  << QString::number(Splitter->count()).toStdString() << std::endl;
1192 #endif
1193  for (int i = 0; i < Splitter->count(); ++i)
1194  {
1195  dumpRecursive(level + 1, Splitter->widget(i));
1196  }
1197  }
1198  else
1199  {
1200  CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(widget);
1201  if (!DockArea)
1202  {
1203  return;
1204  }
1205 #ifdef ADS_DEBUG_PRINT
1206  qDebug("%sDockArea", (const char*)buf);
1207  std::cout << (const char*)buf
1208  << (DockArea->isHidden() ? " " : "v")
1209  << (DockArea->openDockWidgetsCount() > 0 ? " " : "c")
1210  << " DockArea " << "[hs: " << DockArea->sizePolicy().horizontalStretch() << ", vs: " << DockArea->sizePolicy().verticalStretch() << "]" << std::endl;
1211  buf.fill(' ', (level + 1) * 4);
1212  for (int i = 0; i < DockArea->dockWidgetsCount(); ++i)
1213  {
1214  std::cout << (const char*)buf << (i == DockArea->currentIndex() ? "*" : " ");
1215  CDockWidget* DockWidget = DockArea->dockWidget(i);
1216  std::cout << (DockWidget->isHidden() ? " " : "v");
1217  std::cout << (DockWidget->isClosed() ? "c" : " ") << " ";
1218  std::cout << DockWidget->windowTitle().toStdString() << std::endl;
1219  }
1220 #endif
1221  }
1222 #else
1223  Q_UNUSED(level);
1224  Q_UNUSED(widget);
1225 #endif
1226 }
1227 
1228 
1229 //============================================================================
1231  CDockWidget* Dockwidget, CDockAreaWidget* TargetDockArea)
1232 {
1233  if (CenterDockWidgetArea == area)
1234  {
1235  TargetDockArea->addDockWidget(Dockwidget);
1236  TargetDockArea->updateTitleBarVisibility();
1237  return TargetDockArea;
1238  }
1239 
1240  CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this);
1241  NewDockArea->addDockWidget(Dockwidget);
1242  auto InsertParam = internal::dockAreaInsertParameters(area);
1243 
1244  QSplitter* TargetAreaSplitter = internal::findParent<QSplitter*>(TargetDockArea);
1245  int index = TargetAreaSplitter ->indexOf(TargetDockArea);
1246  if (TargetAreaSplitter->orientation() == InsertParam.orientation())
1247  {
1248  ADS_PRINT("TargetAreaSplitter->orientation() == InsertParam.orientation()");
1249  TargetAreaSplitter->insertWidget(index + InsertParam.insertOffset(), NewDockArea);
1250  updateSplitterHandles(TargetAreaSplitter);
1251  // do nothing, if flag is not enabled
1253  {
1254  adjustSplitterSizesOnInsertion(TargetAreaSplitter);
1255  }
1256  }
1257  else
1258  {
1259  ADS_PRINT("TargetAreaSplitter->orientation() != InsertParam.orientation()");
1260  auto TargetAreaSizes = TargetAreaSplitter->sizes();
1261  QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
1262  NewSplitter->addWidget(TargetDockArea);
1263 
1264  insertWidgetIntoSplitter(NewSplitter, NewDockArea, InsertParam.append());
1265  updateSplitterHandles(NewSplitter);
1266  TargetAreaSplitter->insertWidget(index, NewSplitter);
1267  updateSplitterHandles(TargetAreaSplitter);
1269  {
1270  TargetAreaSplitter->setSizes(TargetAreaSizes);
1271  adjustSplitterSizesOnInsertion(NewSplitter);
1272  }
1273  }
1274 
1275  addDockAreasToList({NewDockArea});
1276  return NewDockArea;
1277 }
1278 
1279 
1280 //============================================================================
1282  QFrame(parent),
1283  d(new DockContainerWidgetPrivate(this))
1284 {
1285  d->DockManager = DockManager;
1286  d->isFloating = floatingWidget() != nullptr;
1287 
1288  d->Layout = new QGridLayout();
1289  d->Layout->setContentsMargins(0, 1, 0, 1);
1290  d->Layout->setSpacing(0);
1291  setLayout(d->Layout);
1292 
1293  // The function d->newSplitter() accesses the config flags from dock
1294  // manager which in turn requires a properly constructed dock manager.
1295  // If this dock container is the dock manager, then it is not properly
1296  // constructed yet because this base class constructor is called before
1297  // the constructor of the DockManager private class
1298  if (DockManager != this)
1299  {
1300  d->DockManager->registerDockContainer(this);
1302  }
1303 }
1304 
1305 //============================================================================
1307 {
1308  if (d->DockManager)
1309  {
1310  d->DockManager->removeDockContainer(this);
1311  }
1312  delete d;
1313 }
1314 
1315 
1316 //============================================================================
1318  CDockAreaWidget* DockAreaWidget)
1319 {
1320  CDockAreaWidget* OldDockArea = Dockwidget->dockAreaWidget();
1321  if (OldDockArea)
1322  {
1323  OldDockArea->removeDockWidget(Dockwidget);
1324  }
1325 
1326  Dockwidget->setDockManager(d->DockManager);
1327  if (DockAreaWidget)
1328  {
1329  return d->addDockWidgetToDockArea(area, Dockwidget, DockAreaWidget);
1330  }
1331  else
1332  {
1333  return d->addDockWidgetToContainer(area, Dockwidget);
1334  }
1335 }
1336 
1337 //============================================================================
1339 {
1340  CDockAreaWidget* Area = Dockwidget->dockAreaWidget();
1341  if (Area)
1342  {
1343  Area->removeDockWidget(Dockwidget);
1344  }
1345 }
1346 
1347 //============================================================================
1349 {
1350  return d->zOrderIndex;
1351 }
1352 
1353 
1354 //============================================================================
1356 {
1357  return this->zOrderIndex() > Other->zOrderIndex();
1358 }
1359 
1360 
1361 //============================================================================
1363 {
1364  bool Result = QWidget::event(e);
1365  if (e->type() == QEvent::WindowActivate)
1366  {
1368  }
1369  else if (e->type() == QEvent::Show && !d->zOrderIndex)
1370  {
1372  }
1373 
1374  return Result;
1375 }
1376 
1377 
1378 //============================================================================
1380  DockWidgetArea area)
1381 {
1382  CDockContainerWidget* Container = DockAreaWidget->dockContainer();
1383  if (Container && Container != this)
1384  {
1385  Container->removeDockArea(DockAreaWidget);
1386  }
1387 
1388  d->addDockArea(DockAreaWidget, area);
1389 }
1390 
1391 
1392 //============================================================================
1394 {
1395  ADS_PRINT("CDockContainerWidget::removeDockArea");
1396  area->disconnect(this);
1397  d->DockAreas.removeAll(area);
1398  CDockSplitter* Splitter = internal::findParent<CDockSplitter*>(area);
1399 
1400  // Remove are from parent splitter and recursively hide tree of parent
1401  // splitters if it has no visible content
1402  area->setParent(nullptr);
1404 
1405  // Remove this area from cached areas
1406  auto p = std::find(std::begin(d->LastAddedAreaCache), std::end(d->LastAddedAreaCache), area);
1407  if (p != std::end(d->LastAddedAreaCache)) {
1408  *p = nullptr;
1409  }
1410 
1411  // If splitter has more than 1 widgets, we are finished and can leave
1412  if (Splitter->count() > 1)
1413  {
1414  goto emitAndExit;
1415  }
1416 
1417  // If this is the RootSplitter we need to remove empty splitters to
1418  // avoid too many empty splitters
1419  if (Splitter == d->RootSplitter)
1420  {
1421  ADS_PRINT("Removed from RootSplitter");
1422  // If splitter is empty, we are finished
1423  if (!Splitter->count())
1424  {
1425  Splitter->hide();
1426  goto emitAndExit;
1427  }
1428 
1429  QWidget* widget = Splitter->widget(0);
1430  QSplitter* ChildSplitter = qobject_cast<QSplitter*>(widget);
1431  // If the one and only content widget of the splitter is not a splitter
1432  // then we are finished
1433  if (!ChildSplitter)
1434  {
1435  goto emitAndExit;
1436  }
1437 
1438  // We replace the superfluous RootSplitter with the ChildSplitter
1439  ChildSplitter->setParent(nullptr);
1440  QLayoutItem* li = d->Layout->replaceWidget(Splitter, ChildSplitter);
1441  d->RootSplitter = ChildSplitter;
1442  delete li;
1443  ADS_PRINT("RootSplitter replaced by child splitter");
1444  }
1445  else if (Splitter->count() == 1)
1446  {
1447  ADS_PRINT("Replacing splitter with content");
1448  QSplitter* ParentSplitter = internal::findParent<QSplitter*>(Splitter);
1449  auto Sizes = ParentSplitter->sizes();
1450  QWidget* widget = Splitter->widget(0);
1451  widget->setParent(this);
1452  internal::replaceSplitterWidget(ParentSplitter, Splitter, widget);
1453  ParentSplitter->setSizes(Sizes);
1454  }
1455 
1456  delete Splitter;
1457  Splitter = nullptr;
1458 
1459 emitAndExit:
1460  updateSplitterHandles(Splitter);
1461  CDockWidget* TopLevelWidget = topLevelDockWidget();
1462 
1463  // Updated the title bar visibility of the dock widget if there is only
1464  // one single visible dock widget
1465  CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true);
1466  dumpLayout();
1468 }
1469 
1470 
1471 //============================================================================
1472 CDockAreaWidget* CDockContainerWidget::dockAreaAt(const QPoint& GlobalPos) const
1473 {
1474  for (const auto& DockArea : d->DockAreas)
1475  {
1476  if (DockArea->isVisible() && DockArea->rect().contains(DockArea->mapFromGlobal(GlobalPos)))
1477  {
1478  return DockArea;
1479  }
1480  }
1481 
1482  return nullptr;
1483 }
1484 
1485 
1486 //============================================================================
1488 {
1489  return (Index < dockAreaCount()) ? d->DockAreas[Index] : nullptr;
1490 }
1491 
1492 
1493 //============================================================================
1495 {
1496  return d->isFloating;
1497 }
1498 
1499 
1500 //============================================================================
1502 {
1503  return d->DockAreas.count();
1504 }
1505 
1506 
1507 //============================================================================
1509 {
1510  int Result = 0;
1511  for (auto DockArea : d->DockAreas)
1512  {
1513  Result += DockArea->isHidden() ? 0 : 1;
1514  }
1515 
1516  return Result;
1517 
1518  // TODO Cache or precalculate this to speed it up because it is used during
1519  // movement of floating widget
1520  //return d->visibleDockAreaCount();
1521 }
1522 
1523 
1524 //============================================================================
1526  const QPoint& TargetPos)
1527 {
1528  ADS_PRINT("CDockContainerWidget::dropFloatingWidget");
1529  CDockWidget* SingleDroppedDockWidget = FloatingWidget->topLevelDockWidget();
1530  CDockWidget* SingleDockWidget = topLevelDockWidget();
1531  CDockAreaWidget* DockArea = dockAreaAt(TargetPos);
1532  auto dropArea = InvalidDockWidgetArea;
1533  auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
1534  bool Dropped = false;
1535 
1536  if (DockArea)
1537  {
1538  auto dropOverlay = d->DockManager->dockAreaOverlay();
1539  dropOverlay->setAllowedAreas(DockArea->allowedAreas());
1540  dropArea = dropOverlay->showOverlay(DockArea);
1541  if (ContainerDropArea != InvalidDockWidgetArea &&
1542  ContainerDropArea != dropArea)
1543  {
1544  dropArea = InvalidDockWidgetArea;
1545  }
1546 
1547  if (dropArea != InvalidDockWidgetArea)
1548  {
1549  ADS_PRINT("Dock Area Drop Content: " << dropArea);
1550  d->dropIntoSection(FloatingWidget, DockArea, dropArea);
1551  Dropped = true;
1552  }
1553  }
1554 
1555  // mouse is over container
1556  if (InvalidDockWidgetArea == dropArea)
1557  {
1558  dropArea = ContainerDropArea;
1559  ADS_PRINT("Container Drop Content: " << dropArea);
1560  if (dropArea != InvalidDockWidgetArea)
1561  {
1562  d->dropIntoContainer(FloatingWidget, dropArea);
1563  Dropped = true;
1564  }
1565  }
1566 
1567  if (Dropped)
1568  {
1569  FloatingWidget->deleteLater();
1570 
1571  // If we dropped a floating widget with only one single dock widget, then we
1572  // drop a top level widget that changes from floating to docked now
1573  CDockWidget::emitTopLevelEventForWidget(SingleDroppedDockWidget, false);
1574 
1575  // If there was a top level widget before the drop, then it is not top
1576  // level widget anymore
1577  CDockWidget::emitTopLevelEventForWidget(SingleDockWidget, false);
1578  }
1579 
1580  window()->activateWindow();
1581  if (SingleDroppedDockWidget)
1582  {
1583  d->DockManager->notifyWidgetOrAreaRelocation(SingleDroppedDockWidget);
1584  }
1585  d->DockManager->notifyFloatingWidgetDrop(FloatingWidget);
1586 }
1587 
1588 
1589 //============================================================================
1590 void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget)
1591 {
1592  CDockWidget* SingleDockWidget = topLevelDockWidget();
1593  if (TargetAreaWidget)
1594  {
1595  d->moveToNewSection(Widget, TargetAreaWidget, DropArea);
1596  }
1597  else
1598  {
1599  d->moveToContainer(Widget, DropArea);
1600  }
1601 
1602  // If there was a top level widget before the drop, then it is not top
1603  // level widget anymore
1604  CDockWidget::emitTopLevelEventForWidget(SingleDockWidget, false);
1605 
1606  window()->activateWindow();
1607  d->DockManager->notifyWidgetOrAreaRelocation(Widget);
1608 }
1609 
1610 
1611 //============================================================================
1613 {
1614  QList<CDockAreaWidget*> Result;
1615  for (auto DockArea : d->DockAreas)
1616  {
1617  if (!DockArea->isHidden())
1618  {
1619  Result.append(DockArea);
1620  }
1621  }
1622 
1623  return Result;
1624 }
1625 
1626 
1627 //============================================================================
1628 void CDockContainerWidget::saveState(QXmlStreamWriter& s) const
1629 {
1630  ADS_PRINT("CDockContainerWidget::saveState isFloating "
1631  << isFloating());
1632 
1633  s.writeStartElement("Container");
1634  s.writeAttribute("Floating", QString::number(isFloating() ? 1 : 0));
1635  if (isFloating())
1636  {
1637  CFloatingDockContainer* FloatingWidget = floatingWidget();
1638  QByteArray Geometry = FloatingWidget->saveGeometry();
1639 #if QT_VERSION < 0x050900
1640  s.writeTextElement("Geometry", qByteArrayToHex(Geometry, ' '));
1641 #else
1642  s.writeTextElement("Geometry", Geometry.toHex(' '));
1643 #endif
1644  }
1646  s.writeEndElement();
1647 }
1648 
1649 
1650 //============================================================================
1652 {
1653  bool IsFloating = s.attributes().value("Floating").toInt();
1654  ADS_PRINT("Restore CDockContainerWidget Floating" << IsFloating);
1655 
1656  QWidget*NewRootSplitter {};
1657  if (!Testing)
1658  {
1659  d->VisibleDockAreaCount = -1;// invalidate the dock area count
1660  d->DockAreas.clear();
1661  std::fill(std::begin(d->LastAddedAreaCache),std::end(d->LastAddedAreaCache), nullptr);
1662  }
1663 
1664  if (IsFloating)
1665  {
1666  ADS_PRINT("Restore floating widget");
1667  if (!s.readNextStartElement() || s.name() != "Geometry")
1668  {
1669  return false;
1670  }
1671 
1672  QByteArray GeometryString = s.readElementText(CDockingStateReader::ErrorOnUnexpectedElement).toLocal8Bit();
1673  QByteArray Geometry = QByteArray::fromHex(GeometryString);
1674  if (Geometry.isEmpty())
1675  {
1676  return false;
1677  }
1678 
1679  if (!Testing)
1680  {
1681  CFloatingDockContainer* FloatingWidget = floatingWidget();
1682  FloatingWidget->restoreGeometry(Geometry);
1683  }
1684  }
1685 
1686  if (!d->restoreChildNodes(s, NewRootSplitter, Testing))
1687  {
1688  return false;
1689  }
1690 
1691  if (Testing)
1692  {
1693  return true;
1694  }
1695 
1696  // If the root splitter is empty, rostoreChildNodes returns a 0 pointer
1697  // and we need to create a new empty root splitter
1698  if (!NewRootSplitter)
1699  {
1700  NewRootSplitter = d->newSplitter(Qt::Horizontal);
1701  }
1702 
1703  d->Layout->replaceWidget(d->RootSplitter, NewRootSplitter);
1704  QSplitter* OldRoot = d->RootSplitter;
1705  d->RootSplitter = qobject_cast<QSplitter*>(NewRootSplitter);
1706  OldRoot->deleteLater();
1707 
1708  return true;
1709 }
1710 
1711 
1712 //============================================================================
1714 {
1715  return d->RootSplitter;
1716 }
1717 
1718 
1719 //============================================================================
1721 {
1722  if (d->RootSplitter)
1723  {
1724  return;
1725  }
1726  d->RootSplitter = d->newSplitter(Qt::Horizontal);
1727  d->Layout->addWidget(d->RootSplitter);
1728 }
1729 
1730 
1731 //============================================================================
1733 {
1734 #if (ADS_DEBUG_LEVEL > 0)
1735  qDebug("\n\nDumping layout --------------------------");
1736  std::cout << "\n\nDumping layout --------------------------" << std::endl;
1737  d->dumpRecursive(0, d->RootSplitter);
1738  qDebug("--------------------------\n\n");
1739  std::cout << "--------------------------\n\n" << std::endl;
1740 #endif
1741 }
1742 
1743 
1744 //============================================================================
1746 {
1747  return d->LastAddedAreaCache[areaIdToIndex(area)];
1748 }
1749 
1750 
1751 //============================================================================
1753 {
1754  auto DockAreas = openedDockAreas();
1755  if (DockAreas.count() != 1)
1756  {
1757  return false;
1758  }
1759 
1760  return DockAreas[0]->openDockWidgetsCount() == 1;
1761 }
1762 
1763 
1764 //============================================================================
1766 {
1767  auto TopLevelDockArea = topLevelDockArea();
1768  if (!TopLevelDockArea)
1769  {
1770  return nullptr;
1771  }
1772 
1773  auto DockWidgets = TopLevelDockArea->openedDockWidgets();
1774  if (DockWidgets.count() != 1)
1775  {
1776  return nullptr;
1777  }
1778 
1779  return DockWidgets[0];
1780 
1781 }
1782 
1783 
1784 //============================================================================
1786 {
1787  auto DockAreas = openedDockAreas();
1788  if (DockAreas.count() != 1)
1789  {
1790  return nullptr;
1791  }
1792 
1793  return DockAreas[0];
1794 }
1795 
1796 
1797 //============================================================================
1799 {
1800  QList<CDockWidget*> Result;
1801  for (const auto DockArea : d->DockAreas)
1802  {
1803  Result.append(DockArea->dockWidgets());
1804  }
1805 
1806  return Result;
1807 }
1808 
1809 
1810 //============================================================================
1812 {
1813  d->updateSplitterHandles(splitter);
1814 }
1815 
1816 
1817 //============================================================================
1818 CDockWidget::DockWidgetFeatures CDockContainerWidget::features() const
1819 {
1820  CDockWidget::DockWidgetFeatures Features(CDockWidget::AllDockWidgetFeatures);
1821  for (const auto DockArea : d->DockAreas)
1822  {
1823  Features &= DockArea->features();
1824  }
1825 
1826  return Features;
1827 }
1828 
1829 
1830 //============================================================================
1832 {
1833  return internal::findParent<CFloatingDockContainer*>(this);
1834 }
1835 
1836 
1837 //============================================================================
1839 {
1840  for (const auto DockArea : d->DockAreas)
1841  {
1842  if (DockArea == KeepOpenArea)
1843  {
1844  continue;
1845  }
1846 
1847  if (!DockArea->features(BitwiseAnd).testFlag(CDockWidget::DockWidgetClosable))
1848  {
1849  continue;
1850  }
1851 
1852  // We do not close areas with widgets with custom close handling
1853  if (DockArea->features(BitwiseOr).testFlag(CDockWidget::CustomCloseHandling))
1854  {
1855  continue;
1856  }
1857 
1858  DockArea->closeArea();
1859  }
1860 }
1861 
1862 
1863 } // namespace ads
1864 
1865 //---------------------------------------------------------------------------
1866 // EOF DockContainerWidget.cpp
static bool testConfigFlag(eConfigFlag Flag)
void closeOtherAreas(CDockAreaWidget *KeepOpenArea)
CDockWidget * topLevelDockWidget() const
bool restoreDockArea(CDockingStateReader &Stream, QWidget *&CreatedWidget, bool Testing)
enum MQTTPropertyCodes value
void setClosedState(bool Closed)
Definition: DockWidget.cpp:795
void removeDockWidget(CDockWidget *DockWidget)
void moveToContainer(QWidget *Widgett, DockWidgetArea area)
char toHexLower(uint value)
void updateSplitterHandles(QSplitter *splitter)
DockWidgetArea
Definition: ads_globals.h:73
dock widget has a close button
Definition: DockWidget.h:150
MQTTClient d
Definition: test10.c:1656
void setDockManager(CDockManager *DockManager)
Definition: DockWidget.cpp:373
void replaceSplitterWidget(QSplitter *Splitter, QWidget *From, QWidget *To)
CDockAreaWidget * lastAddedDockAreaWidget(DockWidgetArea area) const
CDockContainerWidget * dockContainer() const
void setDockAreaFlags(DockAreaFlags Flags)
DockContainerWidgetPrivate(CDockContainerWidget *_public)
CDockContainerWidget(CDockManager *DockManager, QWidget *parent=0)
void dockAreaViewToggled(ads::CDockAreaWidget *DockArea, bool Open)
DockWidgetAreas allowedAreas() const
Declaration of CFloatingDockContainer class.
QList< CDockAreaWidget * > openedDockAreas() const
CDockAreaWidget * addDockWidgetToDockArea(DockWidgetArea area, CDockWidget *Dockwidget, CDockAreaWidget *TargetDockArea)
CDockContainerWidget * dockContainer() const
void removeDockArea(CDockAreaWidget *area)
CDockAreaWidget * dockAreaAt(const QPoint &GlobalPos) const
virtual bool event(QEvent *e) override
CDockSplitter * newSplitter(Qt::Orientation orientation, QWidget *parent=nullptr)
void adjustSplitterSizesOnInsertion(QSplitter *Splitter, qreal LastRatio=1.0)
static void insertWidgetIntoSplitter(QSplitter *Splitter, QWidget *widget, bool Append)
void dropWidget(QWidget *Widget, DockWidgetArea DropArea, CDockAreaWidget *TargetAreaWidget)
void saveState(QXmlStreamWriter &Stream) const
static const char *const DirtyProperty
Definition: ads_globals.h:135
bool isInFrontOf(CDockContainerWidget *Other) const
void addDockWidget(CDockWidget *DockWidget)
CDockWidget * dockWidget(int Index) const
FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr &out)
Definition: format.h:2881
void dropIntoSection(CFloatingDockContainer *FloatingWidget, CDockAreaWidget *TargetArea, DockWidgetArea area)
void setAllowedAreas(DockWidgetAreas areas)
bool restoreSplitter(CDockingStateReader &Stream, QWidget *&CreatedWidget, bool Testing)
bool restoreChildNodes(CDockingStateReader &Stream, QWidget *&CreatedWidget, bool Testing)
void dropIntoContainer(CFloatingDockContainer *FloatingWidget, DockWidgetArea area)
void saveChildNodesState(QXmlStreamWriter &Stream, QWidget *Widget)
void setCurrentIndex(int index)
#define ADS_PRINT(s)
Definition: ads_globals.h:60
CDockAreaWidget * addDockWidgetToContainer(DockWidgetArea area, CDockWidget *Dockwidget)
See QSplitter::setOpaqueResize() documentation.
Definition: DockManager.h:162
CDockAreaWidget * dockArea(int Index) const
bool widgetResizesWithContainer(QWidget *widget)
bool isCentralWidgetArea() const
CDockAreaWidget * topLevelDockArea() const
Declaration of CDockSplitter.
void setToggleViewActionChecked(bool Checked)
Definition: DockWidget.cpp:256
Declaration of.
void removeDockWidget(CDockWidget *Dockwidget)
void dropFloatingWidget(CFloatingDockContainer *FloatingWidget, const QPoint &TargetPos)
virtual unsigned int zOrderIndex() const
QByteArray qByteArrayToHex(const QByteArray &src, char separator)
int dockWidgetsCount() const
bool restoreState(CDockingStateReader &Stream, bool Testing)
Declaration of CDockContainerWidget class.
CFloatingDockContainer * floatingWidget() const
QSplitter * rootSplitter() const
bool isResizingWithContainer() const
CDockWidget * topLevelDockWidget() const
Declaration of CDockingStateReader.
invalid mode - do not drop
void hideEmptyParentSplitters(CDockSplitter *FirstParentSplitter)
Declaration of CDockAreaWidget class.
eDropMode getDropMode(const QPoint &TargetPos)
#define uchar(c)
Definition: lstrlib.c:40
CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area)
CDockWidget::DockWidgetFeatures features() const
Declaration of CDockWidget class.
void dumpRecursive(int level, QWidget *widget)
QList< CDockWidget * > dockWidgets() const
void viewToggled(bool Open)
Declaration of CDockManager class.
void updateSplitterHandles(QSplitter *splitter)
static void emitTopLevelEventForWidget(CDockWidget *TopLevelDockWidget, bool Floating)
Definition: DockWidget.cpp:773
QAbstractButton * titleBarButton(TitleBarButton which) const
void moveToNewSection(QWidget *Widget, CDockAreaWidget *TargetArea, DockWidgetArea area)
CDockAreaWidget * addDockWidget(DockWidgetArea area, CDockWidget *Dockwidget, CDockAreaWidget *DockAreaWidget=nullptr)
void addDockAreasToList(const QList< CDockAreaWidget * > NewDockAreas)
dictionary data
Definition: mqtt_test.py:22
static int areaIdToIndex(DockWidgetArea area)
QPointer< CDockManager > DockManager
drop widget into a dock area
clicking the close button will not close the dock widget but emits the closeRequested() signal instea...
Definition: DockWidget.h:154
CDockAreaWidget * dockAreaWidget() const
Definition: DockWidget.cpp:394
int openDockWidgetsCount() const
void appendDockAreas(const QList< CDockAreaWidget * > NewDockAreas)
void saveState(QXmlStreamWriter &Stream) const
static unsigned int zOrderCounter
void addDockArea(CDockAreaWidget *DockAreaWidget, DockWidgetArea area=CenterDockWidgetArea)
void moveIntoCenterOfSection(QWidget *Widget, CDockAreaWidget *TargetArea)
QList< CDockAreaWidget * > DockAreas
void addDockArea(CDockAreaWidget *NewDockWidget, DockWidgetArea area=CenterDockWidgetArea)
DockContainerWidgetPrivate * d
private data (pimpl)
static const char *const ClosedProperty
Definition: ads_globals.h:134
void dropIntoCenterOfSection(CFloatingDockContainer *FloatingWidget, CDockAreaWidget *TargetArea)
void insertDockWidget(int index, CDockWidget *DockWidget, bool Activate=true)
FMT_NOINLINE OutputIt fill(OutputIt it, size_t n, const fill_t< Char > &fill)
Definition: format.h:1483


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 03:47:34