File indexing completed on 2024-05-19 04:55:51

0001 /**
0002  * \file kdemainwindow.cpp
0003  * KDE Kid3 main window.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 9 Jan 2003
0008  *
0009  * Copyright (C) 2003-2024  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #include "kdemainwindow.h"
0028 #include <kconfigwidgets_version.h>
0029 #include <kconfig_version.h>
0030 #include <KToggleAction>
0031 #include <KStandardAction>
0032 #include <KShortcutsDialog>
0033 #include <KRecentFilesAction>
0034 #include <KActionCollection>
0035 #include <KEditToolBar>
0036 #include <KConfigSkeleton>
0037 #include <QApplication>
0038 #include <QUrl>
0039 #include <QAction>
0040 #include "config.h"
0041 #include "kid3form.h"
0042 #include "filelist.h"
0043 #include "sectionactions.h"
0044 #include "kid3application.h"
0045 #include "kdeconfigdialog.h"
0046 #include "guiconfig.h"
0047 #include "tagconfig.h"
0048 #include "useractionsconfig.h"
0049 #include "serverimporter.h"
0050 #include "servertrackimporter.h"
0051 
0052 /**
0053  * Constructor.
0054  *
0055  * @param platformTools platform specific tools
0056  * @param app application context
0057  * @param parent parent widget
0058  */
0059 KdeMainWindow::KdeMainWindow(IPlatformTools* platformTools,
0060                              Kid3Application* app, QWidget* parent)
0061   : KXmlGuiWindow(parent),
0062     BaseMainWindow(this, platformTools, app),
0063     m_platformTools(platformTools), m_fileOpenRecent(nullptr),
0064     m_settingsShowStatusbar(nullptr),
0065     m_settingsAutoHideTags(nullptr), m_settingsShowHidePicture(nullptr)
0066 {
0067   init();
0068 }
0069 
0070 /** Only defined for generation of translation files */
0071 #define MAIN_TOOLBAR_FOR_PO QT_TRANSLATE_NOOP("@default", "Main Toolbar")
0072 
0073 /**
0074  * Init menu and toolbar actions.
0075  */
0076 void KdeMainWindow::initActions()
0077 {
0078   KActionCollection* collection = actionCollection();
0079 #if KCONFIGWIDGETS_VERSION >= 0x051700
0080   QAction* action = KStandardAction::open(
0081       impl(), &BaseMainWindowImpl::slotFileOpen, collection);
0082 #else
0083   QAction* action = KStandardAction::open(
0084       impl(), SLOT(slotFileOpen()), collection);
0085 #endif
0086   action->setStatusTip(tr("Open files"));
0087 #if KCONFIGWIDGETS_VERSION >= 0x051700
0088   m_fileOpenRecent = KStandardAction::openRecent(
0089       this, &KdeMainWindow::slotFileOpenRecentUrl, collection);
0090 #else
0091   m_fileOpenRecent = KStandardAction::openRecent(
0092       this, SLOT(slotFileOpenRecentUrl(QUrl)), collection);
0093 #endif
0094   m_fileOpenRecent->setStatusTip(tr("Opens a recently used folder"));
0095 #if KCONFIGWIDGETS_VERSION >= 0x051700
0096   action = KStandardAction::revert(
0097       app(), &Kid3Application::revertFileModifications, collection);
0098 #else
0099   action = KStandardAction::revert(
0100       app(), SLOT(revertFileModifications()), collection);
0101 #endif
0102   action->setStatusTip(
0103       tr("Reverts the changes of all or the selected files"));
0104   collection->setDefaultShortcuts(action,
0105                           KStandardShortcut::shortcut(KStandardShortcut::Undo));
0106 #if KCONFIGWIDGETS_VERSION >= 0x051700
0107   action = KStandardAction::save(
0108       impl(), &BaseMainWindowImpl::slotFileSave, collection);
0109 #else
0110   action = KStandardAction::save(
0111       impl(), SLOT(slotFileSave()), collection);
0112 #endif
0113   action->setStatusTip(tr("Saves the changed files"));
0114 #if KCONFIGWIDGETS_VERSION >= 0x051700
0115   action = KStandardAction::quit(
0116       impl(), &BaseMainWindowImpl::slotFileQuit, collection);
0117 #else
0118   action = KStandardAction::quit(
0119       impl(), SLOT(slotFileQuit()), collection);
0120 #endif
0121   action->setStatusTip(tr("Quits the application"));
0122 #if KCONFIGWIDGETS_VERSION >= 0x051700
0123   action = KStandardAction::selectAll(
0124       form(), &Kid3Form::selectAllFiles, collection);
0125 #else
0126   action = KStandardAction::selectAll(
0127       form(), SLOT(selectAllFiles()), collection);
0128 #endif
0129   action->setStatusTip(tr("Select all files"));
0130   action->setShortcut(QKeySequence(QLatin1String("Alt+Shift+A")));
0131 #if KCONFIGWIDGETS_VERSION >= 0x051700
0132   action = KStandardAction::deselect(
0133       form(), &Kid3Form::deselectAllFiles, collection);
0134 #else
0135   action = KStandardAction::deselect(
0136       form(), SLOT(deselectAllFiles()), collection);
0137 #endif
0138   action->setStatusTip(tr("Deselect all files"));
0139 #if KCONFIGWIDGETS_VERSION >= 0x051700
0140   action = KStandardAction::find(
0141       impl(), &BaseMainWindowImpl::find, collection);
0142 #else
0143   action = KStandardAction::find(
0144       impl(), SLOT(find()), collection);
0145 #endif
0146   action->setStatusTip(tr("Find"));
0147 #if KCONFIGWIDGETS_VERSION >= 0x051700
0148   action = KStandardAction::replace(
0149       impl(), &BaseMainWindowImpl::findReplace, collection);
0150 #else
0151   action = KStandardAction::replace(
0152       impl(), SLOT(findReplace()), collection);
0153 #endif
0154   action->setStatusTip(tr("Find and replace"));
0155   setStandardToolBarMenuEnabled(true);
0156   createStandardStatusBarAction();
0157 #if KCONFIGWIDGETS_VERSION >= 0x051700
0158   action = KStandardAction::keyBindings(
0159     this, &KdeMainWindow::slotSettingsShortcuts, collection);
0160 #else
0161   action = KStandardAction::keyBindings(
0162     this, SLOT(slotSettingsShortcuts()), collection);
0163 #endif
0164   action->setStatusTip(tr("Configure Shortcuts"));
0165 #if KCONFIGWIDGETS_VERSION >= 0x051700
0166   action = KStandardAction::configureToolbars(
0167     this, &KdeMainWindow::slotSettingsToolbars, collection);
0168 #else
0169   action = KStandardAction::configureToolbars(
0170     this, SLOT(slotSettingsToolbars()), collection);
0171 #endif
0172   action->setStatusTip(tr("Configure Toolbars"));
0173 #if KCONFIGWIDGETS_VERSION >= 0x051700
0174   m_settingsShowStatusbar = KStandardAction::showStatusbar(
0175     this, &KdeMainWindow::slotSettingsShowStatusbar, collection);
0176 #else
0177   m_settingsShowStatusbar = KStandardAction::showStatusbar(
0178     this, SLOT(slotSettingsShowStatusbar()), collection);
0179 #endif
0180   m_settingsShowStatusbar->setStatusTip(tr("Enables/disables the statusbar"));
0181 #if KCONFIGWIDGETS_VERSION >= 0x051700
0182   action = KStandardAction::preferences(
0183       this, &KdeMainWindow::slotSettingsConfigure, collection);
0184 #else
0185   action = KStandardAction::preferences(
0186       this, SLOT(slotSettingsConfigure()), collection);
0187 #endif
0188   action->setStatusTip(tr("Preferences dialog"));
0189 
0190   action = new QAction(QIcon::fromTheme(QLatin1String("document-open")),
0191                        tr("O&pen Folder..."), this);
0192   action->setStatusTip(tr("Opens a folder"));
0193   action->setShortcut(QKeySequence(QLatin1String("Ctrl+D")));
0194   collection->addAction(QLatin1String("open_directory"), action);
0195   connect(action, &QAction::triggered,
0196           impl(), &BaseMainWindowImpl::slotFileOpenDirectory);
0197 
0198   action = new QAction(QIcon::fromTheme(QLatin1String("view-refresh")),
0199                        tr("Re&load"), this);
0200   action->setStatusTip(tr("Reload folder"));
0201   // When using the KDE version on GNOME, a dialog appears "There are two
0202   // actions (Replace..., Reload) that want to use the same shortcut (Ctrl+R)".
0203   // Avoid this by assigning Qt::Key_F5 instead of QKeySequence::Refresh.
0204   // The section "Standard Shortcuts" in the QKeySequence documentation lists
0205   // F5 as a key for "Refresh" on all platforms.
0206   action->setShortcut(Qt::Key_F5);
0207   collection->addAction(QLatin1String("reload"), action);
0208   connect(action, &QAction::triggered,
0209           impl(), &BaseMainWindowImpl::slotFileReload);
0210 
0211   action = new QAction(tr("Unload"), this);
0212   collection->addAction(QLatin1String("unload"), action);
0213   connect(action, &QAction::triggered, app(), &Kid3Application::unloadAllTags);
0214 
0215   action = new QAction(QIcon::fromTheme(QLatin1String("document-import")),
0216                        tr("&Import..."), this);
0217   action->setStatusTip(tr("Import from file or clipboard"));
0218   action->setData(-1);
0219   collection->addAction(QLatin1String("import"), action);
0220   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotImport);
0221 
0222   int importerIdx = 0;
0223   const auto sis = app()->getServerImporters();
0224   for (const ServerImporter* si : sis) {
0225     QString serverName(QCoreApplication::translate("@default", si->name()));
0226     QString actionName = QString::fromLatin1(si->name()).toLower()
0227         .remove(QLatin1Char(' '));
0228     if (int dotPos = actionName.indexOf(QLatin1Char('.')); dotPos != -1)
0229       actionName.truncate(dotPos);
0230     actionName = QLatin1String("import_") + actionName;
0231     action = new QAction(tr("Import from %1...").arg(serverName), this);
0232     action->setData(importerIdx);
0233     action->setStatusTip(tr("Import from %1").arg(serverName));
0234     collection->addAction(actionName, action);
0235     connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotImport);
0236     ++importerIdx;
0237   }
0238 
0239   const auto stis = app()->getServerTrackImporters();
0240   for (const ServerTrackImporter* si : stis) {
0241     QString serverName(QCoreApplication::translate("@default", si->name()));
0242     QString actionName = QString::fromLatin1(si->name()).toLower()
0243         .remove(QLatin1Char(' '));
0244     if (int dotPos = actionName.indexOf(QLatin1Char('.')); dotPos != -1)
0245       actionName.truncate(dotPos);
0246     actionName = QLatin1String("import_") + actionName;
0247     action = new QAction(tr("Import from %1...").arg(serverName), this);
0248     action->setStatusTip(tr("Import from %1").arg(serverName));
0249     action->setData(importerIdx);
0250     collection->addAction(actionName, action);
0251     connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotImport);
0252     ++importerIdx;
0253   }
0254 
0255   action = new QAction(tr("Import from Tags..."), this);
0256   action->setStatusTip(tr("Import from Tags"));
0257   collection->addAction(QLatin1String("import_tags"), action);
0258   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotTagImport);
0259 
0260   action = new QAction(tr("Automatic I&mport..."), this);
0261   action->setStatusTip(tr("Automatic import"));
0262   collection->addAction(QLatin1String("batch_import"), action);
0263   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotBatchImport);
0264 
0265   action = new QAction(tr("&Browse Cover Art..."), this);
0266   action->setStatusTip(tr("Browse album cover artwork"));
0267   collection->addAction(QLatin1String("browse_cover_art"), action);
0268   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotBrowseCoverArt);
0269   action = new QAction(QIcon::fromTheme(QLatin1String("document-export")),
0270                        tr("&Export..."), this);
0271   action->setStatusTip(tr("Export to file or clipboard"));
0272   collection->addAction(QLatin1String("export"), action);
0273   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotExport);
0274   action = new QAction(QIcon::fromTheme(QLatin1String("view-media-playlist")),
0275                        tr("&Create Playlist..."), this);
0276   action->setStatusTip(tr("Create M3U Playlist"));
0277   collection->addAction(QLatin1String("create_playlist"), action);
0278   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotPlaylistDialog);
0279   action = new QAction(tr("Apply &Filename Format"), this);
0280   action->setStatusTip(tr("Apply Filename Format"));
0281   collection->addAction(QLatin1String("apply_filename_format"), action);
0282   connect(action, &QAction::triggered, app(), &Kid3Application::applyFilenameFormat);
0283   action = new QAction(tr("Apply &Tag Format"), this);
0284   action->setStatusTip(tr("Apply Tag Format"));
0285   collection->addAction(QLatin1String("apply_id3_format"), action);
0286   connect(action, &QAction::triggered, app(), &Kid3Application::applyTagFormat);
0287   action = new QAction(tr("Apply Text &Encoding"), this);
0288   action->setStatusTip(tr("Apply Text Encoding"));
0289   collection->addAction(QLatin1String("apply_text_encoding"), action);
0290   connect(action, &QAction::triggered, app(), &Kid3Application::applyTextEncoding);
0291   action = new QAction(tr("&Rename Folder..."), this);
0292   action->setStatusTip(tr("Rename Folder"));
0293   collection->addAction(QLatin1String("rename_directory"), action);
0294   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotRenameDirectory);
0295   action = new QAction(tr("&Number Tracks..."), this);
0296   action->setStatusTip(tr("Number Tracks"));
0297   collection->addAction(QLatin1String("number_tracks"), action);
0298   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotNumberTracks);
0299   action = new QAction(tr("F&ilter..."), this);
0300   action->setStatusTip(tr("Filter"));
0301   collection->addAction(QLatin1String("filter"), action);
0302   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::slotFilter);
0303   if (const TagConfig& tagCfg = TagConfig::instance();
0304       tagCfg.taggedFileFeatures() & TaggedFile::TF_ID3v24) {
0305     action = new QAction(tr("Convert ID3v2.3 to ID3v2.&4"), this);
0306     action->setStatusTip(tr("Convert ID3v2.3 to ID3v2.4"));
0307     collection->addAction(QLatin1String("convert_to_id3v24"), action);
0308     connect(action, &QAction::triggered, app(), &Kid3Application::convertToId3v24);
0309     if (tagCfg.taggedFileFeatures() & TaggedFile::TF_ID3v23) {
0310       action = new QAction(tr("Convert ID3v2.4 to ID3v2.&3"), this);
0311       action->setStatusTip(tr("Convert ID3v2.4 to ID3v2.3"));
0312       collection->addAction(QLatin1String("convert_to_id3v23"), action);
0313       connect(action, &QAction::triggered, app(), &Kid3Application::convertToId3v23);
0314     }
0315   }
0316 #ifdef HAVE_QTMULTIMEDIA
0317   action = new QAction(QIcon::fromTheme(QLatin1String("media-playback-start")),
0318                        tr("&Play"), this);
0319   action->setStatusTip(tr("Play"));
0320   collection->addAction(QLatin1String("play"), action);
0321   connect(action, &QAction::triggered, app(), &Kid3Application::playAudio);
0322 #endif
0323   m_settingsShowHidePicture = new KToggleAction(tr("Show &Picture"), this);
0324   m_settingsShowHidePicture->setStatusTip(tr("Show Picture"));
0325   m_settingsShowHidePicture->setCheckable(true);
0326   collection->addAction(QLatin1String("hide_picture"), m_settingsShowHidePicture);
0327   connect(m_settingsShowHidePicture, &QAction::triggered,
0328           impl(), &BaseMainWindowImpl::slotSettingsShowHidePicture);
0329   m_settingsAutoHideTags = new KToggleAction(tr("Auto &Hide Tags"), this);
0330   m_settingsAutoHideTags->setStatusTip(tr("Auto Hide Tags"));
0331   m_settingsAutoHideTags->setCheckable(true);
0332   collection->addAction(QLatin1String("auto_hide_tags"), m_settingsAutoHideTags);
0333   connect(m_settingsAutoHideTags, &QAction::triggered,
0334           impl(), &BaseMainWindowImpl::slotSettingsAutoHideTags);
0335   action = new QAction(tr("Select All in &Folder"), this);
0336   action->setStatusTip(tr("Select all files in the current folder"));
0337   collection->addAction(QLatin1String("select_all_in_directory"), action);
0338   connect(action, &QAction::triggered, app(), &Kid3Application::selectAllInDirectory);
0339   action = new QAction(tr("&Invert Selection"), this);
0340   collection->addAction(QLatin1String("invert_selection"), action);
0341   connect(action, &QAction::triggered, app(), &Kid3Application::invertSelection);
0342   action = new QAction(QIcon::fromTheme(QLatin1String("go-previous")),
0343                        tr("&Previous File"), this);
0344   action->setStatusTip(tr("Select previous file"));
0345   collection->setDefaultShortcuts(action,
0346                          KStandardShortcut::shortcut(KStandardShortcut::Prior));
0347   collection->addAction(QLatin1String("previous_file"), action);
0348   connect(action, &QAction::triggered, form(), &Kid3Form::selectPreviousTaggedFile);
0349   action = new QAction(QIcon::fromTheme(QLatin1String("go-next")),
0350                        tr("&Next File"), this);
0351   action->setStatusTip(tr("Select next file"));
0352   collection->setDefaultShortcuts(action,
0353                          KStandardShortcut::shortcut(KStandardShortcut::Next));
0354   collection->addAction(QLatin1String("next_file"), action);
0355   connect(action, &QAction::triggered, form(), &Kid3Form::selectNextTaggedFile);
0356   FOR_ALL_TAGS(tagNr) {
0357     Frame::TagNumber otherTagNr = tagNr == Frame::Tag_1
0358         ? Frame::Tag_2
0359         : tagNr == Frame::Tag_2 ? Frame::Tag_1 : Frame::Tag_NumValues;
0360     QString tagStr = Frame::tagNumberToString(tagNr);
0361     Kid3ApplicationTagContext* appTag = app()->tag(tagNr);
0362     Kid3FormTagContext* formTag = form()->tag(tagNr);
0363     QString actionPrefix = tr("Tag %1").arg(tagStr) +
0364         QLatin1String(": ");
0365     action = new QAction(tr("Filename") + QLatin1String(": ") +
0366                          tr("From Tag %1").arg(tagStr), this);
0367     collection->addAction(QLatin1String("filename_from_v") + tagStr, action);
0368     connect(action, &QAction::triggered,
0369             appTag, &Kid3ApplicationTagContext::getFilenameFromTags);
0370     tagStr = QLatin1Char('v') + tagStr + QLatin1Char('_');
0371     action = new QAction(actionPrefix + tr("From Filename"), this);
0372     collection->addAction(tagStr + QLatin1String("from_filename"), action);
0373     connect(action, &QAction::triggered,
0374             appTag, &Kid3ApplicationTagContext::getTagsFromFilename);
0375     if (otherTagNr < Frame::Tag_NumValues) {
0376       QString otherTagStr = Frame::tagNumberToString(otherTagNr);
0377       action = new QAction(actionPrefix + tr("From Tag %1").arg(otherTagStr),
0378                            this);
0379       collection->addAction(tagStr + QLatin1String("from_v") + otherTagStr,
0380                             action);
0381       connect(action, &QAction::triggered,
0382               appTag, &Kid3ApplicationTagContext::copyToOtherTag);
0383     }
0384     action = new QAction(actionPrefix + tr("Copy"), this);
0385     collection->addAction(tagStr + QLatin1String("copy"), action);
0386     connect(action, &QAction::triggered,
0387             appTag, &Kid3ApplicationTagContext::copyTags);
0388     action = new QAction(actionPrefix + tr("Paste"), this);
0389     collection->addAction(tagStr + QLatin1String("paste"), action);
0390     connect(action, &QAction::triggered,
0391             appTag, &Kid3ApplicationTagContext::pasteTags);
0392     action = new QAction(actionPrefix + tr("Remove"), this);
0393     collection->addAction(tagStr + QLatin1String("remove"), action);
0394     connect(action, &QAction::triggered,
0395             appTag, &Kid3ApplicationTagContext::removeTags);
0396     action = new QAction(actionPrefix + tr("Focus"), this);
0397     collection->addAction(tagStr + QLatin1String("focus"), action);
0398     connect(action, &QAction::triggered,
0399             formTag, &Kid3FormTagContext::setFocusTag);
0400     if (tagNr != Frame::Tag_Id3v1) {
0401       actionPrefix += tr("Frames:") + QLatin1Char(' ');
0402       action = new QAction(actionPrefix + tr("Edit"), this);
0403       collection->addAction(tagStr + QLatin1String("frames_edit"), action);
0404       connect(action, &QAction::triggered,
0405               appTag, &Kid3ApplicationTagContext::editFrame);
0406       action = new QAction(actionPrefix + tr("Add"), this);
0407       collection->addAction(tagStr + QLatin1String("frames_add"), action);
0408       connect(action, &QAction::triggered,
0409               appTag, &Kid3ApplicationTagContext::addFrame);
0410       action = new QAction(actionPrefix + tr("Delete"), this);
0411       collection->addAction(tagStr + QLatin1String("frames_delete"), action);
0412       connect(action, &QAction::triggered,
0413               appTag, &Kid3ApplicationTagContext::deleteFrame);
0414     }
0415   }
0416 
0417   action = new QAction(tr("Filename") + QLatin1String(": ") + tr("Focus"),
0418                        this);
0419   collection->addAction(QLatin1String("filename_focus"), action);
0420   connect(action, &QAction::triggered, form(), &Kid3Form::setFocusFilename);
0421 
0422   action = new QAction(tr("File List") + QLatin1String(": ") + tr("Focus"),
0423                        this);
0424   collection->addAction(QLatin1String("filelist_focus"), action);
0425   connect(action, &QAction::triggered, form(), &Kid3Form::setFocusFileList);
0426   action = new QAction(tr("&Rename"), this);
0427   action->setShortcut(QKeySequence(Qt::Key_F2));
0428   action->setShortcutContext(Qt::WidgetShortcut);
0429   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::renameFile);
0430   // This action is not made configurable because its shortcut F2 conflicts
0431   // with a section shortcut and there seems to be no way to avoid it with
0432   // KShortcutsDialog. The same applies to the shortcut with the Delete key.
0433   // collection->addAction(QLatin1String("filelist_rename"), action);
0434   form()->getFileList()->setRenameAction(action);
0435   action = new QAction(tr("&Move to Trash"), this);
0436   action->setShortcut(QKeySequence::Delete);
0437   action->setShortcutContext(Qt::WidgetShortcut);
0438   connect(action, &QAction::triggered, impl(), &BaseMainWindowImpl::deleteFile);
0439   // collection->addAction(QLatin1String("filelist_delete"), action);
0440   form()->getFileList()->setDeleteAction(action);
0441   action = new QAction(tr("Folder List") + QLatin1String(": ") + tr("Focus"),
0442                        this);
0443   collection->addAction(QLatin1String("dirlist_focus"), action);
0444   connect(action, &QAction::triggered, form(), &Kid3Form::setFocusDirList);
0445 
0446   FileList* fileList = form()->getFileList();
0447   // Do not support user action keyboard shortcuts with KDE 4, it would only
0448   // print "Attempt to use QAction (..) with KXMLGUIFactory!" warnings.
0449   connect(fileList, &FileList::userActionAdded,
0450           this, &KdeMainWindow::onUserActionAdded);
0451   connect(fileList, &FileList::userActionRemoved,
0452           this, &KdeMainWindow::onUserActionRemoved);
0453   fileList->initUserActions();
0454   const UserActionsConfig& userActionsCfg = UserActionsConfig::instance();
0455   connect(&userActionsCfg, &UserActionsConfig::contextMenuCommandsChanged,
0456           fileList, &FileList::initUserActions);
0457 
0458   const auto sectionShortcuts = SectionActions::defaultShortcuts();
0459   QString actionPrefix = tr("Section") + QLatin1String(": ");
0460   for (auto it = sectionShortcuts.constBegin();
0461        it != sectionShortcuts.constEnd();
0462        ++it) {
0463     const auto& tpl = *it;
0464     action = new QAction(actionPrefix + std::get<1>(tpl), this);
0465     action->setShortcutContext(Qt::WidgetShortcut);
0466     // The action is only used to configure the shortcuts. Disabling it will
0467     // also avoid "that want to use the same shortcut" error dialogs.
0468     action->setEnabled(false);
0469     collection->setDefaultShortcut(action, std::get<2>(tpl));
0470     collection->addAction(std::get<0>(tpl), action);
0471   }
0472 
0473   actionPrefix = tr("Player") + QLatin1String(": ");
0474   const auto actions = impl()->mediaActions();
0475   for (QAction* mediaAction : actions) {
0476     mediaAction->setText(actionPrefix + mediaAction->text());
0477     collection->addAction(mediaAction->objectName(), mediaAction);
0478   }
0479 
0480   createGUI();
0481 }
0482 
0483 /**
0484  * Get keyboard shortcuts.
0485  * @return mapping of action names to key sequences.
0486  */
0487 QMap<QString, QKeySequence> KdeMainWindow::shortcutsMap() const
0488 {
0489   QMap<QString, QKeySequence> map;
0490   if (KActionCollection* collection = actionCollection()) {
0491     const auto actions = collection->actions();
0492     for (QAction* action : actions) {
0493       if (action) {
0494         if (QString name = action->objectName(); !name.isEmpty()) {
0495           map.insert(name, action->shortcut());
0496         }
0497       }
0498     }
0499   }
0500   return map;
0501 }
0502 
0503 /**
0504  * Add directory to recent files list.
0505  *
0506  * @param dirName path to directory
0507  */
0508 void KdeMainWindow::addDirectoryToRecentFiles(const QString& dirName)
0509 {
0510   QUrl url;
0511   url.setPath(dirName);
0512   m_fileOpenRecent->addUrl(url);
0513 }
0514 
0515 /**
0516  * Read settings from the configuration.
0517  */
0518 void KdeMainWindow::readConfig()
0519 {
0520   auto cfg = KSharedConfig::openConfig();
0521 #if KCONFIG_VERSION >= 0x054300
0522   auto stateCfg = KSharedConfig::openStateConfig();
0523 #else
0524   auto stateCfg = cfg;
0525 #endif
0526   setAutoSaveSettings(stateCfg->group("MainWindow"));
0527   m_settingsShowHidePicture->setChecked(!GuiConfig::instance().hidePicture());
0528   m_settingsAutoHideTags->setChecked(GuiConfig::instance().autoHideTags());
0529   m_fileOpenRecent->loadEntries(stateCfg->group("Recent Files"));
0530 
0531   QString entry = cfg->group("MainWindow").readEntry("StatusBar", "Enabled");
0532   bool statusBarVisible = entry != QLatin1String("Disabled");
0533   if (m_settingsShowStatusbar) {
0534     m_settingsShowStatusbar->setChecked(statusBarVisible);
0535   }
0536   setStatusBarVisible(statusBarVisible);
0537 }
0538 
0539 /**
0540  * Store geometry and recent files in settings.
0541  */
0542 void KdeMainWindow::saveConfig()
0543 {
0544 #if KCONFIG_VERSION >= 0x054300
0545   auto stateCfg = KSharedConfig::openStateConfig();
0546 #else
0547   auto stateCfg = KSharedConfig::openConfig();
0548 #endif
0549   m_fileOpenRecent->saveEntries(stateCfg->group("Recent Files"));
0550 }
0551 
0552 /**
0553  * Set main window caption.
0554  *
0555  * @param caption caption without application name
0556  * @param modified true if any file is modified
0557  */
0558 void KdeMainWindow::setWindowCaption(const QString& caption, bool modified)
0559 {
0560   setCaption(caption, modified);
0561 }
0562 
0563 /**
0564  * Get action for Settings/Auto Hide Tags.
0565  * @return action.
0566  */
0567 QAction* KdeMainWindow::autoHideTagsAction()
0568 {
0569   return m_settingsAutoHideTags;
0570 }
0571 
0572 /**
0573  * Get action for Settings/Hide Picture.
0574  * @return action.
0575  */
0576 QAction* KdeMainWindow::showHidePictureAction()
0577 {
0578  return m_settingsShowHidePicture;
0579 }
0580 
0581 /**
0582  * Update modification state before closing.
0583  * Called on closeEvent() of window.
0584  * If anything was modified, save after asking user.
0585  * Save options before closing.
0586  * This method is called by closeEvent(), which occurs when the
0587  * window is closed or slotFileQuit() (Quit menu) is selected.
0588  *
0589  * @return false if user canceled,
0590  *         true will quit the application.
0591  */
0592 bool KdeMainWindow::queryClose()
0593 {
0594   return queryBeforeClosing();
0595 }
0596 
0597 /**
0598  * Saves the window properties to the session config file.
0599  *
0600  * @param cfg application configuration
0601  */
0602 void KdeMainWindow::saveProperties(KConfigGroup& cfg)
0603 {
0604   cfg.writeEntry("dirname", app()->getDirName());
0605 }
0606 
0607 /**
0608  * Reads the session config file and restores the application's state.
0609  *
0610  * @param cfg application configuration
0611  */
0612 void KdeMainWindow::readProperties(const KConfigGroup& cfg)
0613 {
0614   app()->openDirectory({cfg.readEntry("dirname", "")});
0615 }
0616 
0617 /**
0618  * Open recent directory.
0619  *
0620  * @param url URL of directory to open
0621  */
0622 void KdeMainWindow::slotFileOpenRecentUrl(const QUrl& url)
0623 {
0624   openRecentDirectory(url.path());
0625 }
0626 
0627 /**
0628  * Shortcuts configuration.
0629  */
0630 void KdeMainWindow::slotSettingsShortcuts()
0631 {
0632 #if KCONFIGWIDGETS_VERSION >= 0x05f000
0633   KShortcutsDialog::showDialog(
0634         actionCollection(),
0635         KShortcutsEditor::LetterShortcutsAllowed, this);
0636   impl()->applyChangedShortcuts();
0637 #else
0638   if (KShortcutsDialog::configure(
0639         actionCollection(),
0640         KShortcutsEditor::LetterShortcutsAllowed, this) ==
0641       QDialog::Accepted) {
0642     impl()->applyChangedShortcuts();
0643   }
0644 #endif
0645 }
0646 
0647 /**
0648  * Toolbars configuration.
0649  */
0650 void KdeMainWindow::slotSettingsToolbars()
0651 {
0652   if (KEditToolBar dlg(actionCollection()); dlg.exec()) {
0653     createGUI();
0654   }
0655 }
0656 
0657 /**
0658  * Statusbar configuration.
0659  */
0660 void KdeMainWindow::slotSettingsShowStatusbar()
0661 {
0662   setStatusBarVisible(m_settingsShowStatusbar->isChecked());
0663   setSettingsDirty();
0664 }
0665 
0666 /**
0667  * Preferences.
0668  */
0669 void KdeMainWindow::slotSettingsConfigure()
0670 {
0671   QString caption(tr("Configure - Kid3"));
0672   auto configSkeleton = new KConfigSkeleton;
0673   auto dialog = new KdeConfigDialog(m_platformTools, this, caption,
0674                                                 configSkeleton);
0675   dialog->setConfig();
0676   if (dialog->exec() == QDialog::Accepted) {
0677     dialog->getConfig();
0678     impl()->applyChangedConfiguration();
0679   }
0680   delete configSkeleton;
0681 }
0682 
0683 /**
0684  * Add user action to collection.
0685  * @param name name of action
0686  * @param action action to add
0687  */
0688 void KdeMainWindow::onUserActionAdded(const QString& name, QAction* action)
0689 {
0690   KActionCollection* collection = actionCollection();
0691   collection->addAction(name, action);
0692 }
0693 
0694 /**
0695  * Remove user action from collection.
0696  * @param name name of action
0697  * @param action action to remove
0698  */
0699 void KdeMainWindow::onUserActionRemoved(const QString& name, QAction* action)
0700 {
0701   Q_UNUSED(name)
0702   KActionCollection* collection = actionCollection();
0703   collection->takeAction(action);
0704 }