KXmlGui

kmainwindow.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 2000 Reginald Stadlbauer <[email protected]>
4  SPDX-FileCopyrightText: 1997 Stephan Kulow <[email protected]>
5  SPDX-FileCopyrightText: 1997-2000 Sven Radej <[email protected]>
6  SPDX-FileCopyrightText: 1997-2000 Matthias Ettrich <[email protected]>
7  SPDX-FileCopyrightText: 1999 Chris Schlaeger <[email protected]>
8  SPDX-FileCopyrightText: 2002 Joseph Wenninger <[email protected]>
9  SPDX-FileCopyrightText: 2005-2006 Hamish Rodda <[email protected]>
10  SPDX-FileCopyrightText: 2000-2008 David Faure <[email protected]>
11 
12  SPDX-License-Identifier: LGPL-2.0-only
13 */
14 
15 #include "kmainwindow.h"
16 
17 #include "kmainwindow_p.h"
18 #ifdef QT_DBUS_LIB
19 #include "kmainwindowiface_p.h"
20 #endif
21 #include "khelpmenu.h"
22 #include "ktoolbar.h"
23 #include "ktoolbarhandler_p.h"
24 #include "ktooltiphelper.h"
25 
26 #include <QApplication>
27 #include <QCloseEvent>
28 #include <QDockWidget>
29 #include <QFile>
30 #include <QList>
31 #include <QMenuBar>
32 #include <QObject>
33 #ifndef QT_NO_SESSIONMANAGER
34 #include <QSessionManager>
35 #endif
36 #include <QStatusBar>
37 #include <QStyle>
38 #include <QTimer>
39 #include <QWidget>
40 #include <QWindow>
41 #ifdef QT_DBUS_LIB
42 #include <QDBusConnection>
43 #endif
44 
45 #include <KAboutData>
46 #include <KConfig>
47 #include <KConfigGroup>
48 #include <KConfigGui>
49 #include <KLocalizedString>
50 #include <KSharedConfig>
51 #include <KWindowConfig>
52 
53 //#include <cctype>
54 
55 static const char WINDOW_PROPERTIES[] = "WindowProperties";
56 
57 static QMenuBar *internalMenuBar(KMainWindow *mw)
58 {
60 }
61 
62 static QStatusBar *internalStatusBar(KMainWindow *mw)
63 {
65 }
66 
67 /**
68 
69  * Listens to resize events from QDockWidgets. The KMainWindow
70  * settings are set as dirty, as soon as at least one resize
71  * event occurred. The listener is attached to the dock widgets
72  * by dock->installEventFilter(dockResizeListener) inside
73  * KMainWindow::event().
74  */
75 class DockResizeListener : public QObject
76 {
77  Q_OBJECT
78 public:
79  DockResizeListener(KMainWindow *win);
80  ~DockResizeListener() override;
81  bool eventFilter(QObject *watched, QEvent *event) override;
82 
83 private:
84  KMainWindow *const m_win;
85 };
86 
87 DockResizeListener::DockResizeListener(KMainWindow *win)
88  : QObject(win)
89  , m_win(win)
90 {
91 }
92 
93 DockResizeListener::~DockResizeListener()
94 {
95 }
96 
97 bool DockResizeListener::eventFilter(QObject *watched, QEvent *event)
98 {
99  switch (event->type()) {
100  case QEvent::Resize:
101  case QEvent::Move:
102  case QEvent::Show:
103  case QEvent::Hide:
104  m_win->k_ptr->setSettingsDirty(KMainWindowPrivate::CompressCalls);
105  break;
106 
107  default:
108  break;
109  }
110 
111  return QObject::eventFilter(watched, event);
112 }
113 
114 KMWSessionManager::KMWSessionManager()
115 {
116 #ifndef QT_NO_SESSIONMANAGER
117  connect(qApp, &QGuiApplication::saveStateRequest, this, &KMWSessionManager::saveState);
118  connect(qApp, &QGuiApplication::commitDataRequest, this, &KMWSessionManager::commitData);
119 #endif
120 }
121 
122 KMWSessionManager::~KMWSessionManager()
123 {
124 }
125 
126 void KMWSessionManager::saveState(QSessionManager &sm)
127 {
128 #ifndef QT_NO_SESSIONMANAGER
130 
132  const auto windows = KMainWindow::memberList();
133  if (!windows.isEmpty()) {
134  // According to Jochen Wilhelmy <[email protected]>, this
135  // hook is useful for better document orientation
136  windows.at(0)->saveGlobalProperties(config);
137  }
138 
139  int n = 0;
140  for (KMainWindow *mw : windows) {
141  n++;
142  mw->savePropertiesInternal(config, n);
143  }
144 
145  KConfigGroup group(config, "Number");
146  group.writeEntry("NumberOfWindows", n);
147 
148  // store new status to disk
149  config->sync();
150 
151  // generate discard command for new file
153  if (QFile::exists(localFilePath)) {
155  discard << QStringLiteral("rm");
156  discard << localFilePath;
157  sm.setDiscardCommand(discard);
158  }
159 #else
160  Q_UNUSED(sm)
161 #endif // QT_NO_SESSIONMANAGER
162 }
163 
164 void KMWSessionManager::commitData(QSessionManager &sm)
165 {
166 #ifndef QT_NO_SESSIONMANAGER
167  if (!sm.allowsInteraction()) {
168  return;
169  }
170 
171  /*
172  Purpose of this exercise: invoke queryClose() without actually closing the
173  windows, because
174  - queryClose() may contain session management code, so it must be invoked
175  - actually closing windows may quit the application - cf.
176  QGuiApplication::quitOnLastWindowClosed()
177  - quitting the application and thus closing the session manager connection
178  violates the X11 XSMP protocol.
179  The exact requirement of XSMP that would be broken is,
180  in the description of the client's state machine:
181 
182  save-yourself-done: (changing state is forbidden)
183 
184  Closing the session manager connection causes a state change.
185  Worst of all, that is a real problem with ksmserver - it will not save
186  applications that quit on their own in state save-yourself-done.
187  */
188  const auto windows = KMainWindow::memberList();
189  for (KMainWindow *window : windows) {
191  continue;
192  }
193  QCloseEvent e;
194  QApplication::sendEvent(window, &e);
195  if (!e.isAccepted()) {
196  sm.cancel();
197  return;
198  }
199  }
200 #else
201  Q_UNUSED(sm)
202 #endif // QT_NO_SESSIONMANAGER
203 }
204 
205 Q_GLOBAL_STATIC(KMWSessionManager, ksm)
207 
208 KMainWindow::KMainWindow(QWidget *parent, Qt::WindowFlags f)
209  : QMainWindow(parent, f)
210  , k_ptr(new KMainWindowPrivate)
211 {
212  Q_D(KMainWindow);
213 
214  d->init(this);
215 }
216 
217 KMainWindow::KMainWindow(KMainWindowPrivate &dd, QWidget *parent, Qt::WindowFlags f)
218  : QMainWindow(parent, f)
219  , k_ptr(&dd)
220 {
221  Q_D(KMainWindow);
222 
223  d->init(this);
224 }
225 
226 void KMainWindowPrivate::init(KMainWindow *_q)
227 {
228  q = _q;
229 
230  // Not needed in Qt6 (and doesn't exist at all)
231 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
232 #ifndef QT_NO_SESSIONMANAGER
234 #endif
235 #endif
236 
237  q->setAnimated(q->style()->styleHint(QStyle::SH_Widget_Animate, nullptr, q));
238 
239  q->setAttribute(Qt::WA_DeleteOnClose);
240 
241  helpMenu = nullptr;
242 
243  // actionCollection()->setWidget( this );
244 #if 0
245  QObject::connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)),
246  q, SLOT(_k_slotSettingsChanged(int)));
247 #endif
248 
249 #ifndef QT_NO_SESSIONMANAGER
250  // force KMWSessionManager creation
251  ksm();
252 #endif
253 
254  sMemberList()->append(q);
255 
256  // Set the icon theme fallback to breeze (if not already set)
257  // Most of our apps use "lots" of icons that most of the times
258  // are only available with breeze, we still honour the user icon
259  // theme but if the icon is not found there, we go to breeze
260  // since it's almost sure it'll be there.
261  // This should be done as soon as possible (preferably via
262  // Q_COREAPP_STARTUP_FUNCTION), but as for now it cannot be done too soon
263  // as at that point QPlatformTheme is not instantiated yet and breaks the
264  // internal status of QIconLoader (see QTBUG-74252).
265  // See also discussion at https://phabricator.kde.org/D22488
266  // TODO: remove this once we depend on Qt 5.15.1, where this is fixed
267  if (QIcon::fallbackThemeName().isEmpty()) {
268  QIcon::setFallbackThemeName(QStringLiteral("breeze"));
269  }
270 
271  // If application is translated, load translator information for use in
272  // KAboutApplicationDialog or other getters. The context and messages below
273  // both must be exactly as listed, and are forced to be loaded from the
274  // application's own message catalog instead of kxmlgui's.
276  if (aboutData.translators().isEmpty()) {
277  aboutData.setTranslator(i18ndc(nullptr, "NAME OF TRANSLATORS", "Your names"), //
278  i18ndc(nullptr, "EMAIL OF TRANSLATORS", "Your emails"));
279 
281  }
282 
283  settingsDirty = false;
284  autoSaveSettings = false;
285  autoSaveWindowSize = true; // for compatibility
286  // d->kaccel = actionCollection()->kaccel();
287  settingsTimer = nullptr;
288  sizeTimer = nullptr;
289 
290  dockResizeListener = new DockResizeListener(_q);
291  letDirtySettings = true;
292 
293  sizeApplied = false;
294  suppressCloseEvent = false;
295 
296  qApp->installEventFilter(KToolTipHelper::instance());
297 }
298 
299 static bool endsWithHashNumber(const QString &s)
300 {
301  for (int i = s.length() - 1; i > 0; --i) {
302  if (s[i] == QLatin1Char('#') && i != s.length() - 1) {
303  return true; // ok
304  }
305  if (!s[i].isDigit()) {
306  break;
307  }
308  }
309  return false;
310 }
311 
312 static inline bool isValidDBusObjectPathCharacter(const QChar &c)
313 {
314  ushort u = c.unicode();
315  /* clang-format off */
316  return (u >= QLatin1Char('a') && u <= QLatin1Char('z'))
317  || (u >= QLatin1Char('A') && u <= QLatin1Char('Z'))
318  || (u >= QLatin1Char('0') && u <= QLatin1Char('9'))
319  || (u == QLatin1Char('_')) || (u == QLatin1Char('/'));
320  /* clang-format off */
321 }
322 
323 void KMainWindowPrivate::polish(KMainWindow *q)
324 {
325  // Set a unique object name. Required by session management, window management, and for the dbus interface.
326  QString objname;
327  QString s;
328  int unusedNumber = 1;
329  const QString name = q->objectName();
330  bool startNumberingImmediately = true;
331  bool tryReuse = false;
332  if (name.isEmpty()) {
333  // no name given
334  objname = QStringLiteral("MainWindow#");
335  } else if (name.endsWith(QLatin1Char('#'))) {
336  // trailing # - always add a number - KWin uses this for better grouping
337  objname = name;
338  } else if (endsWithHashNumber(name)) {
339  // trailing # with a number - like above, try to use the given number first
340  objname = name;
341  tryReuse = true;
342  startNumberingImmediately = false;
343  } else {
344  objname = name;
345  startNumberingImmediately = false;
346  }
347 
348  s = objname;
349  if (startNumberingImmediately) {
350  s += QLatin1Char('1');
351  }
352 
353  for (;;) {
354  const QList<QWidget *> list = qApp->topLevelWidgets();
355  bool found = false;
356  for (QWidget *w : list) {
357  if (w != q && w->objectName() == s) {
358  found = true;
359  break;
360  }
361  }
362  if (!found) {
363  break;
364  }
365  if (tryReuse) {
366  objname = name.left(name.length() - 1); // lose the hash
367  unusedNumber = 0; // start from 1 below
368  tryReuse = false;
369  }
370  s.setNum(++unusedNumber);
371  s = objname + s;
372  }
373  q->setObjectName(s);
374  if (!q->window() || q->window() == q) {
375  q->winId(); // workaround for setWindowRole() crashing, and set also window role, just in case TT
376  q->setWindowRole(s); // will keep insisting that object name suddenly should not be used for window role
377  }
378 
379  dbusName = QLatin1Char('/') + QCoreApplication::applicationName() + QLatin1Char('/');
380  dbusName += q->objectName().replace(QLatin1Char('/'), QLatin1Char('_'));
381  // Clean up for dbus usage: any non-alphanumeric char should be turned into '_'
382  for (QChar &c : dbusName) {
383  if (!isValidDBusObjectPathCharacter(c)) {
384  c = QLatin1Char('_');
385  }
386  }
387 
388 #ifdef QT_DBUS_LIB
389  /* clang-format off */
390  constexpr auto opts = QDBusConnection::ExportScriptableSlots
395  /* clang-format on */
396  QDBusConnection::sessionBus().registerObject(dbusName, q, opts);
397 #endif
398 }
399 
400 void KMainWindowPrivate::setSettingsDirty(CallCompression callCompression)
401 {
402  if (!letDirtySettings) {
403  return;
404  }
405 
406  settingsDirty = true;
407  if (autoSaveSettings) {
408  if (callCompression == CompressCalls) {
409  if (!settingsTimer) {
410  settingsTimer = new QTimer(q);
411  settingsTimer->setInterval(500);
412  settingsTimer->setSingleShot(true);
414  }
415  settingsTimer->start();
416  } else {
418  }
419  }
420 }
421 
422 void KMainWindowPrivate::setSizeDirty()
423 {
424  if (autoSaveWindowSize) {
425  if (!sizeTimer) {
426  sizeTimer = new QTimer(q);
427  sizeTimer->setInterval(500);
428  sizeTimer->setSingleShot(true);
429  QObject::connect(sizeTimer, &QTimer::timeout, q, [this]() {
430  _k_slotSaveAutoSaveSize();
431  });
432  }
433  sizeTimer->start();
434  }
435 }
436 
438 {
439  sMemberList()->removeAll(this);
440  delete static_cast<QObject *>(k_ptr->dockResizeListener); // so we don't get anymore events after k_ptr is destroyed
441 }
442 
443 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
444 QMenu *KMainWindow::helpMenu(const QString &aboutAppText, bool showWhatsThis)
445 {
446  Q_D(KMainWindow);
447  if (!d->helpMenu) {
448  if (aboutAppText.isEmpty()) {
449  d->helpMenu = new KHelpMenu(this, KAboutData::applicationData(), showWhatsThis);
450  } else {
451  d->helpMenu = new KHelpMenu(this, aboutAppText, showWhatsThis);
452  }
453 
454  if (!d->helpMenu) {
455  return nullptr;
456  }
457  }
458 
459  return d->helpMenu->menu();
460 }
461 
462 QMenu *KMainWindow::customHelpMenu(bool showWhatsThis)
463 {
464  Q_D(KMainWindow);
465  if (!d->helpMenu) {
466  d->helpMenu = new KHelpMenu(this, QString(), showWhatsThis);
468  }
469 
470  return d->helpMenu->menu();
471 }
472 #endif
473 
475 {
477  if (!config) {
478  return false;
479  }
480 
481  KConfigGroup group(config, "Number");
482  // TODO KF6: we should use 0 as the default value, not 1
483  // See also https://bugs.kde.org/show_bug.cgi?id=427552
484  const int n = group.readEntry("NumberOfWindows", 1);
485  return number >= 1 && number <= n;
486 }
487 
489 {
491  if (!config) {
492  return QString();
493  }
494 
495  KConfigGroup group(config, QByteArray(WINDOW_PROPERTIES).append(QByteArray::number(number)).constData());
496  if (!group.hasKey("ClassName")) {
497  return QString();
498  } else {
499  return group.readEntry("ClassName");
500  }
501 }
502 
503 bool KMainWindow::restore(int number, bool show)
504 {
505  if (!canBeRestored(number)) {
506  return false;
507  }
509  if (readPropertiesInternal(config, number)) {
510  if (show) {
512  }
513  return false;
514  }
515  return false;
516 }
517 
518 void KMainWindow::setCaption(const QString &caption)
519 {
520  setPlainCaption(caption);
521 }
522 
523 void KMainWindow::setCaption(const QString &caption, bool modified)
524 {
525  QString title = caption;
526  if (!title.contains(QLatin1String("[*]")) && !title.isEmpty()) { // append the placeholder so that the modified mechanism works
527  title.append(QLatin1String(" [*]"));
528  }
529  setPlainCaption(title);
530  setWindowModified(modified);
531 }
532 
534 {
535  setWindowTitle(caption);
536 }
537 
539 {
540  Q_D(KMainWindow);
541  if (!d->helpMenu) {
542  d->helpMenu = new KHelpMenu(this);
543  if (!d->helpMenu) {
544  return;
545  }
546  }
547  d->helpMenu->appHelpActivated();
548 }
549 
551 {
552  Q_D(KMainWindow);
553  if (d->suppressCloseEvent) {
554  e->accept();
555  return;
556  }
557 
558  // Save settings if auto-save is enabled, and settings have changed
559  if (d->settingsTimer && d->settingsTimer->isActive()) {
560  d->settingsTimer->stop();
562  }
563  if (d->sizeTimer && d->sizeTimer->isActive()) {
564  d->sizeTimer->stop();
565  d->_k_slotSaveAutoSaveSize();
566  }
567  // Delete the marker that says we don't want to restore the position of the
568  // next-opened instance; now that a window is closing, we do want to do this
569  if (d->autoSaveGroup.isValid()) {
570  d->getValidStateConfig(d->autoSaveGroup).deleteEntry("RestorePositionForNextInstance");
571  }
572  d->_k_slotSaveAutoSavePosition();
573 
574  if (queryClose()) {
575  // widgets will start destroying themselves at this point and we don't
576  // want to save state anymore after this as it might be incorrect
577  d->autoSaveSettings = false;
578  d->letDirtySettings = false;
579  e->accept();
580  } else {
581  e->ignore(); // if the window should not be closed, don't close it
582  }
583 
584 #ifndef QT_NO_SESSIONMANAGER
585  // If saving session, we are processing a fake close event, and might get the real one later.
586  if (e->isAccepted() && qApp->isSavingSession()) {
587  d->suppressCloseEvent = true;
588  }
589 #endif
590 }
591 
593 {
594  return true;
595 }
596 
598 {
599 }
600 
602 {
603 }
604 
605 void KMainWindow::savePropertiesInternal(KConfig *config, int number)
606 {
607  Q_D(KMainWindow);
608  const bool oldASWS = d->autoSaveWindowSize;
609  d->autoSaveWindowSize = true; // make saveMainWindowSettings save the window size
610 
611  KConfigGroup cg(config, QByteArray(WINDOW_PROPERTIES).append(QByteArray::number(number)).constData());
612 
613  // store objectName, className, Width and Height for later restoring
614  // (Only useful for session management)
615  cg.writeEntry("ObjectName", objectName());
616  cg.writeEntry("ClassName", metaObject()->className());
617 
618  saveMainWindowSettings(cg); // Menubar, statusbar and Toolbar settings.
619 
620  cg = KConfigGroup(config, QByteArray::number(number).constData());
621  saveProperties(cg);
622 
623  d->autoSaveWindowSize = oldASWS;
624 }
625 
627 {
628  Q_D(KMainWindow);
629  // qDebug(200) << "KMainWindow::saveMainWindowSettings " << cg.name();
630 
631  KConfigGroup stateConfig = d->getValidStateConfig(cg);
632  // Called by session management - or if we want to save the window size anyway
633  if (d->autoSaveWindowSize) {
636  }
637 
638  // One day will need to save the version number, but for now, assume 0
639  // Utilise the QMainWindow::saveState() functionality.
640  const QByteArray state = saveState();
641  stateConfig.writeEntry("State", state.toBase64());
642 
643  QStatusBar *sb = internalStatusBar(this);
644  if (sb) {
645  if (!cg.hasDefault("StatusBar") && !sb->isHidden()) {
646  cg.revertToDefault("StatusBar");
647  } else {
648  cg.writeEntry("StatusBar", sb->isHidden() ? "Disabled" : "Enabled");
649  }
650  }
651 
652  QMenuBar *mb = internalMenuBar(this);
653  if (mb) {
654  if (!cg.hasDefault("MenuBar") && !mb->isHidden()) {
655  cg.revertToDefault("MenuBar");
656  } else {
657  cg.writeEntry("MenuBar", mb->isHidden() ? "Disabled" : "Enabled");
658  }
659  }
660 
661  if (!autoSaveSettings() || cg.name() == autoSaveGroup()) {
662  // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
663  if (!cg.hasDefault("ToolBarsMovable") && !KToolBar::toolBarsLocked()) {
664  cg.revertToDefault("ToolBarsMovable");
665  } else {
666  cg.writeEntry("ToolBarsMovable", KToolBar::toolBarsLocked() ? "Disabled" : "Enabled");
667  }
668  }
669 
670  int n = 1; // Toolbar counter. toolbars are counted from 1,
671  const auto toolBars = this->toolBars();
672  for (KToolBar *toolbar : toolBars) {
673  QByteArray groupName("Toolbar");
674  // Give a number to the toolbar, but prefer a name if there is one,
675  // because there's no real guarantee on the ordering of toolbars
676  groupName += (toolbar->objectName().isEmpty() ? QByteArray::number(n) : QByteArray(" ").append(toolbar->objectName().toUtf8()));
677 
678  KConfigGroup toolbarGroup(&cg, groupName.constData());
679  toolbar->saveSettings(toolbarGroup);
680  n++;
681  }
682 }
683 
684 bool KMainWindow::readPropertiesInternal(KConfig *config, int number)
685 {
686  Q_D(KMainWindow);
687 
688  const bool oldLetDirtySettings = d->letDirtySettings;
689  d->letDirtySettings = false;
690 
691  if (number == 1) {
692  readGlobalProperties(config);
693  }
694 
695  // in order they are in toolbar list
696  KConfigGroup cg(config, QByteArray(WINDOW_PROPERTIES).append(QByteArray::number(number)).constData());
697 
698  // restore the object name (window role)
699  if (cg.hasKey("ObjectName")) {
700  setObjectName(cg.readEntry("ObjectName"));
701  }
702 
703  d->sizeApplied = false; // since we are changing config file, reload the size of the window
704  // if necessary. Do it before the call to applyMainWindowSettings.
705  applyMainWindowSettings(cg); // Menubar, statusbar and toolbar settings.
706 
707  KConfigGroup grp(config, QByteArray::number(number).constData());
708  readProperties(grp);
709 
710  d->letDirtySettings = oldLetDirtySettings;
711 
712  return true;
713 }
714 
716 {
717  Q_D(KMainWindow);
718  // qDebug(200) << "KMainWindow::applyMainWindowSettings " << cg.name();
719 
720  KConfigGroup cg = _cg;
721  d->migrateStateDataIfNeeded(cg);
722 
723  QWidget *focusedWidget = QApplication::focusWidget();
724 
725  const bool oldLetDirtySettings = d->letDirtySettings;
726  d->letDirtySettings = false;
727 
728  KConfigGroup stateConfig = d->getValidStateConfig(cg);
729 
730  if (!d->sizeApplied && (!window() || window() == this)) {
731  winId(); // ensure there's a window created
732  // Set the window's size from the existing widget geometry to respect the
733  // implicit size when there is no saved geometry in the config file for
734  // KWindowConfig::restoreWindowSize() to restore
735  // TODO: remove once QTBUG-40584 is fixed; see below
739  // NOTICE: QWindow::setGeometry() does NOT impact the backing QWidget geometry even if the platform
740  // window was created -> QTBUG-40584. We therefore copy the size here.
741  // TODO: remove once this was resolved in QWidget QPA
742  resize(windowHandle()->size());
743  d->sizeApplied = true;
744 
745  // Let the user opt out of KDE apps remembering window sizes if they
746  // find it annoying or it doesn't work for them due to other bugs.
747  KSharedConfigPtr config = KSharedConfig::openConfig();
748  KConfigGroup group(config, "General");
749  if (group.readEntry("AllowKDEAppsToRememberWindowPositions", true)) {
750  if (stateConfig.readEntry("RestorePositionForNextInstance", true)) {
752  // Save the fact that we now don't want to restore position
753  // anymore; if we did, the next instance would completely cover
754  // the existing one
755  stateConfig.writeEntry("RestorePositionForNextInstance", false);
756  }
757  }
758  }
759 
760  QStatusBar *sb = internalStatusBar(this);
761  if (sb) {
762  QString entry = cg.readEntry("StatusBar", "Enabled");
763  sb->setVisible(entry != QLatin1String("Disabled"));
764  }
765 
766  QMenuBar *mb = internalMenuBar(this);
767  if (mb) {
768  QString entry = cg.readEntry("MenuBar", "Enabled");
769  mb->setVisible(entry != QLatin1String("Disabled"));
770  }
771 
772  if (!autoSaveSettings() || cg.name() == autoSaveGroup()) { // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
773  QString entry = cg.readEntry("ToolBarsMovable", "Disabled");
774  KToolBar::setToolBarsLocked(entry == QLatin1String("Disabled"));
775  }
776 
777  int n = 1; // Toolbar counter. toolbars are counted from 1,
778  const auto toolBars = this->toolBars();
779  for (KToolBar *toolbar : toolBars) {
780  QByteArray groupName("Toolbar");
781  // Give a number to the toolbar, but prefer a name if there is one,
782  // because there's no real guarantee on the ordering of toolbars
783  groupName += (toolbar->objectName().isEmpty() ? QByteArray::number(n) : QByteArray(" ").append(toolbar->objectName().toUtf8()));
784 
785  KConfigGroup toolbarGroup(&cg, groupName.constData());
786  toolbar->applySettings(toolbarGroup);
787  n++;
788  }
789 
790  if (stateConfig.hasKey("State")) {
791  QByteArray state;
792  state = stateConfig.readEntry("State", state);
793  state = QByteArray::fromBase64(state);
794  // One day will need to load the version number, but for now, assume 0
795  restoreState(state);
796  }
797 
798  if (focusedWidget) {
799  focusedWidget->setFocus();
800  }
801 
802  d->settingsDirty = false;
803  d->letDirtySettings = oldLetDirtySettings;
804 }
805 
806 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
808 {
810 }
811 #endif
812 
813 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
815 {
817 }
818 #endif
819 
821 {
822  Q_D(KMainWindow);
823  d->setSettingsDirty();
824 }
825 
827 {
828  Q_D(const KMainWindow);
829  return d->settingsDirty;
830 }
831 
832 void KMainWindow::setAutoSaveSettings(const QString &groupName, bool saveWindowSize)
833 {
835 }
836 
837 void KMainWindow::setAutoSaveSettings(const KConfigGroup &group, bool saveWindowSize)
838 {
839  // We re making a little assumption that if you want to save the window
840  // size, you probably also want to save the window position too
841  // This avoids having to re-implement a new version of
842  // KMainWindow::setAutoSaveSettings that handles these cases independently
843  Q_D(KMainWindow);
844  d->autoSaveSettings = true;
845  d->autoSaveGroup = group;
846  d->autoSaveWindowSize = saveWindowSize;
847 
848  if (!saveWindowSize && d->sizeTimer) {
849  d->sizeTimer->stop();
850  }
851 
852  // Now read the previously saved settings
853  applyMainWindowSettings(d->autoSaveGroup);
854 }
855 
857 {
858  Q_D(KMainWindow);
859  d->autoSaveSettings = false;
860  if (d->settingsTimer) {
861  d->settingsTimer->stop();
862  }
863 }
864 
865 bool KMainWindow::autoSaveSettings() const
866 {
867  Q_D(const KMainWindow);
868  return d->autoSaveSettings;
869 }
870 
871 QString KMainWindow::autoSaveGroup() const
872 {
873  Q_D(const KMainWindow);
874  return d->autoSaveSettings ? d->autoSaveGroup.name() : QString();
875 }
876 
878 {
879  Q_D(const KMainWindow);
880  return d->autoSaveSettings ? d->autoSaveGroup : KConfigGroup();
881 }
882 
884 {
885  Q_D(KMainWindow);
886  d->m_stateConfigGroup = KSharedConfig::openStateConfig()->group(configGroup);
887 }
888 
889 KConfigGroup KMainWindow::stateConfigGroup() const
890 {
891  Q_D(const KMainWindow);
892  return d->m_stateConfigGroup;
893 }
894 
896 {
897  Q_D(KMainWindow);
898  Q_ASSERT(d->autoSaveSettings);
899  // qDebug(200) << "KMainWindow::saveAutoSaveSettings -> saving settings";
900  saveMainWindowSettings(d->autoSaveGroup);
901  d->autoSaveGroup.sync();
902  d->autoSaveStateGroup().sync();
903  d->settingsDirty = false;
904 }
905 
907 {
908  Q_D(KMainWindow);
909  switch (ev->type()) {
910 #if defined(Q_OS_WIN) || defined(Q_OS_OSX)
911  case QEvent::Move:
912 #endif
913  case QEvent::Resize:
914  d->setSizeDirty();
915  break;
916  case QEvent::Polish:
917  d->polish(this);
918  break;
919  case QEvent::ChildPolished: {
920  QChildEvent *event = static_cast<QChildEvent *>(ev);
921  QDockWidget *dock = qobject_cast<QDockWidget *>(event->child());
922  KToolBar *toolbar = qobject_cast<KToolBar *>(event->child());
923  QMenuBar *menubar = qobject_cast<QMenuBar *>(event->child());
924  if (dock) {
927 
928  // there is no signal emitted if the size of the dock changes,
929  // hence install an event filter instead
930  dock->installEventFilter(d->dockResizeListener);
931  } else if (toolbar) {
932  // there is no signal emitted if the size of the toolbar changes,
933  // hence install an event filter instead
934  toolbar->installEventFilter(d->dockResizeListener);
935  } else if (menubar) {
936  // there is no signal emitted if the size of the menubar changes,
937  // hence install an event filter instead
938  menubar->installEventFilter(d->dockResizeListener);
939  }
940  break;
941  }
942  case QEvent::ChildRemoved: {
943  QChildEvent *event = static_cast<QChildEvent *>(ev);
944  QDockWidget *dock = qobject_cast<QDockWidget *>(event->child());
945  KToolBar *toolbar = qobject_cast<KToolBar *>(event->child());
946  QMenuBar *menubar = qobject_cast<QMenuBar *>(event->child());
947  if (dock) {
950  dock->removeEventFilter(d->dockResizeListener);
951  } else if (toolbar) {
952  toolbar->removeEventFilter(d->dockResizeListener);
953  } else if (menubar) {
954  menubar->removeEventFilter(d->dockResizeListener);
955  }
956  break;
957  }
958  default:
959  break;
960  }
961  return QMainWindow::event(ev);
962 }
963 
964 bool KMainWindow::hasMenuBar()
965 {
966  return internalMenuBar(this);
967 }
968 
969 void KMainWindowPrivate::_k_slotSettingsChanged(int category)
970 {
971  Q_UNUSED(category);
972 
973  // This slot will be called when the style KCM changes settings that need
974  // to be set on the already running applications.
975 
976  // At this level (KMainWindow) the only thing we need to restore is the
977  // animations setting (whether the user wants builtin animations or not).
978 
979  q->setAnimated(q->style()->styleHint(QStyle::SH_Widget_Animate, nullptr, q));
980 }
981 
982 void KMainWindowPrivate::_k_slotSaveAutoSaveSize()
983 {
984  if (autoSaveGroup.isValid()) {
985  KWindowConfig::saveWindowSize(q->windowHandle(), autoSaveStateGroup());
986  }
987 }
988 
989 void KMainWindowPrivate::_k_slotSaveAutoSavePosition()
990 {
991  if (autoSaveGroup.isValid()) {
992  KWindowConfig::saveWindowPosition(q->windowHandle(), autoSaveStateGroup());
993  }
994 }
995 
997 {
998  QString childName = name;
999  if (childName.isEmpty()) {
1000  childName = QStringLiteral("mainToolBar");
1001  }
1002 
1003  KToolBar *tb = findChild<KToolBar *>(childName);
1004  if (tb) {
1005  return tb;
1006  }
1007 
1008  KToolBar *toolbar = new KToolBar(childName, this); // non-XMLGUI toolbar
1009  return toolbar;
1010 }
1011 
1013 {
1014  QList<KToolBar *> ret;
1015 
1016  const auto theChildren = children();
1017  for (QObject *child : theChildren) {
1018  if (KToolBar *toolBar = qobject_cast<KToolBar *>(child)) {
1019  ret.append(toolBar);
1020  }
1021  }
1022 
1023  return ret;
1024 }
1025 
1027 {
1028  return *sMemberList();
1029 }
1030 
1032 {
1033  Q_D(const KMainWindow);
1034 
1035  return d->dbusName;
1036 }
1037 
1038 #include "kmainwindow.moc"
1039 #include "moc_kmainwindow.cpp"
Q_OBJECTQ_OBJECT
void append(const T &value)
virtual bool event(QEvent *event) override
void removeEventFilter(QObject *obj)
KCONFIGGUI_EXPORT void restoreWindowPosition(QWindow *window, const KConfigGroup &config)
QWidget * focusWidget()
void setSettingsDirty()
Tell the main window that it should save its settings when being closed.
QString readEntry(const char *key, const char *aDefault=nullptr) const
void setDiscardCommand(const QStringList &command)
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
QWidget * window() const const
bool event(QEvent *event) override
Reimplemented to catch QEvent::Polish in order to adjust the object name if needed,...
void resetAutoSaveSettings()
Disable the auto-save-settings feature.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
void setFallbackSessionManagementEnabled(bool enabled)
bool settingsDirty() const
For inherited classes.
void appHelpActivated()
Open the help page for the application.
void setFallbackThemeName(const QString &name)
static QList< KMainWindow * > memberList()
List of members of KMainWindow class.
KMainWindow(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
Construct a main window.
static const QString classNameOfToplevel(int number)
Returns the className() of the number of the toplevel window which should be restored.
QByteArray & append(char ch)
void setHeight(int arg)
QString dbusName() const
Returns the path under which this window's D-Bus object is exported.
static KGlobalSettings * self()
static void setApplicationData(const KAboutData &aboutData)
KCONFIGGUI_EXPORT void setSessionConfig(const QString &id, const QString &key)
void setStateConfigGroup(const QString &configGroup)
Set the config group name for state config returned by stateConfigGroup If this method is called the ...
void restoreWindowSize(const KConfigGroup &config)
For inherited classes.
QByteArray number(int n, int base)
void commitDataRequest(QSessionManager &manager)
QList< KToolBar * > toolBars() const
QString fallbackThemeName()
virtual void readProperties(const KConfigGroup &)
Read your instance-specific properties.
Definition: kmainwindow.h:548
QString writableLocation(QStandardPaths::StandardLocation type)
bool registerObject(const QString &path, QObject *object, QDBusConnection::RegisterOptions options)
Standard KDE help menu with dialog boxes.
Definition: khelpmenu.h:108
void saveWindowSize(KConfigGroup &config) const
For inherited classes.
QByteArray toBase64(QByteArray::Base64Options options) const const
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
virtual void showAboutApplication()
This slot does nothing.
Definition: kmainwindow.h:629
bool restore(int number, bool show=true)
Try to restore the toplevel widget as defined by number (1..X).
bool exists() const const
Floatable toolbar with auto resize.
Definition: ktoolbar.h:60
~KMainWindow() override
Destructor.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual void setPlainCaption(const QString &caption)
Make a plain caption without any modifications.
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
virtual void saveGlobalProperties(KConfig *sessionConfig)
Save your application-wide properties.
Q_GLOBAL_STATIC(Internal::StaticControl, s_instance) class ControlPrivate
void saveAutoSaveSettings()
This slot should only be called in case you reimplement closeEvent() and if you are using the "auto-s...
KConfigGroup autoSaveConfigGroup() const
void setWindowRole(const QString &role)
virtual bool eventFilter(QObject *watched, QEvent *event)
virtual void setVisible(bool visible)
typedef WindowFlags
void setWindowModified(bool)
virtual bool queryClose()
Called before the window is closed, either by the user or indirectly by the session manager.
QString i18ndc(const char *domain, const char *context, const char *text, const TYPE &arg...)
QMenu * helpMenu(const QString &aboutAppText=QString(), bool showWhatsThis=true)
Retrieve the standard help menu.
QString & setNum(short n, int base)
QDBusConnection sessionBus()
QStyle * style() const const
void dockLocationChanged(Qt::DockWidgetArea area)
bool sendEvent(QObject *receiver, QEvent *event)
bool isAccepted() const const
QString sessionKey() const const
static bool canBeRestored(int number)
If the session did contain so high a number, true is returned, else false.
void installEventFilter(QObject *filterObj)
void closeEvent(QCloseEvent *) override
Reimplemented to autosave settings and call queryClose().
void timeout()
bool isEmpty() const const
FindDirectChildrenOnly
int length() const const
void setWindowTitle(const QString &)
void topLevelChanged(bool topLevel)
virtual void setVisible(bool visible) override
static KSharedConfig::Ptr openStateConfig(const QString &fileName=QString())
QByteArray fromBase64(const QByteArray &base64, QByteArray::Base64Options options)
static KAboutData applicationData()
QMenu * customHelpMenu(bool showWhatsThis=true)
Returns the help menu.
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
KCONFIGGUI_EXPORT void saveWindowPosition(const QWindow *window, KConfigGroup &config, KConfigGroup::WriteConfigFlags options=KConfigGroup::Normal)
bool hasKey(const char *key) const
KSharedConfigPtr config()
bool testAttribute(Qt::WidgetAttribute attribute) const const
virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const const=0
void setWidth(int arg)
virtual const QMetaObject * metaObject() const const
void show()
bool restoreState(const QByteArray &state, int version)
T findChild(const QString &name, Qt::FindChildOptions options) const const
static bool toolBarsLocked()
Returns whether the toolbars are locked (i.e., moving of the toobars disallowed).
Definition: ktoolbar.cpp:1459
void revertToDefault(const char *key)
SH_Widget_Animate
void resize(int w, int h)
QWindow * windowHandle() const const
bool hasDefault(const char *key) const
KToolBar * toolBar(const QString &name=QString())
Returns a pointer to the toolbar with the specified name.
void showAboutApplication()
This signal is emitted from aboutApplication() if no "about application" string has been defined.
const char * constData() const const
Top level main window.
Definition: kmainwindow.h:92
static void setToolBarsLocked(bool locked)
Allows you to lock and unlock all toolbars (i.e., disallow/allow moving of the toobars).
Definition: ktoolbar.cpp:1444
virtual void setCaption(const QString &caption)
Makes a KDE compliant caption (window title).
KCONFIGGUI_EXPORT void restoreWindowSize(QWindow *window, const KConfigGroup &config)
QEvent::Type type() const const
void ignore()
const char * name(StandardAction id)
bool allowsInteraction()
virtual void saveProperties(KConfigGroup &)
Save your instance-specific properties.
Definition: kmainwindow.h:539
void saveMainWindowSettings(KConfigGroup &config)
Save settings for statusbar, menubar and toolbar to their respective groups in the config group confi...
QByteArray saveState(int version) const const
WId winId() const const
void saveStateRequest(QSessionManager &manager)
QString name() const
virtual void applyMainWindowSettings(const KConfigGroup &config)
Read settings for statusbar, menubar and toolbar from their respective groups in the config file and ...
void setAutoSaveSettings(const QString &groupName=QStringLiteral("MainWindow"), bool saveWindowSize=true)
Call this to enable "auto-save" of toolbar/menubar/statusbar settings (and optionally window size).
KCONFIGGUI_EXPORT KConfig * sessionConfig()
KGuiItem discard()
bool isHidden() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
KJOBWIDGETS_EXPORT QWidget * window(KJob *job)
virtual void readGlobalProperties(KConfig *sessionConfig)
The counterpart of saveGlobalProperties().
void setAnimated(bool enabled)
void setFocus()
WA_WState_Hidden
QString & append(QChar ch)
QString sessionId() const const
Q_D(Todo)
ushort unicode() const const
const QObjectList & children() const const
void accept()
KCONFIGGUI_EXPORT void saveWindowSize(const QWindow *window, KConfigGroup &config, KConfigGroup::WriteConfigFlags options=KConfigGroup::Normal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu May 26 2022 03:55:17 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.