File indexing completed on 2024-11-24 04:50:43

0001 // SPDX-FileCopyrightText: 2023 Carl Schwan <carlschwan@kde.org>
0002 // SPDX-License-Identifier: LGPL-2.1-or-later
0003 
0004 #include "abstractapplication.h"
0005 #include "commandbarfiltermodel.h"
0006 #include <KAboutData>
0007 #include <KAuthorized>
0008 #include <KConfigGroup>
0009 #include <KLocalizedString>
0010 #include <KSharedConfig>
0011 #include <KShortcutsDialog>
0012 #include <QDebug>
0013 #include <QGuiApplication>
0014 #include <QMenu>
0015 
0016 AbstractApplication::AbstractApplication(QObject *parent)
0017     : QObject(parent)
0018     , mCollection(new KActionCollection(parent))
0019 {
0020 }
0021 
0022 AbstractApplication::~AbstractApplication()
0023 {
0024     if (m_actionModel) {
0025         auto lastUsedActions = m_actionModel->lastUsedActions();
0026         auto cfg = KSharedConfig::openConfig();
0027         KConfigGroup cg(cfg, QStringLiteral("General"));
0028         cg.writeEntry("CommandBarLastUsedActions", lastUsedActions);
0029     }
0030 }
0031 
0032 /**
0033  * A helper function that takes a list of KActionCollection* and converts it
0034  * to KCommandBar::ActionGroup
0035  */
0036 static QList<KalCommandBarModel::ActionGroup> actionCollectionToActionGroup(const QList<KActionCollection *> &actionCollections)
0037 {
0038     using ActionGroup = KalCommandBarModel::ActionGroup;
0039 
0040     QList<ActionGroup> actionList;
0041     actionList.reserve(actionCollections.size());
0042 
0043     for (const auto collection : actionCollections) {
0044         const auto collectionActions = collection->actions();
0045         const auto componentName = collection->componentDisplayName();
0046 
0047         ActionGroup ag;
0048         ag.name = componentName;
0049         ag.actions.reserve(collection->count());
0050         for (const auto action : collectionActions) {
0051             /**
0052              * If this action is a menu, fetch all its child actions
0053              * and skip the menu action itself
0054              */
0055             if (const auto menu = action->menu()) {
0056                 const auto menuActions = menu->actions();
0057 
0058                 ActionGroup menuActionGroup;
0059                 menuActionGroup.name = KLocalizedString::removeAcceleratorMarker(action->text());
0060                 menuActionGroup.actions.reserve(menuActions.size());
0061                 for (const auto mAct : menuActions) {
0062                     if (mAct) {
0063                         menuActionGroup.actions.append(mAct);
0064                     }
0065                 }
0066 
0067                 /**
0068                  * If there were no actions in the menu, we
0069                  * add the menu to the list instead because it could
0070                  * be that the actions are created on demand i.e., aboutToShow()
0071                  */
0072                 if (!menuActions.isEmpty()) {
0073                     actionList.append(menuActionGroup);
0074                     continue;
0075                 }
0076             }
0077 
0078             if (action && !action->text().isEmpty()) {
0079                 ag.actions.append(action);
0080             }
0081         }
0082         actionList.append(ag);
0083     }
0084     return actionList;
0085 }
0086 
0087 QSortFilterProxyModel *AbstractApplication::actionsModel()
0088 {
0089     if (!m_proxyModel) {
0090         m_actionModel = new KalCommandBarModel(this);
0091         m_proxyModel = new CommandBarFilterModel(this);
0092         m_proxyModel->setSortRole(KalCommandBarModel::Score);
0093         m_proxyModel->setFilterRole(Qt::DisplayRole);
0094         m_proxyModel->setSourceModel(m_actionModel);
0095     }
0096 
0097     // setLastUsedActions
0098     auto cfg = KSharedConfig::openConfig();
0099     KConfigGroup cg(cfg, QStringLiteral("General"));
0100 
0101     const auto actionNames = cg.readEntry(QStringLiteral("CommandBarLastUsedActions"), QStringList());
0102 
0103     m_actionModel->setLastUsedActions(actionNames);
0104     m_actionModel->refresh(actionCollectionToActionGroup(actionCollections()));
0105     return m_proxyModel;
0106 }
0107 
0108 void AbstractApplication::configureShortcuts()
0109 {
0110     // TODO replace with QML version
0111     KShortcutsDialog dlg(KShortcutsEditor::ApplicationAction, KShortcutsEditor::LetterShortcutsAllowed, nullptr);
0112     dlg.setModal(true);
0113     const auto collections = actionCollections();
0114     for (const auto collection : collections) {
0115         dlg.addCollection(collection);
0116     }
0117     dlg.configure();
0118 }
0119 
0120 QAction *AbstractApplication::action(const QString &name)
0121 {
0122     const auto collections = actionCollections();
0123     for (const auto collection : collections) {
0124         auto resultAction = collection->action(name);
0125         if (resultAction) {
0126             return resultAction;
0127         }
0128     }
0129 
0130     qWarning() << "Not found action for name" << name;
0131 
0132     return nullptr;
0133 }
0134 
0135 void AbstractApplication::setupActions()
0136 {
0137     auto actionName = QLatin1StringView("open_kcommand_bar");
0138     if (KAuthorized::authorizeAction(actionName)) {
0139         auto openKCommandBarAction = mCollection->addAction(actionName, this, &AbstractApplication::openKCommandBarAction);
0140         openKCommandBarAction->setText(i18n("Open Command Bar"));
0141         openKCommandBarAction->setIcon(QIcon::fromTheme(QStringLiteral("new-command-alarm")));
0142 
0143         mCollection->addAction(openKCommandBarAction->objectName(), openKCommandBarAction);
0144         mCollection->setDefaultShortcut(openKCommandBarAction, QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_I));
0145     }
0146 
0147     actionName = QLatin1StringView("file_quit");
0148     if (KAuthorized::authorizeAction(actionName)) {
0149         auto action = KStandardAction::quit(this, &AbstractApplication::quit, this);
0150         mCollection->addAction(action->objectName(), action);
0151     }
0152 
0153     actionName = QLatin1StringView("switch_application_language");
0154     if (KAuthorized::authorizeAction(actionName)) {
0155         auto action = KStandardAction::switchApplicationLanguage(this, &AbstractApplication::openLanguageSwitcher, this);
0156         mCollection->addAction(action->objectName(), action);
0157     }
0158 
0159     actionName = QLatin1StringView("options_configure_keybinding");
0160     if (KAuthorized::authorizeAction(actionName)) {
0161         auto keyBindingsAction = KStandardAction::keyBindings(this, &AbstractApplication::configureShortcuts, this);
0162         mCollection->addAction(keyBindingsAction->objectName(), keyBindingsAction);
0163     }
0164 
0165     actionName = QLatin1StringView("open_about_page");
0166     if (KAuthorized::authorizeAction(actionName)) {
0167         auto action = mCollection->addAction(actionName, this, &AbstractApplication::openAboutPage);
0168         action->setText(i18n("About %1", KAboutData::applicationData().displayName()));
0169         action->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
0170     }
0171 
0172     actionName = QLatin1StringView("open_about_kde_page");
0173     if (KAuthorized::authorizeAction(actionName)) {
0174         auto action = mCollection->addAction(actionName, this, &AbstractApplication::openAboutKDEPage);
0175         action->setText(i18n("About KDE"));
0176         action->setIcon(QIcon::fromTheme(QStringLiteral("kde")));
0177     }
0178 
0179     actionName = QLatin1StringView("options_configure");
0180     if (KAuthorized::authorizeAction(actionName)) {
0181         auto action = KStandardAction::preferences(this, &AbstractApplication::openSettings, this);
0182         mCollection->addAction(action->objectName(), action);
0183     }
0184 
0185     actionName = QLatin1StringView("open_tag_manager");
0186     if (KAuthorized::authorizeAction(actionName)) {
0187         auto openTagManagerAction = mCollection->addAction(actionName, this, &AbstractApplication::openTagManager);
0188         openTagManagerAction->setText(i18n("Manage Tagsā€¦"));
0189         openTagManagerAction->setIcon(QIcon::fromTheme(QStringLiteral("action-rss_tag")));
0190     }
0191 }
0192 
0193 void AbstractApplication::quit()
0194 {
0195     qGuiApp->exit();
0196 }
0197 
0198 #include "moc_abstractapplication.cpp"