File indexing completed on 2024-05-12 05:37:16

0001 /*
0002     SPDX-FileCopyrightText: 2009 Chani Armitage <chani@kde.org>
0003     SPDX-FileCopyrightText: 2018 Eike Hein <hein@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "switch.h"
0009 
0010 #include "abstracttasksmodel.h"
0011 #include "activityinfo.h"
0012 #include "tasksmodel.h"
0013 #include "virtualdesktopinfo.h"
0014 
0015 #include <KConfigGroup>
0016 #include <KPluginFactory>
0017 
0018 #include <QAction>
0019 #include <QMenu>
0020 #include <QVariantMap>
0021 
0022 using namespace TaskManager;
0023 
0024 ActivityInfo *SwitchWindow::s_activityInfo = nullptr;
0025 TasksModel *SwitchWindow::s_tasksModel = nullptr;
0026 int SwitchWindow::s_instanceCount = 0;
0027 
0028 SwitchWindow::SwitchWindow(QObject *parent, const QVariantList &args)
0029     : Plasma::ContainmentActions(parent, args)
0030     , m_mode(AllFlat)
0031     , m_virtualDesktopInfo(new VirtualDesktopInfo(this))
0032 {
0033     ++s_instanceCount;
0034 
0035     if (!s_activityInfo) {
0036         s_activityInfo = new ActivityInfo();
0037     }
0038 
0039     if (!s_tasksModel) {
0040         s_tasksModel = new TasksModel();
0041 
0042         s_tasksModel->setGroupMode(TasksModel::GroupDisabled);
0043 
0044         s_tasksModel->setActivity(s_activityInfo->currentActivity());
0045         s_tasksModel->setFilterByActivity(true);
0046         connect(s_activityInfo, &ActivityInfo::currentActivityChanged, this, []() {
0047             s_tasksModel->setActivity(s_activityInfo->currentActivity());
0048         });
0049     }
0050 }
0051 
0052 SwitchWindow::~SwitchWindow()
0053 {
0054     --s_instanceCount;
0055 
0056     if (!s_instanceCount) {
0057         delete s_activityInfo;
0058         s_activityInfo = nullptr;
0059         delete s_tasksModel;
0060         s_tasksModel = nullptr;
0061     }
0062 
0063     qDeleteAll(m_actions);
0064 }
0065 
0066 void SwitchWindow::restore(const KConfigGroup &config)
0067 {
0068     m_mode = (MenuMode)config.readEntry("mode", (int)AllFlat);
0069 }
0070 
0071 QWidget *SwitchWindow::createConfigurationInterface(QWidget *parent)
0072 {
0073     QWidget *widget = new QWidget(parent);
0074     m_ui.setupUi(widget);
0075     widget->setWindowTitle(i18nc("plasma_containmentactions_switchwindow", "Configure Switch Window Plugin"));
0076     switch (m_mode) {
0077     case AllFlat:
0078         m_ui.flatButton->setChecked(true);
0079         break;
0080     case DesktopSubmenus:
0081         m_ui.subButton->setChecked(true);
0082         break;
0083     case CurrentDesktop:
0084         m_ui.curButton->setChecked(true);
0085         break;
0086     }
0087     return widget;
0088 }
0089 
0090 void SwitchWindow::configurationAccepted()
0091 {
0092     if (m_ui.flatButton->isChecked()) {
0093         m_mode = AllFlat;
0094     } else if (m_ui.subButton->isChecked()) {
0095         m_mode = DesktopSubmenus;
0096     } else {
0097         m_mode = CurrentDesktop;
0098     }
0099 }
0100 
0101 void SwitchWindow::save(KConfigGroup &config)
0102 {
0103     config.writeEntry("mode", (int)m_mode);
0104 }
0105 
0106 void SwitchWindow::makeMenu()
0107 {
0108     qDeleteAll(m_actions);
0109     m_actions.clear();
0110 
0111     if (s_tasksModel->rowCount() == 0) {
0112         return;
0113     }
0114 
0115     QMultiMap<QString, QAction *> desktops;
0116     QList<QAction *> allDesktops;
0117 
0118     // Make all the window actions.
0119     for (int i = 0; i < s_tasksModel->rowCount(); ++i) {
0120         const QModelIndex &idx = s_tasksModel->index(i, 0);
0121 
0122         if (!idx.data(AbstractTasksModel::IsWindow).toBool()) {
0123             continue;
0124         }
0125 
0126         const QString &name = idx.data().toString();
0127 
0128         if (name.isEmpty()) {
0129             continue;
0130         }
0131 
0132         QAction *action = new QAction(name, this);
0133         action->setIcon(idx.data(Qt::DecorationRole).value<QIcon>());
0134         action->setData(idx.data(AbstractTasksModel::WinIdList).toList());
0135 
0136         const QStringList &desktopList = idx.data(AbstractTasksModel::VirtualDesktops).toStringList();
0137 
0138         for (const QString &desktop : desktopList) {
0139             desktops.insert(desktop, action);
0140         }
0141 
0142         if (idx.data(AbstractTasksModel::IsOnAllVirtualDesktops).toBool()) {
0143             allDesktops << action;
0144         }
0145 
0146         connect(action, &QAction::triggered, [=, this]() {
0147             switchTo(action);
0148         });
0149     }
0150 
0151     // Sort into menu(s).
0152     if (m_mode == CurrentDesktop) {
0153         const QString &currentDesktop = m_virtualDesktopInfo->currentDesktop().toString();
0154 
0155         QAction *a = new QAction(i18nc("plasma_containmentactions_switchwindow", "Windows"), this);
0156         a->setSeparator(true);
0157         m_actions << a;
0158         m_actions << desktops.values(currentDesktop);
0159         m_actions << allDesktops;
0160 
0161     } else {
0162         const QVariantList &desktopIds = m_virtualDesktopInfo->desktopIds();
0163         const QStringList &desktopNames = m_virtualDesktopInfo->desktopNames();
0164 
0165         if (m_mode == AllFlat) {
0166             for (int i = 0; i < desktopIds.count(); ++i) {
0167                 const QString &desktop = desktopIds.at(i).toString();
0168 
0169                 if (desktops.contains(desktop)) {
0170                     const QString &name = QStringLiteral("%1: %2").arg(QString::number(i + 1), desktopNames.at(i));
0171                     QAction *a = new QAction(name, this);
0172                     a->setSeparator(true);
0173                     m_actions << a;
0174                     m_actions << desktops.values(desktop);
0175                 }
0176             }
0177 
0178             if (allDesktops.count()) {
0179                 QAction *a = new QAction(i18nc("plasma_containmentactions_switchwindow", "All Desktops"), this);
0180                 a->setSeparator(true);
0181                 m_actions << a;
0182                 m_actions << allDesktops;
0183             }
0184         } else { // Submenus.
0185             for (int i = 0; i < desktopIds.count(); ++i) {
0186                 const QString &desktop = desktopIds.at(i).toString();
0187 
0188                 if (desktops.contains(desktop)) {
0189                     const QString &name = QStringLiteral("%1: %2").arg(QString::number(i + 1), desktopNames.at(i));
0190                     QMenu *subMenu = new QMenu(name);
0191                     subMenu->addActions(desktops.values(desktop));
0192 
0193                     QAction *a = new QAction(name, this);
0194                     a->setMenu(subMenu);
0195                     m_actions << a;
0196                 }
0197             }
0198 
0199             if (allDesktops.count()) {
0200                 QMenu *subMenu = new QMenu(i18nc("plasma_containmentactions_switchwindow", "All Desktops"));
0201                 subMenu->addActions(allDesktops);
0202                 QAction *a = new QAction(i18nc("plasma_containmentactions_switchwindow", "All Desktops"), this);
0203                 a->setMenu(subMenu);
0204                 m_actions << a;
0205             }
0206         }
0207     }
0208 }
0209 
0210 QList<QAction *> SwitchWindow::contextualActions()
0211 {
0212     makeMenu();
0213     return m_actions;
0214 }
0215 
0216 void SwitchWindow::switchTo(QAction *action)
0217 {
0218     const QVariantList &idList = action->data().toList();
0219 
0220     for (int i = 0; i < s_tasksModel->rowCount(); ++i) {
0221         const QModelIndex &idx = s_tasksModel->index(i, 0);
0222 
0223         if (idList == idx.data(AbstractTasksModel::WinIdList).toList()) {
0224             s_tasksModel->requestActivate(idx);
0225 
0226             return;
0227         }
0228     }
0229 }
0230 
0231 void SwitchWindow::performNextAction()
0232 {
0233     doSwitch(true);
0234 }
0235 
0236 void SwitchWindow::performPreviousAction()
0237 {
0238     doSwitch(false);
0239 }
0240 
0241 void SwitchWindow::doSwitch(bool up)
0242 {
0243     const QModelIndex &activeTask = s_tasksModel->activeTask();
0244 
0245     if (!activeTask.isValid()) {
0246         return;
0247     }
0248 
0249     if (up) {
0250         const QModelIndex &next = activeTask.sibling(activeTask.row() + 1, 0);
0251 
0252         if (next.isValid()) {
0253             s_tasksModel->requestActivate(next);
0254         } else if (s_tasksModel->rowCount() > 1) {
0255             s_tasksModel->requestActivate(s_tasksModel->index(0, 0));
0256         }
0257     } else {
0258         const QModelIndex &previous = activeTask.sibling(activeTask.row() - 1, 0);
0259 
0260         if (previous.isValid()) {
0261             s_tasksModel->requestActivate(previous);
0262         } else if (s_tasksModel->rowCount() > 1) {
0263             s_tasksModel->requestActivate(s_tasksModel->index(s_tasksModel->rowCount() - 1, 0));
0264         }
0265     }
0266 }
0267 
0268 K_PLUGIN_CLASS_WITH_JSON(SwitchWindow, "plasma-containmentactions-switchwindow.json")
0269 
0270 #include "switch.moc"