17#include "moc_qgsdockablewidgethelper.cpp"
33std::function<void( Qt::DockWidgetArea, QDockWidget *,
const QStringList &,
bool )> QgsDockableWidgetHelper::sAddTabifiedDockWidgetFunction = []( Qt::DockWidgetArea, QDockWidget *,
const QStringList &, bool ) {};
34std::function<QString()> QgsDockableWidgetHelper::sAppStylesheetFunction = [] {
return QString(); };
35QMainWindow *QgsDockableWidgetHelper::sOwnerWindow =
nullptr;
37QgsDockableWidgetHelper::QgsDockableWidgetHelper(
const QString &windowTitle, QWidget *widget, QMainWindow *ownerWindow,
const QString &dockId,
const QStringList &tabifyWith, OpeningMode openingMode,
bool defaultIsDocked, Qt::DockWidgetArea defaultDockArea, Options options )
40 , mDialogGeometry( 0, 0, 0, 0 )
41 , mWindowTitle( windowTitle )
42 , mOwnerWindow( ownerWindow )
43 , mTabifyWith( tabifyWith )
45 , mUuid( QUuid::createUuid().toString() )
46 , mSettingKeyDockId( dockId )
48 bool isDocked = sSettingsIsDocked->valueWithDefaultOverride( defaultIsDocked, mSettingKeyDockId );
49 if ( openingMode == OpeningMode::ForceDocked )
51 else if ( openingMode == OpeningMode::ForceDialog )
54 mDockArea = sSettingsDockArea->valueWithDefaultOverride( defaultDockArea, mSettingKeyDockId );
55 mIsDockFloating = mDockArea == Qt::DockWidgetArea::NoDockWidgetArea;
56 toggleDockMode( isDocked );
59QgsDockableWidgetHelper::~QgsDockableWidgetHelper()
63 if ( !mSettingKeyDockId.isEmpty() )
64 sSettingsDockGeometry->setValue( mDock->saveGeometry(), mSettingKeyDockId );
67 mOwnerWindow->removeDockWidget( mDock );
69 mDock->setWidget(
nullptr );
70 mWidget->setParent(
nullptr );
77 mDialogGeometry = mDialog->geometry();
79 if ( !mSettingKeyDockId.isEmpty() )
80 sSettingsDialogGeometry->setValue( mDialog->saveGeometry(), mSettingKeyDockId );
82 mDialog->layout()->removeWidget( mWidget );
83 mDialog->deleteLater();
88void QgsDockableWidgetHelper::writeXml( QDomElement &viewDom )
90 viewDom.setAttribute( QStringLiteral(
"isDocked" ), mIsDocked );
94 mDockGeometry = mDock->geometry();
95 mIsDockFloating = mDock->isFloating();
97 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
100 viewDom.setAttribute( QStringLiteral(
"x" ), mDockGeometry.x() );
101 viewDom.setAttribute( QStringLiteral(
"y" ), mDockGeometry.y() );
102 viewDom.setAttribute( QStringLiteral(
"width" ), mDockGeometry.width() );
103 viewDom.setAttribute( QStringLiteral(
"height" ), mDockGeometry.height() );
104 viewDom.setAttribute( QStringLiteral(
"floating" ), mIsDockFloating );
105 viewDom.setAttribute( QStringLiteral(
"area" ), mDockArea );
106 viewDom.setAttribute( QStringLiteral(
"uuid" ), mUuid );
110 const QList<QDockWidget *> tabSiblings = mOwnerWindow ? mOwnerWindow->tabifiedDockWidgets( mDock ) : QList<QDockWidget *>();
111 QDomElement tabSiblingsElement = viewDom.ownerDocument().createElement( QStringLiteral(
"tab_siblings" ) );
112 for ( QDockWidget *dock : tabSiblings )
114 QDomElement siblingElement = viewDom.ownerDocument().createElement( QStringLiteral(
"sibling" ) );
115 siblingElement.setAttribute( QStringLiteral(
"uuid" ), dock->property(
"dock_uuid" ).toString() );
116 siblingElement.setAttribute( QStringLiteral(
"object_name" ), dock->objectName() );
117 tabSiblingsElement.appendChild( siblingElement );
119 viewDom.appendChild( tabSiblingsElement );
123 mDialogGeometry = mDialog->geometry();
125 viewDom.setAttribute( QStringLiteral(
"d_x" ), mDialogGeometry.x() );
126 viewDom.setAttribute( QStringLiteral(
"d_y" ), mDialogGeometry.y() );
127 viewDom.setAttribute( QStringLiteral(
"d_width" ), mDialogGeometry.width() );
128 viewDom.setAttribute( QStringLiteral(
"d_height" ), mDialogGeometry.height() );
131void QgsDockableWidgetHelper::readXml(
const QDomElement &viewDom )
133 mUuid = viewDom.attribute( QStringLiteral(
"uuid" ), mUuid );
136 int x = viewDom.attribute( QStringLiteral(
"d_x" ), QStringLiteral(
"0" ) ).toInt();
137 int y = viewDom.attribute( QStringLiteral(
"d_x" ), QStringLiteral(
"0" ) ).toInt();
138 int w = viewDom.attribute( QStringLiteral(
"d_width" ), QStringLiteral(
"200" ) ).toInt();
139 int h = viewDom.attribute( QStringLiteral(
"d_height" ), QStringLiteral(
"200" ) ).toInt();
140 mDialogGeometry = QRect( x, y, w, h );
142 mDialog->setGeometry( mDialogGeometry );
146 int x = viewDom.attribute( QStringLiteral(
"x" ), QStringLiteral(
"0" ) ).toInt();
147 int y = viewDom.attribute( QStringLiteral(
"y" ), QStringLiteral(
"0" ) ).toInt();
148 int w = viewDom.attribute( QStringLiteral(
"width" ), QStringLiteral(
"200" ) ).toInt();
149 int h = viewDom.attribute( QStringLiteral(
"height" ), QStringLiteral(
"200" ) ).toInt();
150 mDockGeometry = QRect( x, y, w, h );
151 mIsDockFloating = viewDom.attribute( QStringLiteral(
"floating" ), QStringLiteral(
"0" ) ).toInt();
152 mDockArea =
static_cast<Qt::DockWidgetArea
>( viewDom.attribute( QStringLiteral(
"area" ), QString::number( Qt::RightDockWidgetArea ) ).toInt() );
154 if ( mDockArea == Qt::DockWidgetArea::NoDockWidgetArea && !mIsDockFloating )
156 mDockArea = Qt::RightDockWidgetArea;
159 QStringList tabSiblings;
160 const QDomElement tabSiblingsElement = viewDom.firstChildElement( QStringLiteral(
"tab_siblings" ) );
161 const QDomNodeList tabSiblingNodes = tabSiblingsElement.childNodes();
162 for (
int i = 0; i < tabSiblingNodes.size(); ++i )
164 const QDomElement tabSiblingElement = tabSiblingNodes.at( i ).toElement();
166 QString tabId = tabSiblingElement.attribute( QStringLiteral(
"uuid" ) );
167 if ( tabId.isEmpty() )
168 tabId = tabSiblingElement.attribute( QStringLiteral(
"object_name" ) );
169 if ( !tabId.isEmpty() )
170 tabSiblings.append( tabId );
173 setupDockWidget( tabSiblings );
178 mDock->setProperty(
"dock_uuid", mUuid );
182void QgsDockableWidgetHelper::setWidget( QWidget *widget )
185 if ( mWidget && mOwnerWindow )
187 mWidget->setParent( mOwnerWindow );
191 mDialog->layout()->removeWidget( mWidget );
195 mDock->setWidget(
nullptr );
199 toggleDockMode( mIsDocked );
207QDialog *QgsDockableWidgetHelper::dialog()
209 return mDialog.data();
212void QgsDockableWidgetHelper::toggleDockMode(
bool docked )
215 if ( mWidget && mOwnerWindow )
217 mWidget->setParent( mOwnerWindow );
223 mDockGeometry = mDock->geometry();
224 mIsDockFloating = mDock->isFloating();
226 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
228 mDock->setWidget(
nullptr );
230 mOwnerWindow->removeDockWidget( mDock );
238 if ( !mSettingKeyDockId.isEmpty() )
239 sSettingsDialogGeometry->setValue( mDialog->saveGeometry(), mSettingKeyDockId );
241 mDialogGeometry = mDialog->geometry();
244 mDialog->layout()->removeWidget( mWidget );
251 if ( !mSettingKeyDockId.isEmpty() )
252 sSettingsIsDocked->setValue( mIsDocked, mSettingKeyDockId );
262 mDock->setWindowTitle( mWindowTitle );
263 mDock->setWidget( mWidget );
264 mDock->setObjectName( mObjectName );
265 mDock->setProperty(
"dock_uuid", mUuid );
268 if ( !mSettingKeyDockId.isEmpty() )
270 connect( mDock, &QgsDockWidget::dockLocationChanged,
this, [=]( Qt::DockWidgetArea area ) {
271 sSettingsDockArea->setValue( area, mSettingKeyDockId );
276 mDockGeometry = mDock->geometry();
277 mIsDockFloating = mDock->isFloating();
279 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
283 if ( mOptions.testFlag( Option::PermanentWidget ) )
284 mDock->installEventFilter(
this );
286 connect( mDock, &QgsDockWidget::visibilityChanged,
this, &QgsDockableWidgetHelper::visibilityChanged );
287 mDock->setUserVisible(
true );
288 emit visibilityChanged(
true );
295 if ( mOptions.testFlag( Option::PermanentWidget ) )
296 mDialog =
new QgsNonRejectableDialog(
nullptr, Qt::Window );
298 mDialog =
new QDialog(
nullptr, Qt::Window );
299 mDialog->setStyleSheet( sAppStylesheetFunction() );
301 mDialog->setWindowTitle( mWindowTitle );
302 mDialog->setObjectName( mObjectName );
304 if ( mOptions.testFlag( Option::PermanentWidget ) )
305 mDialog->installEventFilter(
this );
307 QVBoxLayout *vl =
new QVBoxLayout();
308 vl->setContentsMargins( 0, 0, 0, 0 );
309 vl->addWidget( mWidget );
311 if ( !mSettingKeyDockId.isEmpty() )
313 mDialog->restoreGeometry( sSettingsDialogGeometry->value( mSettingKeyDockId ).toByteArray() );
317 if ( !mDockGeometry.isEmpty() )
318 mDialog->setGeometry( mDockGeometry );
319 else if ( !mDialogGeometry.isEmpty() )
320 mDialog->setGeometry( mDialogGeometry );
322 mDialog->setLayout( vl );
326 connect( mDialog, &QDialog::finished,
this, [=]() {
327 mDialogGeometry = mDialog->geometry();
329 emit visibilityChanged(
false );
332 emit visibilityChanged(
true );
334 emit dockModeToggled( docked );
337void QgsDockableWidgetHelper::setUserVisible(
bool visible )
345 mDialog->setWindowState( mDialog->windowState() & ~Qt::WindowMinimized );
346 mDialog->activateWindow();
355 mDock->setUserVisible( visible );
359void QgsDockableWidgetHelper::setWindowTitle(
const QString &title )
361 mWindowTitle = title;
364 mDialog->setWindowTitle( title );
368 mDock->setWindowTitle( title );
372void QgsDockableWidgetHelper::setDockObjectName(
const QString &name )
377 mDialog->setObjectName( name );
381 mDock->setObjectName( name );
385QString QgsDockableWidgetHelper::dockObjectName()
const {
return mObjectName; }
387bool QgsDockableWidgetHelper::isUserVisible()
const
391 return mDialog->isVisible();
395 return mDock->isUserVisible();
400void QgsDockableWidgetHelper::setupDockWidget(
const QStringList &tabSiblings )
405 mDock->setFloating( mIsDockFloating );
407 if ( mDockGeometry.isEmpty() && mOwnerWindow )
409 const QFontMetrics fm( mOwnerWindow->font() );
410 const int initialDockSize = fm.horizontalAdvance(
'0' ) * 75;
411 mDockGeometry = QRect(
static_cast<int>( mOwnerWindow->rect().width() * 0.75 ),
static_cast<int>( mOwnerWindow->rect().height() * 0.5 ), initialDockSize, initialDockSize );
413 if ( !tabSiblings.isEmpty() )
415 sAddTabifiedDockWidgetFunction( mDockArea, mDock, tabSiblings,
false );
417 else if ( mOptions.testFlag( Option::RaiseTab ) )
419 sAddTabifiedDockWidgetFunction( mDockArea, mDock, mTabifyWith,
true );
421 else if ( mOwnerWindow )
423 mOwnerWindow->addDockWidget( mDockArea, mDock );
428 QMetaObject::invokeMethod( mDock, [
this] {
429 if (mIsDockFloating && sSettingsDockGeometry->exists( mSettingKeyDockId ) )
430 mDock->restoreGeometry( sSettingsDockGeometry->value( mSettingKeyDockId ).toByteArray() );
432 mDock->setGeometry( mDockGeometry ); }, Qt::QueuedConnection );
435QToolButton *QgsDockableWidgetHelper::createDockUndockToolButton()
437 QToolButton *toggleButton =
new QToolButton;
439 toggleButton->setCheckable(
true );
440 toggleButton->setChecked( mIsDocked );
441 toggleButton->setEnabled(
true );
443 connect( toggleButton, &QToolButton::toggled,
this, &QgsDockableWidgetHelper::toggleDockMode );
447QAction *QgsDockableWidgetHelper::createDockUndockAction(
const QString &title, QWidget *parent )
449 QAction *toggleAction =
new QAction( title, parent );
451 toggleAction->setCheckable(
true );
452 toggleAction->setChecked( mIsDocked );
453 toggleAction->setEnabled(
true );
455 connect( toggleAction, &QAction::toggled,
this, &QgsDockableWidgetHelper::toggleDockMode );
459bool QgsDockableWidgetHelper::eventFilter( QObject *watched, QEvent *event )
461 if ( watched == mDialog )
463 if ( event->type() == QEvent::Close )
467 emit visibilityChanged(
false );
471 else if ( watched == mDock )
473 if ( event->type() == QEvent::Close )
477 emit visibilityChanged(
false );
481 return QObject::eventFilter( watched, event );
488QgsNonRejectableDialog::QgsNonRejectableDialog( QWidget *parent, Qt::WindowFlags f )
489 : QDialog( parent, f )
493void QgsNonRejectableDialog::reject()
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A boolean settings entry.
A template class for enum and flag settings entry.
A variant settings entry.