File indexing completed on 2024-04-14 15:49:49

0001 // SPDX-License-Identifier: GPL-3.0-or-later
0002 /*
0003   Copyright 2017 Martin Koller, kollix@aon.at
0004 
0005   This file is part of liquidshell.
0006 
0007   liquidshell is free software: you can redistribute it and/or modify
0008   it under the terms of the GNU General Public License as published by
0009   the Free Software Foundation, either version 3 of the License, or
0010   (at your option) any later version.
0011 
0012   liquidshell is distributed in the hope that it will be useful,
0013   but WITHOUT ANY WARRANTY; without even the implied warranty of
0014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0015   GNU General Public License for more details.
0016 
0017   You should have received a copy of the GNU General Public License
0018   along with liquidshell.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include <StartMenu.hxx>
0022 #include <PopupMenu.hxx>
0023 
0024 #include <QAction>
0025 #include <QContextMenuEvent>
0026 #include <QDBusConnection>
0027 #include <QDBusMessage>
0028 
0029 #include <kio_version.h>
0030 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
0031 #  include <KIO/ApplicationLauncherJob>
0032 #  include <KIO/CommandLauncherJob>
0033 #  include <KIO/JobUiDelegateFactory>
0034 #else
0035 #  include <KRun>
0036 #endif
0037 
0038 #include <KSycoca>
0039 #include <KService>
0040 #include <KLocalizedString>
0041 #include <KIconLoader>
0042 
0043 //--------------------------------------------------------------------------------
0044 
0045 StartMenu::StartMenu(DesktopPanel *parent)
0046   : QToolButton(parent)
0047 {
0048   setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
0049 
0050   setThemeIcon("liquidshell");
0051 
0052   popup = new PopupMenu(this);
0053   connect(this, &QToolButton::pressed, this, &StartMenu::showMenu);
0054 
0055   fill();
0056   adjustIconSize();
0057 
0058   connect(KSycoca::self(), SIGNAL(databaseChanged()), this, SLOT(fill()));
0059   connect(parent, &DesktopPanel::rowsChanged, this, &StartMenu::adjustIconSize);
0060   connect(KIconLoader::global(), &KIconLoader::iconLoaderSettingsChanged, this, &StartMenu::adjustIconSize);
0061 }
0062 
0063 //--------------------------------------------------------------------------------
0064 
0065 void StartMenu::adjustIconSize()
0066 {
0067   const int MAX_ROWS = qobject_cast<DesktopPanel *>(parentWidget())->getRows();
0068 
0069   if ( MAX_ROWS > 1 )
0070     setIconSize(QSize(48, 48));
0071   else
0072   {
0073     int size = KIconLoader::global()->currentSize(KIconLoader::Panel);
0074     setIconSize(QSize(size, size));
0075   }
0076 }
0077 
0078 //--------------------------------------------------------------------------------
0079 
0080 void StartMenu::setThemeIcon(const QString &icon)
0081 {
0082   themeIcon = icon;
0083   setIcon(QIcon::fromTheme(themeIcon));
0084 }
0085 
0086 //--------------------------------------------------------------------------------
0087 
0088 void StartMenu::fill()
0089 {
0090   popup->clear();
0091 
0092   fillFromGroup(popup, KServiceGroup::root());
0093 
0094   popup->addSeparator();
0095 
0096   // add important actions
0097   QAction *action = popup->addAction(QIcon::fromTheme("system-switch-user"), i18n("Switch User"));
0098   connect(action, &QAction::triggered,
0099           []()
0100           {
0101             QDBusConnection::sessionBus().send(
0102                 QDBusMessage::createMethodCall("org.kde.ksmserver", "/KSMServer",
0103                                                "org.kde.KSMServerInterface", "openSwitchUserDialog"));
0104           });
0105 
0106   KService::Ptr sysSettings = KService::serviceByDesktopName("systemsettings");
0107   if ( sysSettings )
0108   {
0109     action = popup->addAction(QIcon::fromTheme(sysSettings->icon()), sysSettings->name());
0110     connect(action, &QAction::triggered,
0111             [this, sysSettings]()
0112             {
0113 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
0114               auto *job = new KIO::ApplicationLauncherJob(sysSettings);
0115               job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0116               job->start();
0117 #else
0118               KRun::runApplication(*sysSettings, QList<QUrl>(), this);
0119 #endif
0120             });
0121   }
0122 
0123   action = popup->addAction(QIcon::fromTheme("system-run"), i18n("Run Command..."));
0124   connect(action, &QAction::triggered,
0125           []()
0126           {
0127             QDBusConnection::sessionBus().send(
0128                 QDBusMessage::createMethodCall("org.kde.krunner", "/App",
0129                                                "org.kde.krunner.App", "display"));
0130           });
0131 }
0132 
0133 //--------------------------------------------------------------------------------
0134 
0135 void StartMenu::fillFromGroup(QMenu *menu, KServiceGroup::Ptr group)
0136 {
0137   if ( !group || !group->isValid() )
0138     return;
0139 
0140   QList<KServiceGroup::Ptr> groupEntries =
0141       group->groupEntries(static_cast<KServiceGroup::EntriesOptions>(KServiceGroup::SortEntries |
0142                                                                      KServiceGroup::ExcludeNoDisplay));
0143 
0144   for (KServiceGroup::Ptr groupEntry : groupEntries)
0145   {
0146     if ( groupEntry->childCount() == 0 )
0147       continue;
0148 
0149     QMenu *submenu = new PopupMenu(menu);
0150     menu->addMenu(submenu);
0151     submenu->setTitle(groupEntry->caption());
0152     submenu->setIcon(QIcon::fromTheme(groupEntry->icon()));
0153     fillFromGroup(submenu, groupEntry);
0154   }
0155 
0156   KService::List serviceEntries =
0157       group->serviceEntries(static_cast<KServiceGroup::EntriesOptions>(KServiceGroup::SortEntries |
0158                                                                        KServiceGroup::ExcludeNoDisplay));
0159 
0160   for (KService::Ptr serviceEntry : serviceEntries)
0161   {
0162     if ( !serviceEntry->isType(KST_KService) )
0163       continue;
0164 
0165     QIcon icon = QIcon::fromTheme(serviceEntry->icon());
0166     QString text = serviceEntry->name();
0167     if ( !serviceEntry->genericName().isEmpty() && (serviceEntry->genericName() != serviceEntry->name()) )
0168       text += QString(" (%1)").arg(serviceEntry->genericName());
0169 
0170     QAction *action = menu->addAction(icon, text);
0171     action->setData(QUrl::fromLocalFile(serviceEntry->entryPath()));
0172 
0173     action->setToolTip(static_cast<const KService *>(serviceEntry.data())->comment());
0174 
0175     connect(action, &QAction::triggered,
0176             [this, serviceEntry]()
0177             {
0178 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
0179               auto *job = new KIO::ApplicationLauncherJob(serviceEntry);
0180               job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0181               job->start();
0182 #else
0183               KRun::runApplication(*serviceEntry, QList<QUrl>(), nullptr);
0184 #endif
0185             });
0186   }
0187 }
0188 
0189 //--------------------------------------------------------------------------------
0190 
0191 void StartMenu::contextMenuEvent(QContextMenuEvent *event)
0192 {
0193   QMenu menu;
0194 
0195   QAction *action = menu.addAction(QIcon::fromTheme("configure"), i18n("Configure Menu..."));
0196   connect(action, &QAction::triggered,
0197           [this]()
0198           {
0199 #if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0)
0200             auto *job = new KIO::CommandLauncherJob("kmenuedit");
0201             job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0202             job->start();
0203 #else
0204             KRun::runCommand("kmenuedit", nullptr);
0205 #endif
0206           });
0207 
0208   menu.exec(event->globalPos());
0209 }
0210 
0211 //--------------------------------------------------------------------------------
0212 
0213 void StartMenu::showMenu()
0214 {
0215   popup->adjustSize();
0216   QPoint p = mapToGlobal(QPoint(0, 0));
0217   popup->move(p.x(), p.y() - popup->sizeHint().height());
0218   popup->exec();
0219   setDown(false);
0220 }
0221 
0222 //--------------------------------------------------------------------------------