File indexing completed on 2024-04-21 05:27:18

0001 /*
0002  *   SPDX-FileCopyrightText: 2000 Matthias Elter <elter@kde.org>
0003  *   SPDX-FileCopyrightText: 2001-2002 Raffaele Sandrini <sandrini@kde.org>
0004  *
0005  *   SPDX-License-Identifier: GPL-2.0-or-later
0006  *
0007  */
0008 #include "kmenuedit.h"
0009 
0010 #include <QFrame>
0011 #include <QSplitter>
0012 #include <QVBoxLayout>
0013 
0014 #include <KActionCollection>
0015 #include <KActionMenu>
0016 #include <KLocalizedString>
0017 #include <KMessageBox>
0018 #include <KStandardAction>
0019 #include <KStandardShortcut>
0020 #include <KTreeWidgetSearchLine>
0021 #include <KXMLGUIFactory>
0022 #include <QAction>
0023 #include <QIcon>
0024 #include <sonnet/configdialog.h>
0025 
0026 #include "basictab.h"
0027 #include "configurationmanager.h"
0028 #include "kmenueditadaptor.h"
0029 #include "preferencesdlg.h"
0030 #include "treeview.h"
0031 
0032 KMenuEdit::KMenuEdit()
0033     : KXmlGuiWindow(nullptr)
0034 {
0035     // dbus
0036     (void)new KmenueditAdaptor(this);
0037     QDBusConnection::sessionBus().registerObject(QStringLiteral("/KMenuEdit"), this);
0038 
0039     m_showHidden = ConfigurationManager::getInstance()->hiddenEntriesVisible();
0040 
0041     // setup GUI
0042     setupActions();
0043     slotChangeView();
0044 }
0045 
0046 KMenuEdit::~KMenuEdit()
0047 {
0048     ConfigurationManager::getInstance()->setSplitterSizes(m_splitter->sizes());
0049 }
0050 
0051 void KMenuEdit::setupActions()
0052 {
0053     QAction *action = actionCollection()->addAction(NEW_SUBMENU_ACTION_NAME);
0054     action->setIcon(QIcon::fromTheme(QStringLiteral("menu_new")));
0055     action->setText(i18n("&New Submenu..."));
0056     actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_N));
0057     action = actionCollection()->addAction(NEW_ITEM_ACTION_NAME);
0058     action->setIcon(QIcon::fromTheme(QStringLiteral("document-new")));
0059     action->setText(i18n("New &Item..."));
0060     actionCollection()->setDefaultShortcuts(action, KStandardShortcut::openNew());
0061     action = actionCollection()->addAction(NEW_SEPARATOR_ACTION_NAME);
0062     action->setIcon(QIcon::fromTheme(QStringLiteral("menu_new_sep")));
0063     action->setText(i18n("New S&eparator"));
0064     actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_I));
0065 
0066     // "sort selection" menu
0067     KActionMenu *sortMenu = new KActionMenu(QIcon::fromTheme(QStringLiteral("view-sort-ascending")), i18n("&Sort"), this);
0068     sortMenu->setPopupMode(QToolButton::InstantPopup);
0069     actionCollection()->addAction(SORT_ACTION_NAME, sortMenu);
0070     action = actionCollection()->addAction(SORT_BY_NAME_ACTION_NAME);
0071     action->setText(i18n("&Sort selection by Name"));
0072     sortMenu->addAction(action);
0073     action = actionCollection()->addAction(SORT_BY_DESCRIPTION_ACTION_NAME);
0074     action->setText(i18n("&Sort selection by Description"));
0075     sortMenu->addAction(action);
0076     sortMenu->addSeparator();
0077     action = actionCollection()->addAction(SORT_ALL_BY_NAME_ACTION_NAME);
0078     action->setText(i18n("&Sort all by Name"));
0079     sortMenu->addAction(action);
0080     action = actionCollection()->addAction(SORT_ALL_BY_DESCRIPTION_ACTION_NAME);
0081     action->setText(i18n("&Sort all by Description"));
0082     sortMenu->addAction(action);
0083 
0084     // move up/down
0085     action = actionCollection()->addAction(MOVE_UP_ACTION_NAME);
0086     action->setIcon(QIcon::fromTheme(QStringLiteral("go-up")));
0087     action->setText(i18n("Move &Up"));
0088     action = actionCollection()->addAction(MOVE_DOWN_ACTION_NAME);
0089     action->setIcon(QIcon::fromTheme(QStringLiteral("go-down")));
0090     action->setText(i18n("Move &Down"));
0091 
0092     actionCollection()->addAction(KStandardAction::Save, this, SLOT(slotSave()));
0093     actionCollection()->addAction(KStandardAction::Quit, this, SLOT(close()));
0094     actionCollection()->addAction(KStandardAction::Cut);
0095     actionCollection()->addAction(KStandardAction::Copy);
0096     actionCollection()->addAction(KStandardAction::Paste);
0097 
0098     action = new QAction(i18n("Restore to System Menu"), this);
0099     actionCollection()->addAction(QStringLiteral("restore_system_menu"), action);
0100     connect(action, &QAction::triggered, this, &KMenuEdit::slotRestoreMenu);
0101 
0102     KStandardAction::preferences(this, SLOT(slotConfigure()), actionCollection());
0103 }
0104 
0105 void KMenuEdit::slotConfigure()
0106 {
0107     PreferencesDialog dialog(this);
0108     if (dialog.exec()) {
0109         bool newShowHiddenValue = ConfigurationManager::getInstance()->hiddenEntriesVisible();
0110         if (newShowHiddenValue != m_showHidden) {
0111             m_showHidden = newShowHiddenValue;
0112             m_tree->updateTreeView(m_showHidden);
0113             m_basicTab->updateHiddenEntry(m_showHidden);
0114         }
0115     }
0116 }
0117 
0118 void KMenuEdit::setupView()
0119 {
0120     // setup search and tree view
0121     m_tree = new TreeView(actionCollection(), this);
0122 
0123     auto wrapper = new QWidget(this);
0124     wrapper->setContentsMargins(wrapper->style()->pixelMetric(QStyle::PM_LayoutLeftMargin),
0125                                 wrapper->style()->pixelMetric(QStyle::PM_LayoutTopMargin),
0126                                 wrapper->style()->pixelMetric(QStyle::PM_LayoutRightMargin),
0127                                 wrapper->style()->pixelMetric(QStyle::PM_LayoutBottomMargin));
0128     auto wrapperLayout = new QVBoxLayout(wrapper);
0129     wrapperLayout->setContentsMargins({});
0130 
0131     m_searchLine = new KTreeWidgetSearchLine(wrapper, m_tree);
0132     m_searchLine->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
0133     m_searchLine->setKeepParentsVisible(true);
0134     m_searchLine->setPlaceholderText(i18n("Search..."));
0135     m_searchLine->setToolTip(i18n("Search through the list of applications below"));
0136 
0137     wrapperLayout->addWidget(m_searchLine);
0138 
0139     auto horizontalSeparator = new QFrame(this);
0140     horizontalSeparator->setFrameStyle(QFrame::HLine);
0141 
0142     QVBoxLayout *treeLayout = new QVBoxLayout;
0143     treeLayout->addWidget(wrapper);
0144     treeLayout->addWidget(horizontalSeparator);
0145     treeLayout->addWidget(m_tree);
0146     treeLayout->setSpacing(0);
0147     treeLayout->setContentsMargins(0, 0, 0, 0); // no padding, fixes alignment issues
0148     QFrame *treeFrame = new QFrame; // required to insert tree + search into splitter
0149     treeFrame->setLayout(treeLayout);
0150 
0151     m_splitter = new QSplitter(this);
0152     m_splitter->setOrientation(Qt::Horizontal);
0153     m_splitter->addWidget(treeFrame);
0154 
0155     // setup info tab view
0156     m_basicTab = new BasicTab;
0157     m_splitter->addWidget(m_basicTab);
0158 
0159     // add padding to splitter
0160     m_splitter->setContentsMargins(0, 0, 0, 0);
0161 
0162     // clang-format off
0163     connect(m_tree, SIGNAL(entrySelected(MenuFolderInfo*)), m_basicTab, SLOT(setFolderInfo(MenuFolderInfo*)));
0164     connect(m_tree, SIGNAL(entrySelected(MenuEntryInfo*)), m_basicTab, SLOT(setEntryInfo(MenuEntryInfo*)));
0165     connect(m_tree, &TreeView::disableAction, m_basicTab, &BasicTab::slotDisableAction);
0166 
0167     connect(m_basicTab, SIGNAL(changed(MenuFolderInfo*)), m_tree, SLOT(currentDataChanged(MenuFolderInfo*)));
0168     connect(m_basicTab, SIGNAL(changed(MenuEntryInfo*)), m_tree, SLOT(currentDataChanged(MenuEntryInfo*)));
0169     // clang-format on
0170 
0171     connect(m_basicTab, &BasicTab::findServiceShortcut, m_tree, &TreeView::findServiceShortcut);
0172 
0173     connect(m_searchLine, &KTreeWidgetSearchLine::searchUpdated, m_tree, &TreeView::searchUpdated);
0174     // restore splitter sizes
0175     QList<int> sizes = ConfigurationManager::getInstance()->getSplitterSizes();
0176     if (sizes.isEmpty()) {
0177         sizes << 1 << 3;
0178     }
0179     m_splitter->setSizes(sizes);
0180     m_searchLine->setFocus();
0181 
0182     setCentralWidget(m_splitter);
0183 }
0184 
0185 void KMenuEdit::selectMenu(const QString &menu)
0186 {
0187     m_tree->selectMenu(menu);
0188 }
0189 
0190 void KMenuEdit::selectMenuEntry(const QString &menuEntry)
0191 {
0192     m_tree->selectMenuEntry(menuEntry);
0193 }
0194 
0195 void KMenuEdit::slotChangeView()
0196 {
0197     guiFactory()->removeClient(this);
0198 
0199     delete m_actionDelete;
0200 
0201     m_actionDelete = actionCollection()->addAction(DELETE_ACTION_NAME);
0202     m_actionDelete->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
0203     m_actionDelete->setText(i18n("&Delete"));
0204     actionCollection()->setDefaultShortcut(m_actionDelete, QKeySequence(Qt::Key_Delete));
0205 
0206     if (!m_splitter) {
0207         setupView();
0208     }
0209     setupGUI(KXmlGuiWindow::ToolBar | Keys | Save | Create, QStringLiteral("kmenueditui.rc"));
0210 
0211     m_tree->setViewMode(m_showHidden);
0212     m_basicTab->updateHiddenEntry(m_showHidden);
0213 }
0214 
0215 void KMenuEdit::slotSave()
0216 {
0217     m_tree->save();
0218 }
0219 
0220 bool KMenuEdit::queryClose()
0221 {
0222     if (!m_tree->dirty()) {
0223         return true;
0224     }
0225 
0226     int result;
0227     result = KMessageBox::warningTwoActionsCancel(this,
0228                                                   i18n("You have made changes to the menu.\n"
0229                                                        "Do you want to save the changes or discard them?"),
0230                                                   i18n("Save Menu Changes?"),
0231                                                   KStandardGuiItem::save(),
0232                                                   KStandardGuiItem::discard());
0233 
0234     switch (result) {
0235     case KMessageBox::PrimaryAction:
0236         return m_tree->save();
0237 
0238     case KMessageBox::SecondaryAction:
0239         return true;
0240 
0241     default:
0242         break;
0243     }
0244     return false;
0245 }
0246 
0247 void KMenuEdit::slotRestoreMenu()
0248 {
0249     m_tree->restoreMenuSystem();
0250 }
0251 
0252 void KMenuEdit::restoreSystemMenu()
0253 {
0254     m_tree->restoreMenuSystem();
0255 }