27#include "moc_qgsdockablewidgethelper.cpp"
29using namespace Qt::StringLiterals;
39QMainWindow *QgsDockableWidgetHelper::sOwnerWindow =
nullptr;
41QgsDockableWidgetHelper::QgsDockableWidgetHelper(
42 const QString &windowTitle,
44 QMainWindow *ownerWindow,
45 const QString &dockId,
46 const QStringList &tabifyWith,
49 Qt::DockWidgetArea defaultDockArea,
54 , mDialogGeometry( 0, 0, 0, 0 )
55 , mWindowTitle( windowTitle )
56 , mOwnerWindow( ownerWindow )
57 , mTabifyWith( tabifyWith )
59 , mUuid( QUuid::createUuid().toString() )
60 , mSettingKeyDockId( dockId )
63 switch ( openingMode )
66 isDocked = sSettingsIsDocked->valueWithDefaultOverride( defaultIsDocked, mSettingKeyDockId );
76 mDockArea = sSettingsDockArea->valueWithDefaultOverride( defaultDockArea, mSettingKeyDockId );
77 mIsDockFloating = mDockArea == Qt::DockWidgetArea::NoDockWidgetArea;
78 toggleDockMode( isDocked );
81QgsDockableWidgetHelper::~QgsDockableWidgetHelper()
85 if ( !mSettingKeyDockId.isEmpty() )
86 sSettingsDockGeometry->setValue( mDock->saveGeometry(), mSettingKeyDockId );
89 mOwnerWindow->removeDockWidget( mDock );
91 mDock->setWidget(
nullptr );
92 mWidget->setParent(
nullptr );
101 mDialogGeometry = mDialog->geometry();
103 if ( !mSettingKeyDockId.isEmpty() )
104 sSettingsDialogGeometry->setValue( mDialog->saveGeometry(), mSettingKeyDockId );
106 mDialog->layout()->removeWidget( mWidget );
107 mDialog->deleteLater();
112void QgsDockableWidgetHelper::writeXml( QDomElement &viewDom )
114 viewDom.setAttribute( u
"isDocked"_s, mIsDocked );
118 mDockGeometry = mDock->geometry();
119 mIsDockFloating = mDock->isFloating();
121 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
124 viewDom.setAttribute( u
"x"_s, mDockGeometry.x() );
125 viewDom.setAttribute( u
"y"_s, mDockGeometry.y() );
126 viewDom.setAttribute( u
"width"_s, mDockGeometry.width() );
127 viewDom.setAttribute( u
"height"_s, mDockGeometry.height() );
128 viewDom.setAttribute( u
"floating"_s, mIsDockFloating );
129 viewDom.setAttribute( u
"area"_s, mDockArea );
130 viewDom.setAttribute( u
"uuid"_s, mUuid );
134 const QList<QDockWidget *> tabSiblings = mOwnerWindow ? mOwnerWindow->tabifiedDockWidgets( mDock ) : QList<QDockWidget *>();
135 QDomElement tabSiblingsElement = viewDom.ownerDocument().createElement( u
"tab_siblings"_s );
136 for ( QDockWidget *dock : tabSiblings )
138 QDomElement siblingElement = viewDom.ownerDocument().createElement( u
"sibling"_s );
139 siblingElement.setAttribute( u
"uuid"_s, dock->property(
"dock_uuid" ).toString() );
140 siblingElement.setAttribute( u
"object_name"_s, dock->objectName() );
141 tabSiblingsElement.appendChild( siblingElement );
143 viewDom.appendChild( tabSiblingsElement );
147 mDialogGeometry = mDialog->geometry();
149 viewDom.setAttribute( u
"d_x"_s, mDialogGeometry.x() );
150 viewDom.setAttribute( u
"d_y"_s, mDialogGeometry.y() );
151 viewDom.setAttribute( u
"d_width"_s, mDialogGeometry.width() );
152 viewDom.setAttribute( u
"d_height"_s, mDialogGeometry.height() );
155void QgsDockableWidgetHelper::readXml(
const QDomElement &viewDom )
157 mUuid = viewDom.attribute( u
"uuid"_s, mUuid );
160 int x = viewDom.attribute( u
"d_x"_s, u
"0"_s ).toInt();
161 int y = viewDom.attribute( u
"d_x"_s, u
"0"_s ).toInt();
162 int w = viewDom.attribute( u
"d_width"_s, u
"200"_s ).toInt();
163 int h = viewDom.attribute( u
"d_height"_s, u
"200"_s ).toInt();
164 mDialogGeometry = QRect( x, y, w, h );
166 mDialog->setGeometry( mDialogGeometry );
170 int x = viewDom.attribute( u
"x"_s, u
"0"_s ).toInt();
171 int y = viewDom.attribute( u
"y"_s, u
"0"_s ).toInt();
172 int w = viewDom.attribute( u
"width"_s, u
"200"_s ).toInt();
173 int h = viewDom.attribute( u
"height"_s, u
"200"_s ).toInt();
174 mDockGeometry = QRect( x, y, w, h );
175 mIsDockFloating = viewDom.attribute( u
"floating"_s, u
"0"_s ).toInt();
176 mDockArea =
static_cast<Qt::DockWidgetArea
>( viewDom.attribute( u
"area"_s, QString::number( Qt::RightDockWidgetArea ) ).toInt() );
178 if ( mDockArea == Qt::DockWidgetArea::NoDockWidgetArea && !mIsDockFloating )
180 mDockArea = Qt::RightDockWidgetArea;
183 QStringList tabSiblings;
184 const QDomElement tabSiblingsElement = viewDom.firstChildElement( u
"tab_siblings"_s );
185 const QDomNodeList tabSiblingNodes = tabSiblingsElement.childNodes();
186 for (
int i = 0; i < tabSiblingNodes.size(); ++i )
188 const QDomElement tabSiblingElement = tabSiblingNodes.at( i ).toElement();
190 QString tabId = tabSiblingElement.attribute( u
"uuid"_s );
191 if ( tabId.isEmpty() )
192 tabId = tabSiblingElement.attribute( u
"object_name"_s );
193 if ( !tabId.isEmpty() )
194 tabSiblings.append( tabId );
197 setupDockWidget( tabSiblings );
202 mDock->setProperty(
"dock_uuid", mUuid );
206void QgsDockableWidgetHelper::setWidget( QWidget *widget )
209 if ( mWidget && mOwnerWindow )
211 mWidget->setParent( mOwnerWindow );
215 mDialog->layout()->removeWidget( mWidget );
219 mDock->setWidget(
nullptr );
223 toggleDockMode( mIsDocked );
231QDialog *QgsDockableWidgetHelper::dialog()
233 return mDialog.data();
236void QgsDockableWidgetHelper::toggleDockMode(
bool docked )
239 if ( mWidget && mOwnerWindow )
241 mWidget->setParent( mOwnerWindow );
247 mDockGeometry = mDock->geometry();
248 mIsDockFloating = mDock->isFloating();
250 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
252 mDock->setWidget(
nullptr );
254 mOwnerWindow->removeDockWidget( mDock );
262 if ( !mSettingKeyDockId.isEmpty() )
263 sSettingsDialogGeometry->setValue( mDialog->saveGeometry(), mSettingKeyDockId );
265 mDialogGeometry = mDialog->geometry();
268 mDialog->layout()->removeWidget( mWidget );
275 if ( !mSettingKeyDockId.isEmpty() )
276 sSettingsIsDocked->setValue( mIsDocked, mSettingKeyDockId );
286 mDock->setWindowTitle( mWindowTitle );
287 mDock->setWidget( mWidget );
288 mDock->setObjectName( mObjectName );
289 mDock->setProperty(
"dock_uuid", mUuid );
292 if ( !mSettingKeyDockId.isEmpty() )
294 connect( mDock, &QgsDockWidget::dockLocationChanged,
this, [
this]( Qt::DockWidgetArea area ) { sSettingsDockArea->setValue( area, mSettingKeyDockId ); } );
298 mDockGeometry = mDock->geometry();
299 mIsDockFloating = mDock->isFloating();
301 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
305 if ( mOptions.testFlag( Option::PermanentWidget ) )
306 mDock->installEventFilter(
this );
308 connect( mDock, &QgsDockWidget::visibilityChanged,
this, &QgsDockableWidgetHelper::visibilityChanged );
309 mDock->setUserVisible(
true );
310 emit visibilityChanged(
true );
317 if ( mOptions.testFlag( Option::PermanentWidget ) )
318 mDialog =
new QgsNonRejectableDialog(
nullptr, Qt::Window );
320 mDialog =
new QDialog(
nullptr, Qt::Window );
324 mDialog->setWindowTitle( mWindowTitle );
325 mDialog->setObjectName( mObjectName );
327 if ( mOptions.testFlag( Option::PermanentWidget ) )
328 mDialog->installEventFilter(
this );
330 QVBoxLayout *vl =
new QVBoxLayout();
331 vl->setContentsMargins( 0, 0, 0, 0 );
332 vl->addWidget( mWidget );
334 if ( !mSettingKeyDockId.isEmpty() )
336 mDialog->restoreGeometry( sSettingsDialogGeometry->value( mSettingKeyDockId ).toByteArray() );
340 if ( !mDockGeometry.isEmpty() )
341 mDialog->setGeometry( mDockGeometry );
342 else if ( !mDialogGeometry.isEmpty() )
343 mDialog->setGeometry( mDialogGeometry );
345 mDialog->setLayout( vl );
349 connect( mDialog, &QDialog::finished,
this, [
this]() {
350 mDialogGeometry = mDialog->geometry();
352 emit visibilityChanged(
false );
355 emit visibilityChanged(
true );
357 emit dockModeToggled( docked );
360void QgsDockableWidgetHelper::setUserVisible(
bool visible )
368 mDialog->setWindowState( mDialog->windowState() & ~Qt::WindowMinimized );
369 mDialog->activateWindow();
370 emit visibilityChanged(
true );
375 emit visibilityChanged(
false );
380 mDock->setUserVisible( visible );
384void QgsDockableWidgetHelper::reject()
396void QgsDockableWidgetHelper::setWindowTitle(
const QString &title )
398 mWindowTitle = title;
401 mDialog->setWindowTitle( title );
405 mDock->setWindowTitle( title );
409void QgsDockableWidgetHelper::setDockObjectName(
const QString &name )
414 mDialog->setObjectName( name );
418 mDock->setObjectName( name );
422QString QgsDockableWidgetHelper::dockObjectName()
const
427void QgsDockableWidgetHelper::setSettingKeyDockId(
const QString &
id )
429 mSettingKeyDockId = id;
432bool QgsDockableWidgetHelper::isUserVisible()
const
436 return mDialog->isVisible();
440 return mDock->isUserVisible();
445void QgsDockableWidgetHelper::setupDockWidget(
const QStringList &tabSiblings )
450 mDock->setFloating( mIsDockFloating );
452 if ( mDockGeometry.isEmpty() && mOwnerWindow )
454 const QFontMetrics fm( mOwnerWindow->font() );
455 const int initialDockSize = fm.horizontalAdvance(
'0' ) * 75;
456 mDockGeometry = QRect(
static_cast<int>( mOwnerWindow->rect().width() * 0.75 ),
static_cast<int>( mOwnerWindow->rect().height() * 0.5 ), initialDockSize, initialDockSize );
458 if ( mOwnerWindow && !tabSiblings.isEmpty() )
462 else if ( mOwnerWindow && mOptions.testFlag( Option::RaiseTab ) )
466 else if ( mOwnerWindow )
468 mOwnerWindow->addDockWidget( mDockArea, mDock );
473 QMetaObject::invokeMethod(
476 if ( mIsDockFloating && sSettingsDockGeometry->exists( mSettingKeyDockId ) )
477 mDock->restoreGeometry( sSettingsDockGeometry->value( mSettingKeyDockId ).toByteArray() );
478 else if ( mIsDockFloating )
479 mDock->setGeometry( mDockGeometry );
485QToolButton *QgsDockableWidgetHelper::createDockUndockToolButton()
487 QToolButton *toggleButton =
new QToolButton;
489 toggleButton->setCheckable(
true );
490 toggleButton->setChecked( mIsDocked );
491 toggleButton->setEnabled(
true );
493 connect( toggleButton, &QToolButton::toggled,
this, &QgsDockableWidgetHelper::toggleDockMode );
497QAction *QgsDockableWidgetHelper::createDockUndockAction(
const QString &title, QWidget *parent )
499 QAction *toggleAction =
new QAction( title, parent );
501 toggleAction->setCheckable(
true );
502 toggleAction->setChecked( mIsDocked );
503 toggleAction->setEnabled(
true );
505 connect( toggleAction, &QAction::toggled,
this, &QgsDockableWidgetHelper::toggleDockMode );
509bool QgsDockableWidgetHelper::eventFilter( QObject *watched, QEvent *event )
511 if ( watched == mDialog )
513 if ( event->type() == QEvent::Close )
517 emit visibilityChanged(
false );
521 else if ( watched == mDock )
523 if ( event->type() == QEvent::Close )
527 emit visibilityChanged(
false );
531 return QObject::eventFilter( watched, event );
538QgsNonRejectableDialog::QgsNonRejectableDialog( QWidget *parent, Qt::WindowFlags f )
539 : QDialog( parent, f )
542void QgsNonRejectableDialog::reject()
DockableWidgetInitialState
Dockable widget initial states.
@ ForceDocked
Force the widget to be docked.
@ ForceDialog
Force the widget to be shown in a dialog.
@ RestorePreviousState
Restore the previous state of this dock.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
void applicationStyleSheetChanged(const QString &styleSheet)
Emitted whenever the application style sheet is changed.
static QString applicationStyleSheet()
Returns the application style sheet.
static QgsGui * instance()
Returns a pointer to the singleton instance.
A boolean settings entry.
A template class for enum and flag settings entry.
A variant settings entry.
void addTabifiedDockWidget(QMainWindow *window, Qt::DockWidgetArea area, QDockWidget *dockWidget, const QStringList &tabifyWith, bool raiseTab)
Add a dock widget to the given area and tabify it (if other dock widgets exist in the same area).