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 "ktoolbarhandler_p.h"
22 #include "khelpmenu.h"
23 #include "ktoolbar.h"
24 
25 #include <QApplication>
26 #include <QList>
27 #include <QObject>
28 #include <QTimer>
29 #include <QCloseEvent>
30 #include <QDockWidget>
31 #include <QMenuBar>
32 #include <QSessionManager>
33 #include <QStatusBar>
34 #include <QStyle>
35 #include <QWidget>
36 #include <QWindow>
37 #ifdef QT_DBUS_LIB
38 #include <QDBusConnection>
39 #endif
40 
41 #include <ktoggleaction.h>
42 #include <kaboutdata.h>
43 #include <kconfig.h>
44 #include <ksharedconfig.h>
45 #include <klocalizedstring.h>
46 #include <kconfiggroup.h>
47 #include <kwindowconfig.h>
48 #include <kconfiggui.h>
49 
50 //#include <ctype.h>
51 
52 static const char WINDOW_PROPERTIES[]="WindowProperties";
53 
54 static QMenuBar *internalMenuBar(KMainWindow *mw)
55 {
57 }
58 
59 static QStatusBar *internalStatusBar(KMainWindow *mw)
60 {
62 }
63 
72 class DockResizeListener : public QObject
73 {
74  Q_OBJECT
75 public:
76  DockResizeListener(KMainWindow *win);
77  ~DockResizeListener() override;
78  bool eventFilter(QObject *watched, QEvent *event) override;
79 
80 private:
81  KMainWindow *const m_win;
82 };
83 
84 DockResizeListener::DockResizeListener(KMainWindow *win) :
85  QObject(win),
86  m_win(win)
87 {
88 }
89 
90 DockResizeListener::~DockResizeListener()
91 {
92 }
93 
94 bool DockResizeListener::eventFilter(QObject *watched, QEvent *event)
95 {
96  switch (event->type()) {
97  case QEvent::Resize:
98  case QEvent::Move:
99  case QEvent::Show:
100  case QEvent::Hide:
101  m_win->k_ptr->setSettingsDirty(KMainWindowPrivate::CompressCalls);
102  break;
103 
104  default:
105  break;
106  }
107 
108  return QObject::eventFilter(watched, event);
109 }
110 
111 KMWSessionManager::KMWSessionManager()
112 {
114  this, &KMWSessionManager::saveState);
116  this, &KMWSessionManager::commitData);
117 }
118 
119 KMWSessionManager::~KMWSessionManager()
120 {
121 }
122 
123 void KMWSessionManager::saveState(QSessionManager &sm)
124 {
126 
128  const auto windows = KMainWindow::memberList();
129  if (!windows.isEmpty()) {
130  // According to Jochen Wilhelmy <[email protected]>, this
131  // hook is useful for better document orientation
132  windows.at(0)->saveGlobalProperties(config);
133  }
134 
135  int n = 0;
136  for (KMainWindow *mw : windows) {
137  n++;
138  mw->savePropertiesInternal(config, n);
139  }
140 
141  KConfigGroup group(config, "Number");
142  group.writeEntry("NumberOfWindows", n);
143 
144  // store new status to disk
145  config->sync();
146 
147  // generate discard command for new file
149  if (QFile::exists(localFilePath)) {
151  discard << QStringLiteral("rm");
152  discard << localFilePath;
153  sm.setDiscardCommand(discard);
154  }
155 }
156 
157 void KMWSessionManager::commitData(QSessionManager &sm)
158 {
159  if (!sm.allowsInteraction()) {
160  return;
161  }
162 
163  /*
164  Purpose of this exercise: invoke queryClose() without actually closing the
165  windows, because
166  - queryClose() may contain session management code, so it must be invoked
167  - actually closing windows may quit the application - cf.
168  QGuiApplication::quitOnLastWindowClosed()
169  - quitting the application and thus closing the session manager connection
170  violates the X11 XSMP protocol.
171  The exact requirement of XSMP that would be broken is,
172  in the description of the client's state machine:
173 
174  save-yourself-done: (changing state is forbidden)
175 
176  Closing the session manager connection causes a state change.
177  Worst of all, that is a real problem with ksmserver - it will not save
178  applications that quit on their own in state save-yourself-done.
179  */
180  const auto windows = KMainWindow::memberList();
181  for (KMainWindow *window : windows) {
183  continue;
184  }
185  QCloseEvent e;
187  if (!e.isAccepted()) {
188  sm.cancel();
189  return;
190  }
191  }
192 }
193 
194 Q_GLOBAL_STATIC(KMWSessionManager, ksm)
195 Q_GLOBAL_STATIC(QList<KMainWindow *>, sMemberList)
196 
197 KMainWindow::KMainWindow(QWidget *parent, Qt::WindowFlags f)
198  : QMainWindow(parent, f), 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), k_ptr(&dd)
207 {
208  Q_D(KMainWindow);
209 
210  d->init(this);
211 }
212 
213 void KMainWindowPrivate::init(KMainWindow *_q)
214 {
215  q = _q;
217  q->setAnimated(q->style()->styleHint(QStyle::SH_Widget_Animate, nullptr, q));
218 
219  q->setAttribute(Qt::WA_DeleteOnClose);
220 
221  helpMenu = nullptr;
222 
223  //actionCollection()->setWidget( this );
224 #if 0
225  QObject::connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)),
226  q, SLOT(_k_slotSettingsChanged(int)));
227 #endif
228 
229  // force KMWSessionManager creation
230  ksm();
231 
232  sMemberList()->append(q);
233 
234  // Set the icon theme fallback to breeze (if not already set)
235  // Most of our apps use "lots" of icons that most of the times
236  // are only available with breeze, we still honour the user icon
237  // theme but if the icon is not found there, we go to breeze
238  // since it's almost sure it'll be there.
239  // This should be done as soon as possible (preferably via
240  // Q_COREAPP_STARTUP_FUNCTION), but as for now it cannot be done too soon
241  // as at that point QPlatformTheme is not instantiated yet and breaks the
242  // internal status of QIconLoader (see QTBUG-74252).
243  // See also discussion at https://phabricator.kde.org/D22488
244  // TODO: remove this once we depend on Qt 5.15.1, where this is fixed
245  if (QIcon::fallbackThemeName().isEmpty()) {
246  QIcon::setFallbackThemeName(QStringLiteral("breeze"));
247  }
248 
249  // If application is translated, load translator information for use in
250  // KAboutApplicationDialog or other getters. The context and messages below
251  // both must be exactly as listed, and are forced to be loaded from the
252  // application's own message catalog instead of kxmlgui's.
254  if (aboutData.translators().isEmpty()) {
255  aboutData.setTranslator(
256  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 
276 static bool endsWithHashNumber(const QString &s)
277 {
278  for (int i = s.length() - 1;
279  i > 0;
280  --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  return (u >= QLatin1Char('a') && u <= QLatin1Char('z'))
295  || (u >= QLatin1Char('A') && u <= QLatin1Char('Z'))
296  || (u >= QLatin1Char('0') && u <= QLatin1Char('9'))
297  || (u == QLatin1Char('_')) || (u == QLatin1Char('/'));
298 }
299 
300 void KMainWindowPrivate::polish(KMainWindow *q)
301 {
302  // Set a unique object name. Required by session management, window management, and for the dbus interface.
303  QString objname;
304  QString s;
305  int unusedNumber = 1;
306  const QString name = q->objectName();
307  bool startNumberingImmediately = true;
308  bool tryReuse = false;
309  if (name.isEmpty()) {
310  // no name given
311  objname = QStringLiteral("MainWindow#");
312  } else if (name.endsWith(QLatin1Char('#'))) {
313  // trailing # - always add a number - KWin uses this for better grouping
314  objname = name;
315  } else if (endsWithHashNumber(name)) {
316  // trailing # with a number - like above, try to use the given number first
317  objname = name;
318  tryReuse = true;
319  startNumberingImmediately = false;
320  } else {
321  objname = name;
322  startNumberingImmediately = false;
323  }
324 
325  s = objname;
326  if (startNumberingImmediately) {
327  s += QLatin1Char('1');
328  }
329 
330  for (;;) {
331  const QList<QWidget *> list = qApp->topLevelWidgets();
332  bool found = false;
333  for (QWidget *w : list) {
334  if (w != q && w->objectName() == s) {
335  found = true;
336  break;
337  }
338  }
339  if (!found) {
340  break;
341  }
342  if (tryReuse) {
343  objname = name.left(name.length() - 1); // lose the hash
344  unusedNumber = 0; // start from 1 below
345  tryReuse = false;
346  }
347  s.setNum(++unusedNumber);
348  s = objname + s;
349  }
350  q->setObjectName(s);
351  if (!q->window() || q->window() == q) {
352  q->winId(); // workaround for setWindowRole() crashing, and set also window role, just in case TT
353  q->setWindowRole(s); // will keep insisting that object name suddenly should not be used for window role
354  }
355 
356  dbusName = QLatin1Char('/') + QCoreApplication::applicationName() + QLatin1Char('/');
357  dbusName += q->objectName().replace(QLatin1Char('/'), QLatin1Char('_'));
358  // Clean up for dbus usage: any non-alphanumeric char should be turned into '_'
359  for (QChar &c : dbusName) {
360  if (!isValidDBusObjectPathCharacter(c)) {
361  c = QLatin1Char('_');
362  }
363  }
364 
365 #ifdef QT_DBUS_LIB
371 #endif
372 }
373 
374 void KMainWindowPrivate::setSettingsDirty(CallCompression callCompression)
375 {
376  if (!letDirtySettings) {
377  return;
378  }
379 
380  settingsDirty = true;
381  if (autoSaveSettings) {
382  if (callCompression == CompressCalls) {
383  if (!settingsTimer) {
384  settingsTimer = new QTimer(q);
385  settingsTimer->setInterval(500);
386  settingsTimer->setSingleShot(true);
387  QObject::connect(settingsTimer, &QTimer::timeout,
389  }
390  settingsTimer->start();
391  } else {
393  }
394  }
395 }
396 
397 void KMainWindowPrivate::setSizeDirty()
398 {
399  if (autoSaveWindowSize) {
400  if (!sizeTimer) {
401  sizeTimer = new QTimer(q);
402  sizeTimer->setInterval(500);
403  sizeTimer->setSingleShot(true);
404  QObject::connect(sizeTimer, SIGNAL(timeout()), q, SLOT(_k_slotSaveAutoSaveSize()));
405  }
406  sizeTimer->start();
407  }
408 }
409 
411 {
412  sMemberList()->removeAll(this);
413  delete static_cast<QObject *>(k_ptr->dockResizeListener); //so we don't get anymore events after k_ptr is destroyed
414 }
415 
416 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
417 QMenu *KMainWindow::helpMenu(const QString &aboutAppText, bool showWhatsThis)
418 {
419  Q_D(KMainWindow);
420  if (!d->helpMenu) {
421  if (aboutAppText.isEmpty()) {
422  d->helpMenu = new KHelpMenu(this, KAboutData::applicationData(), showWhatsThis);
423  } else {
424  d->helpMenu = new KHelpMenu(this, aboutAppText, showWhatsThis);
425  }
426 
427  if (!d->helpMenu) {
428  return nullptr;
429  }
430  }
431 
432  return d->helpMenu->menu();
433 }
434 
435 QMenu *KMainWindow::customHelpMenu(bool showWhatsThis)
436 {
437  Q_D(KMainWindow);
438  if (!d->helpMenu) {
439  d->helpMenu = new KHelpMenu(this, QString(), showWhatsThis);
442  }
443 
444  return d->helpMenu->menu();
445 }
446 #endif
447 
449 {
451  if (!config) {
452  return false;
453  }
454 
455  KConfigGroup group(config, "Number");
456  // TODO KF6: we should use 0 as the default value, not 1
457  // See also https://bugs.kde.org/show_bug.cgi?id=427552
458  const int n = group.readEntry("NumberOfWindows", 1);
459  return number >= 1 && number <= n;
460 }
461 
463 {
465  if (!config) {
466  return QString();
467  }
468 
469  KConfigGroup group(config, QByteArray(WINDOW_PROPERTIES).append(QByteArray::number(number)).constData());
470  if (!group.hasKey("ClassName")) {
471  return QString();
472  } else {
473  return group.readEntry("ClassName");
474  }
475 }
476 
477 bool KMainWindow::restore(int number, bool show)
478 {
479  if (!canBeRestored(number)) {
480  return false;
481  }
483  if (readPropertiesInternal(config, number)) {
484  if (show) {
486  }
487  return false;
488  }
489  return false;
490 }
491 
492 void KMainWindow::setCaption(const QString &caption)
493 {
494  setPlainCaption(caption);
495 }
496 
497 void KMainWindow::setCaption(const QString &caption, bool modified)
498 {
499  QString title = caption;
500  if (!title.contains(QLatin1String("[*]")) && !title.isEmpty()) { // append the placeholder so that the modified mechanism works
501  title.append(QLatin1String(" [*]"));
502  }
503  setPlainCaption(title);
504  setWindowModified(modified);
505 }
506 
508 {
509  setWindowTitle(caption);
510 }
511 
513 {
514  Q_D(KMainWindow);
515  if (!d->helpMenu) {
516  d->helpMenu = new KHelpMenu(this);
517  if (!d->helpMenu) {
518  return;
519  }
520  }
521  d->helpMenu->appHelpActivated();
522 }
523 
525 {
526  Q_D(KMainWindow);
527  if (d->suppressCloseEvent) {
528  e->accept();
529  return;
530  }
531 
532  // Save settings if auto-save is enabled, and settings have changed
533  if (d->settingsTimer && d->settingsTimer->isActive()) {
534  d->settingsTimer->stop();
535  saveAutoSaveSettings();
536  }
537  if (d->sizeTimer && d->sizeTimer->isActive()) {
538  d->sizeTimer->stop();
539  d->_k_slotSaveAutoSaveSize();
540  }
541  // Delete the marker that says we don't want to restore the position of the
542  // next-opened instance; now that a window is closing, we do want to do this
543  if (d->autoSaveGroup.isValid()) {
544  d->autoSaveGroup.deleteEntry("RestorePositionForNextInstance");
545  }
546  d->_k_slotSaveAutoSavePosition();
547 
548  if (queryClose()) {
549  // widgets will start destroying themselves at this point and we don't
550  // want to save state anymore after this as it might be incorrect
551  d->autoSaveSettings = false;
552  d->letDirtySettings = false;
553  e->accept();
554  } else {
555  e->ignore(); //if the window should not be closed, don't close it
556  }
557  // If saving session, we are processing a fake close event, and might get the real one later.
558  if (e->isAccepted() && qApp->isSavingSession())
559  d->suppressCloseEvent = true;
560 }
561 
563 {
564  return true;
565 }
566 
568 {
569 }
570 
572 {
573 }
574 
575 void KMainWindow::savePropertiesInternal(KConfig *config, int number)
576 {
577  Q_D(KMainWindow);
578  const bool oldASWS = d->autoSaveWindowSize;
579  d->autoSaveWindowSize = true; // make saveMainWindowSettings save the window size
580 
581  KConfigGroup cg(config, QByteArray(WINDOW_PROPERTIES).append(QByteArray::number(number)).constData());
582 
583  // store objectName, className, Width and Height for later restoring
584  // (Only useful for session management)
585  cg.writeEntry("ObjectName", objectName());
586  cg.writeEntry("ClassName", metaObject()->className());
587 
588  saveMainWindowSettings(cg); // Menubar, statusbar and Toolbar settings.
589 
590  cg = KConfigGroup(config, QByteArray::number(number).constData());
591  saveProperties(cg);
592 
593  d->autoSaveWindowSize = oldASWS;
594 }
595 
597 {
598  Q_D(KMainWindow);
599  //qDebug(200) << "KMainWindow::saveMainWindowSettings " << cg.name();
600 
601  // Called by session management - or if we want to save the window size anyway
602  if (d->autoSaveWindowSize) {
605  }
606 
607  // One day will need to save the version number, but for now, assume 0
608  // Utilise the QMainWindow::saveState() functionality.
609  const QByteArray state = saveState();
610  cg.writeEntry("State", state.toBase64());
611 
612  QStatusBar *sb = internalStatusBar(this);
613  if (sb) {
614  if (!cg.hasDefault("StatusBar") && !sb->isHidden()) {
615  cg.revertToDefault("StatusBar");
616  } else {
617  cg.writeEntry("StatusBar", sb->isHidden() ? "Disabled" : "Enabled");
618  }
619  }
620 
621  QMenuBar *mb = internalMenuBar(this);
622  if (mb) {
623  if (!cg.hasDefault("MenuBar") && !mb->isHidden()) {
624  cg.revertToDefault("MenuBar");
625  } else {
626  cg.writeEntry("MenuBar", mb->isHidden() ? "Disabled" : "Enabled");
627  }
628  }
629 
630  if (!autoSaveSettings() || cg.name() == autoSaveGroup()) {
631  // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
632  if (!cg.hasDefault("ToolBarsMovable") && !KToolBar::toolBarsLocked()) {
633  cg.revertToDefault("ToolBarsMovable");
634  } else {
635  cg.writeEntry("ToolBarsMovable", KToolBar::toolBarsLocked() ? "Disabled" : "Enabled");
636  }
637  }
638 
639  int n = 1; // Toolbar counter. toolbars are counted from 1,
640  const auto toolBars = this->toolBars();
641  for (KToolBar *toolbar : toolBars) {
642  QByteArray groupName("Toolbar");
643  // Give a number to the toolbar, but prefer a name if there is one,
644  // because there's no real guarantee on the ordering of toolbars
645  groupName += (toolbar->objectName().isEmpty() ? QByteArray::number(n) : QByteArray(" ").append(toolbar->objectName().toUtf8()));
646 
647  KConfigGroup toolbarGroup(&cg, groupName.constData());
648  toolbar->saveSettings(toolbarGroup);
649  n++;
650  }
651 }
652 
653 bool KMainWindow::readPropertiesInternal(KConfig *config, int number)
654 {
655  Q_D(KMainWindow);
656 
657  const bool oldLetDirtySettings = d->letDirtySettings;
658  d->letDirtySettings = false;
659 
660  if (number == 1) {
661  readGlobalProperties(config);
662  }
663 
664  // in order they are in toolbar list
665  KConfigGroup cg(config, QByteArray(WINDOW_PROPERTIES).append(QByteArray::number(number)).constData());
666 
667  // restore the object name (window role)
668  if (cg.hasKey("ObjectName")) {
669  setObjectName(cg.readEntry("ObjectName"));
670  }
671 
672  d->sizeApplied = false; // since we are changing config file, reload the size of the window
673  // if necessary. Do it before the call to applyMainWindowSettings.
674  applyMainWindowSettings(cg); // Menubar, statusbar and toolbar settings.
675 
676  KConfigGroup grp(config, QByteArray::number(number).constData());
677  readProperties(grp);
678 
679  d->letDirtySettings = oldLetDirtySettings;
680 
681  return true;
682 }
683 
685 {
686  Q_D(KMainWindow);
687  //qDebug(200) << "KMainWindow::applyMainWindowSettings " << cg.name();
688 
689  QWidget *focusedWidget = QApplication::focusWidget();
690 
691  const bool oldLetDirtySettings = d->letDirtySettings;
692  d->letDirtySettings = false;
693 
694  if (!d->sizeApplied && (!window() || window() == this)) {
695  winId(); // ensure there's a window created
697  // NOTICE: QWindow::setGeometry() does NOT impact the backing QWidget geometry even if the platform
698  // window was created -> QTBUG-40584. We therefore copy the size here.
699  // TODO: remove once this was resolved in QWidget QPA
700  resize(windowHandle()->size());
701  d->sizeApplied = true;
702 
703  // Let the user opt out of KDE apps remembering window sizes if they
704  // find it annoying or it doesn't work for them due to other bugs.
705  KSharedConfigPtr config = KSharedConfig::openConfig();
706  KConfigGroup group(config, "General");
707  if (group.readEntry("AllowKDEAppsToRememberWindowPositions", true)) {
708  if (cg.readEntry("RestorePositionForNextInstance", true)) {
710  // Save the fact that we now don't want to restore position
711  // anymore; if we did, the next instance would completely cover
712  // the existing one
713  KConfigGroup cgWritable = cg; // because cg is const
714  cgWritable.writeEntry("RestorePositionForNextInstance", false);
715  }
716  }
717  }
718 
719  QStatusBar *sb = internalStatusBar(this);
720  if (sb) {
721  QString entry = cg.readEntry("StatusBar", "Enabled");
722  sb->setVisible( entry != QLatin1String("Disabled") );
723  }
724 
725  QMenuBar *mb = internalMenuBar(this);
726  if (mb) {
727  QString entry = cg.readEntry("MenuBar", "Enabled");
728  mb->setVisible( entry != QLatin1String("Disabled") );
729  }
730 
731  if (!autoSaveSettings() || cg.name() == autoSaveGroup()) { // TODO should be cg == d->autoSaveGroup, to compare both kconfig and group name
732  QString entry = cg.readEntry("ToolBarsMovable", "Disabled");
733  KToolBar::setToolBarsLocked(entry == QLatin1String("Disabled"));
734  }
735 
736  int n = 1; // Toolbar counter. toolbars are counted from 1,
737  const auto toolBars = this->toolBars();
738  for (KToolBar *toolbar : toolBars) {
739  QByteArray groupName("Toolbar");
740  // Give a number to the toolbar, but prefer a name if there is one,
741  // because there's no real guarantee on the ordering of toolbars
742  groupName += (toolbar->objectName().isEmpty() ? QByteArray::number(n) : QByteArray(" ").append(toolbar->objectName().toUtf8()));
743 
744  KConfigGroup toolbarGroup(&cg, groupName.constData());
745  toolbar->applySettings(toolbarGroup);
746  n++;
747  }
748 
749  QByteArray state;
750  if (cg.hasKey("State")) {
751  state = cg.readEntry("State", state);
752  state = QByteArray::fromBase64(state);
753  // One day will need to load the version number, but for now, assume 0
754  restoreState(state);
755  }
756 
757  if (focusedWidget) {
758  focusedWidget->setFocus();
759  }
760 
761  d->settingsDirty = false;
762  d->letDirtySettings = oldLetDirtySettings;
763 }
764 
765 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
767 {
769 }
770 #endif
771 
772 #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0)
774 {
776 }
777 #endif
778 
780 {
781  Q_D(KMainWindow);
782  d->setSettingsDirty();
783 }
784 
786 {
787  Q_D(const KMainWindow);
788  return d->settingsDirty;
789 }
790 
791 void KMainWindow::setAutoSaveSettings(const QString &groupName, bool saveWindowSize)
792 {
793  setAutoSaveSettings(KConfigGroup(KSharedConfig::openConfig(), groupName), saveWindowSize);
794 }
795 
797  bool saveWindowSize)
798 {
799  // We re making a little assumption that if you want to save the window
800  // size, you probably also want to save the window position too
801  // This avoids having to re-implement a new version of
802  // KMainWindow::setAutoSaveSettings that handles these cases independently
803  Q_D(KMainWindow);
804  d->autoSaveSettings = true;
805  d->autoSaveGroup = group;
806  d->autoSaveWindowSize = saveWindowSize;
807 
808  if (!saveWindowSize && d->sizeTimer) {
809  d->sizeTimer->stop();
810  }
811 
812  // Now read the previously saved settings
813  applyMainWindowSettings(d->autoSaveGroup);
814 }
815 
817 {
818  Q_D(KMainWindow);
819  d->autoSaveSettings = false;
820  if (d->settingsTimer) {
821  d->settingsTimer->stop();
822  }
823 }
824 
826 {
827  Q_D(const KMainWindow);
828  return d->autoSaveSettings;
829 }
830 
832 {
833  Q_D(const KMainWindow);
834  return d->autoSaveSettings ? d->autoSaveGroup.name() : QString();
835 }
836 
838 {
839  Q_D(const KMainWindow);
840  return d->autoSaveSettings ? d->autoSaveGroup : KConfigGroup();
841 }
842 
844 {
845  Q_D(KMainWindow);
846  Q_ASSERT(d->autoSaveSettings);
847  //qDebug(200) << "KMainWindow::saveAutoSaveSettings -> saving settings";
848  saveMainWindowSettings(d->autoSaveGroup);
849  d->autoSaveGroup.sync();
850  d->settingsDirty = false;
851 }
852 
854 {
855  Q_D(KMainWindow);
856  switch (ev->type()) {
857 #if defined(Q_OS_WIN) || defined(Q_OS_OSX)
858  case QEvent::Move:
859 #endif
860  case QEvent::Resize:
861  d->setSizeDirty();
862  break;
863  case QEvent::Polish:
864  d->polish(this);
865  break;
866  case QEvent::ChildPolished: {
867  QChildEvent *event = static_cast<QChildEvent *>(ev);
868  QDockWidget *dock = qobject_cast<QDockWidget *>(event->child());
869  KToolBar *toolbar = qobject_cast<KToolBar *>(event->child());
870  QMenuBar *menubar = qobject_cast<QMenuBar *>(event->child());
871  if (dock) {
876 
877  // there is no signal emitted if the size of the dock changes,
878  // hence install an event filter instead
879  dock->installEventFilter(d->dockResizeListener);
880  } else if (toolbar) {
881  // there is no signal emitted if the size of the toolbar changes,
882  // hence install an event filter instead
883  toolbar->installEventFilter(d->dockResizeListener);
884  } else if (menubar) {
885  // there is no signal emitted if the size of the menubar changes,
886  // hence install an event filter instead
887  menubar->installEventFilter(d->dockResizeListener);
888  }
889  }
890  break;
891  case QEvent::ChildRemoved: {
892  QChildEvent *event = static_cast<QChildEvent *>(ev);
893  QDockWidget *dock = qobject_cast<QDockWidget *>(event->child());
894  KToolBar *toolbar = qobject_cast<KToolBar *>(event->child());
895  QMenuBar *menubar = qobject_cast<QMenuBar *>(event->child());
896  if (dock) {
901  dock->removeEventFilter(d->dockResizeListener);
902  } else if (toolbar) {
903  toolbar->removeEventFilter(d->dockResizeListener);
904  } else if (menubar) {
905  menubar->removeEventFilter(d->dockResizeListener);
906  }
907  }
908  break;
909  default:
910  break;
911  }
912  return QMainWindow::event(ev);
913 }
914 
916 {
917  return internalMenuBar(this);
918 }
919 
920 void KMainWindowPrivate::_k_slotSettingsChanged(int category)
921 {
922  Q_UNUSED(category);
923 
924  // This slot will be called when the style KCM changes settings that need
925  // to be set on the already running applications.
926 
927  // At this level (KMainWindow) the only thing we need to restore is the
928  // animations setting (whether the user wants builtin animations or not).
929 
930  q->setAnimated(q->style()->styleHint(QStyle::SH_Widget_Animate, nullptr, q));
931 }
932 
933 void KMainWindowPrivate::_k_slotSaveAutoSaveSize()
934 {
935  if (autoSaveGroup.isValid()) {
936  KWindowConfig::saveWindowSize(q->windowHandle(), autoSaveGroup);
937  }
938 }
939 
940 void KMainWindowPrivate::_k_slotSaveAutoSavePosition()
941 {
942  if (autoSaveGroup.isValid()) {
943  KWindowConfig::saveWindowPosition(q->windowHandle(), autoSaveGroup);
944  }
945 }
946 
948 {
949  QString childName = name;
950  if (childName.isEmpty()) {
951  childName = QStringLiteral("mainToolBar");
952  }
953 
954  KToolBar *tb = findChild<KToolBar *>(childName);
955  if (tb) {
956  return tb;
957  }
958 
959  KToolBar *toolbar = new KToolBar(childName, this); // non-XMLGUI toolbar
960  return toolbar;
961 }
962 
964 {
965  QList<KToolBar *> ret;
966 
967  const auto theChildren = children();
968  for (QObject *child : theChildren)
969  if (KToolBar *toolBar = qobject_cast<KToolBar *>(child)) {
970  ret.append(toolBar);
971  }
972 
973  return ret;
974 }
975 
977 {
978  return *sMemberList();
979 }
980 
982 {
983  Q_D(const KMainWindow);
984 
985  return d->dbusName;
986 }
987 
988 #include "moc_kmainwindow.cpp"
989 #include "kmainwindow.moc"
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:1379
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:606
void setWindowRole(const QString &role)
bool hasDefault(const QString &key) const
KCONFIGGUI_EXPORT void restoreWindowPosition(QWindow *window, const KConfigGroup &config)
QStyle * style() const const
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)
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 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).
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)
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:109
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:91
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.
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)
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:1394
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 Mon Jan 18 2021 22:52:36 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.