DockContainerWidget.cpp 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290
  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. /// \file DockContainerWidget.cpp
  20. /// \author Uwe Kindler
  21. /// \date 24.02.2017
  22. /// \brief Implementation of CDockContainerWidget class
  23. //============================================================================
  24. //============================================================================
  25. // INCLUDES
  26. //============================================================================
  27. #include "DockContainerWidget.h"
  28. #include <QEvent>
  29. #include <QList>
  30. #include <QGridLayout>
  31. #include <QPointer>
  32. #include <QVariant>
  33. #include <QDebug>
  34. #include <QXmlStreamWriter>
  35. #include <QAbstractButton>
  36. #include <QLabel>
  37. #include <QTimer>
  38. #include <QMetaObject>
  39. #include <QMetaType>
  40. #include <QApplication>
  41. #include "DockManager.h"
  42. #include "DockAreaWidget.h"
  43. #include "DockWidget.h"
  44. #include "DockingStateReader.h"
  45. #include "FloatingDockContainer.h"
  46. #include "DockOverlay.h"
  47. #include "ads_globals.h"
  48. #include "DockSplitter.h"
  49. #include "DockWidgetTab.h"
  50. #include "DockAreaTitleBar.h"
  51. #include "DockFocusController.h"
  52. #include "AutoHideDockContainer.h"
  53. #include "AutoHideSideBar.h"
  54. #include "AutoHideTab.h"
  55. #include <functional>
  56. #include <iostream>
  57. #if QT_VERSION < 0x050900
  58. inline char toHexLower(uint value)
  59. {
  60. return "0123456789abcdef"[value & 0xF];
  61. }
  62. QByteArray qByteArrayToHex(const QByteArray& src, char separator)
  63. {
  64. if(src.size() == 0)
  65. return QByteArray();
  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. if ((separator) && (o < length))
  74. hexData[o++] = separator;
  75. }
  76. return hex;
  77. }
  78. #endif
  79. namespace ads
  80. {
  81. static unsigned int zOrderCounter = 0;
  82. enum eDropMode
  83. {
  84. DropModeIntoArea,///< drop widget into a dock area
  85. DropModeIntoContainer,///< drop into container
  86. DropModeInvalid///< invalid mode - do not drop
  87. };
  88. /**
  89. * Converts dock area ID to an index for array access
  90. */
  91. static int areaIdToIndex(DockWidgetArea area)
  92. {
  93. switch (area)
  94. {
  95. case LeftDockWidgetArea: return 0;
  96. case RightDockWidgetArea: return 1;
  97. case TopDockWidgetArea: return 2;
  98. case BottomDockWidgetArea: return 3;
  99. case CenterDockWidgetArea: return 4;
  100. default:
  101. return 4;
  102. }
  103. }
  104. /**
  105. * Helper function to ease insertion of dock area into splitter
  106. */
  107. static void insertWidgetIntoSplitter(QSplitter* Splitter, QWidget* widget, bool Append)
  108. {
  109. if (Append)
  110. {
  111. Splitter->addWidget(widget);
  112. }
  113. else
  114. {
  115. Splitter->insertWidget(0, widget);
  116. }
  117. }
  118. /**
  119. * Private data class of CDockContainerWidget class (pimpl)
  120. */
  121. class DockContainerWidgetPrivate
  122. {
  123. public:
  124. CDockContainerWidget* _this;
  125. QPointer<CDockManager> DockManager;
  126. unsigned int zOrderIndex = 0;
  127. QList<QPointer<CDockAreaWidget>> DockAreas;
  128. QList<CAutoHideDockContainer*> AutoHideWidgets;
  129. QMap<SideBarLocation, CAutoHideSideBar*> SideTabBarWidgets;
  130. QGridLayout* Layout = nullptr;
  131. CDockSplitter* RootSplitter = nullptr;
  132. bool isFloating = false;
  133. CDockAreaWidget* LastAddedAreaCache[5];
  134. int VisibleDockAreaCount = -1;
  135. CDockAreaWidget* TopLevelDockArea = nullptr;
  136. QTimer DelayedAutoHideTimer;
  137. CAutoHideTab* DelayedAutoHideTab;
  138. bool DelayedAutoHideShow = false;
  139. /**
  140. * Private data constructor
  141. */
  142. DockContainerWidgetPrivate(CDockContainerWidget* _public);
  143. /**
  144. * Adds dock widget to container and returns the dock area that contains
  145. * the inserted dock widget
  146. */
  147. CDockAreaWidget* addDockWidgetToContainer(DockWidgetArea area, CDockWidget* Dockwidget);
  148. /**
  149. * Adds dock widget to a existing DockWidgetArea
  150. */
  151. CDockAreaWidget* addDockWidgetToDockArea(DockWidgetArea area, CDockWidget* Dockwidget,
  152. CDockAreaWidget* TargetDockArea, int Index = -1);
  153. /**
  154. * Add dock area to this container
  155. */
  156. void addDockArea(CDockAreaWidget* NewDockWidget, DockWidgetArea area = CenterDockWidgetArea);
  157. /**
  158. * Drop floating widget into container
  159. */
  160. void dropIntoContainer(CFloatingDockContainer* FloatingWidget, DockWidgetArea area);
  161. /**
  162. * Drop floating widget into auto hide side bar
  163. */
  164. void dropIntoAutoHideSideBar(CFloatingDockContainer* FloatingWidget, DockWidgetArea area);
  165. /**
  166. * Creates a new tab for a widget dropped into the center of a section
  167. */
  168. void dropIntoCenterOfSection(CFloatingDockContainer* FloatingWidget,
  169. CDockAreaWidget* TargetArea, int TabIndex = 0);
  170. /**
  171. * Drop floating widget into dock area
  172. */
  173. void dropIntoSection(CFloatingDockContainer* FloatingWidget,
  174. CDockAreaWidget* TargetArea, DockWidgetArea area, int TabIndex = 0);
  175. /**
  176. * Moves the dock widget or dock area given in Widget parameter to a
  177. * new dock widget area
  178. */
  179. void moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area,
  180. int TabIndex = 0);
  181. /**
  182. * Moves the dock widget or dock area given in Widget parameter to a
  183. * a dock area in container
  184. */
  185. void moveToContainer(QWidget* Widgett, DockWidgetArea area);
  186. /**
  187. * Creates a new tab for a widget dropped into the center of a section
  188. */
  189. void moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea, int TabIndex = 0);
  190. /**
  191. * Moves the dock widget or dock area given in Widget parameter to
  192. * a auto hide sidebar area
  193. */
  194. void moveToAutoHideSideBar(QWidget* Widget, DockWidgetArea area, int TabIndex = TabDefaultInsertIndex);
  195. /**
  196. * Adds new dock areas to the internal dock area list
  197. */
  198. void addDockAreasToList(const QList<CDockAreaWidget*> NewDockAreas);
  199. /**
  200. * Wrapper function for DockAreas append, that ensures that dock area signals
  201. * are properly connected to dock container slots
  202. */
  203. void appendDockAreas(const QList<CDockAreaWidget*> NewDockAreas);
  204. /**
  205. * Save state of child nodes
  206. */
  207. void saveChildNodesState(QXmlStreamWriter& Stream, QWidget* Widget);
  208. /**
  209. * Save state of auto hide widgets
  210. */
  211. void saveAutoHideWidgetsState(QXmlStreamWriter& Stream);
  212. /**
  213. * Restore state of child nodes.
  214. * \param[in] Stream The data stream that contains the serialized state
  215. * \param[out] CreatedWidget The widget created from parsed data or 0 if
  216. * the parsed widget was an empty splitter
  217. * \param[in] Testing If Testing is true, only the stream data is
  218. * parsed without modifying anything.
  219. */
  220. bool restoreChildNodes(CDockingStateReader& Stream, QWidget*& CreatedWidget,
  221. bool Testing);
  222. /**
  223. * Restores a splitter.
  224. * \see restoreChildNodes() for details
  225. */
  226. bool restoreSplitter(CDockingStateReader& Stream, QWidget*& CreatedWidget,
  227. bool Testing);
  228. /**
  229. * Restores a dock area.
  230. * \see restoreChildNodes() for details
  231. */
  232. bool restoreDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget,
  233. bool Testing);
  234. /**
  235. * Restores a auto hide side bar
  236. */
  237. bool restoreSideBar(CDockingStateReader& Stream, QWidget*& CreatedWidget,
  238. bool Testing);
  239. /**
  240. * Helper function for recursive dumping of layout
  241. */
  242. void dumpRecursive(int level, QWidget* widget);
  243. /**
  244. * Calculate the drop mode from the given target position
  245. */
  246. eDropMode getDropMode(const QPoint& TargetPos);
  247. /**
  248. * Initializes the visible dock area count variable if it is not initialized
  249. * yet
  250. */
  251. void initVisibleDockAreaCount()
  252. {
  253. if (VisibleDockAreaCount > -1)
  254. {
  255. return;
  256. }
  257. VisibleDockAreaCount = 0;
  258. for (auto DockArea : DockAreas)
  259. {
  260. if (!DockArea)
  261. {
  262. continue;
  263. }
  264. VisibleDockAreaCount += (DockArea->isHidden() ? 0 : 1);
  265. }
  266. }
  267. /**
  268. * Access function for the visible dock area counter
  269. */
  270. int& visibleDockAreaCount()
  271. {
  272. // Lazy initialisation - we initialize the VisibleDockAreaCount variable
  273. // on first use
  274. initVisibleDockAreaCount();
  275. return VisibleDockAreaCount;
  276. }
  277. /**
  278. * The visible dock area count changes, if dock areas are remove, added or
  279. * when its view is toggled
  280. */
  281. void onVisibleDockAreaCountChanged();
  282. void emitDockAreasRemoved()
  283. {
  284. onVisibleDockAreaCountChanged();
  285. Q_EMIT _this->dockAreasRemoved();
  286. }
  287. void emitDockAreasAdded()
  288. {
  289. onVisibleDockAreaCountChanged();
  290. Q_EMIT _this->dockAreasAdded();
  291. }
  292. /**
  293. * Helper function for creation of new splitter
  294. */
  295. CDockSplitter* newSplitter(Qt::Orientation orientation, QWidget* parent = nullptr)
  296. {
  297. CDockSplitter* s = new CDockSplitter(orientation, parent);
  298. s->setOpaqueResize(CDockManager::testConfigFlag(CDockManager::OpaqueSplitterResize));
  299. s->setChildrenCollapsible(false);
  300. return s;
  301. }
  302. /**
  303. * Ensures equal distribution of the sizes of a splitter if an dock widget
  304. * is inserted from code
  305. */
  306. void adjustSplitterSizesOnInsertion(QSplitter* Splitter, qreal LastRatio = 1.0)
  307. {
  308. int AreaSize = (Splitter->orientation() == Qt::Horizontal) ? Splitter->width() : Splitter->height();
  309. auto SplitterSizes = Splitter->sizes();
  310. qreal TotRatio = SplitterSizes.size() - 1.0 + LastRatio;
  311. for(int i = 0; i < SplitterSizes.size() -1; i++)
  312. {
  313. SplitterSizes[i] = AreaSize / TotRatio;
  314. }
  315. SplitterSizes.back() = AreaSize * LastRatio / TotRatio;
  316. Splitter->setSizes(SplitterSizes);
  317. }
  318. /**
  319. * This function forces the dock container widget to update handles of splitters
  320. * based if a central widget exists.
  321. */
  322. void updateSplitterHandles(QSplitter* splitter);
  323. /**
  324. * If no central widget exists, the widgets resize with the container.
  325. * If a central widget exists, the widgets surrounding the central widget
  326. * do not resize its height or width.
  327. */
  328. bool widgetResizesWithContainer(QWidget* widget);
  329. // private slots: ------------------------------------------------------------
  330. void onDockAreaViewToggled(bool Visible)
  331. {
  332. CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(_this->sender());
  333. VisibleDockAreaCount += Visible ? 1 : -1;
  334. onVisibleDockAreaCountChanged();
  335. Q_EMIT _this->dockAreaViewToggled(DockArea, Visible);
  336. }
  337. }; // struct DockContainerWidgetPrivate
  338. //============================================================================
  339. DockContainerWidgetPrivate::DockContainerWidgetPrivate(CDockContainerWidget* _public) :
  340. _this(_public)
  341. {
  342. std::fill(std::begin(LastAddedAreaCache),std::end(LastAddedAreaCache), nullptr);
  343. DelayedAutoHideTimer.setSingleShot(true);
  344. DelayedAutoHideTimer.setInterval(500);
  345. QObject::connect(&DelayedAutoHideTimer, &QTimer::timeout, [this](){
  346. auto GlobalPos = DelayedAutoHideTab->mapToGlobal(QPoint(0, 0));
  347. qApp->sendEvent(DelayedAutoHideTab, new QMouseEvent(QEvent::MouseButtonPress,
  348. QPoint(0, 0), GlobalPos, Qt::LeftButton, {Qt::LeftButton}, Qt::NoModifier));
  349. });
  350. }
  351. //============================================================================
  352. eDropMode DockContainerWidgetPrivate::getDropMode(const QPoint& TargetPos)
  353. {
  354. CDockAreaWidget* DockArea = _this->dockAreaAt(TargetPos);
  355. auto dropArea = InvalidDockWidgetArea;
  356. auto ContainerDropArea = DockManager->containerOverlay()->dropAreaUnderCursor();
  357. if (DockArea)
  358. {
  359. auto dropOverlay = DockManager->dockAreaOverlay();
  360. dropOverlay->setAllowedAreas(DockArea->allowedAreas());
  361. dropArea = dropOverlay->showOverlay(DockArea);
  362. if (ContainerDropArea != InvalidDockWidgetArea &&
  363. ContainerDropArea != dropArea)
  364. {
  365. dropArea = InvalidDockWidgetArea;
  366. }
  367. if (dropArea != InvalidDockWidgetArea)
  368. {
  369. ADS_PRINT("Dock Area Drop Content: " << dropArea);
  370. return DropModeIntoArea;
  371. }
  372. }
  373. // mouse is over container
  374. if (InvalidDockWidgetArea == dropArea)
  375. {
  376. dropArea = ContainerDropArea;
  377. ADS_PRINT("Container Drop Content: " << dropArea);
  378. if (dropArea != InvalidDockWidgetArea)
  379. {
  380. return DropModeIntoContainer;
  381. }
  382. }
  383. return DropModeInvalid;
  384. }
  385. //============================================================================
  386. void DockContainerWidgetPrivate::onVisibleDockAreaCountChanged()
  387. {
  388. auto TopLevelDockArea = _this->topLevelDockArea();
  389. if (TopLevelDockArea)
  390. {
  391. this->TopLevelDockArea = TopLevelDockArea;
  392. TopLevelDockArea->updateTitleBarButtonVisibility(true);
  393. }
  394. else if (this->TopLevelDockArea)
  395. {
  396. this->TopLevelDockArea->updateTitleBarButtonVisibility(false);
  397. this->TopLevelDockArea = nullptr;
  398. }
  399. }
  400. //============================================================================
  401. void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* FloatingWidget,
  402. DockWidgetArea area)
  403. {
  404. auto InsertParam = internal::dockAreaInsertParameters(area);
  405. CDockContainerWidget* FloatingDockContainer = FloatingWidget->dockContainer();
  406. auto NewDockAreas = FloatingDockContainer->findChildren<CDockAreaWidget*>(
  407. QString(), Qt::FindChildrenRecursively);
  408. auto Splitter = RootSplitter;
  409. if (DockAreas.count() <= 1)
  410. {
  411. Splitter->setOrientation(InsertParam.orientation());
  412. }
  413. else if (Splitter->orientation() != InsertParam.orientation())
  414. {
  415. auto NewSplitter = newSplitter(InsertParam.orientation());
  416. QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
  417. NewSplitter->addWidget(Splitter);
  418. updateSplitterHandles(NewSplitter);
  419. Splitter = NewSplitter;
  420. delete li;
  421. }
  422. // Now we can insert the floating widget content into this container
  423. auto FloatingSplitter = FloatingDockContainer->rootSplitter();
  424. if (FloatingSplitter->count() == 1)
  425. {
  426. insertWidgetIntoSplitter(Splitter, FloatingSplitter->widget(0), InsertParam.append());
  427. updateSplitterHandles(Splitter);
  428. }
  429. else if (FloatingSplitter->orientation() == InsertParam.orientation())
  430. {
  431. int InsertIndex = InsertParam.append() ? Splitter->count() : 0;
  432. while (FloatingSplitter->count())
  433. {
  434. Splitter->insertWidget(InsertIndex++, FloatingSplitter->widget(0));
  435. updateSplitterHandles(Splitter);
  436. }
  437. }
  438. else
  439. {
  440. insertWidgetIntoSplitter(Splitter, FloatingSplitter, InsertParam.append());
  441. }
  442. RootSplitter = Splitter;
  443. addDockAreasToList(NewDockAreas);
  444. // If we dropped the floating widget into the main dock container that does
  445. // not contain any dock widgets, then splitter is invisible and we need to
  446. // show it to display the docked widgets
  447. if (!Splitter->isVisible())
  448. {
  449. Splitter->show();
  450. }
  451. _this->dumpLayout();
  452. }
  453. //============================================================================
  454. void DockContainerWidgetPrivate::dropIntoAutoHideSideBar(CFloatingDockContainer* FloatingWidget, DockWidgetArea area)
  455. {
  456. auto SideBarLocation = internal::toSideBarLocation(area);
  457. auto NewDockAreas = FloatingWidget->findChildren<CDockAreaWidget*>(
  458. QString(), Qt::FindChildrenRecursively);
  459. int TabIndex = DockManager->containerOverlay()->tabIndexUnderCursor();
  460. for (auto DockArea : NewDockAreas)
  461. {
  462. auto DockWidgets = DockArea->dockWidgets();
  463. for (auto DockWidget : DockWidgets)
  464. {
  465. _this->createAndSetupAutoHideContainer(SideBarLocation, DockWidget, TabIndex++);
  466. }
  467. }
  468. }
  469. //============================================================================
  470. void DockContainerWidgetPrivate::dropIntoCenterOfSection(
  471. CFloatingDockContainer* FloatingWidget, CDockAreaWidget* TargetArea, int TabIndex)
  472. {
  473. CDockContainerWidget* FloatingContainer = FloatingWidget->dockContainer();
  474. auto NewDockWidgets = FloatingContainer->dockWidgets();
  475. auto TopLevelDockArea = FloatingContainer->topLevelDockArea();
  476. int NewCurrentIndex = -1;
  477. TabIndex = qMax(0, TabIndex);
  478. // If the floating widget contains only one single dock are, then the
  479. // current dock widget of the dock area will also be the future current
  480. // dock widget in the drop area.
  481. if (TopLevelDockArea)
  482. {
  483. NewCurrentIndex = TopLevelDockArea->currentIndex();
  484. }
  485. for (int i = 0; i < NewDockWidgets.count(); ++i)
  486. {
  487. CDockWidget* DockWidget = NewDockWidgets[i];
  488. TargetArea->insertDockWidget(TabIndex + i, DockWidget, false);
  489. // If the floating widget contains multiple visible dock areas, then we
  490. // simply pick the first visible open dock widget and make it
  491. // the current one.
  492. if (NewCurrentIndex < 0 && !DockWidget->isClosed())
  493. {
  494. NewCurrentIndex = i;
  495. }
  496. }
  497. TargetArea->setCurrentIndex(NewCurrentIndex + TabIndex);
  498. TargetArea->updateTitleBarVisibility();
  499. return;
  500. }
  501. //============================================================================
  502. void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* FloatingWidget,
  503. CDockAreaWidget* TargetArea, DockWidgetArea area, int TabIndex)
  504. {
  505. // Dropping into center means all dock widgets in the dropped floating
  506. // widget will become tabs of the drop area
  507. if (CenterDockWidgetArea == area)
  508. {
  509. dropIntoCenterOfSection(FloatingWidget, TargetArea, TabIndex);
  510. return;
  511. }
  512. CDockContainerWidget* FloatingContainer = FloatingWidget->dockContainer();
  513. auto InsertParam = internal::dockAreaInsertParameters(area);
  514. auto NewDockAreas = FloatingContainer->findChildren<CDockAreaWidget*>(
  515. QString(), Qt::FindChildrenRecursively);
  516. auto TargetAreaSplitter = TargetArea->parentSplitter();
  517. int AreaIndex = TargetAreaSplitter->indexOf(TargetArea);
  518. auto FloatingSplitter = FloatingContainer->rootSplitter();
  519. if (TargetAreaSplitter->orientation() == InsertParam.orientation())
  520. {
  521. auto Sizes = TargetAreaSplitter->sizes();
  522. int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
  523. bool AdjustSplitterSizes = true;
  524. if ((FloatingSplitter->orientation() != InsertParam.orientation()) && FloatingSplitter->count() > 1)
  525. {
  526. TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), FloatingSplitter);
  527. updateSplitterHandles(TargetAreaSplitter);
  528. }
  529. else
  530. {
  531. AdjustSplitterSizes = (FloatingSplitter->count() == 1);
  532. int InsertIndex = AreaIndex + InsertParam.insertOffset();
  533. while (FloatingSplitter->count())
  534. {
  535. TargetAreaSplitter->insertWidget(InsertIndex++, FloatingSplitter->widget(0));
  536. updateSplitterHandles(TargetAreaSplitter);
  537. }
  538. }
  539. if (AdjustSplitterSizes)
  540. {
  541. int Size = (TargetAreaSize - TargetAreaSplitter->handleWidth()) / 2;
  542. Sizes[AreaIndex] = Size;
  543. Sizes.insert(AreaIndex, Size);
  544. TargetAreaSplitter->setSizes(Sizes);
  545. }
  546. }
  547. else
  548. {
  549. QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
  550. int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
  551. bool AdjustSplitterSizes = true;
  552. if ((FloatingSplitter->orientation() != InsertParam.orientation()) && FloatingSplitter->count() > 1)
  553. {
  554. NewSplitter->addWidget(FloatingSplitter);
  555. updateSplitterHandles(NewSplitter);
  556. }
  557. else
  558. {
  559. AdjustSplitterSizes = (FloatingSplitter->count() == 1);
  560. while (FloatingSplitter->count())
  561. {
  562. NewSplitter->addWidget(FloatingSplitter->widget(0));
  563. updateSplitterHandles(NewSplitter);
  564. }
  565. }
  566. // Save the sizes before insertion and restore it later to prevent
  567. // shrinking of existing area
  568. auto Sizes = TargetAreaSplitter->sizes();
  569. insertWidgetIntoSplitter(NewSplitter, TargetArea, !InsertParam.append());
  570. updateSplitterHandles(NewSplitter);
  571. if (AdjustSplitterSizes)
  572. {
  573. int Size = TargetAreaSize / 2;
  574. NewSplitter->setSizes({Size, Size});
  575. }
  576. TargetAreaSplitter->insertWidget(AreaIndex, NewSplitter);
  577. TargetAreaSplitter->setSizes(Sizes);
  578. updateSplitterHandles(TargetAreaSplitter);
  579. }
  580. addDockAreasToList(NewDockAreas);
  581. _this->dumpLayout();
  582. }
  583. //============================================================================
  584. void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea,
  585. int TabIndex)
  586. {
  587. auto DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
  588. auto DroppedArea = qobject_cast<CDockAreaWidget*>(Widget);
  589. TabIndex = qMax(0, TabIndex);
  590. if (DroppedDockWidget)
  591. {
  592. CDockAreaWidget* OldDockArea = DroppedDockWidget->dockAreaWidget();
  593. if (OldDockArea == TargetArea)
  594. {
  595. return;
  596. }
  597. if (OldDockArea)
  598. {
  599. OldDockArea->removeDockWidget(DroppedDockWidget);
  600. }
  601. TargetArea->insertDockWidget(TabIndex, DroppedDockWidget, true);
  602. }
  603. else
  604. {
  605. QList<CDockWidget*> NewDockWidgets = DroppedArea->dockWidgets();
  606. int NewCurrentIndex = DroppedArea->currentIndex();
  607. for (int i = 0; i < NewDockWidgets.count(); ++i)
  608. {
  609. CDockWidget* DockWidget = NewDockWidgets[i];
  610. TargetArea->insertDockWidget(TabIndex + i, DockWidget, false);
  611. }
  612. TargetArea->setCurrentIndex(TabIndex + NewCurrentIndex);
  613. DroppedArea->dockContainer()->removeDockArea(DroppedArea);
  614. DroppedArea->deleteLater();
  615. }
  616. TargetArea->updateTitleBarVisibility();
  617. return;
  618. }
  619. //============================================================================
  620. void DockContainerWidgetPrivate::moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area,
  621. int TabIndex)
  622. {
  623. // Dropping into center means all dock widgets in the dropped floating
  624. // widget will become tabs of the drop area
  625. if (CenterDockWidgetArea == area)
  626. {
  627. moveIntoCenterOfSection(Widget, TargetArea, TabIndex);
  628. return;
  629. }
  630. CDockWidget* DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
  631. CDockAreaWidget* DroppedDockArea = qobject_cast<CDockAreaWidget*>(Widget);
  632. CDockAreaWidget* NewDockArea;
  633. if (DroppedDockWidget)
  634. {
  635. NewDockArea = new CDockAreaWidget(DockManager, _this);
  636. CDockAreaWidget* OldDockArea = DroppedDockWidget->dockAreaWidget();
  637. if (OldDockArea)
  638. {
  639. OldDockArea->removeDockWidget(DroppedDockWidget);
  640. }
  641. NewDockArea->addDockWidget(DroppedDockWidget);
  642. }
  643. else
  644. {
  645. DroppedDockArea->dockContainer()->removeDockArea(DroppedDockArea);
  646. NewDockArea = DroppedDockArea;
  647. }
  648. auto InsertParam = internal::dockAreaInsertParameters(area);
  649. auto TargetAreaSplitter = TargetArea->parentSplitter();
  650. int AreaIndex = TargetAreaSplitter->indexOf(TargetArea);
  651. auto Sizes = TargetAreaSplitter->sizes();
  652. if (TargetAreaSplitter->orientation() == InsertParam.orientation())
  653. {
  654. int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
  655. TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), NewDockArea);
  656. updateSplitterHandles(TargetAreaSplitter);
  657. int Size = (TargetAreaSize - TargetAreaSplitter->handleWidth()) / 2;
  658. Sizes[AreaIndex] = Size;
  659. Sizes.insert(AreaIndex, Size);
  660. }
  661. else
  662. {
  663. int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
  664. QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
  665. NewSplitter->addWidget(TargetArea);
  666. insertWidgetIntoSplitter(NewSplitter, NewDockArea, InsertParam.append());
  667. updateSplitterHandles(NewSplitter);
  668. int Size = TargetAreaSize / 2;
  669. NewSplitter->setSizes({Size, Size});
  670. TargetAreaSplitter->insertWidget(AreaIndex, NewSplitter);
  671. updateSplitterHandles(TargetAreaSplitter);
  672. }
  673. TargetAreaSplitter->setSizes(Sizes);
  674. addDockAreasToList({NewDockArea});
  675. }
  676. //============================================================================
  677. void DockContainerWidgetPrivate::moveToAutoHideSideBar(QWidget* Widget, DockWidgetArea area, int TabIndex)
  678. {
  679. CDockWidget* DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
  680. CDockAreaWidget* DroppedDockArea = qobject_cast<CDockAreaWidget*>(Widget);
  681. auto SideBarLocation = internal::toSideBarLocation(area);
  682. if (DroppedDockWidget)
  683. {
  684. if (_this == DroppedDockWidget->dockContainer())
  685. {
  686. DroppedDockWidget->setAutoHide(true, SideBarLocation, TabIndex);
  687. }
  688. else
  689. {
  690. _this->createAndSetupAutoHideContainer(SideBarLocation, DroppedDockWidget, TabIndex);
  691. }
  692. }
  693. else
  694. {
  695. if (_this == DroppedDockArea->dockContainer())
  696. {
  697. DroppedDockArea->setAutoHide(true, SideBarLocation, TabIndex);
  698. }
  699. else
  700. {
  701. for (const auto DockWidget : DroppedDockArea->openedDockWidgets())
  702. {
  703. if (!DockWidget->features().testFlag(
  704. CDockWidget::DockWidgetPinnable))
  705. {
  706. continue;
  707. }
  708. _this->createAndSetupAutoHideContainer(SideBarLocation,
  709. DockWidget, TabIndex++);
  710. }
  711. }
  712. }
  713. }
  714. //============================================================================
  715. void DockContainerWidgetPrivate::updateSplitterHandles( QSplitter* splitter )
  716. {
  717. if (!DockManager->centralWidget() || !splitter)
  718. {
  719. return;
  720. }
  721. for (int i = 0; i < splitter->count(); ++i)
  722. {
  723. splitter->setStretchFactor(i, widgetResizesWithContainer(splitter->widget(i)) ? 1 : 0);
  724. }
  725. }
  726. //============================================================================
  727. bool DockContainerWidgetPrivate::widgetResizesWithContainer(QWidget* widget)
  728. {
  729. if (!DockManager->centralWidget())
  730. {
  731. return true;
  732. }
  733. auto Area = qobject_cast<CDockAreaWidget*>(widget);
  734. if(Area)
  735. {
  736. return Area->isCentralWidgetArea();
  737. }
  738. auto innerSplitter = qobject_cast<CDockSplitter*>(widget);
  739. if (innerSplitter)
  740. {
  741. return innerSplitter->isResizingWithContainer();
  742. }
  743. return false;
  744. }
  745. //============================================================================
  746. void DockContainerWidgetPrivate::moveToContainer(QWidget* Widget, DockWidgetArea area)
  747. {
  748. CDockWidget* DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
  749. CDockAreaWidget* DroppedDockArea = qobject_cast<CDockAreaWidget*>(Widget);
  750. CDockAreaWidget* NewDockArea;
  751. if (DroppedDockWidget)
  752. {
  753. NewDockArea = new CDockAreaWidget(DockManager, _this);
  754. CDockAreaWidget* OldDockArea = DroppedDockWidget->dockAreaWidget();
  755. if (OldDockArea)
  756. {
  757. OldDockArea->removeDockWidget(DroppedDockWidget);
  758. }
  759. NewDockArea->addDockWidget(DroppedDockWidget);
  760. }
  761. else
  762. {
  763. // We check, if we insert the dropped widget into the same place that
  764. // it already has and do nothing, if it is the same place. It would
  765. // also work without this check, but it looks nicer with the check
  766. // because there will be no layout updates
  767. auto Splitter = DroppedDockArea->parentSplitter();
  768. auto InsertParam = internal::dockAreaInsertParameters(area);
  769. if (Splitter == RootSplitter && InsertParam.orientation() == Splitter->orientation())
  770. {
  771. if (InsertParam.append() && Splitter->lastWidget() == DroppedDockArea)
  772. {
  773. return;
  774. }
  775. else if (!InsertParam.append() && Splitter->firstWidget() == DroppedDockArea)
  776. {
  777. return;
  778. }
  779. }
  780. DroppedDockArea->dockContainer()->removeDockArea(DroppedDockArea);
  781. NewDockArea = DroppedDockArea;
  782. }
  783. addDockArea(NewDockArea, area);
  784. LastAddedAreaCache[areaIdToIndex(area)] = NewDockArea;
  785. }
  786. //============================================================================
  787. void DockContainerWidgetPrivate::addDockAreasToList(const QList<CDockAreaWidget*> NewDockAreas)
  788. {
  789. int CountBefore = DockAreas.count();
  790. int NewAreaCount = NewDockAreas.count();
  791. appendDockAreas(NewDockAreas);
  792. // If the user dropped a floating widget that contains only one single
  793. // visible dock area, then its title bar button TitleBarButtonUndock is
  794. // likely hidden. We need to ensure, that it is visible
  795. for (auto DockArea : NewDockAreas)
  796. {
  797. DockArea->titleBarButton(TitleBarButtonClose)->setVisible(true);
  798. DockArea->titleBarButton(TitleBarButtonAutoHide)->setVisible(true);
  799. }
  800. // We need to ensure, that the dock area title bar is visible. The title bar
  801. // is invisible, if the dock are is a single dock area in a floating widget.
  802. if (1 == CountBefore)
  803. {
  804. DockAreas.at(0)->updateTitleBarVisibility();
  805. }
  806. if (1 == NewAreaCount)
  807. {
  808. DockAreas.last()->updateTitleBarVisibility();
  809. }
  810. emitDockAreasAdded();
  811. }
  812. //============================================================================
  813. void DockContainerWidgetPrivate::appendDockAreas(const QList<CDockAreaWidget*> NewDockAreas)
  814. {
  815. for (auto *newDockArea : NewDockAreas)
  816. {
  817. DockAreas.append(newDockArea);
  818. }
  819. for (auto DockArea : NewDockAreas)
  820. {
  821. QObject::connect(DockArea,
  822. &CDockAreaWidget::viewToggled,
  823. _this,
  824. std::bind(&DockContainerWidgetPrivate::onDockAreaViewToggled, this, std::placeholders::_1));
  825. }
  826. }
  827. //============================================================================
  828. void DockContainerWidgetPrivate::saveChildNodesState(QXmlStreamWriter& s, QWidget* Widget)
  829. {
  830. QSplitter* Splitter = qobject_cast<QSplitter*>(Widget);
  831. if (Splitter)
  832. {
  833. s.writeStartElement("Splitter");
  834. s.writeAttribute("Orientation", (Splitter->orientation() == Qt::Horizontal) ? "|" : "-");
  835. s.writeAttribute("Count", QString::number(Splitter->count()));
  836. ADS_PRINT("NodeSplitter orient: " << Splitter->orientation()
  837. << " WidgetCont: " << Splitter->count());
  838. for (int i = 0; i < Splitter->count(); ++i)
  839. {
  840. saveChildNodesState(s, Splitter->widget(i));
  841. }
  842. s.writeStartElement("Sizes");
  843. for (auto Size : Splitter->sizes())
  844. {
  845. s.writeCharacters(QString::number(Size) + " ");
  846. }
  847. s.writeEndElement();
  848. s.writeEndElement();
  849. }
  850. else
  851. {
  852. CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(Widget);
  853. if (DockArea)
  854. {
  855. DockArea->saveState(s);
  856. }
  857. }
  858. }
  859. //============================================================================
  860. void DockContainerWidgetPrivate::saveAutoHideWidgetsState(QXmlStreamWriter& s)
  861. {
  862. for (const auto sideTabBar : SideTabBarWidgets.values())
  863. {
  864. if (!sideTabBar->count())
  865. {
  866. continue;
  867. }
  868. sideTabBar->saveState(s);
  869. }
  870. }
  871. //============================================================================
  872. bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s,
  873. QWidget*& CreatedWidget, bool Testing)
  874. {
  875. bool Ok;
  876. QString OrientationStr = s.attributes().value("Orientation").toString();
  877. // Check if the orientation string is right
  878. if (!OrientationStr.startsWith("|") && !OrientationStr.startsWith("-"))
  879. {
  880. return false;
  881. }
  882. // The "|" shall indicate a vertical splitter handle which in turn means
  883. // a Horizontal orientation of the splitter layout.
  884. bool HorizontalSplitter = OrientationStr.startsWith("|");
  885. // In version 0 we had a small bug. The "|" indicated a vertical orientation,
  886. // but this is wrong, because only the splitter handle is vertical, the
  887. // layout of the splitter is a horizontal layout. We fix this here
  888. if (s.fileVersion() == 0)
  889. {
  890. HorizontalSplitter = !HorizontalSplitter;
  891. }
  892. int Orientation = HorizontalSplitter ? Qt::Horizontal : Qt::Vertical;
  893. int WidgetCount = s.attributes().value("Count").toInt(&Ok);
  894. if (!Ok)
  895. {
  896. return false;
  897. }
  898. ADS_PRINT("Restore NodeSplitter Orientation: " << Orientation <<
  899. " WidgetCount: " << WidgetCount);
  900. QSplitter* Splitter = nullptr;
  901. if (!Testing)
  902. {
  903. Splitter = newSplitter(static_cast<Qt::Orientation>(Orientation));
  904. }
  905. bool Visible = false;
  906. QList<int> Sizes;
  907. while (s.readNextStartElement())
  908. {
  909. QWidget* ChildNode = nullptr;
  910. bool Result = true;
  911. if (s.name() == QLatin1String("Splitter"))
  912. {
  913. Result = restoreSplitter(s, ChildNode, Testing);
  914. }
  915. else if (s.name() == QLatin1String("Area"))
  916. {
  917. Result = restoreDockArea(s, ChildNode, Testing);
  918. }
  919. else if (s.name() == QLatin1String("Sizes"))
  920. {
  921. QString sSizes = s.readElementText().trimmed();
  922. ADS_PRINT("Sizes: " << sSizes);
  923. QTextStream TextStream(&sSizes);
  924. while (!TextStream.atEnd())
  925. {
  926. int value;
  927. TextStream >> value;
  928. Sizes.append(value);
  929. }
  930. }
  931. else
  932. {
  933. s.skipCurrentElement();
  934. }
  935. if (!Result)
  936. {
  937. return false;
  938. }
  939. if (Testing || !ChildNode)
  940. {
  941. continue;
  942. }
  943. ADS_PRINT("ChildNode isVisible " << ChildNode->isVisible()
  944. << " isVisibleTo " << ChildNode->isVisibleTo(Splitter));
  945. Splitter->addWidget(ChildNode);
  946. Visible |= ChildNode->isVisibleTo(Splitter);
  947. }
  948. if(!Testing)
  949. {
  950. updateSplitterHandles(Splitter);
  951. }
  952. if (Sizes.count() != WidgetCount)
  953. {
  954. return false;
  955. }
  956. if (!Testing)
  957. {
  958. if (!Splitter->count())
  959. {
  960. delete Splitter;
  961. Splitter = nullptr;
  962. }
  963. else
  964. {
  965. Splitter->setSizes(Sizes);
  966. Splitter->setVisible(Visible);
  967. }
  968. CreatedWidget = Splitter;
  969. }
  970. else
  971. {
  972. CreatedWidget = nullptr;
  973. }
  974. return true;
  975. }
  976. //============================================================================
  977. bool DockContainerWidgetPrivate::restoreDockArea(CDockingStateReader& s,
  978. QWidget*& CreatedWidget, bool Testing)
  979. {
  980. CDockAreaWidget* DockArea = nullptr;
  981. auto Result = CDockAreaWidget::restoreState(s, DockArea, Testing, _this);
  982. if (Result && DockArea)
  983. {
  984. appendDockAreas({DockArea});
  985. }
  986. CreatedWidget = DockArea;
  987. return Result;
  988. }
  989. //============================================================================
  990. bool DockContainerWidgetPrivate::restoreSideBar(CDockingStateReader& s,
  991. QWidget*& CreatedWidget, bool Testing)
  992. {
  993. Q_UNUSED(CreatedWidget)
  994. // Simply ignore side bar auto hide widgets from saved state if
  995. // auto hide support is disabled
  996. if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled))
  997. {
  998. return true;
  999. }
  1000. bool Ok;
  1001. auto Area = (ads::SideBarLocation)s.attributes().value("Area").toInt(&Ok);
  1002. if (!Ok)
  1003. {
  1004. return false;
  1005. }
  1006. while (s.readNextStartElement())
  1007. {
  1008. if (s.name() != QLatin1String("Widget"))
  1009. {
  1010. continue;
  1011. }
  1012. auto Name = s.attributes().value("Name");
  1013. if (Name.isEmpty())
  1014. {
  1015. return false;
  1016. }
  1017. bool Ok;
  1018. bool Closed = s.attributes().value("Closed").toInt(&Ok);
  1019. if (!Ok)
  1020. {
  1021. return false;
  1022. }
  1023. int Size = s.attributes().value("Size").toInt(&Ok);
  1024. if (!Ok)
  1025. {
  1026. return false;
  1027. }
  1028. s.skipCurrentElement();
  1029. CDockWidget* DockWidget = DockManager->findDockWidget(Name.toString());
  1030. if (!DockWidget || Testing)
  1031. {
  1032. continue;
  1033. }
  1034. auto SideBar = _this->autoHideSideBar(Area);
  1035. CAutoHideDockContainer* AutoHideContainer;
  1036. if (DockWidget->isAutoHide())
  1037. {
  1038. AutoHideContainer = DockWidget->autoHideDockContainer();
  1039. if (AutoHideContainer->autoHideSideBar() != SideBar)
  1040. {
  1041. SideBar->addAutoHideWidget(AutoHideContainer);
  1042. }
  1043. }
  1044. else
  1045. {
  1046. AutoHideContainer = SideBar->insertDockWidget(-1, DockWidget);
  1047. }
  1048. AutoHideContainer->setSize(Size);
  1049. DockWidget->setProperty(internal::ClosedProperty, Closed);
  1050. DockWidget->setProperty(internal::DirtyProperty, false);
  1051. }
  1052. return true;
  1053. }
  1054. //============================================================================
  1055. bool DockContainerWidgetPrivate::restoreChildNodes(CDockingStateReader& s,
  1056. QWidget*& CreatedWidget, bool Testing)
  1057. {
  1058. bool Result = true;
  1059. while (s.readNextStartElement())
  1060. {
  1061. if (s.name() == QLatin1String("Splitter"))
  1062. {
  1063. Result = restoreSplitter(s, CreatedWidget, Testing);
  1064. ADS_PRINT("Splitter");
  1065. }
  1066. else if (s.name() == QLatin1String("Area"))
  1067. {
  1068. Result = restoreDockArea(s, CreatedWidget, Testing);
  1069. ADS_PRINT("DockAreaWidget");
  1070. }
  1071. else if (s.name() == QLatin1String("SideBar"))
  1072. {
  1073. Result = restoreSideBar(s, CreatedWidget, Testing);
  1074. ADS_PRINT("SideBar");
  1075. }
  1076. else
  1077. {
  1078. s.skipCurrentElement();
  1079. ADS_PRINT("Unknown element");
  1080. }
  1081. }
  1082. return Result;
  1083. }
  1084. //============================================================================
  1085. CDockAreaWidget* DockContainerWidgetPrivate::addDockWidgetToContainer(DockWidgetArea area,
  1086. CDockWidget* Dockwidget)
  1087. {
  1088. CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this);
  1089. NewDockArea->addDockWidget(Dockwidget);
  1090. addDockArea(NewDockArea, area);
  1091. NewDockArea->updateTitleBarVisibility();
  1092. LastAddedAreaCache[areaIdToIndex(area)] = NewDockArea;
  1093. return NewDockArea;
  1094. }
  1095. //============================================================================
  1096. void DockContainerWidgetPrivate::addDockArea(CDockAreaWidget* NewDockArea, DockWidgetArea area)
  1097. {
  1098. auto InsertParam = internal::dockAreaInsertParameters(area);
  1099. // As long as we have only one dock area in the splitter we can adjust
  1100. // its orientation
  1101. if (DockAreas.count() <= 1)
  1102. {
  1103. RootSplitter->setOrientation(InsertParam.orientation());
  1104. }
  1105. QSplitter* Splitter = RootSplitter;
  1106. if (Splitter->orientation() == InsertParam.orientation())
  1107. {
  1108. insertWidgetIntoSplitter(Splitter, NewDockArea, InsertParam.append());
  1109. updateSplitterHandles(Splitter);
  1110. if (Splitter->isHidden())
  1111. {
  1112. Splitter->show();
  1113. }
  1114. }
  1115. else
  1116. {
  1117. auto NewSplitter = newSplitter(InsertParam.orientation());
  1118. if (InsertParam.append())
  1119. {
  1120. QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
  1121. NewSplitter->addWidget(Splitter);
  1122. NewSplitter->addWidget(NewDockArea);
  1123. updateSplitterHandles(NewSplitter);
  1124. delete li;
  1125. }
  1126. else
  1127. {
  1128. NewSplitter->addWidget(NewDockArea);
  1129. QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
  1130. NewSplitter->addWidget(Splitter);
  1131. updateSplitterHandles(NewSplitter);
  1132. delete li;
  1133. }
  1134. RootSplitter = NewSplitter;
  1135. }
  1136. addDockAreasToList({NewDockArea});
  1137. }
  1138. //============================================================================
  1139. void DockContainerWidgetPrivate::dumpRecursive(int level, QWidget* widget)
  1140. {
  1141. #if defined(QT_DEBUG)
  1142. QSplitter* Splitter = qobject_cast<QSplitter*>(widget);
  1143. QByteArray buf;
  1144. buf.fill(' ', level * 4);
  1145. if (Splitter)
  1146. {
  1147. #ifdef ADS_DEBUG_PRINT
  1148. qDebug("%sSplitter %s v: %s c: %s",
  1149. (const char*)buf,
  1150. (Splitter->orientation() == Qt::Vertical) ? "--" : "|",
  1151. Splitter->isHidden() ? " " : "v",
  1152. QString::number(Splitter->count()).toStdString().c_str());
  1153. std::cout << (const char*)buf << "Splitter "
  1154. << ((Splitter->orientation() == Qt::Vertical) ? "--" : "|") << " "
  1155. << (Splitter->isHidden() ? " " : "v") << " "
  1156. << QString::number(Splitter->count()).toStdString() << std::endl;
  1157. #endif
  1158. for (int i = 0; i < Splitter->count(); ++i)
  1159. {
  1160. dumpRecursive(level + 1, Splitter->widget(i));
  1161. }
  1162. }
  1163. else
  1164. {
  1165. CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(widget);
  1166. if (!DockArea)
  1167. {
  1168. return;
  1169. }
  1170. #ifdef ADS_DEBUG_PRINT
  1171. qDebug("%sDockArea", (const char*)buf);
  1172. std::cout << (const char*)buf
  1173. << (DockArea->isHidden() ? " " : "v")
  1174. << (DockArea->openDockWidgetsCount() > 0 ? " " : "c")
  1175. << " DockArea " << "[hs: " << DockArea->sizePolicy().horizontalStretch() << ", vs: " << DockArea->sizePolicy().verticalStretch() << "]" << std::endl;
  1176. buf.fill(' ', (level + 1) * 4);
  1177. for (int i = 0; i < DockArea->dockWidgetsCount(); ++i)
  1178. {
  1179. std::cout << (const char*)buf << (i == DockArea->currentIndex() ? "*" : " ");
  1180. CDockWidget* DockWidget = DockArea->dockWidget(i);
  1181. std::cout << (DockWidget->isHidden() ? " " : "v");
  1182. std::cout << (DockWidget->isClosed() ? "c" : " ") << " ";
  1183. std::cout << DockWidget->windowTitle().toStdString() << std::endl;
  1184. }
  1185. #endif
  1186. }
  1187. #else
  1188. Q_UNUSED(level);
  1189. Q_UNUSED(widget);
  1190. #endif
  1191. }
  1192. //============================================================================
  1193. CDockAreaWidget* DockContainerWidgetPrivate::addDockWidgetToDockArea(DockWidgetArea area,
  1194. CDockWidget* Dockwidget, CDockAreaWidget* TargetDockArea, int Index)
  1195. {
  1196. if (CenterDockWidgetArea == area)
  1197. {
  1198. TargetDockArea->insertDockWidget(Index, Dockwidget);
  1199. TargetDockArea->updateTitleBarVisibility();
  1200. return TargetDockArea;
  1201. }
  1202. CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this);
  1203. NewDockArea->addDockWidget(Dockwidget);
  1204. auto InsertParam = internal::dockAreaInsertParameters(area);
  1205. auto TargetAreaSplitter = TargetDockArea->parentSplitter();
  1206. int index = TargetAreaSplitter ->indexOf(TargetDockArea);
  1207. if (TargetAreaSplitter->orientation() == InsertParam.orientation())
  1208. {
  1209. ADS_PRINT("TargetAreaSplitter->orientation() == InsertParam.orientation()");
  1210. TargetAreaSplitter->insertWidget(index + InsertParam.insertOffset(), NewDockArea);
  1211. updateSplitterHandles(TargetAreaSplitter);
  1212. // do nothing, if flag is not enabled
  1213. if (CDockManager::testConfigFlag(CDockManager::EqualSplitOnInsertion))
  1214. {
  1215. adjustSplitterSizesOnInsertion(TargetAreaSplitter);
  1216. }
  1217. }
  1218. else
  1219. {
  1220. ADS_PRINT("TargetAreaSplitter->orientation() != InsertParam.orientation()");
  1221. auto TargetAreaSizes = TargetAreaSplitter->sizes();
  1222. auto NewSplitter = newSplitter(InsertParam.orientation());
  1223. NewSplitter->addWidget(TargetDockArea);
  1224. insertWidgetIntoSplitter(NewSplitter, NewDockArea, InsertParam.append());
  1225. updateSplitterHandles(NewSplitter);
  1226. TargetAreaSplitter->insertWidget(index, NewSplitter);
  1227. updateSplitterHandles(TargetAreaSplitter);
  1228. if (CDockManager::testConfigFlag(CDockManager::EqualSplitOnInsertion))
  1229. {
  1230. TargetAreaSplitter->setSizes(TargetAreaSizes);
  1231. adjustSplitterSizesOnInsertion(NewSplitter);
  1232. }
  1233. }
  1234. addDockAreasToList({NewDockArea});
  1235. return NewDockArea;
  1236. }
  1237. //============================================================================
  1238. CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *parent) :
  1239. QFrame(parent),
  1240. d(new DockContainerWidgetPrivate(this))
  1241. {
  1242. d->DockManager = DockManager;
  1243. d->isFloating = floatingWidget() != nullptr;
  1244. d->Layout = new QGridLayout();
  1245. d->Layout->setContentsMargins(0, 0, 0, 0);
  1246. d->Layout->setSpacing(0);
  1247. d->Layout->setColumnStretch(1, 1);
  1248. d->Layout->setRowStretch(1, 1);
  1249. setLayout(d->Layout);
  1250. // The function d->newSplitter() accesses the config flags from dock
  1251. // manager which in turn requires a properly constructed dock manager.
  1252. // If this dock container is the dock manager, then it is not properly
  1253. // constructed yet because this base class constructor is called before
  1254. // the constructor of the DockManager private class
  1255. if (DockManager != this)
  1256. {
  1257. d->DockManager->registerDockContainer(this);
  1258. createRootSplitter();
  1259. createSideTabBarWidgets();
  1260. }
  1261. }
  1262. //============================================================================
  1263. CDockContainerWidget::~CDockContainerWidget()
  1264. {
  1265. if (d->DockManager)
  1266. {
  1267. d->DockManager->removeDockContainer(this);
  1268. }
  1269. delete d;
  1270. }
  1271. //============================================================================
  1272. CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
  1273. CDockAreaWidget* DockAreaWidget, int Index)
  1274. {
  1275. auto TopLevelDockWidget = topLevelDockWidget();
  1276. CDockAreaWidget* OldDockArea = Dockwidget->dockAreaWidget();
  1277. if (OldDockArea)
  1278. {
  1279. OldDockArea->removeDockWidget(Dockwidget);
  1280. }
  1281. Dockwidget->setDockManager(d->DockManager);
  1282. CDockAreaWidget* DockArea;
  1283. if (DockAreaWidget)
  1284. {
  1285. DockArea = d->addDockWidgetToDockArea(area, Dockwidget, DockAreaWidget, Index);
  1286. }
  1287. else
  1288. {
  1289. DockArea = d->addDockWidgetToContainer(area, Dockwidget);
  1290. }
  1291. if (TopLevelDockWidget)
  1292. {
  1293. auto NewTopLevelDockWidget = topLevelDockWidget();
  1294. // If the container contained only one visible dock widget, the we need
  1295. // to emit a top level event for this widget because it is not the one and
  1296. // only visible docked widget anymore
  1297. if (!NewTopLevelDockWidget)
  1298. {
  1299. CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidget, false);
  1300. }
  1301. }
  1302. return DockArea;
  1303. }
  1304. //============================================================================
  1305. CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer(
  1306. SideBarLocation area, CDockWidget* DockWidget, int TabIndex)
  1307. {
  1308. if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled))
  1309. {
  1310. Q_ASSERT_X(false, "CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer",
  1311. "Requested area does not exist in config");
  1312. return nullptr;
  1313. }
  1314. if (d->DockManager != DockWidget->dockManager())
  1315. {
  1316. DockWidget->setDockManager(d->DockManager); // Auto hide Dock Container needs a valid dock manager
  1317. }
  1318. return autoHideSideBar(area)->insertDockWidget(TabIndex, DockWidget);
  1319. }
  1320. //============================================================================
  1321. void CDockContainerWidget::removeDockWidget(CDockWidget* Dockwidget)
  1322. {
  1323. CDockAreaWidget* Area = Dockwidget->dockAreaWidget();
  1324. if (Area)
  1325. {
  1326. Area->removeDockWidget(Dockwidget);
  1327. }
  1328. }
  1329. //============================================================================
  1330. unsigned int CDockContainerWidget::zOrderIndex() const
  1331. {
  1332. return d->zOrderIndex;
  1333. }
  1334. //============================================================================
  1335. bool CDockContainerWidget::isInFrontOf(CDockContainerWidget* Other) const
  1336. {
  1337. return this->zOrderIndex() > Other->zOrderIndex();
  1338. }
  1339. //============================================================================
  1340. bool CDockContainerWidget::event(QEvent *e)
  1341. {
  1342. bool Result = QWidget::event(e);
  1343. if (e->type() == QEvent::WindowActivate)
  1344. {
  1345. d->zOrderIndex = ++zOrderCounter;
  1346. }
  1347. else if (e->type() == QEvent::Show && !d->zOrderIndex)
  1348. {
  1349. d->zOrderIndex = ++zOrderCounter;
  1350. }
  1351. return Result;
  1352. }
  1353. //============================================================================
  1354. QList<CAutoHideDockContainer*> CDockContainerWidget::autoHideWidgets() const
  1355. {
  1356. return d->AutoHideWidgets;
  1357. }
  1358. //============================================================================
  1359. void CDockContainerWidget::addDockArea(CDockAreaWidget* DockAreaWidget,
  1360. DockWidgetArea area)
  1361. {
  1362. CDockContainerWidget* Container = DockAreaWidget->dockContainer();
  1363. if (Container && Container != this)
  1364. {
  1365. Container->removeDockArea(DockAreaWidget);
  1366. }
  1367. d->addDockArea(DockAreaWidget, area);
  1368. }
  1369. //============================================================================
  1370. void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
  1371. {
  1372. ADS_PRINT("CDockContainerWidget::removeDockArea");
  1373. // If it is an auto hide area, then there is nothing much to do
  1374. if (area->isAutoHide())
  1375. {
  1376. area->setAutoHideDockContainer(nullptr);
  1377. return;
  1378. }
  1379. area->disconnect(this);
  1380. d->DockAreas.removeAll(area);
  1381. auto Splitter = area->parentSplitter();
  1382. // Remove are from parent splitter and recursively hide tree of parent
  1383. // splitters if it has no visible content
  1384. area->setParent(nullptr);
  1385. internal::hideEmptyParentSplitters(Splitter);
  1386. // Remove this area from cached areas
  1387. auto p = std::find(std::begin(d->LastAddedAreaCache), std::end(d->LastAddedAreaCache), area);
  1388. if (p != std::end(d->LastAddedAreaCache)) {
  1389. *p = nullptr;
  1390. }
  1391. // If splitter has more than 1 widgets, we are finished and can leave
  1392. if (Splitter->count() > 1)
  1393. {
  1394. goto emitAndExit;
  1395. }
  1396. // If this is the RootSplitter we need to remove empty splitters to
  1397. // avoid too many empty splitters
  1398. if (Splitter == d->RootSplitter)
  1399. {
  1400. ADS_PRINT("Removed from RootSplitter");
  1401. // If splitter is empty, we are finished
  1402. if (!Splitter->count())
  1403. {
  1404. Splitter->hide();
  1405. goto emitAndExit;
  1406. }
  1407. QWidget* widget = Splitter->widget(0);
  1408. auto ChildSplitter = qobject_cast<CDockSplitter*>(widget);
  1409. // If the one and only content widget of the splitter is not a splitter
  1410. // then we are finished
  1411. if (!ChildSplitter)
  1412. {
  1413. goto emitAndExit;
  1414. }
  1415. // We replace the superfluous RootSplitter with the ChildSplitter
  1416. ChildSplitter->setParent(nullptr);
  1417. QLayoutItem* li = d->Layout->replaceWidget(Splitter, ChildSplitter);
  1418. d->RootSplitter = ChildSplitter;
  1419. delete li;
  1420. ADS_PRINT("RootSplitter replaced by child splitter");
  1421. }
  1422. else if (Splitter->count() == 1)
  1423. {
  1424. ADS_PRINT("Replacing splitter with content");
  1425. QSplitter* ParentSplitter = internal::findParent<QSplitter*>(Splitter);
  1426. auto Sizes = ParentSplitter->sizes();
  1427. QWidget* widget = Splitter->widget(0);
  1428. widget->setParent(this);
  1429. internal::replaceSplitterWidget(ParentSplitter, Splitter, widget);
  1430. ParentSplitter->setSizes(Sizes);
  1431. }
  1432. delete Splitter;
  1433. Splitter = nullptr;
  1434. emitAndExit:
  1435. updateSplitterHandles(Splitter);
  1436. CDockWidget* TopLevelWidget = topLevelDockWidget();
  1437. // Updated the title bar visibility of the dock widget if there is only
  1438. // one single visible dock widget
  1439. CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true);
  1440. dumpLayout();
  1441. d->emitDockAreasRemoved();
  1442. }
  1443. //============================================================================
  1444. QList<QPointer<CDockAreaWidget>> CDockContainerWidget::removeAllDockAreas()
  1445. {
  1446. auto Result = d->DockAreas;
  1447. d->DockAreas.clear();
  1448. return Result;
  1449. }
  1450. //============================================================================
  1451. CDockAreaWidget* CDockContainerWidget::dockAreaAt(const QPoint& GlobalPos) const
  1452. {
  1453. for (const auto& DockArea : d->DockAreas)
  1454. {
  1455. if (DockArea && DockArea->isVisible() && DockArea->rect().contains(DockArea->mapFromGlobal(GlobalPos)))
  1456. {
  1457. return DockArea;
  1458. }
  1459. }
  1460. return nullptr;
  1461. }
  1462. //============================================================================
  1463. CDockAreaWidget* CDockContainerWidget::dockArea(int Index) const
  1464. {
  1465. return (Index < dockAreaCount()) ? d->DockAreas[Index] : nullptr;
  1466. }
  1467. //============================================================================
  1468. bool CDockContainerWidget::isFloating() const
  1469. {
  1470. return d->isFloating;
  1471. }
  1472. //============================================================================
  1473. int CDockContainerWidget::dockAreaCount() const
  1474. {
  1475. return d->DockAreas.count();
  1476. }
  1477. //============================================================================
  1478. int CDockContainerWidget::visibleDockAreaCount() const
  1479. {
  1480. int Result = 0;
  1481. for (auto DockArea : d->DockAreas)
  1482. {
  1483. Result += (!DockArea || DockArea->isHidden()) ? 0 : 1;
  1484. }
  1485. return Result;
  1486. // TODO Cache or precalculate this to speed it up because it is used during
  1487. // movement of floating widget
  1488. //return d->visibleDockAreaCount();
  1489. }
  1490. //============================================================================
  1491. void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWidget,
  1492. const QPoint& TargetPos)
  1493. {
  1494. ADS_PRINT("CDockContainerWidget::dropFloatingWidget");
  1495. CDockWidget* SingleDroppedDockWidget = FloatingWidget->topLevelDockWidget();
  1496. CDockWidget* SingleDockWidget = topLevelDockWidget();
  1497. auto dropArea = InvalidDockWidgetArea;
  1498. auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
  1499. bool Dropped = false;
  1500. CDockAreaWidget* DockArea = dockAreaAt(TargetPos);
  1501. // mouse is over dock area
  1502. if (DockArea)
  1503. {
  1504. auto dropOverlay = d->DockManager->dockAreaOverlay();
  1505. dropOverlay->setAllowedAreas(DockArea->allowedAreas());
  1506. dropArea = dropOverlay->showOverlay(DockArea);
  1507. if (ContainerDropArea != InvalidDockWidgetArea &&
  1508. ContainerDropArea != dropArea)
  1509. {
  1510. dropArea = InvalidDockWidgetArea;
  1511. }
  1512. if (dropArea != InvalidDockWidgetArea)
  1513. {
  1514. ADS_PRINT("Dock Area Drop Content: " << dropArea);
  1515. int TabIndex = d->DockManager->dockAreaOverlay()->tabIndexUnderCursor();
  1516. d->dropIntoSection(FloatingWidget, DockArea, dropArea, TabIndex);
  1517. Dropped = true;
  1518. }
  1519. }
  1520. // mouse is over container or auto hide side bar
  1521. if (InvalidDockWidgetArea == dropArea && InvalidDockWidgetArea != ContainerDropArea)
  1522. {
  1523. if (internal::isSideBarArea(ContainerDropArea))
  1524. {
  1525. ADS_PRINT("Container Drop Content: " << ContainerDropArea);
  1526. d->dropIntoAutoHideSideBar(FloatingWidget, ContainerDropArea);
  1527. }
  1528. else
  1529. {
  1530. ADS_PRINT("Container Drop Content: " << ContainerDropArea);
  1531. d->dropIntoContainer(FloatingWidget, ContainerDropArea);
  1532. }
  1533. Dropped = true;
  1534. }
  1535. // Remove the auto hide widgets from the FloatingWidget and insert
  1536. // them into this widget
  1537. for (auto AutohideWidget : FloatingWidget->dockContainer()->autoHideWidgets())
  1538. {
  1539. auto SideBar = autoHideSideBar(AutohideWidget->sideBarLocation());
  1540. SideBar->addAutoHideWidget(AutohideWidget);
  1541. }
  1542. if (Dropped)
  1543. {
  1544. // Fix https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/351
  1545. FloatingWidget->finishDropOperation();
  1546. // If we dropped a floating widget with only one single dock widget, then we
  1547. // drop a top level widget that changes from floating to docked now
  1548. CDockWidget::emitTopLevelEventForWidget(SingleDroppedDockWidget, false);
  1549. // If there was a top level widget before the drop, then it is not top
  1550. // level widget anymore
  1551. CDockWidget::emitTopLevelEventForWidget(SingleDockWidget, false);
  1552. }
  1553. window()->activateWindow();
  1554. if (SingleDroppedDockWidget)
  1555. {
  1556. d->DockManager->notifyWidgetOrAreaRelocation(SingleDroppedDockWidget);
  1557. }
  1558. d->DockManager->notifyFloatingWidgetDrop(FloatingWidget);
  1559. }
  1560. //============================================================================
  1561. void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget,
  1562. int TabIndex)
  1563. {
  1564. CDockWidget* SingleDockWidget = topLevelDockWidget();
  1565. if (TargetAreaWidget)
  1566. {
  1567. d->moveToNewSection(Widget, TargetAreaWidget, DropArea, TabIndex);
  1568. }
  1569. else if (internal::isSideBarArea(DropArea))
  1570. {
  1571. d->moveToAutoHideSideBar(Widget, DropArea, TabIndex);
  1572. }
  1573. else
  1574. {
  1575. d->moveToContainer(Widget, DropArea);
  1576. }
  1577. // If there was a top level widget before the drop, then it is not top
  1578. // level widget anymore
  1579. CDockWidget::emitTopLevelEventForWidget(SingleDockWidget, false);
  1580. window()->activateWindow();
  1581. d->DockManager->notifyWidgetOrAreaRelocation(Widget);
  1582. }
  1583. //============================================================================
  1584. QList<CDockAreaWidget*> CDockContainerWidget::openedDockAreas() const
  1585. {
  1586. QList<CDockAreaWidget*> Result;
  1587. for (auto DockArea : d->DockAreas)
  1588. {
  1589. if (DockArea && !DockArea->isHidden())
  1590. {
  1591. Result.append(DockArea);
  1592. }
  1593. }
  1594. return Result;
  1595. }
  1596. //============================================================================
  1597. QList<CDockWidget*> CDockContainerWidget::openedDockWidgets() const
  1598. {
  1599. QList<CDockWidget*> DockWidgetList;
  1600. for (auto DockArea : d->DockAreas)
  1601. {
  1602. if (DockArea && !DockArea->isHidden())
  1603. {
  1604. DockWidgetList.append(DockArea->openedDockWidgets());
  1605. }
  1606. }
  1607. return DockWidgetList;
  1608. }
  1609. //============================================================================
  1610. bool CDockContainerWidget::hasOpenDockAreas() const
  1611. {
  1612. for (auto DockArea : d->DockAreas)
  1613. {
  1614. if (DockArea && !DockArea->isHidden())
  1615. {
  1616. return true;
  1617. }
  1618. }
  1619. return false;
  1620. }
  1621. //============================================================================
  1622. void CDockContainerWidget::saveState(QXmlStreamWriter& s) const
  1623. {
  1624. ADS_PRINT("CDockContainerWidget::saveState isFloating "
  1625. << isFloating());
  1626. s.writeStartElement("Container");
  1627. s.writeAttribute("Floating", QString::number(isFloating() ? 1 : 0));
  1628. if (isFloating())
  1629. {
  1630. CFloatingDockContainer* FloatingWidget = floatingWidget();
  1631. QByteArray Geometry = FloatingWidget->saveGeometry();
  1632. #if QT_VERSION < 0x050900
  1633. s.writeTextElement("Geometry", qByteArrayToHex(Geometry, ' '));
  1634. #else
  1635. s.writeTextElement("Geometry", Geometry.toHex(' '));
  1636. #endif
  1637. }
  1638. d->saveChildNodesState(s, d->RootSplitter);
  1639. d->saveAutoHideWidgetsState(s);
  1640. s.writeEndElement();
  1641. }
  1642. //============================================================================
  1643. bool CDockContainerWidget::restoreState(CDockingStateReader& s, bool Testing)
  1644. {
  1645. bool IsFloating = s.attributes().value("Floating").toInt();
  1646. ADS_PRINT("Restore CDockContainerWidget Floating" << IsFloating);
  1647. QWidget* NewRootSplitter {};
  1648. if (!Testing)
  1649. {
  1650. d->VisibleDockAreaCount = -1;// invalidate the dock area count
  1651. d->DockAreas.clear();
  1652. std::fill(std::begin(d->LastAddedAreaCache),std::end(d->LastAddedAreaCache), nullptr);
  1653. }
  1654. if (IsFloating)
  1655. {
  1656. ADS_PRINT("Restore floating widget");
  1657. if (!s.readNextStartElement() || s.name() != QLatin1String("Geometry"))
  1658. {
  1659. return false;
  1660. }
  1661. QByteArray GeometryString = s.readElementText(CDockingStateReader::ErrorOnUnexpectedElement).toLocal8Bit();
  1662. QByteArray Geometry = QByteArray::fromHex(GeometryString);
  1663. if (Geometry.isEmpty())
  1664. {
  1665. return false;
  1666. }
  1667. if (!Testing)
  1668. {
  1669. CFloatingDockContainer* FloatingWidget = floatingWidget();
  1670. if (FloatingWidget)
  1671. {
  1672. FloatingWidget->restoreGeometry(Geometry);
  1673. }
  1674. }
  1675. }
  1676. if (!d->restoreChildNodes(s, NewRootSplitter, Testing))
  1677. {
  1678. return false;
  1679. }
  1680. if (Testing)
  1681. {
  1682. return true;
  1683. }
  1684. // If the root splitter is empty, rostoreChildNodes returns a 0 pointer
  1685. // and we need to create a new empty root splitter
  1686. if (!NewRootSplitter)
  1687. {
  1688. NewRootSplitter = d->newSplitter(Qt::Horizontal);
  1689. }
  1690. QLayoutItem* li = d->Layout->replaceWidget(d->RootSplitter, NewRootSplitter);
  1691. auto OldRoot = d->RootSplitter;
  1692. d->RootSplitter = qobject_cast<CDockSplitter*>(NewRootSplitter);
  1693. OldRoot->deleteLater();
  1694. delete li;
  1695. return true;
  1696. }
  1697. //============================================================================
  1698. CDockSplitter* CDockContainerWidget::rootSplitter() const
  1699. {
  1700. return d->RootSplitter;
  1701. }
  1702. //============================================================================
  1703. void CDockContainerWidget::createRootSplitter()
  1704. {
  1705. if (d->RootSplitter)
  1706. {
  1707. return;
  1708. }
  1709. d->RootSplitter = d->newSplitter(Qt::Horizontal);
  1710. d->Layout->addWidget(d->RootSplitter, 1, 1); // Add it to the center - the 0 and 2 indexes are used for the SideTabBar widgets
  1711. }
  1712. //============================================================================
  1713. void CDockContainerWidget::createSideTabBarWidgets()
  1714. {
  1715. if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled))
  1716. {
  1717. return;
  1718. }
  1719. {
  1720. auto Area = SideBarLocation::SideBarLeft;
  1721. d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area);
  1722. d->Layout->addWidget(d->SideTabBarWidgets[Area], 1, 0);
  1723. }
  1724. {
  1725. auto Area = SideBarLocation::SideBarRight;
  1726. d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area);
  1727. d->Layout->addWidget(d->SideTabBarWidgets[Area], 1, 2);
  1728. }
  1729. {
  1730. auto Area = SideBarLocation::SideBarBottom;
  1731. d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area);
  1732. d->Layout->addWidget(d->SideTabBarWidgets[Area], 2, 1);
  1733. }
  1734. {
  1735. auto Area = SideBarLocation::SideBarTop;
  1736. d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area);
  1737. d->Layout->addWidget(d->SideTabBarWidgets[Area], 0, 1);
  1738. }
  1739. }
  1740. //============================================================================
  1741. void CDockContainerWidget::dumpLayout()
  1742. {
  1743. #if (ADS_DEBUG_LEVEL > 0)
  1744. qDebug("\n\nDumping layout --------------------------");
  1745. std::cout << "\n\nDumping layout --------------------------" << std::endl;
  1746. d->dumpRecursive(0, d->RootSplitter);
  1747. qDebug("--------------------------\n\n");
  1748. std::cout << "--------------------------\n\n" << std::endl;
  1749. #endif
  1750. }
  1751. //============================================================================
  1752. CDockAreaWidget* CDockContainerWidget::lastAddedDockAreaWidget(DockWidgetArea area) const
  1753. {
  1754. return d->LastAddedAreaCache[areaIdToIndex(area)];
  1755. }
  1756. //============================================================================
  1757. bool CDockContainerWidget::hasTopLevelDockWidget() const
  1758. {
  1759. auto DockAreas = openedDockAreas();
  1760. if (DockAreas.count() != 1)
  1761. {
  1762. return false;
  1763. }
  1764. return DockAreas[0]->openDockWidgetsCount() == 1;
  1765. }
  1766. //============================================================================
  1767. CDockWidget* CDockContainerWidget::topLevelDockWidget() const
  1768. {
  1769. auto TopLevelDockArea = topLevelDockArea();
  1770. if (!TopLevelDockArea)
  1771. {
  1772. return nullptr;
  1773. }
  1774. auto DockWidgets = TopLevelDockArea->openedDockWidgets();
  1775. if (DockWidgets.count() != 1)
  1776. {
  1777. return nullptr;
  1778. }
  1779. return DockWidgets[0];
  1780. }
  1781. //============================================================================
  1782. CDockAreaWidget* CDockContainerWidget::topLevelDockArea() const
  1783. {
  1784. auto DockAreas = openedDockAreas();
  1785. if (DockAreas.count() != 1)
  1786. {
  1787. return nullptr;
  1788. }
  1789. return DockAreas[0];
  1790. }
  1791. //============================================================================
  1792. QList<CDockWidget*> CDockContainerWidget::dockWidgets() const
  1793. {
  1794. QList<CDockWidget*> Result;
  1795. for (const auto& DockArea : d->DockAreas)
  1796. {
  1797. if (!DockArea)
  1798. {
  1799. continue;
  1800. }
  1801. Result.append(DockArea->dockWidgets());
  1802. }
  1803. return Result;
  1804. }
  1805. //============================================================================
  1806. void CDockContainerWidget::updateSplitterHandles(QSplitter* splitter)
  1807. {
  1808. d->updateSplitterHandles(splitter);
  1809. }
  1810. //============================================================================
  1811. void CDockContainerWidget::registerAutoHideWidget(CAutoHideDockContainer* AutohideWidget)
  1812. {
  1813. d->AutoHideWidgets.append(AutohideWidget);
  1814. Q_EMIT autoHideWidgetCreated(AutohideWidget);
  1815. ADS_PRINT("d->AutoHideWidgets.count() " << d->AutoHideWidgets.count());
  1816. }
  1817. //============================================================================
  1818. void CDockContainerWidget::removeAutoHideWidget(CAutoHideDockContainer* AutohideWidget)
  1819. {
  1820. d->AutoHideWidgets.removeAll(AutohideWidget);
  1821. }
  1822. //============================================================================
  1823. CDockWidget::DockWidgetFeatures CDockContainerWidget::features() const
  1824. {
  1825. CDockWidget::DockWidgetFeatures Features(CDockWidget::AllDockWidgetFeatures);
  1826. for (const auto& DockArea : d->DockAreas)
  1827. {
  1828. if (!DockArea)
  1829. {
  1830. continue;
  1831. }
  1832. Features &= DockArea->features();
  1833. }
  1834. return Features;
  1835. }
  1836. //============================================================================
  1837. CFloatingDockContainer* CDockContainerWidget::floatingWidget() const
  1838. {
  1839. return internal::findParent<CFloatingDockContainer*>(this);
  1840. }
  1841. //============================================================================
  1842. void CDockContainerWidget::closeOtherAreas(CDockAreaWidget* KeepOpenArea)
  1843. {
  1844. for (const auto& DockArea : d->DockAreas)
  1845. {
  1846. if (!DockArea || DockArea == KeepOpenArea)
  1847. {
  1848. continue;
  1849. }
  1850. if (!DockArea->features(BitwiseAnd).testFlag(CDockWidget::DockWidgetClosable))
  1851. {
  1852. continue;
  1853. }
  1854. // We do not close areas with widgets with custom close handling
  1855. if (DockArea->features(BitwiseOr).testFlag(CDockWidget::CustomCloseHandling))
  1856. {
  1857. continue;
  1858. }
  1859. DockArea->closeArea();
  1860. }
  1861. }
  1862. //============================================================================
  1863. CAutoHideSideBar* CDockContainerWidget::autoHideSideBar(SideBarLocation area) const
  1864. {
  1865. return d->SideTabBarWidgets[area];
  1866. }
  1867. //============================================================================
  1868. QRect CDockContainerWidget::contentRect() const
  1869. {
  1870. if (!d->RootSplitter)
  1871. {
  1872. return QRect();
  1873. }
  1874. if (d->RootSplitter->hasVisibleContent())
  1875. {
  1876. return d->RootSplitter->geometry();
  1877. }
  1878. else
  1879. {
  1880. auto ContentRect = this->rect();
  1881. ContentRect.adjust(
  1882. autoHideSideBar(SideBarLeft)->sizeHint().width(),
  1883. autoHideSideBar(SideBarTop)->sizeHint().height(),
  1884. -autoHideSideBar(SideBarRight)->sizeHint().width(),
  1885. -autoHideSideBar(SideBarBottom)->sizeHint().height());
  1886. return ContentRect;
  1887. }
  1888. }
  1889. //===========================================================================
  1890. QRect CDockContainerWidget::contentRectGlobal() const
  1891. {
  1892. if (!d->RootSplitter)
  1893. {
  1894. return QRect();
  1895. }
  1896. return internal::globalGeometry(d->RootSplitter);
  1897. }
  1898. //===========================================================================
  1899. CDockManager* CDockContainerWidget::dockManager() const
  1900. {
  1901. return d->DockManager;
  1902. }
  1903. //===========================================================================
  1904. void CDockContainerWidget::handleAutoHideWidgetEvent(QEvent* e, QWidget* w)
  1905. {
  1906. if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideShowOnMouseOver))
  1907. {
  1908. return;
  1909. }
  1910. if (dockManager()->isRestoringState())
  1911. {
  1912. return;
  1913. }
  1914. auto AutoHideTab = qobject_cast<CAutoHideTab*>(w);
  1915. if (AutoHideTab)
  1916. {
  1917. switch (e->type())
  1918. {
  1919. case QEvent::Enter:
  1920. if (!AutoHideTab->dockWidget()->isVisible())
  1921. {
  1922. d->DelayedAutoHideTab = AutoHideTab;
  1923. d->DelayedAutoHideShow = true;
  1924. d->DelayedAutoHideTimer.start();
  1925. }
  1926. else
  1927. {
  1928. d->DelayedAutoHideTimer.stop();
  1929. }
  1930. break;
  1931. case QEvent::MouseButtonPress:
  1932. d->DelayedAutoHideTimer.stop();
  1933. break;
  1934. case QEvent::Leave:
  1935. if (AutoHideTab->dockWidget()->isVisible())
  1936. {
  1937. d->DelayedAutoHideTab = AutoHideTab;
  1938. d->DelayedAutoHideShow = false;
  1939. d->DelayedAutoHideTimer.start();
  1940. }
  1941. else
  1942. {
  1943. d->DelayedAutoHideTimer.stop();
  1944. }
  1945. break;
  1946. default:
  1947. break;
  1948. }
  1949. return;
  1950. }
  1951. auto AutoHideContainer = qobject_cast<CAutoHideDockContainer*>(w);
  1952. if (AutoHideContainer)
  1953. {
  1954. switch (e->type())
  1955. {
  1956. case QEvent::Enter:
  1957. case QEvent::Hide:
  1958. d->DelayedAutoHideTimer.stop();
  1959. break;
  1960. case QEvent::Leave:
  1961. if (AutoHideContainer->isVisible())
  1962. {
  1963. d->DelayedAutoHideTab = AutoHideContainer->autoHideTab();
  1964. d->DelayedAutoHideShow = false;
  1965. d->DelayedAutoHideTimer.start();
  1966. }
  1967. break;
  1968. default:
  1969. break;
  1970. }
  1971. return;
  1972. return;
  1973. }
  1974. }
  1975. } // namespace ads
  1976. //---------------------------------------------------------------------------
  1977. // EOF DockContainerWidget.cpp