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

KDE's Doxygen guidelines are available online.