28#include "moc_qgsdockablewidgethelper.cpp"
30using namespace Qt::StringLiterals;
40QMainWindow *QgsDockableWidgetHelper::sOwnerWindow =
nullptr;
42QgsDockableWidgetHelper::QgsDockableWidgetHelper(
43 const QString &windowTitle,
45 QMainWindow *ownerWindow,
46 const QString &dockId,
47 const QStringList &tabifyWith,
50 Qt::DockWidgetArea defaultDockArea,
55 , mDialogGeometry( 0, 0, 0, 0 )
56 , mWindowTitle( windowTitle )
57 , mOwnerWindow( ownerWindow )
58 , mTabifyWith( tabifyWith )
60 , mUuid( QUuid::createUuid().toString() )
61 , mSettingKeyDockId( dockId )
64 switch ( openingMode )
67 isDocked = sSettingsIsDocked->valueWithDefaultOverride( defaultIsDocked, mSettingKeyDockId );
77 mDockArea = sSettingsDockArea->valueWithDefaultOverride( defaultDockArea, mSettingKeyDockId );
78 mIsDockFloating = mDockArea == Qt::DockWidgetArea::NoDockWidgetArea;
79 toggleDockMode( isDocked );
82QgsDockableWidgetHelper::~QgsDockableWidgetHelper()
86 if ( !mSettingKeyDockId.isEmpty() )
87 sSettingsDockGeometry->setValue( mDock->saveGeometry(), mSettingKeyDockId );
90 mOwnerWindow->removeDockWidget( mDock );
92 mDock->setWidget(
nullptr );
93 mWidget->setParent(
nullptr );
102 mDialogGeometry = mDialog->geometry();
104 if ( !mSettingKeyDockId.isEmpty() )
105 sSettingsDialogGeometry->setValue( mDialog->saveGeometry(), mSettingKeyDockId );
107 mDialog->layout()->removeWidget( mWidget );
108 mDialog->deleteLater();
113void QgsDockableWidgetHelper::writeXml( QDomElement &viewDom )
115 viewDom.setAttribute( u
"isDocked"_s, mIsDocked );
119 mDockGeometry = mDock->geometry();
120 mIsDockFloating = mDock->isFloating();
122 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
125 viewDom.setAttribute( u
"x"_s, mDockGeometry.x() );
126 viewDom.setAttribute( u
"y"_s, mDockGeometry.y() );
127 viewDom.setAttribute( u
"width"_s, mDockGeometry.width() );
128 viewDom.setAttribute( u
"height"_s, mDockGeometry.height() );
129 viewDom.setAttribute( u
"floating"_s, mIsDockFloating );
130 viewDom.setAttribute( u
"area"_s, mDockArea );
131 viewDom.setAttribute( u
"uuid"_s, mUuid );
135 const QList<QDockWidget *> tabSiblings = mOwnerWindow ? mOwnerWindow->tabifiedDockWidgets( mDock ) : QList<QDockWidget *>();
136 QDomElement tabSiblingsElement = viewDom.ownerDocument().createElement( u
"tab_siblings"_s );
137 for ( QDockWidget *dock : tabSiblings )
139 QDomElement siblingElement = viewDom.ownerDocument().createElement( u
"sibling"_s );
140 siblingElement.setAttribute( u
"uuid"_s, dock->property(
"dock_uuid" ).toString() );
141 siblingElement.setAttribute( u
"object_name"_s, dock->objectName() );
142 tabSiblingsElement.appendChild( siblingElement );
144 viewDom.appendChild( tabSiblingsElement );
148 mDialogGeometry = mDialog->geometry();
150 viewDom.setAttribute( u
"d_x"_s, mDialogGeometry.x() );
151 viewDom.setAttribute( u
"d_y"_s, mDialogGeometry.y() );
152 viewDom.setAttribute( u
"d_width"_s, mDialogGeometry.width() );
153 viewDom.setAttribute( u
"d_height"_s, mDialogGeometry.height() );
156void QgsDockableWidgetHelper::readXml(
const QDomElement &viewDom )
158 mUuid = viewDom.attribute( u
"uuid"_s, mUuid );
161 int x = viewDom.attribute( u
"d_x"_s, u
"0"_s ).toInt();
162 int y = viewDom.attribute( u
"d_x"_s, u
"0"_s ).toInt();
163 int w = viewDom.attribute( u
"d_width"_s, u
"200"_s ).toInt();
164 int h = viewDom.attribute( u
"d_height"_s, u
"200"_s ).toInt();
165 mDialogGeometry = QRect( x, y, w, h );
167 mDialog->setGeometry( mDialogGeometry );
171 int x = viewDom.attribute( u
"x"_s, u
"0"_s ).toInt();
172 int y = viewDom.attribute( u
"y"_s, u
"0"_s ).toInt();
173 int w = viewDom.attribute( u
"width"_s, u
"200"_s ).toInt();
174 int h = viewDom.attribute( u
"height"_s, u
"200"_s ).toInt();
175 mDockGeometry = QRect( x, y, w, h );
176 mIsDockFloating = viewDom.attribute( u
"floating"_s, u
"0"_s ).toInt();
177 mDockArea =
static_cast<Qt::DockWidgetArea
>( viewDom.attribute( u
"area"_s, QString::number( Qt::RightDockWidgetArea ) ).toInt() );
179 if ( mDockArea == Qt::DockWidgetArea::NoDockWidgetArea && !mIsDockFloating )
181 mDockArea = Qt::RightDockWidgetArea;
184 QStringList tabSiblings;
185 const QDomElement tabSiblingsElement = viewDom.firstChildElement( u
"tab_siblings"_s );
186 const QDomNodeList tabSiblingNodes = tabSiblingsElement.childNodes();
187 for (
int i = 0; i < tabSiblingNodes.size(); ++i )
189 const QDomElement tabSiblingElement = tabSiblingNodes.at( i ).toElement();
191 QString tabId = tabSiblingElement.attribute( u
"uuid"_s );
192 if ( tabId.isEmpty() )
193 tabId = tabSiblingElement.attribute( u
"object_name"_s );
194 if ( !tabId.isEmpty() )
195 tabSiblings.append( tabId );
198 setupDockWidget( tabSiblings );
203 mDock->setProperty(
"dock_uuid", mUuid );
207void QgsDockableWidgetHelper::setWidget( QWidget *widget )
210 if ( mWidget && mOwnerWindow )
212 mWidget->setParent( mOwnerWindow );
216 mDialog->layout()->removeWidget( mWidget );
220 mDock->setWidget(
nullptr );
224 toggleDockMode( mIsDocked );
232QDialog *QgsDockableWidgetHelper::dialog()
234 return mDialog.data();
237void QgsDockableWidgetHelper::toggleDockMode(
bool docked )
240 if ( mWidget && mOwnerWindow )
242 mWidget->setParent( mOwnerWindow );
248 mDockGeometry = mDock->geometry();
249 mIsDockFloating = mDock->isFloating();
251 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
253 mDock->setWidget(
nullptr );
255 mOwnerWindow->removeDockWidget( mDock );
263 if ( !mSettingKeyDockId.isEmpty() )
264 sSettingsDialogGeometry->setValue( mDialog->saveGeometry(), mSettingKeyDockId );
266 mDialogGeometry = mDialog->geometry();
269 mDialog->layout()->removeWidget( mWidget );
276 if ( !mSettingKeyDockId.isEmpty() )
277 sSettingsIsDocked->setValue( mIsDocked, mSettingKeyDockId );
287 mDock->setWindowTitle( mWindowTitle );
288 mDock->setWidget( mWidget );
289 mDock->setObjectName( mObjectName );
290 mDock->setProperty(
"dock_uuid", mUuid );
293 if ( !mSettingKeyDockId.isEmpty() )
295 connect( mDock, &QgsDockWidget::dockLocationChanged,
this, [
this]( Qt::DockWidgetArea area ) { sSettingsDockArea->setValue( area, mSettingKeyDockId ); } );
299 mDockGeometry = mDock->geometry();
300 mIsDockFloating = mDock->isFloating();
302 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
306 if ( mOptions.testFlag( Option::PermanentWidget ) )
307 mDock->installEventFilter(
this );
309 connect( mDock, &QgsDockWidget::visibilityChanged,
this, &QgsDockableWidgetHelper::visibilityChanged );
310 mDock->setUserVisible(
true );
311 emit visibilityChanged(
true );
318 if ( mOptions.testFlag( Option::PermanentWidget ) )
319 mDialog =
new QgsNonRejectableDialog(
nullptr, Qt::Window );
321 mDialog =
new QDialog(
nullptr, Qt::Window );
325 mDialog->setWindowTitle( mWindowTitle );
326 mDialog->setObjectName( mObjectName );
328 if ( mOptions.testFlag( Option::PermanentWidget ) )
329 mDialog->installEventFilter(
this );
331 QVBoxLayout *vl =
new QVBoxLayout();
332 vl->setContentsMargins( 0, 0, 0, 0 );
333 vl->addWidget( mWidget );
335 mDialogRestored =
false;
336 if ( !mSettingKeyDockId.isEmpty() )
338 mDialogRestored = mDialog->restoreGeometry( sSettingsDialogGeometry->value( mSettingKeyDockId ).toByteArray() );
342 if ( !mDockGeometry.isEmpty() )
344 mDialog->setGeometry( mDockGeometry );
345 mDialogRestored =
true;
347 else if ( !mDialogGeometry.isEmpty() )
349 mDialog->setGeometry( mDialogGeometry );
350 mDialogRestored =
true;
353 mDialog->setLayout( vl );
357 connect( mDialog, &QDialog::finished,
this, [
this]() {
358 mDialogGeometry = mDialog->geometry();
360 emit visibilityChanged(
false );
363 emit visibilityChanged(
true );
365 emit dockModeToggled( docked );
368void QgsDockableWidgetHelper::setUserVisible(
bool visible )
376 mDialog->setWindowState( mDialog->windowState() & ~Qt::WindowMinimized );
377 mDialog->activateWindow();
378 emit visibilityChanged(
true );
383 emit visibilityChanged(
false );
388 mDock->setUserVisible( visible );
392void QgsDockableWidgetHelper::reject()
404void QgsDockableWidgetHelper::setWindowTitle(
const QString &title )
406 mWindowTitle = title;
409 mDialog->setWindowTitle( title );
413 mDock->setWindowTitle( title );
417void QgsDockableWidgetHelper::setDefaultDialogSize(
const QSize &size )
419 mDefaultDialogSize = size;
420 if ( mDialog && !mDialogRestored && mDefaultDialogSize.isValid() )
421 mDialog->resize( mDefaultDialogSize.expandedTo( mDialog->sizeHint() ) );
424void QgsDockableWidgetHelper::setDockObjectName(
const QString &name )
429 mDialog->setObjectName( name );
433 mDock->setObjectName( name );
437QString QgsDockableWidgetHelper::dockObjectName()
const
442void QgsDockableWidgetHelper::setSettingKeyDockId(
const QString &
id )
444 mSettingKeyDockId = id;
447bool QgsDockableWidgetHelper::isUserVisible()
const
451 return mDialog->isVisible();
455 return mDock->isUserVisible();
460void QgsDockableWidgetHelper::setupDockWidget(
const QStringList &tabSiblings )
465 mDock->setFloating( mIsDockFloating );
467 if ( mDockGeometry.isEmpty() && mOwnerWindow )
469 const QFontMetrics fm( mOwnerWindow->font() );
470 const int initialDockSize = fm.horizontalAdvance(
'0' ) * 75;
471 mDockGeometry = QRect(
static_cast<int>( mOwnerWindow->rect().width() * 0.75 ),
static_cast<int>( mOwnerWindow->rect().height() * 0.5 ), initialDockSize, initialDockSize );
473 if ( mOwnerWindow && !tabSiblings.isEmpty() )
477 else if ( mOwnerWindow && mOptions.testFlag( Option::RaiseTab ) )
481 else if ( mOwnerWindow )
483 mOwnerWindow->addDockWidget( mDockArea, mDock );
488 QMetaObject::invokeMethod(
491 if ( mIsDockFloating && sSettingsDockGeometry->exists( mSettingKeyDockId ) )
492 mDock->restoreGeometry( sSettingsDockGeometry->value( mSettingKeyDockId ).toByteArray() );
493 else if ( mIsDockFloating )
494 mDock->setGeometry( mDockGeometry );
500QToolButton *QgsDockableWidgetHelper::createDockUndockToolButton()
502 QToolButton *toggleButton =
new QToolButton;
504 toggleButton->setCheckable(
true );
505 toggleButton->setChecked( mIsDocked );
506 toggleButton->setEnabled(
true );
508 connect( toggleButton, &QToolButton::toggled,
this, &QgsDockableWidgetHelper::toggleDockMode );
512QAction *QgsDockableWidgetHelper::createDockUndockAction(
const QString &title, QWidget *parent )
514 QAction *toggleAction =
new QAction( title, parent );
516 toggleAction->setCheckable(
true );
517 toggleAction->setChecked( mIsDocked );
518 toggleAction->setEnabled(
true );
520 connect( toggleAction, &QAction::toggled,
this, &QgsDockableWidgetHelper::toggleDockMode );
524bool QgsDockableWidgetHelper::eventFilter( QObject *watched, QEvent *event )
526 if ( watched == mDialog )
528 if ( event->type() == QEvent::Close )
532 emit visibilityChanged(
false );
536 else if ( watched == mDock )
538 if ( event->type() == QEvent::Close )
542 emit visibilityChanged(
false );
546 return QObject::eventFilter( watched, event );
553QgsNonRejectableDialog::QgsNonRejectableDialog( QWidget *parent, Qt::WindowFlags f )
554 : QDialog( parent, f )
557void 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).