1 /*
2 * SPDX-FileCopyrightText: 2000 Matthias Elter <elter@kde.org>
3 * SPDX-FileCopyrightText: 2001-2002 Raffaele Sandrini <sandrini@kde.org>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 *
7 */
8 #include "kmenuedit.h"
9
10 #include <QFrame>
11 #include <QSplitter>
12 #include <QVBoxLayout>
13
14 #include <KActionCollection>
15 #include <KActionMenu>
16 #include <KLocalizedString>
17 #include <KMessageBox>
18 #include <KService>
19 #include <KStandardAction>
20 #include <KStandardShortcut>
21 #include <KTreeWidgetSearchLine>
22 #include <KXMLGUIFactory>
23 #include <QAction>
24 #include <QIcon>
25 #include <sonnet/configdialog.h>
26
27 #include "basictab.h"
28 #include "configurationmanager.h"
29 #include "kmenueditadaptor.h"
30 #include "preferencesdlg.h"
31 #include "treeview.h"
32
KMenuEdit()33 KMenuEdit::KMenuEdit()
34 : KXmlGuiWindow(nullptr)
35 {
36 // dbus
37 (void)new KmenueditAdaptor(this);
38 QDBusConnection::sessionBus().registerObject(QStringLiteral("/KMenuEdit"), this);
39
40 m_showHidden = ConfigurationManager::getInstance()->hiddenEntriesVisible();
41
42 // setup GUI
43 setupActions();
44 slotChangeView();
45 }
46
~KMenuEdit()47 KMenuEdit::~KMenuEdit()
48 {
49 ConfigurationManager::getInstance()->setSplitterSizes(m_splitter->sizes());
50 }
51
setupActions()52 void KMenuEdit::setupActions()
53 {
54 QAction *action = actionCollection()->addAction(NEW_SUBMENU_ACTION_NAME);
55 action->setIcon(QIcon::fromTheme(QStringLiteral("menu_new")));
56 action->setText(i18n("&New Submenu..."));
57 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_N));
58 action = actionCollection()->addAction(NEW_ITEM_ACTION_NAME);
59 action->setIcon(QIcon::fromTheme(QStringLiteral("document-new")));
60 action->setText(i18n("New &Item..."));
61 actionCollection()->setDefaultShortcuts(action, KStandardShortcut::openNew());
62 action = actionCollection()->addAction(NEW_SEPARATOR_ACTION_NAME);
63 action->setIcon(QIcon::fromTheme(QStringLiteral("menu_new_sep")));
64 action->setText(i18n("New S&eparator"));
65 actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL | Qt::Key_I));
66
67 // "sort selection" menu
68 KActionMenu *sortMenu = new KActionMenu(QIcon::fromTheme(QStringLiteral("view-sort-ascending")), i18n("&Sort"), this);
69 sortMenu->setPopupMode(QToolButton::InstantPopup);
70 actionCollection()->addAction(SORT_ACTION_NAME, sortMenu);
71 action = actionCollection()->addAction(SORT_BY_NAME_ACTION_NAME);
72 action->setText(i18n("&Sort selection by Name"));
73 sortMenu->addAction(action);
74 action = actionCollection()->addAction(SORT_BY_DESCRIPTION_ACTION_NAME);
75 action->setText(i18n("&Sort selection by Description"));
76 sortMenu->addAction(action);
77 sortMenu->addSeparator();
78 action = actionCollection()->addAction(SORT_ALL_BY_NAME_ACTION_NAME);
79 action->setText(i18n("&Sort all by Name"));
80 sortMenu->addAction(action);
81 action = actionCollection()->addAction(SORT_ALL_BY_DESCRIPTION_ACTION_NAME);
82 action->setText(i18n("&Sort all by Description"));
83 sortMenu->addAction(action);
84
85 // move up/down
86 action = actionCollection()->addAction(MOVE_UP_ACTION_NAME);
87 action->setIcon(QIcon::fromTheme(QStringLiteral("go-up")));
88 action->setText(i18n("Move &Up"));
89 action = actionCollection()->addAction(MOVE_DOWN_ACTION_NAME);
90 action->setIcon(QIcon::fromTheme(QStringLiteral("go-down")));
91 action->setText(i18n("Move &Down"));
92
93 actionCollection()->addAction(KStandardAction::Save, this, SLOT(slotSave()));
94 actionCollection()->addAction(KStandardAction::Quit, this, SLOT(close()));
95 actionCollection()->addAction(KStandardAction::Cut);
96 actionCollection()->addAction(KStandardAction::Copy);
97 actionCollection()->addAction(KStandardAction::Paste);
98
99 action = new QAction(i18n("Restore to System Menu"), this);
100 actionCollection()->addAction(QStringLiteral("restore_system_menu"), action);
101 connect(action, &QAction::triggered, this, &KMenuEdit::slotRestoreMenu);
102
103 KStandardAction::preferences(this, SLOT(slotConfigure()), actionCollection());
104 }
105
slotConfigure()106 void KMenuEdit::slotConfigure()
107 {
108 PreferencesDialog dialog(this);
109 if (dialog.exec()) {
110 bool newShowHiddenValue = ConfigurationManager::getInstance()->hiddenEntriesVisible();
111 if (newShowHiddenValue != m_showHidden) {
112 m_showHidden = newShowHiddenValue;
113 m_tree->updateTreeView(m_showHidden);
114 m_basicTab->updateHiddenEntry(m_showHidden);
115 }
116 }
117 }
118
setupView()119 void KMenuEdit::setupView()
120 {
121 // setup search and tree view
122 m_tree = new TreeView(actionCollection(), this);
123
124 m_searchLine = new KTreeWidgetSearchLine(this, m_tree);
125 m_searchLine->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
126 m_searchLine->setKeepParentsVisible(true);
127 m_searchLine->setPlaceholderText(i18n("Search..."));
128 m_searchLine->setToolTip(i18n("Search through the list of applications below"));
129
130 QVBoxLayout *treeLayout = new QVBoxLayout;
131 treeLayout->addWidget(m_searchLine);
132 treeLayout->addWidget(m_tree);
133 treeLayout->setContentsMargins(0, 0, 0, 0); // no padding, fixes alignment issues
134 QFrame *treeFrame = new QFrame; // required to insert tree + search into splitter
135 treeFrame->setLayout(treeLayout);
136
137 m_splitter = new QSplitter(this);
138 m_splitter->setOrientation(Qt::Horizontal);
139 m_splitter->addWidget(treeFrame);
140
141 // setup info tab view
142 m_basicTab = new BasicTab;
143 m_splitter->addWidget(m_basicTab);
144
145 // add padding to splitter
146 m_splitter->setContentsMargins(/*left=*/5, /*top=*/0, /*right=*/5, /*bottom=*/0);
147
148 // clang-format off
149 connect(m_tree, SIGNAL(entrySelected(MenuFolderInfo*)), m_basicTab, SLOT(setFolderInfo(MenuFolderInfo*)));
150 connect(m_tree, SIGNAL(entrySelected(MenuEntryInfo*)), m_basicTab, SLOT(setEntryInfo(MenuEntryInfo*)));
151 connect(m_tree, &TreeView::disableAction, m_basicTab, &BasicTab::slotDisableAction);
152
153 connect(m_basicTab, SIGNAL(changed(MenuFolderInfo*)), m_tree, SLOT(currentDataChanged(MenuFolderInfo*)));
154 connect(m_basicTab, SIGNAL(changed(MenuEntryInfo*)), m_tree, SLOT(currentDataChanged(MenuEntryInfo*)));
155 // clang-format on
156
157 connect(m_basicTab, &BasicTab::findServiceShortcut, m_tree, &TreeView::findServiceShortcut);
158
159 connect(m_searchLine, &KTreeWidgetSearchLine::searchUpdated, m_tree, &TreeView::searchUpdated);
160 // restore splitter sizes
161 QList<int> sizes = ConfigurationManager::getInstance()->getSplitterSizes();
162 if (sizes.isEmpty()) {
163 sizes << 1 << 3;
164 }
165 m_splitter->setSizes(sizes);
166 m_searchLine->setFocus();
167
168 setCentralWidget(m_splitter);
169 }
170
selectMenu(const QString & menu)171 void KMenuEdit::selectMenu(const QString &menu)
172 {
173 m_tree->selectMenu(menu);
174 }
175
selectMenuEntry(const QString & menuEntry)176 void KMenuEdit::selectMenuEntry(const QString &menuEntry)
177 {
178 m_tree->selectMenuEntry(menuEntry);
179 }
180
slotChangeView()181 void KMenuEdit::slotChangeView()
182 {
183 guiFactory()->removeClient(this);
184
185 delete m_actionDelete;
186
187 m_actionDelete = actionCollection()->addAction(DELETE_ACTION_NAME);
188 m_actionDelete->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
189 m_actionDelete->setText(i18n("&Delete"));
190 actionCollection()->setDefaultShortcut(m_actionDelete, QKeySequence(Qt::Key_Delete));
191
192 if (!m_splitter) {
193 setupView();
194 }
195 setupGUI(KXmlGuiWindow::ToolBar | Keys | Save | Create, QStringLiteral("kmenueditui.rc"));
196
197 m_tree->setViewMode(m_showHidden);
198 m_basicTab->updateHiddenEntry(m_showHidden);
199 }
200
slotSave()201 void KMenuEdit::slotSave()
202 {
203 m_tree->save();
204 }
205
queryClose()206 bool KMenuEdit::queryClose()
207 {
208 if (!m_tree->dirty()) {
209 return true;
210 }
211
212 int result;
213 result = KMessageBox::warningYesNoCancel(this,
214 i18n("You have made changes to the menu.\n"
215 "Do you want to save the changes or discard them?"),
216 i18n("Save Menu Changes?"),
217 KStandardGuiItem::save(),
218 KStandardGuiItem::discard());
219
220 switch (result) {
221 case KMessageBox::Yes:
222 return m_tree->save();
223
224 case KMessageBox::No:
225 return true;
226
227 default:
228 break;
229 }
230 return false;
231 }
232
slotRestoreMenu()233 void KMenuEdit::slotRestoreMenu()
234 {
235 m_tree->restoreMenuSystem();
236 }
237
restoreSystemMenu()238 void KMenuEdit::restoreSystemMenu()
239 {
240 m_tree->restoreMenuSystem();
241 }
242