File indexing completed on 2024-06-09 04:26:06
0001 /* This file is part of the KDE libraries 0002 Copyright 0003 (C) 2000 Reginald Stadlbauer (reggie@kde.org) 0004 (C) 1997 Stephan Kulow (coolo@kde.org) 0005 (C) 1997-2000 Sven Radej (radej@kde.org) 0006 (C) 1997-2000 Matthias Ettrich (ettrich@kde.org) 0007 (C) 1999 Chris Schlaeger (cs@kde.org) 0008 (C) 2002 Joseph Wenninger (jowenn@kde.org) 0009 (C) 2005-2006 Hamish Rodda (rodda@kde.org) 0010 0011 SPDX-License-Identifier: LGPL-2.0-only 0012 */ 0013 0014 #include "kxmlguiwindow.h" 0015 0016 #include "config-xmlgui.h" 0017 0018 #include "kmainwindow_p.h" 0019 #include "kactioncollection.h" 0020 #ifdef HAVE_DBUS 0021 #include "kmainwindowiface_p.h" 0022 #endif 0023 #include "ktoolbarhandler_p.h" 0024 #include "kxmlguifactory.h" 0025 #include "kedittoolbar.h" 0026 #include "khelpmenu.h" 0027 #include "ktoolbar.h" 0028 0029 #include <QCloseEvent> 0030 #ifdef HAVE_DBUS 0031 #include <QDBusConnection> 0032 #endif 0033 #include <QDomDocument> 0034 #include <QLayout> 0035 #include <QDebug> 0036 #include <QMenuBar> 0037 #include <QObject> 0038 #include <QStatusBar> 0039 #include <QStyle> 0040 #include <QWidget> 0041 #include <QList> 0042 0043 #include <ktoggleaction.h> 0044 #include <kstandardaction.h> 0045 #include <kconfig.h> 0046 #include <klocalizedstring.h> 0047 #include <kaboutdata.h> 0048 #include <ksharedconfig.h> 0049 #include <kconfiggroup.h> 0050 0051 #include <stdlib.h> 0052 #include <ctype.h> 0053 0054 class KXmlGuiWindowPrivate : public KisKMainWindowPrivate 0055 { 0056 public: 0057 void _k_slotFactoryMakingChanges(bool b) 0058 { 0059 // While the GUI factory is adding/removing clients, 0060 // don't let KisKMainWindow think those are changes made by the user 0061 // #105525 0062 letDirtySettings = !b; 0063 } 0064 0065 bool showHelpMenu: 1; 0066 QSize defaultSize; 0067 0068 KDEPrivate::ToolBarHandler *toolBarHandler; 0069 KToggleAction *showStatusBarAction; 0070 QPointer<KisKEditToolBar> toolBarEditor; 0071 KisKXMLGUIFactory *factory; 0072 }; 0073 0074 KXmlGuiWindow::KXmlGuiWindow(QWidget *parent, Qt::WindowFlags f) 0075 : KisKMainWindow(*new KXmlGuiWindowPrivate, parent, f), KisKXMLGUIBuilder(this) 0076 { 0077 K_D(KXmlGuiWindow); 0078 d->showHelpMenu = true; 0079 d->toolBarHandler = 0; 0080 d->showStatusBarAction = 0; 0081 d->factory = 0; 0082 #ifdef HAVE_DBUS 0083 new KisKMainWindowInterface(this); 0084 #endif 0085 } 0086 0087 QAction *KXmlGuiWindow::toolBarMenuAction() 0088 { 0089 K_D(KXmlGuiWindow); 0090 if (!d->toolBarHandler) { 0091 return 0; 0092 } 0093 0094 return d->toolBarHandler->toolBarMenuAction(); 0095 } 0096 0097 void KXmlGuiWindow::setupToolbarMenuActions() 0098 { 0099 K_D(KXmlGuiWindow); 0100 if (d->toolBarHandler) { 0101 d->toolBarHandler->setupActions(); 0102 } 0103 } 0104 0105 KXmlGuiWindow::~KXmlGuiWindow() 0106 { 0107 K_D(KXmlGuiWindow); 0108 delete d->factory; 0109 } 0110 0111 bool KXmlGuiWindow::event(QEvent *ev) 0112 { 0113 bool ret = KisKMainWindow::event(ev); 0114 #ifdef HAVE_DBUS 0115 if (ev->type() == QEvent::Polish) { 0116 QDBusConnection::sessionBus().registerObject(dbusName() + QStringLiteral("/actions"), actionCollection(), 0117 QDBusConnection::ExportScriptableSlots | 0118 QDBusConnection::ExportScriptableProperties | 0119 QDBusConnection::ExportNonScriptableSlots | 0120 QDBusConnection::ExportNonScriptableProperties | 0121 QDBusConnection::ExportChildObjects); 0122 } 0123 #endif 0124 return ret; 0125 } 0126 0127 void KXmlGuiWindow::setHelpMenuEnabled(bool showHelpMenu) 0128 { 0129 K_D(KXmlGuiWindow); 0130 d->showHelpMenu = showHelpMenu; 0131 } 0132 0133 bool KXmlGuiWindow::isHelpMenuEnabled() const 0134 { 0135 K_D(const KXmlGuiWindow); 0136 return d->showHelpMenu; 0137 } 0138 0139 KisKXMLGUIFactory *KXmlGuiWindow::guiFactory() 0140 { 0141 K_D(KXmlGuiWindow); 0142 if (!d->factory) { 0143 d->factory = new KisKXMLGUIFactory(this, this); 0144 connect(d->factory, SIGNAL(makingChanges(bool)), 0145 this, SLOT(_k_slotFactoryMakingChanges(bool))); 0146 } 0147 return d->factory; 0148 } 0149 0150 void KXmlGuiWindow::configureToolbars() 0151 { 0152 K_D(KXmlGuiWindow); 0153 KConfigGroup cg(KSharedConfig::openConfig(), ""); 0154 saveMainWindowSettings(cg); 0155 if (!d->toolBarEditor) { 0156 d->toolBarEditor = new KisKEditToolBar(guiFactory(), this); 0157 d->toolBarEditor->setAttribute(Qt::WA_DeleteOnClose); 0158 connect(d->toolBarEditor, SIGNAL(newToolBarConfig()), SLOT(saveNewToolbarConfig())); 0159 } 0160 d->toolBarEditor->show(); 0161 } 0162 0163 void KXmlGuiWindow::saveNewToolbarConfig() 0164 { 0165 // createGUI(xmlFile()); // this loses any plugged-in guiclients, so we use remove+add instead. 0166 0167 guiFactory()->removeClient(this); 0168 guiFactory()->addClient(this); 0169 0170 KConfigGroup cg(KSharedConfig::openConfig(), ""); 0171 applyMainWindowSettings(cg); 0172 } 0173 0174 void KXmlGuiWindow::setupGUI(StandardWindowOptions options, const QString &xmlfile) 0175 { 0176 setupGUI(QSize(), options, xmlfile); 0177 } 0178 0179 void KXmlGuiWindow::setupGUI(const QSize &defaultSize, StandardWindowOptions options, const QString &xmlfile) 0180 { 0181 K_D(KXmlGuiWindow); 0182 if (options & Keys) { 0183 KStandardAction::keyBindings(guiFactory(), 0184 SLOT(configureShortcuts()), actionCollection()); 0185 } 0186 if ((options & StatusBar) && statusBar()) { 0187 createStandardStatusBarAction(); 0188 } 0189 0190 if (options & ToolBar) { 0191 setStandardToolBarMenuEnabled(true); 0192 KStandardAction::configureToolbars(this, 0193 SLOT(configureToolbars()), actionCollection()); 0194 } 0195 0196 d->defaultSize = defaultSize; 0197 0198 if (options & Create) { 0199 createGUI(xmlfile); 0200 } 0201 0202 if (d->defaultSize.isValid()) { 0203 resize(d->defaultSize); 0204 } else if (isHidden()) { 0205 adjustSize(); 0206 } 0207 0208 if (options & Save) { 0209 const KConfigGroup cg(autoSaveConfigGroup()); 0210 if (cg.isValid()) { 0211 setAutoSaveSettings(cg); 0212 } else { 0213 setAutoSaveSettings(); 0214 } 0215 } 0216 } 0217 void KXmlGuiWindow::createGUI(const QString &xmlfile) 0218 { 0219 K_D(KXmlGuiWindow); 0220 // disabling the updates prevents unnecessary redraws 0221 //setUpdatesEnabled( false ); 0222 0223 // just in case we are rebuilding, let's remove our old client 0224 guiFactory()->removeClient(this); 0225 0226 // make sure to have an empty GUI 0227 QMenuBar *mb = menuBar(); 0228 if (mb) { 0229 mb->clear(); 0230 } 0231 0232 qDeleteAll(toolBars()); // delete all toolbars 0233 0234 // don't build a help menu unless the user ask for it 0235 if (d->showHelpMenu) { 0236 delete d->helpMenu; 0237 // we always want a help menu 0238 d->helpMenu = new KisKHelpMenu(this, KAboutData::applicationData(), true); 0239 0240 KisKActionCollection *actions = actionCollection(); 0241 QAction *helpContentsAction = d->helpMenu->action(KisKHelpMenu::menuHelpContents); 0242 QAction *whatsThisAction = d->helpMenu->action(KisKHelpMenu::menuWhatsThis); 0243 QAction *reportBugAction = d->helpMenu->action(KisKHelpMenu::menuReportBug); 0244 QAction *switchLanguageAction = d->helpMenu->action(KisKHelpMenu::menuSwitchLanguage); 0245 QAction *aboutAppAction = d->helpMenu->action(KisKHelpMenu::menuAboutApp); 0246 QAction *aboutKdeAction = d->helpMenu->action(KisKHelpMenu::menuAboutKDE); 0247 0248 if (helpContentsAction) { 0249 actions->addAction(helpContentsAction->objectName(), helpContentsAction); 0250 } 0251 if (whatsThisAction) { 0252 actions->addAction(whatsThisAction->objectName(), whatsThisAction); 0253 } 0254 if (reportBugAction) { 0255 actions->addAction(reportBugAction->objectName(), reportBugAction); 0256 } 0257 if (switchLanguageAction) { 0258 actions->addAction(switchLanguageAction->objectName(), switchLanguageAction); 0259 } 0260 if (aboutAppAction) { 0261 actions->addAction(aboutAppAction->objectName(), aboutAppAction); 0262 } 0263 if (aboutKdeAction) { 0264 actions->addAction(aboutKdeAction->objectName(), aboutKdeAction); 0265 } 0266 } 0267 0268 const QString windowXmlFile = xmlfile.isNull() ? componentName() + QStringLiteral("ui.xmlgui") : xmlfile; 0269 0270 // Help beginners who call setXMLFile and then setupGUI... 0271 if (!xmlFile().isEmpty() && xmlFile() != windowXmlFile) { 0272 qWarning() << "You called setXMLFile(" << xmlFile() << ") and then createGUI or setupGUI," 0273 << "which also calls setXMLFile and will overwrite the file you have previously set.\n" 0274 << "You should call createGUI(" << xmlFile() << ") or setupGUI(<options>," << xmlFile() << ") instead."; 0275 } 0276 0277 // we always want to load in our global standards file 0278 loadStandardsXmlFile(); 0279 0280 // now, merge in our local xml file. 0281 setXMLFile(windowXmlFile, true); 0282 0283 // make sure we don't have any state saved already 0284 setXMLGUIBuildDocument(QDomDocument()); 0285 0286 // do the actual GUI building 0287 guiFactory()->reset(); 0288 guiFactory()->addClient(this); 0289 0290 // setUpdatesEnabled( true ); 0291 } 0292 0293 void KXmlGuiWindow::slotStateChanged(const QString &newstate) 0294 { 0295 stateChanged(newstate, KisKXMLGUIClient::StateNoReverse); 0296 } 0297 0298 void KXmlGuiWindow::slotStateChanged(const QString &newstate, 0299 bool reverse) 0300 { 0301 stateChanged(newstate, 0302 reverse ? KisKXMLGUIClient::StateReverse : KisKXMLGUIClient::StateNoReverse); 0303 } 0304 0305 void KXmlGuiWindow::setStandardToolBarMenuEnabled(bool enable) 0306 { 0307 K_D(KXmlGuiWindow); 0308 if (enable) { 0309 if (d->toolBarHandler) { 0310 return; 0311 } 0312 0313 d->toolBarHandler = new KDEPrivate::ToolBarHandler(this); 0314 0315 if (factory()) { 0316 factory()->addClient(d->toolBarHandler); 0317 } 0318 } else { 0319 if (!d->toolBarHandler) { 0320 return; 0321 } 0322 0323 if (factory()) { 0324 factory()->removeClient(d->toolBarHandler); 0325 } 0326 0327 delete d->toolBarHandler; 0328 d->toolBarHandler = 0; 0329 } 0330 } 0331 0332 bool KXmlGuiWindow::isStandardToolBarMenuEnabled() const 0333 { 0334 K_D(const KXmlGuiWindow); 0335 return (d->toolBarHandler); 0336 } 0337 0338 void KXmlGuiWindow::createStandardStatusBarAction() 0339 { 0340 K_D(KXmlGuiWindow); 0341 if (!d->showStatusBarAction) { 0342 d->showStatusBarAction = KStandardAction::showStatusbar(this, SLOT(setSettingsDirty()), actionCollection()); 0343 QStatusBar *sb = statusBar(); // Creates statusbar if it doesn't exist already. 0344 connect(d->showStatusBarAction, SIGNAL(toggled(bool)), sb, SLOT(setVisible(bool))); 0345 d->showStatusBarAction->setChecked(sb->isHidden()); 0346 } else { 0347 // If the language has changed, we'll need to grab the new text and whatsThis 0348 QAction *tmpStatusBar = KStandardAction::showStatusbar(0, 0, 0); 0349 d->showStatusBarAction->setText(tmpStatusBar->text()); 0350 d->showStatusBarAction->setWhatsThis(tmpStatusBar->whatsThis()); 0351 delete tmpStatusBar; 0352 } 0353 } 0354 0355 void KXmlGuiWindow::finalizeGUI(bool /*force*/) 0356 { 0357 // FIXME: this really needs to be removed with a code more like the one we had on KDE3. 0358 // what we need to do here is to position correctly toolbars so they don't overlap. 0359 // Also, take in count plugins could provide their own toolbars and those also need to 0360 // be restored. 0361 if (autoSaveSettings() && autoSaveConfigGroup().isValid()) { 0362 applyMainWindowSettings(autoSaveConfigGroup()); 0363 } 0364 } 0365 0366 void KXmlGuiWindow::applyMainWindowSettings(const KConfigGroup &config) 0367 { 0368 K_D(KXmlGuiWindow); 0369 KisKMainWindow::applyMainWindowSettings(config); 0370 QStatusBar *sb = findChild<QStatusBar *>(); 0371 if (sb && d->showStatusBarAction) { 0372 d->showStatusBarAction->setChecked(!sb->isHidden()); 0373 } 0374 } 0375 0376 // KDE5 TODO: change it to "using KisKXMLGUIBuilder::finalizeGUI;" in the header 0377 // and remove the reimplementation 0378 void KXmlGuiWindow::finalizeGUI(KisKXMLGUIClient *client) 0379 { 0380 KisKXMLGUIBuilder::finalizeGUI(client); 0381 } 0382 0383 #include "moc_kxmlguiwindow.cpp" 0384