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 mDockGeometry = mDock->geometry();
64 if ( !mSettingKeyDockId.isEmpty() )
65 sSettingsDockGeometry->setValue( mDock->saveGeometry(), mSettingKeyDockId );
66 mIsDockFloating = mDock->isFloating();
68 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
70 mDock->setWidget(
nullptr );
73 mOwnerWindow->removeDockWidget( mDock );
80 mDialogGeometry = mDialog->geometry();
82 if ( !mSettingKeyDockId.isEmpty() )
83 sSettingsDialogGeometry->setValue( mDialog->saveGeometry(), mSettingKeyDockId );
85 mDialog->layout()->removeWidget( mWidget );
86 mDialog->deleteLater();
91void QgsDockableWidgetHelper::writeXml( QDomElement &viewDom )
93 viewDom.setAttribute( QStringLiteral(
"isDocked" ), mIsDocked );
97 mDockGeometry = mDock->geometry();
98 mIsDockFloating = mDock->isFloating();
100 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
103 viewDom.setAttribute( QStringLiteral(
"x" ), mDockGeometry.x() );
104 viewDom.setAttribute( QStringLiteral(
"y" ), mDockGeometry.y() );
105 viewDom.setAttribute( QStringLiteral(
"width" ), mDockGeometry.width() );
106 viewDom.setAttribute( QStringLiteral(
"height" ), mDockGeometry.height() );
107 viewDom.setAttribute( QStringLiteral(
"floating" ), mIsDockFloating );
108 viewDom.setAttribute( QStringLiteral(
"area" ), mDockArea );
109 viewDom.setAttribute( QStringLiteral(
"uuid" ), mUuid );
113 const QList<QDockWidget *> tabSiblings = mOwnerWindow ? mOwnerWindow->tabifiedDockWidgets( mDock ) : QList<QDockWidget *>();
114 QDomElement tabSiblingsElement = viewDom.ownerDocument().createElement( QStringLiteral(
"tab_siblings" ) );
115 for ( QDockWidget *dock : tabSiblings )
117 QDomElement siblingElement = viewDom.ownerDocument().createElement( QStringLiteral(
"sibling" ) );
118 siblingElement.setAttribute( QStringLiteral(
"uuid" ), dock->property(
"dock_uuid" ).toString() );
119 siblingElement.setAttribute( QStringLiteral(
"object_name" ), dock->objectName() );
120 tabSiblingsElement.appendChild( siblingElement );
122 viewDom.appendChild( tabSiblingsElement );
126 mDialogGeometry = mDialog->geometry();
128 viewDom.setAttribute( QStringLiteral(
"d_x" ), mDialogGeometry.x() );
129 viewDom.setAttribute( QStringLiteral(
"d_y" ), mDialogGeometry.y() );
130 viewDom.setAttribute( QStringLiteral(
"d_width" ), mDialogGeometry.width() );
131 viewDom.setAttribute( QStringLiteral(
"d_height" ), mDialogGeometry.height() );
134void QgsDockableWidgetHelper::readXml(
const QDomElement &viewDom )
136 mUuid = viewDom.attribute( QStringLiteral(
"uuid" ), mUuid );
139 int x = viewDom.attribute( QStringLiteral(
"d_x" ), QStringLiteral(
"0" ) ).toInt();
140 int y = viewDom.attribute( QStringLiteral(
"d_x" ), QStringLiteral(
"0" ) ).toInt();
141 int w = viewDom.attribute( QStringLiteral(
"d_width" ), QStringLiteral(
"200" ) ).toInt();
142 int h = viewDom.attribute( QStringLiteral(
"d_height" ), QStringLiteral(
"200" ) ).toInt();
143 mDialogGeometry = QRect( x, y, w, h );
145 mDialog->setGeometry( mDialogGeometry );
149 int x = viewDom.attribute( QStringLiteral(
"x" ), QStringLiteral(
"0" ) ).toInt();
150 int y = viewDom.attribute( QStringLiteral(
"y" ), QStringLiteral(
"0" ) ).toInt();
151 int w = viewDom.attribute( QStringLiteral(
"width" ), QStringLiteral(
"200" ) ).toInt();
152 int h = viewDom.attribute( QStringLiteral(
"height" ), QStringLiteral(
"200" ) ).toInt();
153 mDockGeometry = QRect( x, y, w, h );
154 mIsDockFloating = viewDom.attribute( QStringLiteral(
"floating" ), QStringLiteral(
"0" ) ).toInt();
155 mDockArea =
static_cast<Qt::DockWidgetArea
>( viewDom.attribute( QStringLiteral(
"area" ), QString::number( Qt::RightDockWidgetArea ) ).toInt() );
157 if ( mDockArea == Qt::DockWidgetArea::NoDockWidgetArea && !mIsDockFloating )
159 mDockArea = Qt::RightDockWidgetArea;
162 QStringList tabSiblings;
163 const QDomElement tabSiblingsElement = viewDom.firstChildElement( QStringLiteral(
"tab_siblings" ) );
164 const QDomNodeList tabSiblingNodes = tabSiblingsElement.childNodes();
165 for (
int i = 0; i < tabSiblingNodes.size(); ++i )
167 const QDomElement tabSiblingElement = tabSiblingNodes.at( i ).toElement();
169 QString tabId = tabSiblingElement.attribute( QStringLiteral(
"uuid" ) );
170 if ( tabId.isEmpty() )
171 tabId = tabSiblingElement.attribute( QStringLiteral(
"object_name" ) );
172 if ( !tabId.isEmpty() )
173 tabSiblings.append( tabId );
176 setupDockWidget( tabSiblings );
181 mDock->setProperty(
"dock_uuid", mUuid );
185void QgsDockableWidgetHelper::setWidget( QWidget *widget )
188 if ( mWidget && mOwnerWindow )
190 mWidget->setParent( mOwnerWindow );
194 mDialog->layout()->removeWidget( mWidget );
198 mDock->setWidget(
nullptr );
202 toggleDockMode( mIsDocked );
210QDialog *QgsDockableWidgetHelper::dialog()
212 return mDialog.data();
215void QgsDockableWidgetHelper::toggleDockMode(
bool docked )
218 if ( mWidget && mOwnerWindow )
220 mWidget->setParent( mOwnerWindow );
226 mDockGeometry = mDock->geometry();
227 mIsDockFloating = mDock->isFloating();
229 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
231 mDock->setWidget(
nullptr );
233 mOwnerWindow->removeDockWidget( mDock );
241 if ( !mSettingKeyDockId.isEmpty() )
242 sSettingsDialogGeometry->setValue( mDialog->saveGeometry(), mSettingKeyDockId );
244 mDialogGeometry = mDialog->geometry();
247 mDialog->layout()->removeWidget( mWidget );
254 if ( !mSettingKeyDockId.isEmpty() )
255 sSettingsIsDocked->setValue( mIsDocked, mSettingKeyDockId );
265 mDock->setWindowTitle( mWindowTitle );
266 mDock->setWidget( mWidget );
267 mDock->setObjectName( mObjectName );
268 mDock->setProperty(
"dock_uuid", mUuid );
271 if ( !mSettingKeyDockId.isEmpty() )
273 connect( mDock, &QgsDockWidget::dockLocationChanged,
this, [=]( Qt::DockWidgetArea area ) {
274 sSettingsDockArea->setValue( area, mSettingKeyDockId );
279 mDockGeometry = mDock->geometry();
280 mIsDockFloating = mDock->isFloating();
282 mDockArea = mOwnerWindow->dockWidgetArea( mDock );
286 if ( mOptions.testFlag( Option::PermanentWidget ) )
287 mDock->installEventFilter(
this );
289 connect( mDock, &QgsDockWidget::visibilityChanged,
this, &QgsDockableWidgetHelper::visibilityChanged );
290 mDock->setUserVisible(
true );
291 emit visibilityChanged(
true );
298 if ( mOptions.testFlag( Option::PermanentWidget ) )
299 mDialog =
new QgsNonRejectableDialog(
nullptr, Qt::Window );
301 mDialog =
new QDialog(
nullptr, Qt::Window );
302 mDialog->setStyleSheet( sAppStylesheetFunction() );
304 mDialog->setWindowTitle( mWindowTitle );
305 mDialog->setObjectName( mObjectName );
307 if ( mOptions.testFlag( Option::PermanentWidget ) )
308 mDialog->installEventFilter(
this );
310 QVBoxLayout *vl =
new QVBoxLayout();
311 vl->setContentsMargins( 0, 0, 0, 0 );
312 vl->addWidget( mWidget );
314 if ( !mSettingKeyDockId.isEmpty() )
316 mDialog->restoreGeometry( sSettingsDialogGeometry->value( mSettingKeyDockId ).toByteArray() );
320 if ( !mDockGeometry.isEmpty() )
321 mDialog->setGeometry( mDockGeometry );
322 else if ( !mDialogGeometry.isEmpty() )
323 mDialog->setGeometry( mDialogGeometry );
325 mDialog->setLayout( vl );
329 connect( mDialog, &QDialog::finished,
this, [=]() {
330 mDialogGeometry = mDialog->geometry();
332 emit visibilityChanged(
false );
335 emit visibilityChanged(
true );
337 emit dockModeToggled( docked );
340void QgsDockableWidgetHelper::setUserVisible(
bool visible )
348 mDialog->setWindowState( mDialog->windowState() & ~Qt::WindowMinimized );
349 mDialog->activateWindow();
358 mDock->setUserVisible( visible );
362void QgsDockableWidgetHelper::setWindowTitle(
const QString &title )
364 mWindowTitle = title;
367 mDialog->setWindowTitle( title );
371 mDock->setWindowTitle( title );
375void QgsDockableWidgetHelper::setDockObjectName(
const QString &name )
380 mDialog->setObjectName( name );
384 mDock->setObjectName( name );
388QString QgsDockableWidgetHelper::dockObjectName()
const {
return mObjectName; }
390bool QgsDockableWidgetHelper::isUserVisible()
const
394 return mDialog->isVisible();
398 return mDock->isUserVisible();
403void QgsDockableWidgetHelper::setupDockWidget(
const QStringList &tabSiblings )
408 mDock->setFloating( mIsDockFloating );
410 if ( mDockGeometry.isEmpty() && mOwnerWindow )
412 const QFontMetrics fm( mOwnerWindow->font() );
413 const int initialDockSize = fm.horizontalAdvance(
'0' ) * 75;
414 mDockGeometry = QRect(
static_cast<int>( mOwnerWindow->rect().width() * 0.75 ),
static_cast<int>( mOwnerWindow->rect().height() * 0.5 ), initialDockSize, initialDockSize );
416 if ( !tabSiblings.isEmpty() )
418 sAddTabifiedDockWidgetFunction( mDockArea, mDock, tabSiblings,
false );
420 else if ( mOptions.testFlag( Option::RaiseTab ) )
422 sAddTabifiedDockWidgetFunction( mDockArea, mDock, mTabifyWith,
true );
424 else if ( mOwnerWindow )
426 mOwnerWindow->addDockWidget( mDockArea, mDock );
431 QMetaObject::invokeMethod( mDock, [
this] {
432 if (mIsDockFloating && sSettingsDockGeometry->exists( mSettingKeyDockId ) )
433 mDock->restoreGeometry( sSettingsDockGeometry->value( mSettingKeyDockId ).toByteArray() );
435 mDock->setGeometry( mDockGeometry ); }, Qt::QueuedConnection );
438QToolButton *QgsDockableWidgetHelper::createDockUndockToolButton()
440 QToolButton *toggleButton =
new QToolButton;
442 toggleButton->setCheckable(
true );
443 toggleButton->setChecked( mIsDocked );
444 toggleButton->setEnabled(
true );
446 connect( toggleButton, &QToolButton::toggled,
this, &QgsDockableWidgetHelper::toggleDockMode );
450QAction *QgsDockableWidgetHelper::createDockUndockAction(
const QString &title, QWidget *parent )
452 QAction *toggleAction =
new QAction( title, parent );
454 toggleAction->setCheckable(
true );
455 toggleAction->setChecked( mIsDocked );
456 toggleAction->setEnabled(
true );
458 connect( toggleAction, &QAction::toggled,
this, &QgsDockableWidgetHelper::toggleDockMode );
462bool QgsDockableWidgetHelper::eventFilter( QObject *watched, QEvent *event )
464 if ( watched == mDialog )
466 if ( event->type() == QEvent::Close )
470 emit visibilityChanged(
false );
474 else if ( watched == mDock )
476 if ( event->type() == QEvent::Close )
480 emit visibilityChanged(
false );
484 return QObject::eventFilter( watched, event );
491QgsNonRejectableDialog::QgsNonRejectableDialog( QWidget *parent, Qt::WindowFlags f )
492 : QDialog( parent, f )
496void 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.