1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2020 Uwe Kindler 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of Qt Creator. 7 ** 8 ** Commercial License Usage 9 ** Licensees holding valid commercial Qt licenses may use this file in 10 ** accordance with the commercial license agreement provided with the 11 ** Software or, alternatively, in accordance with the terms contained in 12 ** a written agreement between you and The Qt Company. For licensing terms 13 ** and conditions see https://www.qt.io/terms-conditions. For further 14 ** information use the contact form at https://www.qt.io/contact-us. 15 ** 16 ** GNU Lesser General Public License Usage 17 ** Alternatively, this file may be used under the terms of the GNU Lesser 18 ** General Public License version 2.1 or (at your option) any later version. 19 ** The licenses are as published by the Free Software Foundation 20 ** and appearing in the file LICENSE.LGPLv21 included in the packaging 21 ** of this file. Please review the following information to ensure 22 ** the GNU Lesser General Public License version 2.1 requirements 23 ** will be met: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 24 ** 25 ** GNU General Public License Usage 26 ** Alternatively, this file may be used under the terms of the GNU 27 ** General Public License version 3 or (at your option) any later version 28 ** approved by the KDE Free Qt Foundation. The licenses are as published by 29 ** the Free Software Foundation and appearing in the file LICENSE.GPL3 30 ** included in the packaging of this file. Please review the following 31 ** information to ensure the GNU General Public License requirements will 32 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 33 ** 34 ****************************************************************************/ 35 36 #pragma once 37 38 #include "ads_globals.h" 39 #include "dockcontainerwidget.h" 40 #include "dockwidget.h" 41 #include "floatingdockcontainer.h" 42 43 #include <utils/persistentsettings.h> 44 45 #include <QByteArray> 46 #include <QDateTime> 47 #include <QFlags> 48 #include <QList> 49 #include <QMap> 50 #include <QString> 51 #include <QStringList> 52 #include <QtGui/QIcon> 53 #include <qobjectdefs.h> 54 55 QT_BEGIN_NAMESPACE 56 class QMenu; 57 class QSettings; 58 QT_END_NAMESPACE 59 60 namespace ADS { 61 62 namespace Constants { 63 const char DEFAULT_WORKSPACE[] = "Essentials"; // This needs to align with a name of the shipped presets 64 const char STARTUP_WORKSPACE_SETTINGS_KEY[] = "QML/Designer/StartupWorkspace"; 65 const char AUTO_RESTORE_WORKSPACE_SETTINGS_KEY[] = "QML/Designer/AutoRestoreLastWorkspace"; 66 } // namespace Constants 67 68 class DockManagerPrivate; 69 class FloatingDockContainer; 70 class FloatingDockContainerPrivate; 71 class DockComponentsFactory; 72 class DockContainerWidget; 73 class DockContainerWidgetPrivate; 74 class DockOverlay; 75 class DockAreaTabBar; 76 class DockWidgetTab; 77 class DockWidgetTabPrivate; 78 struct DockAreaWidgetPrivate; 79 class IconProvider; 80 81 /** 82 * The central dock manager that maintains the complete docking system. 83 * With the configuration flags you can globally control the functionality 84 * of the docking system. The dock manager uses an internal stylesheet to 85 * style its components like splitters, tabs and buttons. If you want to 86 * disable this stylesheet because your application uses its own, 87 * just call the function for settings the stylesheet with an empty 88 * string. 89 * \code 90 * dockManager->setStyleSheet(""); 91 * \endcode 92 **/ 93 class ADS_EXPORT DockManager : public DockContainerWidget 94 { 95 Q_OBJECT 96 private: 97 DockManagerPrivate *d; ///< private data (pimpl) 98 friend class DockManagerPrivate; 99 friend class FloatingDockContainer; 100 friend class FloatingDockContainerPrivate; 101 friend class DockContainerWidget; 102 friend class DockContainerWidgetPrivate; 103 friend class DockAreaTabBar; 104 friend class DockWidgetTab; 105 friend struct DockAreaWidgetPrivate; 106 friend class DockWidgetTabPrivate; 107 friend class FloatingDragPreview; 108 friend class FloatingDragPreviewPrivate; 109 friend class DockAreaTitleBar; 110 111 protected: 112 /** 113 * Registers the given floating widget in the internal list of 114 * floating widgets 115 */ 116 void registerFloatingWidget(FloatingDockContainer *floatingWidget); 117 118 /** 119 * Remove the given floating widget from the list of registered floating 120 * widgets 121 */ 122 void removeFloatingWidget(FloatingDockContainer *floatingWidget); 123 124 /** 125 * Registers the given dock container widget 126 */ 127 void registerDockContainer(DockContainerWidget *dockContainer); 128 129 /** 130 * Remove dock container from the internal list of registered dock 131 * containers 132 */ 133 void removeDockContainer(DockContainerWidget *dockContainer); 134 135 /** 136 * Overlay for containers 137 */ 138 DockOverlay *containerOverlay() const; 139 140 /** 141 * Overlay for dock areas 142 */ 143 DockOverlay *dockAreaOverlay() const; 144 145 /** 146 * A container needs to call this function if a widget has been dropped 147 * into it 148 */ 149 void notifyWidgetOrAreaRelocation(QWidget *droppedWidget); 150 151 /** 152 * This function is called, if a floating widget has been dropped into 153 * an new position. 154 * When this function is called, all dock widgets of the FloatingWidget 155 * are already inserted into its new position 156 */ 157 void notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget); 158 159 /** 160 * This function is called, if the given DockWidget has been relocated from 161 * the old container ContainerOld to the new container DockWidget->dockContainer() 162 */ 163 void notifyDockWidgetRelocation(DockWidget *dockWidget, DockContainerWidget *containerOld); 164 165 /** 166 * This function is called, if the given DockAreahas been relocated from 167 * the old container ContainerOld to the new container DockArea->dockContainer() 168 */ 169 void notifyDockAreaRelocation(DockAreaWidget *dockArea, DockContainerWidget *containerOld); 170 171 /** 172 * Show the floating widgets that has been created floating 173 */ 174 void showEvent(QShowEvent *event) override; 175 176 public: 177 using Super = DockContainerWidget; 178 179 /** 180 * These global configuration flags configure some global dock manager settings. 181 * Set the dock manager flags, before you create the dock manager instance. 182 */ 183 enum eConfigFlag { 184 ActiveTabHasCloseButton 185 = 0x0001, //!< If this flag is set, the active tab in a tab area has a close button 186 DockAreaHasCloseButton 187 = 0x0002, //!< If the flag is set each dock area has a close button 188 DockAreaCloseButtonClosesTab 189 = 0x0004, //!< If the flag is set, the dock area close button closes the active tab, if not set, it closes the complete dock area 190 OpaqueSplitterResize 191 = 0x0008, //!< See QSplitter::setOpaqueResize() documentation 192 XmlAutoFormattingEnabled 193 = 0x0010, //!< If enabled, the XML writer automatically adds line-breaks and indentation to empty sections between elements (ignorable whitespace). 194 XmlCompressionEnabled 195 = 0x0020, //!< If enabled, the XML output will be compressed and is not human readable anymore 196 TabCloseButtonIsToolButton 197 = 0x0040, //! If enabled the tab close buttons will be QToolButtons instead of QPushButtons - disabled by default 198 AllTabsHaveCloseButton 199 = 0x0080, //!< if this flag is set, then all tabs that are closable show a close button 200 RetainTabSizeWhenCloseButtonHidden 201 = 0x0100, //!< if this flag is set, the space for the close button is reserved even if the close button is not visible 202 OpaqueUndocking 203 = 0x0200, ///< If enabled, the widgets are immediately undocked into floating widgets, if disabled, only a draw preview is undocked and the real undocking is deferred until the mouse is released 204 DragPreviewIsDynamic 205 = 0x0400, ///< If opaque undocking is disabled, this flag defines the behavior of the drag preview window, if this flag is enabled, the preview will be adjusted dynamically to the drop area 206 DragPreviewShowsContentPixmap 207 = 0x0800, ///< If opaque undocking is disabled, the created drag preview window shows a copy of the content of the dock widget / dock are that is dragged 208 DragPreviewHasWindowFrame 209 = 0x1000, ///< If opaque undocking is disabled, then this flag configures if the drag preview is frameless or looks like a real window 210 AlwaysShowTabs 211 = 0x2000, ///< If this option is enabled, the tab of a dock widget is always displayed - even if it is the only visible dock widget in a floating widget. 212 DockAreaHasUndockButton 213 = 0x4000, //!< If the flag is set each dock area has an undock button 214 DockAreaHasTabsMenuButton 215 = 0x8000, //!< If the flag is set each dock area has a tabs menu button 216 DockAreaHideDisabledButtons 217 = 0x10000, //!< If the flag is set disabled dock area buttons will not appear on the tollbar at all (enabling them will bring them back) 218 DockAreaDynamicTabsMenuButtonVisibility 219 = 0x20000, //!< If the flag is set, the tabs menu button will be shown only when it is required - that means, if the tabs are elided. If the tabs are not elided, it is hidden 220 FloatingContainerHasWidgetTitle 221 = 0x40000, //!< If set, the Floating Widget window title reflects the title of the current dock widget otherwise it displays application name as window title 222 FloatingContainerHasWidgetIcon 223 = 0x80000, //!< If set, the Floating Widget icon reflects the icon of the current dock widget otherwise it displays application icon 224 HideSingleCentralWidgetTitleBar 225 = 0x100000, //!< If there is only one single visible dock widget in the main dock container (the dock manager) and if this flag is set, then the titlebar of this dock widget will be hidden 226 //!< this only makes sense for non draggable and non floatable widgets and enables the creation of some kind of "central" widget 227 FocusHighlighting 228 = 0x200000, //!< enables styling of focused dock widget tabs or floating widget titlebar 229 EqualSplitOnInsertion 230 = 0x400000, ///!< if enabled, the space is equally distributed to all widgets in a splitter 231 232 DefaultDockAreaButtons = DockAreaHasCloseButton 233 | DockAreaHasUndockButton 234 | DockAreaHasTabsMenuButton,///< default configuration of dock area title bar buttons 235 236 DefaultBaseConfig = DefaultDockAreaButtons 237 | ActiveTabHasCloseButton 238 | XmlCompressionEnabled 239 | FloatingContainerHasWidgetTitle,///< default base configuration settings 240 241 DefaultOpaqueConfig = DefaultBaseConfig 242 | OpaqueSplitterResize 243 | OpaqueUndocking, ///< the default configuration with opaque operations - this may cause issues if ActiveX or Qt 3D windows are involved 244 245 DefaultNonOpaqueConfig = DefaultBaseConfig 246 | DragPreviewShowsContentPixmap, ///< the default configuration for non opaque operations 247 248 NonOpaqueWithWindowFrame = DefaultNonOpaqueConfig 249 | DragPreviewHasWindowFrame ///< the default configuration for non opaque operations that show a real window with frame 250 }; 251 Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag) 252 253 /** 254 * Default Constructor. 255 * If the given parent is a QMainWindow, the dock manager sets itself as the 256 * central widget. 257 * Before you create any dock widgets, you should properly setup the 258 * configuration flags via setConfigFlags(). 259 */ 260 DockManager(QWidget *parent = nullptr); 261 262 /** 263 * Virtual Destructor 264 */ 265 ~DockManager() override; 266 267 /** 268 * This function returns the global configuration flags. 269 */ 270 static ConfigFlags configFlags(); 271 272 /** 273 * Sets the global configuration flags for the whole docking system. 274 * Call this function before you create the dock manager and before 275 * your create the first dock widget. 276 */ 277 static void setConfigFlags(const ConfigFlags flags); 278 279 /** 280 * Set a certain config flag. 281 * \see setConfigFlags() 282 */ 283 static void setConfigFlag(eConfigFlag flag, bool on = true); 284 285 /** 286 * Returns true if the given config flag is set. 287 */ 288 static bool testConfigFlag(eConfigFlag flag); 289 290 /** 291 * Returns the global icon provider. 292 * The icon provider enables the use of custom icons in case using 293 * styleheets for icons is not an option. 294 */ 295 static IconProvider &iconProvider(); 296 297 /** 298 * The distance the user needs to move the mouse with the left button 299 * hold down before a dock widget start floating. 300 */ 301 static int startDragDistance(); 302 303 /** 304 * Helper function to set focus depending on the configuration of the 305 * FocusStyling flag 306 */ 307 template <class QWidgetPtr> setWidgetFocus(QWidgetPtr widget)308 static void setWidgetFocus(QWidgetPtr widget) 309 { 310 if (!DockManager::testConfigFlag(DockManager::FocusHighlighting)) 311 return; 312 313 widget->setFocus(Qt::OtherFocusReason); 314 } 315 316 /** 317 * Set the QtCreator settings. 318 */ 319 void setSettings(QSettings *settings); 320 321 /** 322 * Set the path to the workspace presets folder. 323 */ 324 void setWorkspacePresetsPath(const QString &path); 325 326 void initialize(); 327 328 /** 329 * Adds dockwidget into the given area. 330 * If DockAreaWidget is not null, then the area parameter indicates the area 331 * into the DockAreaWidget. If DockAreaWidget is null, the Dockwidget will 332 * be dropped into the container. If you would like to add a dock widget 333 * tabified, then you need to add it to an existing dock area object 334 * into the CenterDockWidgetArea. The following code shows this: 335 * \code 336 * DockManager->addDockWidget(ads::CenterDockWidgetArea, NewDockWidget, 337 * ExisitingDockArea); 338 * \endcode 339 * \return Returns the dock area widget that contains the new DockWidget 340 */ 341 DockAreaWidget *addDockWidget(DockWidgetArea area, 342 DockWidget *dockWidget, 343 DockAreaWidget *dockAreaWidget = nullptr); 344 345 /** 346 * This function will add the given Dockwidget to the given dock area as 347 * a new tab. 348 * If no dock area widget exists for the given area identifier, a new 349 * dock area widget is created. 350 */ 351 DockAreaWidget *addDockWidgetTab(DockWidgetArea area, DockWidget *dockWidget); 352 353 /** 354 * This function will add the given Dockwidget to the given DockAreaWidget 355 * as a new tab. 356 */ 357 DockAreaWidget *addDockWidgetTabToArea(DockWidget *dockWidget, DockAreaWidget *dockAreaWidget); 358 359 /** 360 * Adds the given DockWidget floating and returns the created 361 * CFloatingDockContainer instance. 362 */ 363 FloatingDockContainer *addDockWidgetFloating(DockWidget *dockWidget); 364 365 /** 366 * Searches for a registered doc widget with the given ObjectName 367 * \return Return the found dock widget or nullptr if a dock widget with the 368 * given name is not registered. 369 */ 370 DockWidget *findDockWidget(const QString &objectName) const; 371 372 /** 373 * Remove the given DockWidget from the dock manager. 374 */ 375 void removeDockWidget(DockWidget *dockWidget); 376 377 /** 378 * This function returns a readable reference to the internal dock 379 * widgets map so that it is possible to iterate over all dock widgets. 380 */ 381 QMap<QString, DockWidget *> dockWidgetsMap() const; 382 383 /** 384 * Returns the list of all active and visible dock containers 385 * Dock containers are the main dock manager and all floating widgets. 386 */ 387 const QList<DockContainerWidget *> dockContainers() const; 388 389 /** 390 * Returns the list of all floating widgets. 391 */ 392 const QList<QPointer<FloatingDockContainer> > floatingWidgets() const; 393 394 /** 395 * This function always return 0 because the main window is always behind 396 * any floating widget. 397 */ 398 unsigned int zOrderIndex() const override; 399 400 /** 401 * Saves the current state of the dockmanger and all its dock widgets 402 * into the returned QByteArray. 403 * The XmlMode enables / disables the auto formatting for the XmlStreamWriter. 404 * If auto formatting is enabled, the output is intended and line wrapped. 405 * The XmlMode XmlAutoFormattingDisabled is better if you would like to have 406 * a more compact XML output - i.e. for storage in ini files. 407 * The version number is stored as part of the data. 408 * To restore the saved state, pass the return value and version number 409 * to restoreState(). 410 * \see restoreState() 411 */ 412 QByteArray saveState(int version = 0) const; 413 414 /** 415 * Restores the state of this dockmanagers dockwidgets. 416 * The version number is compared with that stored in state. If they do 417 * not match, the dockmanager's state is left unchanged, and this function 418 * returns false; otherwise, the state is restored, and this function 419 * returns true. 420 * \see saveState() 421 */ 422 bool restoreState(const QByteArray &state, int version = 0); 423 424 /** 425 * This function returns true between the restoringState() and 426 * stateRestored() signals. 427 */ 428 bool isRestoringState() const; 429 430 /** 431 * Request a focus change to the given dock widget. 432 * This function only has an effect, if the flag CDockManager::FocusStyling 433 * is enabled 434 */ 435 void setDockWidgetFocused(DockWidget *dockWidget); 436 437 signals: 438 /** 439 * This signal is emitted if the list of workspaces changed. 440 */ 441 void workspaceListChanged(); 442 443 /** 444 * This signal is emitted if workspaces have been removed. 445 */ 446 void workspacesRemoved(); 447 448 /** 449 * This signal is emitted, if the restore function is called, just before 450 * the dock manager starts restoring the state. 451 * If this function is called, nothing has changed yet. 452 */ 453 void restoringState(); 454 455 /** 456 * This signal is emitted if the state changed in restoreState. 457 * The signal is emitted if the restoreState() function is called or 458 * if the openWorkspace() function is called. 459 */ 460 void stateRestored(); 461 462 /** 463 * This signal is emitted, if the dock manager starts opening a 464 * workspace. 465 * Opening a workspace may take more than a second if there are 466 * many complex widgets. The application may use this signal 467 * to show some progress indicator or to change the mouse cursor 468 * into a busy cursor. 469 */ 470 void openingWorkspace(const QString &workspaceName); 471 472 /** 473 * This signal is emitted if the dock manager finished opening a 474 * workspace. 475 */ 476 void workspaceOpened(const QString &workspaceName); 477 478 /** 479 * This signal is emitted, if a new floating widget has been created. 480 * An application can use this signal to e.g. subscribe to events of 481 * the newly created window. 482 */ 483 void floatingWidgetCreated(FloatingDockContainer *floatingWidget); 484 485 /** 486 * This signal is emitted, if a new DockArea has been created. 487 * An application can use this signal to set custom icons or custom 488 * tooltips for the DockArea buttons. 489 */ 490 void dockAreaCreated(DockAreaWidget *dockArea); 491 492 /** 493 * This signal is emitted just before removal of the given DockWidget. 494 */ 495 void dockWidgetAboutToBeRemoved(DockWidget *dockWidget); 496 497 /** 498 * This signal is emitted if a dock widget has been removed with the remove 499 * removeDockWidget() function. 500 * If this signal is emitted, the dock widget has been removed from the 501 * docking system but it is not deleted yet. 502 */ 503 void dockWidgetRemoved(DockWidget *dockWidget); 504 505 /** 506 * This signal is emitted if the focused dock widget changed. 507 * Both old and now can be nullptr. 508 * The focused dock widget is the one that is highlighted in the GUI 509 */ 510 void focusedDockWidgetChanged(DockWidget *old, DockWidget *now); 511 512 public: 513 void showWorkspaceMananger(); 514 515 // higher level workspace management 516 QString activeWorkspace() const; 517 QString lastWorkspace() const; 518 bool autoRestorLastWorkspace() const; 519 QString workspaceFileExtension() const; 520 QStringList workspaces(); 521 QSet<QString> workspacePresets() const; 522 QDateTime workspaceDateTime(const QString &workspace) const; 523 Utils::FilePath workspaceNameToFilePath(const QString &workspaceName) const; 524 QString fileNameToWorkspaceName(const QString &fileName) const; 525 QString workspaceNameToFileName(const QString &workspaceName) const; 526 527 bool createWorkspace(const QString &workspace); 528 529 bool openWorkspace(const QString &workspace); 530 bool reloadActiveWorkspace(); 531 532 bool confirmWorkspaceDelete(const QStringList &workspaces); 533 bool deleteWorkspace(const QString &workspace); 534 void deleteWorkspaces(const QStringList &workspaces); 535 536 bool cloneWorkspace(const QString &original, const QString &clone); 537 bool renameWorkspace(const QString &original, const QString &newName); 538 539 bool resetWorkspacePreset(const QString &workspace); 540 541 bool save(); 542 543 bool isWorkspacePreset(const QString &workspace) const; 544 545 void setModeChangeState(bool value); 546 bool isModeChangeState() const; 547 548 void importWorkspace(const QString &workspace); 549 void exportWorkspace(const QString &target, const QString &workspace); 550 551 signals: 552 void aboutToUnloadWorkspace(QString workspaceName); 553 void aboutToLoadWorkspace(QString workspaceName); 554 void workspaceLoaded(QString workspaceName); 555 void workspaceReloaded(QString workspaceName); 556 void aboutToSaveWorkspace(); 557 558 private: 559 bool write(const QString &workspace, const QByteArray &data, QString *errorString) const; 560 bool write(const QString &workspace, const QByteArray &data, QWidget *parent) const; 561 562 QByteArray loadWorkspace(const QString &workspace) const; 563 564 void syncWorkspacePresets(); 565 566 void saveStartupWorkspace(); 567 }; // class DockManager 568 569 } // namespace ADS 570