File indexing completed on 2024-04-28 05:45:25
0001 /* 0002 * SPDX-FileCopyrightText: 2008 David Faure <faure@kde.org> 0003 * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "dolphinviewactionhandler.h" 0009 0010 #include "kitemviews/kfileitemlisttostring.h" 0011 #include "kitemviews/kfileitemmodel.h" 0012 #include "selectionmode/actiontexthelper.h" 0013 #include "settings/viewpropertiesdialog.h" 0014 #include "views/zoomlevelinfo.h" 0015 0016 #if HAVE_BALOO 0017 #include <Baloo/IndexerConfig> 0018 #endif 0019 #include <KActionCollection> 0020 #include <KActionMenu> 0021 #include <KFileItemListProperties> 0022 #include <KLocalizedString> 0023 #include <KNewFileMenu> 0024 #include <KPropertiesDialog> 0025 #include <KProtocolManager> 0026 0027 #include <QActionGroup> 0028 #include <QMenu> 0029 #include <QPointer> 0030 0031 DolphinViewActionHandler::DolphinViewActionHandler(KActionCollection *collection, SelectionMode::ActionTextHelper *actionTextHelper, QObject *parent) 0032 : QObject(parent) 0033 , m_actionCollection(collection) 0034 , m_currentView(nullptr) 0035 , m_sortByActions() 0036 , m_visibleRoles() 0037 { 0038 Q_ASSERT(m_actionCollection); 0039 createActions(actionTextHelper); 0040 } 0041 0042 void DolphinViewActionHandler::setCurrentView(DolphinView *view) 0043 { 0044 Q_ASSERT(view); 0045 0046 if (m_currentView) { 0047 disconnect(m_currentView, nullptr, this, nullptr); 0048 } 0049 0050 m_currentView = view; 0051 0052 connect(view, &DolphinView::modeChanged, this, &DolphinViewActionHandler::updateViewActions); 0053 connect(view, &DolphinView::previewsShownChanged, this, &DolphinViewActionHandler::slotPreviewsShownChanged); 0054 connect(view, &DolphinView::sortOrderChanged, this, &DolphinViewActionHandler::slotSortOrderChanged); 0055 connect(view, &DolphinView::sortFoldersFirstChanged, this, &DolphinViewActionHandler::slotSortFoldersFirstChanged); 0056 connect(view, &DolphinView::sortHiddenLastChanged, this, &DolphinViewActionHandler::slotSortHiddenLastChanged); 0057 connect(view, &DolphinView::visibleRolesChanged, this, &DolphinViewActionHandler::slotVisibleRolesChanged); 0058 connect(view, &DolphinView::groupedSortingChanged, this, &DolphinViewActionHandler::slotGroupedSortingChanged); 0059 connect(view, &DolphinView::hiddenFilesShownChanged, this, &DolphinViewActionHandler::slotHiddenFilesShownChanged); 0060 connect(view, &DolphinView::sortRoleChanged, this, &DolphinViewActionHandler::slotSortRoleChanged); 0061 connect(view, &DolphinView::zoomLevelChanged, this, &DolphinViewActionHandler::slotZoomLevelChanged); 0062 connect(view, &DolphinView::writeStateChanged, this, &DolphinViewActionHandler::slotWriteStateChanged); 0063 slotWriteStateChanged(view->isFolderWritable()); 0064 connect(view, &DolphinView::selectionModeChangeRequested, this, [this](bool enabled) { 0065 Q_EMIT selectionModeChangeTriggered(enabled); 0066 }); 0067 connect(view, &DolphinView::selectionChanged, this, &DolphinViewActionHandler::slotSelectionChanged); 0068 slotSelectionChanged(m_currentView->selectedItems()); 0069 } 0070 0071 DolphinView *DolphinViewActionHandler::currentView() 0072 { 0073 return m_currentView; 0074 } 0075 0076 void DolphinViewActionHandler::createActions(SelectionMode::ActionTextHelper *actionTextHelper) 0077 { 0078 // This action doesn't appear in the GUI, it's for the shortcut only. 0079 // KNewFileMenu takes care of the GUI stuff. 0080 QAction *newDirAction = m_actionCollection->addAction(QStringLiteral("create_dir")); 0081 newDirAction->setText(i18nc("@action", "Create Folder…")); 0082 m_actionCollection->setDefaultShortcuts(newDirAction, KStandardShortcut::createFolder()); 0083 newDirAction->setIcon(QIcon::fromTheme(QStringLiteral("folder-new"))); 0084 newDirAction->setEnabled(false); // Will be enabled in slotWriteStateChanged(bool) if the current URL is writable 0085 connect(newDirAction, &QAction::triggered, this, &DolphinViewActionHandler::createDirectoryTriggered); 0086 0087 // File menu 0088 0089 auto renameAction = KStandardAction::renameFile(this, &DolphinViewActionHandler::slotRename, m_actionCollection); 0090 renameAction->setWhatsThis(xi18nc("@info:whatsthis", 0091 "This renames the " 0092 "items in your current selection.<nl/>Renaming multiple items " 0093 "at once amounts to their new names differing only in a number.")); 0094 0095 auto trashAction = KStandardAction::moveToTrash(this, &DolphinViewActionHandler::slotTrashActivated, m_actionCollection); 0096 auto trashShortcuts = trashAction->shortcuts(); 0097 trashAction->setAutoRepeat(false); 0098 if (!trashShortcuts.contains(QKeySequence::Delete)) { 0099 trashShortcuts.append(QKeySequence::Delete); 0100 m_actionCollection->setDefaultShortcuts(trashAction, trashShortcuts); 0101 } 0102 trashAction->setWhatsThis(xi18nc("@info:whatsthis", 0103 "This moves the " 0104 "items in your current selection to the <filename>Trash" 0105 "</filename>.<nl/>The trash is a temporary storage where " 0106 "items can be deleted from if disk space is needed.")); 0107 0108 auto deleteAction = KStandardAction::deleteFile(this, &DolphinViewActionHandler::slotDeleteItems, m_actionCollection); 0109 auto deleteShortcuts = deleteAction->shortcuts(); 0110 deleteAction->setAutoRepeat(false); 0111 if (!deleteShortcuts.contains(Qt::SHIFT | Qt::Key_Delete)) { 0112 deleteShortcuts.append(Qt::SHIFT | Qt::Key_Delete); 0113 m_actionCollection->setDefaultShortcuts(deleteAction, deleteShortcuts); 0114 } 0115 deleteAction->setWhatsThis(xi18nc("@info:whatsthis", 0116 "This deletes " 0117 "the items in your current selection completely. They can " 0118 "not be recovered by normal means.")); 0119 0120 // This action is useful for being enabled when KStandardAction::MoveToTrash should be 0121 // disabled and KStandardAction::DeleteFile is enabled (e.g. non-local files), so that Key_Del 0122 // can be used for deleting the file (#76016). It needs to be a separate action 0123 // so that the Edit menu isn't affected. 0124 QAction *deleteWithTrashShortcut = m_actionCollection->addAction(QStringLiteral("delete_shortcut")); 0125 // The descriptive text is just for the shortcuts editor. 0126 deleteWithTrashShortcut->setText(i18nc("@action \"Move to Trash\" for non-local files, etc.", "Delete (using shortcut for Trash)")); 0127 m_actionCollection->setDefaultShortcuts(deleteWithTrashShortcut, KStandardShortcut::moveToTrash()); 0128 deleteWithTrashShortcut->setEnabled(false); 0129 connect(deleteWithTrashShortcut, &QAction::triggered, this, &DolphinViewActionHandler::slotDeleteItems); 0130 0131 QAction *duplicateAction = m_actionCollection->addAction(QStringLiteral("duplicate")); 0132 duplicateAction->setText(i18nc("@action:inmenu File", "Duplicate Here")); 0133 duplicateAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-duplicate"))); 0134 m_actionCollection->setDefaultShortcut(duplicateAction, Qt::CTRL | Qt::Key_D); 0135 duplicateAction->setEnabled(false); 0136 connect(duplicateAction, &QAction::triggered, this, &DolphinViewActionHandler::slotDuplicate); 0137 0138 QAction *propertiesAction = m_actionCollection->addAction(QStringLiteral("properties")); 0139 // Well, it's the File menu in dolphinmainwindow and the Edit menu in dolphinpart... :) 0140 propertiesAction->setText(i18nc("@action:inmenu File", "Properties")); 0141 propertiesAction->setWhatsThis(xi18nc("@info:whatsthis properties", 0142 "This shows a complete list of properties of the currently " 0143 "selected items in a new window.<nl/>If nothing is selected the " 0144 "window will be about the currently viewed folder instead.<nl/>" 0145 "You can configure advanced options there like managing " 0146 "read- and write-permissions.")); 0147 propertiesAction->setIcon(QIcon::fromTheme(QStringLiteral("document-properties"))); 0148 m_actionCollection->setDefaultShortcuts(propertiesAction, {Qt::ALT | Qt::Key_Return, Qt::ALT | Qt::Key_Enter}); 0149 connect(propertiesAction, &QAction::triggered, this, &DolphinViewActionHandler::slotProperties); 0150 0151 QAction *copyPathAction = m_actionCollection->addAction(QStringLiteral("copy_location")); 0152 copyPathAction->setText(i18nc("@action:incontextmenu", "Copy Location")); 0153 copyPathAction->setWhatsThis(i18nc("@info:whatsthis copy_location", "This will copy the path of the first selected item into the clipboard.")); 0154 0155 copyPathAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy-path"))); 0156 m_actionCollection->setDefaultShortcuts(copyPathAction, {Qt::CTRL | Qt::ALT | Qt::Key_C}); 0157 connect(copyPathAction, &QAction::triggered, this, &DolphinViewActionHandler::slotCopyPath); 0158 0159 if (actionTextHelper) { 0160 // The "…" at the end make clear that they won't trigger their respective actions directly. 0161 actionTextHelper->registerTextWhenNothingIsSelected(trashAction, i18nc("@action:inmenu File", "Move to Trash…")); 0162 actionTextHelper->registerTextWhenNothingIsSelected(deleteAction, i18nc("@action:inmenu File", "Delete…")); 0163 actionTextHelper->registerTextWhenNothingIsSelected(duplicateAction, i18nc("@action:inmenu File", "Duplicate Here…")); 0164 actionTextHelper->registerTextWhenNothingIsSelected(copyPathAction, i18nc("@action:incontextmenu", "Copy Location…")); 0165 } 0166 0167 // This menu makes sure that users who don't know how to open a context menu and haven't 0168 // figured out how to enable the menu bar can still perform basic file manipulation. 0169 // This only works if they know how to select a file. 0170 // The text when nothing is selected at least implies that a selection can /somehow/ be made. 0171 // This menu is by default only used in the hamburger menu but created here so users can put 0172 // it on their toolbar. 0173 KActionMenu *basicActionsMenu = m_actionCollection->add<KActionMenu>(QStringLiteral("basic_actions"), this); 0174 // The text is set later depending on the selection in the currently active view. 0175 basicActionsMenu->setPopupMode(QToolButton::InstantPopup); 0176 basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::Cut))); 0177 basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::Copy))); 0178 basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::Paste))); 0179 basicActionsMenu->addSeparator(); 0180 basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::RenameFile))); 0181 basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::MoveToTrash))); 0182 basicActionsMenu->addSeparator(); 0183 basicActionsMenu->addAction(m_actionCollection->action(QStringLiteral("properties"))); 0184 basicActionsMenu->addSeparator(); // We add one more separator because we sometimes add contextual 0185 // actions in slotSelectionChanged() after the static ones above. 0186 0187 // View menu 0188 KToggleAction *iconsAction = iconsModeAction(); 0189 KToggleAction *compactAction = compactModeAction(); 0190 KToggleAction *detailsAction = detailsModeAction(); 0191 0192 iconsAction->setWhatsThis(xi18nc("@info:whatsthis Icons view mode", 0193 "<para>This switches to a view mode that focuses on the folder " 0194 "and file icons. This mode makes it easy to distinguish folders " 0195 "from files and to detect items with distinctive <emphasis>" 0196 "file types</emphasis>.</para><para> This mode is handy to " 0197 "browse through pictures when the <interface>Preview" 0198 "</interface> option is enabled.</para>")); 0199 compactAction->setWhatsThis(xi18nc("@info:whatsthis Compact view mode", 0200 "<para>This switches to a compact view mode that lists the folders " 0201 "and files in columns with the names beside the icons.</para><para>" 0202 "This helps to keep the overview in folders with many items.</para>")); 0203 detailsAction->setWhatsThis(xi18nc("@info:whatsthis Details view mode", 0204 "<para>This switches to a list view mode that focuses on folder " 0205 "and file details.</para><para>Click on a detail in the column " 0206 "header to sort the items by it. Click again to sort the other " 0207 "way around. To select which details should be displayed click " 0208 "the header with the right mouse button.</para><para>You can " 0209 "view the contents of a folder without leaving the current " 0210 "location by clicking to the left of it. This way you can view " 0211 "the contents of multiple folders in the same list.</para>")); 0212 0213 KSelectAction *viewModeActions = m_actionCollection->add<KSelectAction>(QStringLiteral("view_mode")); 0214 viewModeActions->setText(i18nc("@action:intoolbar", "View Mode")); 0215 viewModeActions->addAction(iconsAction); 0216 viewModeActions->addAction(compactAction); 0217 viewModeActions->addAction(detailsAction); 0218 viewModeActions->setToolBarMode(KSelectAction::MenuMode); 0219 connect(viewModeActions, &KSelectAction::actionTriggered, this, &DolphinViewActionHandler::slotViewModeActionTriggered); 0220 0221 QAction *zoomInAction = KStandardAction::zoomIn(this, &DolphinViewActionHandler::zoomIn, m_actionCollection); 0222 zoomInAction->setWhatsThis(i18nc("@info:whatsthis zoom in", "This increases the icon size.")); 0223 0224 QAction *zoomResetAction = m_actionCollection->addAction(QStringLiteral("view_zoom_reset")); 0225 zoomResetAction->setText(i18nc("@action:inmenu View", "Reset Zoom Level")); 0226 zoomResetAction->setToolTip(i18n("Zoom To Default")); 0227 zoomResetAction->setWhatsThis(i18nc("@info:whatsthis zoom reset", "This resets the icon size to default.")); 0228 zoomResetAction->setIcon(QIcon::fromTheme(QStringLiteral("zoom-original"))); 0229 m_actionCollection->setDefaultShortcuts(zoomResetAction, {Qt::CTRL | Qt::Key_0}); 0230 connect(zoomResetAction, &QAction::triggered, this, &DolphinViewActionHandler::zoomReset); 0231 0232 QAction *zoomOutAction = KStandardAction::zoomOut(this, &DolphinViewActionHandler::zoomOut, m_actionCollection); 0233 zoomOutAction->setWhatsThis(i18nc("@info:whatsthis zoom out", "This reduces the icon size.")); 0234 0235 KActionMenu *zoomMenu = m_actionCollection->add<KActionMenu>(QStringLiteral("zoom")); 0236 zoomMenu->setText(i18nc("@action:inmenu menu of zoom actions", "Zoom")); 0237 zoomMenu->setIcon(QIcon::fromTheme(QStringLiteral("zoom"))); 0238 zoomMenu->setPopupMode(QToolButton::InstantPopup); 0239 zoomMenu->addAction(zoomInAction); 0240 zoomMenu->addAction(zoomResetAction); 0241 zoomMenu->addAction(zoomOutAction); 0242 0243 KToggleAction *showPreview = m_actionCollection->add<KToggleAction>(QStringLiteral("show_preview")); 0244 showPreview->setText(i18nc("@action:intoolbar", "Show Previews")); 0245 showPreview->setToolTip(i18nc("@info", "Show preview of files and folders")); 0246 showPreview->setWhatsThis(xi18nc("@info:whatsthis", 0247 "When this is " 0248 "enabled, the icons are based on the actual file or folder " 0249 "contents.<nl/>For example the icons of images become scaled " 0250 "down versions of the images.")); 0251 showPreview->setIcon(QIcon::fromTheme(QStringLiteral("view-preview"))); 0252 m_actionCollection->setDefaultShortcut(showPreview, QKeySequence(Qt::Key_F12)); 0253 connect(showPreview, &KToggleAction::triggered, this, &DolphinViewActionHandler::togglePreview); 0254 0255 KToggleAction *sortFoldersFirst = m_actionCollection->add<KToggleAction>(QStringLiteral("folders_first")); 0256 sortFoldersFirst->setText(i18nc("@action:inmenu Sort", "Folders First")); 0257 connect(sortFoldersFirst, &KToggleAction::triggered, this, &DolphinViewActionHandler::toggleSortFoldersFirst); 0258 0259 KToggleAction *sortHiddenLast = m_actionCollection->add<KToggleAction>(QStringLiteral("hidden_last")); 0260 sortHiddenLast->setText(i18nc("@action:inmenu Sort", "Hidden Files Last")); 0261 connect(sortHiddenLast, &KToggleAction::triggered, this, &DolphinViewActionHandler::toggleSortHiddenLast); 0262 0263 // View -> Sort By 0264 QActionGroup *sortByActionGroup = createFileItemRolesActionGroup(QStringLiteral("sort_by_")); 0265 0266 KActionMenu *sortByActionMenu = m_actionCollection->add<KActionMenu>(QStringLiteral("sort")); 0267 sortByActionMenu->setIcon(QIcon::fromTheme(QStringLiteral("view-sort"))); 0268 sortByActionMenu->setText(i18nc("@action:inmenu View", "Sort By")); 0269 sortByActionMenu->setPopupMode(QToolButton::InstantPopup); 0270 0271 const auto sortByActionGroupActions = sortByActionGroup->actions(); 0272 for (QAction *action : sortByActionGroupActions) { 0273 sortByActionMenu->addAction(action); 0274 } 0275 0276 sortByActionMenu->addSeparator(); 0277 0278 QActionGroup *group = new QActionGroup(sortByActionMenu); 0279 group->setExclusive(true); 0280 0281 KToggleAction *ascendingAction = m_actionCollection->add<KToggleAction>(QStringLiteral("ascending")); 0282 ascendingAction->setActionGroup(group); 0283 connect(ascendingAction, &QAction::triggered, this, [this] { 0284 m_currentView->setSortOrder(Qt::AscendingOrder); 0285 }); 0286 0287 KToggleAction *descendingAction = m_actionCollection->add<KToggleAction>(QStringLiteral("descending")); 0288 descendingAction->setActionGroup(group); 0289 connect(descendingAction, &QAction::triggered, this, [this] { 0290 m_currentView->setSortOrder(Qt::DescendingOrder); 0291 }); 0292 0293 sortByActionMenu->addAction(ascendingAction); 0294 sortByActionMenu->addAction(descendingAction); 0295 sortByActionMenu->addSeparator(); 0296 sortByActionMenu->addAction(sortFoldersFirst); 0297 sortByActionMenu->addAction(sortHiddenLast); 0298 0299 // View -> Additional Information 0300 QActionGroup *visibleRolesGroup = createFileItemRolesActionGroup(QStringLiteral("show_")); 0301 0302 KActionMenu *visibleRolesMenu = m_actionCollection->add<KActionMenu>(QStringLiteral("additional_info")); 0303 visibleRolesMenu->setText(i18nc("@action:inmenu View", "Show Additional Information")); 0304 visibleRolesMenu->setIcon(QIcon::fromTheme(QStringLiteral("documentinfo"))); 0305 visibleRolesMenu->setPopupMode(QToolButton::InstantPopup); 0306 0307 const auto visibleRolesGroupActions = visibleRolesGroup->actions(); 0308 for (QAction *action : visibleRolesGroupActions) { 0309 visibleRolesMenu->addAction(action); 0310 } 0311 0312 KToggleAction *showInGroups = m_actionCollection->add<KToggleAction>(QStringLiteral("show_in_groups")); 0313 showInGroups->setIcon(QIcon::fromTheme(QStringLiteral("view-group"))); 0314 showInGroups->setText(i18nc("@action:inmenu View", "Show in Groups")); 0315 showInGroups->setWhatsThis(i18nc("@info:whatsthis", "This groups files and folders by their first letter.")); 0316 connect(showInGroups, &KToggleAction::triggered, this, &DolphinViewActionHandler::toggleGroupedSorting); 0317 0318 KToggleAction *showHiddenFiles = m_actionCollection->add<KToggleAction>(QStringLiteral("show_hidden_files")); 0319 showHiddenFiles->setIcon(QIcon::fromTheme(QStringLiteral("view-visible"))); 0320 showHiddenFiles->setText(i18nc("@action:inmenu View", "Show Hidden Files")); 0321 showHiddenFiles->setWhatsThis(xi18nc("@info:whatsthis", 0322 "<para>When " 0323 "this is enabled <emphasis>hidden</emphasis> files and folders " 0324 "are visible. They will be displayed semi-transparent.</para>" 0325 "<para>Hidden items only differ from other ones in that their " 0326 "name starts with a \".\". In general there is no need for " 0327 "users to access them which is why they are hidden.</para>")); 0328 m_actionCollection->setDefaultShortcuts(showHiddenFiles, KStandardShortcut::showHideHiddenFiles()); 0329 connect(showHiddenFiles, &KToggleAction::triggered, this, &DolphinViewActionHandler::toggleShowHiddenFiles); 0330 0331 QAction *adjustViewProps = m_actionCollection->addAction(QStringLiteral("view_properties")); 0332 adjustViewProps->setText(i18nc("@action:inmenu View", "Adjust View Display Style…")); 0333 adjustViewProps->setIcon(QIcon::fromTheme(QStringLiteral("view-choose"))); 0334 adjustViewProps->setWhatsThis(i18nc("@info:whatsthis", 0335 "This opens a window " 0336 "in which all folder view properties can be adjusted.")); 0337 connect(adjustViewProps, &QAction::triggered, this, &DolphinViewActionHandler::slotAdjustViewProperties); 0338 } 0339 0340 QActionGroup *DolphinViewActionHandler::createFileItemRolesActionGroup(const QString &groupPrefix) 0341 { 0342 const bool isSortGroup = (groupPrefix == QLatin1String("sort_by_")); 0343 Q_ASSERT(isSortGroup || groupPrefix == QLatin1String("show_")); 0344 0345 QActionGroup *rolesActionGroup = new QActionGroup(m_actionCollection); 0346 rolesActionGroup->setExclusive(isSortGroup); 0347 if (isSortGroup) { 0348 connect(rolesActionGroup, &QActionGroup::triggered, this, &DolphinViewActionHandler::slotSortTriggered); 0349 } else { 0350 connect(rolesActionGroup, &QActionGroup::triggered, this, &DolphinViewActionHandler::toggleVisibleRole); 0351 } 0352 0353 QString groupName; 0354 KActionMenu *groupMenu = nullptr; 0355 QActionGroup *groupMenuGroup = nullptr; 0356 0357 bool indexingEnabled = false; 0358 #if HAVE_BALOO 0359 Baloo::IndexerConfig config; 0360 indexingEnabled = config.fileIndexingEnabled(); 0361 #endif 0362 0363 const QList<KFileItemModel::RoleInfo> rolesInfo = KFileItemModel::rolesInformation(); 0364 for (const KFileItemModel::RoleInfo &info : rolesInfo) { 0365 if (!isSortGroup && info.role == "text") { 0366 // It should not be possible to hide the "text" role 0367 continue; 0368 } 0369 0370 KToggleAction *action = nullptr; 0371 const QString name = groupPrefix + info.role; 0372 if (info.group.isEmpty()) { 0373 action = m_actionCollection->add<KToggleAction>(name); 0374 action->setActionGroup(rolesActionGroup); 0375 } else { 0376 if (!groupMenu || info.group != groupName) { 0377 groupName = info.group; 0378 groupMenu = m_actionCollection->add<KActionMenu>(groupName); 0379 groupMenu->setText(groupName); 0380 groupMenu->setActionGroup(rolesActionGroup); 0381 0382 groupMenuGroup = new QActionGroup(groupMenu); 0383 groupMenuGroup->setExclusive(isSortGroup); 0384 if (isSortGroup) { 0385 connect(groupMenuGroup, &QActionGroup::triggered, this, &DolphinViewActionHandler::slotSortTriggered); 0386 } else { 0387 connect(groupMenuGroup, &QActionGroup::triggered, this, &DolphinViewActionHandler::toggleVisibleRole); 0388 } 0389 } 0390 0391 action = new KToggleAction(groupMenu); 0392 action->setActionGroup(groupMenuGroup); 0393 groupMenu->addAction(action); 0394 } 0395 action->setText(info.translation); 0396 action->setData(info.role); 0397 0398 const bool enable = (!info.requiresBaloo && !info.requiresIndexer) || (info.requiresBaloo) || (info.requiresIndexer && indexingEnabled); 0399 action->setEnabled(enable); 0400 0401 if (isSortGroup) { 0402 m_sortByActions.insert(info.role, action); 0403 } else { 0404 m_visibleRoles.insert(info.role, action); 0405 } 0406 } 0407 0408 return rolesActionGroup; 0409 } 0410 0411 void DolphinViewActionHandler::slotViewModeActionTriggered(QAction *action) 0412 { 0413 const DolphinView::Mode mode = action->data().value<DolphinView::Mode>(); 0414 m_currentView->setViewMode(mode); 0415 0416 QAction *viewModeMenu = m_actionCollection->action(QStringLiteral("view_mode")); 0417 viewModeMenu->setIcon(action->icon()); 0418 } 0419 0420 void DolphinViewActionHandler::slotRename() 0421 { 0422 if (m_currentView->selectedItemsCount() == 0) { 0423 Q_EMIT selectionModeChangeTriggered(true, SelectionMode::BottomBar::Contents::RenameContents); 0424 } else { 0425 Q_EMIT actionBeingHandled(); 0426 m_currentView->renameSelectedItems(); 0427 // We don't exit selectionMode here because users might want to rename more items. 0428 } 0429 } 0430 0431 void DolphinViewActionHandler::slotTrashActivated() 0432 { 0433 if (m_currentView->selectedItemsCount() == 0) { 0434 Q_EMIT selectionModeChangeTriggered(true, SelectionMode::BottomBar::Contents::MoveToTrashContents); 0435 } else { 0436 Q_EMIT actionBeingHandled(); 0437 m_currentView->trashSelectedItems(); 0438 Q_EMIT selectionModeChangeTriggered(false); 0439 } 0440 } 0441 0442 void DolphinViewActionHandler::slotDeleteItems() 0443 { 0444 if (m_currentView->selectedItemsCount() == 0) { 0445 Q_EMIT selectionModeChangeTriggered(true, SelectionMode::BottomBar::Contents::DeleteContents); 0446 } else { 0447 Q_EMIT actionBeingHandled(); 0448 m_currentView->deleteSelectedItems(); 0449 Q_EMIT selectionModeChangeTriggered(false); 0450 } 0451 } 0452 0453 void DolphinViewActionHandler::togglePreview(bool show) 0454 { 0455 Q_EMIT actionBeingHandled(); 0456 m_currentView->setPreviewsShown(show); 0457 } 0458 0459 void DolphinViewActionHandler::slotPreviewsShownChanged(bool shown) 0460 { 0461 Q_UNUSED(shown) 0462 // It is not enough to update the 'Show Preview' action, also 0463 // the 'Zoom In', 'Zoom Out' and 'Zoom Reset' actions must be adapted. 0464 updateViewActions(); 0465 } 0466 0467 QString DolphinViewActionHandler::currentViewModeActionName() const 0468 { 0469 switch (m_currentView->viewMode()) { 0470 case DolphinView::IconsView: 0471 return QStringLiteral("icons"); 0472 case DolphinView::DetailsView: 0473 return QStringLiteral("details"); 0474 case DolphinView::CompactView: 0475 return QStringLiteral("compact"); 0476 default: 0477 Q_ASSERT(false); 0478 break; 0479 } 0480 return QString(); // can't happen 0481 } 0482 0483 KActionCollection *DolphinViewActionHandler::actionCollection() 0484 { 0485 return m_actionCollection; 0486 } 0487 0488 void DolphinViewActionHandler::updateViewActions() 0489 { 0490 QAction *viewModeAction = m_actionCollection->action(currentViewModeActionName()); 0491 if (viewModeAction) { 0492 viewModeAction->setChecked(true); 0493 0494 QAction *viewModeMenu = m_actionCollection->action(QStringLiteral("view_mode")); 0495 viewModeMenu->setIcon(viewModeAction->icon()); 0496 } 0497 0498 QAction *showPreviewAction = m_actionCollection->action(QStringLiteral("show_preview")); 0499 showPreviewAction->setChecked(m_currentView->previewsShown()); 0500 0501 slotSortOrderChanged(m_currentView->sortOrder()); 0502 slotSortFoldersFirstChanged(m_currentView->sortFoldersFirst()); 0503 slotSortHiddenLastChanged(m_currentView->sortHiddenLast()); 0504 slotVisibleRolesChanged(m_currentView->visibleRoles(), QList<QByteArray>()); 0505 slotGroupedSortingChanged(m_currentView->groupedSorting()); 0506 slotSortRoleChanged(m_currentView->sortRole()); 0507 slotZoomLevelChanged(m_currentView->zoomLevel(), -1); 0508 0509 // Updates the "show_hidden_files" action state and icon 0510 slotHiddenFilesShownChanged(m_currentView->hiddenFilesShown()); 0511 } 0512 0513 void DolphinViewActionHandler::zoomIn() 0514 { 0515 const int level = m_currentView->zoomLevel(); 0516 m_currentView->setZoomLevel(level + 1); 0517 updateViewActions(); 0518 } 0519 0520 void DolphinViewActionHandler::zoomOut() 0521 { 0522 const int level = m_currentView->zoomLevel(); 0523 m_currentView->setZoomLevel(level - 1); 0524 updateViewActions(); 0525 } 0526 0527 void DolphinViewActionHandler::zoomReset() 0528 { 0529 m_currentView->resetZoomLevel(); 0530 updateViewActions(); 0531 } 0532 0533 void DolphinViewActionHandler::toggleSortFoldersFirst() 0534 { 0535 const bool sortFirst = m_currentView->sortFoldersFirst(); 0536 m_currentView->setSortFoldersFirst(!sortFirst); 0537 } 0538 0539 void DolphinViewActionHandler::toggleSortHiddenLast() 0540 { 0541 const bool sortHiddenLast = m_currentView->sortHiddenLast(); 0542 m_currentView->setSortHiddenLast(!sortHiddenLast); 0543 } 0544 0545 void DolphinViewActionHandler::slotSortOrderChanged(Qt::SortOrder order) 0546 { 0547 QAction *descending = m_actionCollection->action(QStringLiteral("descending")); 0548 QAction *ascending = m_actionCollection->action(QStringLiteral("ascending")); 0549 const bool sortDescending = (order == Qt::DescendingOrder); 0550 descending->setChecked(sortDescending); 0551 ascending->setChecked(!sortDescending); 0552 } 0553 0554 void DolphinViewActionHandler::slotSortFoldersFirstChanged(bool foldersFirst) 0555 { 0556 m_actionCollection->action(QStringLiteral("folders_first"))->setChecked(foldersFirst); 0557 } 0558 0559 void DolphinViewActionHandler::slotSortHiddenLastChanged(bool hiddenLast) 0560 { 0561 m_actionCollection->action(QStringLiteral("hidden_last"))->setChecked(hiddenLast); 0562 } 0563 0564 void DolphinViewActionHandler::toggleVisibleRole(QAction *action) 0565 { 0566 Q_EMIT actionBeingHandled(); 0567 0568 const QByteArray toggledRole = action->data().toByteArray(); 0569 0570 QList<QByteArray> roles = m_currentView->visibleRoles(); 0571 0572 const bool show = action->isChecked(); 0573 0574 const int index = roles.indexOf(toggledRole); 0575 const bool containsInfo = (index >= 0); 0576 if (show && !containsInfo) { 0577 roles.append(toggledRole); 0578 m_currentView->setVisibleRoles(roles); 0579 } else if (!show && containsInfo) { 0580 roles.removeAt(index); 0581 m_currentView->setVisibleRoles(roles); 0582 Q_ASSERT(roles.indexOf(toggledRole) < 0); 0583 } 0584 } 0585 0586 void DolphinViewActionHandler::slotVisibleRolesChanged(const QList<QByteArray> ¤t, const QList<QByteArray> &previous) 0587 { 0588 Q_UNUSED(previous) 0589 0590 const auto checkedRoles = QSet<QByteArray>(current.constBegin(), current.constEnd()); 0591 QHashIterator<QByteArray, KToggleAction *> it(m_visibleRoles); 0592 while (it.hasNext()) { 0593 it.next(); 0594 const QByteArray &role = it.key(); 0595 KToggleAction *action = it.value(); 0596 action->setChecked(checkedRoles.contains(role)); 0597 } 0598 } 0599 0600 void DolphinViewActionHandler::toggleGroupedSorting(bool grouped) 0601 { 0602 m_currentView->setGroupedSorting(grouped); 0603 } 0604 0605 void DolphinViewActionHandler::slotGroupedSortingChanged(bool groupedSorting) 0606 { 0607 QAction *showInGroupsAction = m_actionCollection->action(QStringLiteral("show_in_groups")); 0608 showInGroupsAction->setChecked(groupedSorting); 0609 } 0610 0611 void DolphinViewActionHandler::toggleShowHiddenFiles(bool show) 0612 { 0613 Q_EMIT actionBeingHandled(); 0614 m_currentView->setHiddenFilesShown(show); 0615 } 0616 0617 void DolphinViewActionHandler::slotHiddenFilesShownChanged(bool shown) 0618 { 0619 QAction *showHiddenFilesAction = m_actionCollection->action(QStringLiteral("show_hidden_files")); 0620 showHiddenFilesAction->setChecked(shown); 0621 } 0622 0623 void DolphinViewActionHandler::slotWriteStateChanged(bool isFolderWritable) 0624 { 0625 m_actionCollection->action(QStringLiteral("create_dir"))->setEnabled(isFolderWritable && KProtocolManager::supportsMakeDir(currentView()->url())); 0626 } 0627 0628 KToggleAction *DolphinViewActionHandler::iconsModeAction() 0629 { 0630 KToggleAction *iconsView = m_actionCollection->add<KToggleAction>(QStringLiteral("icons")); 0631 iconsView->setText(i18nc("@action:inmenu View Mode", "Icons")); 0632 iconsView->setToolTip(i18nc("@info", "Icons view mode")); 0633 m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL | Qt::Key_1); 0634 iconsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-icons"))); 0635 iconsView->setData(QVariant::fromValue(DolphinView::IconsView)); 0636 return iconsView; 0637 } 0638 0639 KToggleAction *DolphinViewActionHandler::compactModeAction() 0640 { 0641 KToggleAction *iconsView = m_actionCollection->add<KToggleAction>(QStringLiteral("compact")); 0642 iconsView->setText(i18nc("@action:inmenu View Mode", "Compact")); 0643 iconsView->setToolTip(i18nc("@info", "Compact view mode")); 0644 m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL | Qt::Key_2); 0645 iconsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-details"))); // TODO: discuss with Oxygen-team the wrong (?) name 0646 iconsView->setData(QVariant::fromValue(DolphinView::CompactView)); 0647 return iconsView; 0648 } 0649 0650 KToggleAction *DolphinViewActionHandler::detailsModeAction() 0651 { 0652 KToggleAction *detailsView = m_actionCollection->add<KToggleAction>(QStringLiteral("details")); 0653 detailsView->setText(i18nc("@action:inmenu View Mode", "Details")); 0654 detailsView->setToolTip(i18nc("@info", "Details view mode")); 0655 m_actionCollection->setDefaultShortcut(detailsView, Qt::CTRL | Qt::Key_3); 0656 detailsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree"))); 0657 detailsView->setData(QVariant::fromValue(DolphinView::DetailsView)); 0658 return detailsView; 0659 } 0660 0661 void DolphinViewActionHandler::slotSortRoleChanged(const QByteArray &role) 0662 { 0663 KToggleAction *action = m_sortByActions.value(role); 0664 if (action) { 0665 action->setChecked(true); 0666 0667 if (!action->icon().isNull()) { 0668 QAction *sortByMenu = m_actionCollection->action(QStringLiteral("sort")); 0669 sortByMenu->setIcon(action->icon()); 0670 } 0671 } 0672 0673 QAction *descending = m_actionCollection->action(QStringLiteral("descending")); 0674 QAction *ascending = m_actionCollection->action(QStringLiteral("ascending")); 0675 0676 if (role == "text" || role == "type" || role == "extension" || role == "tags" || role == "comment") { 0677 descending->setText(i18nc("Sort descending", "Z-A")); 0678 ascending->setText(i18nc("Sort ascending", "A-Z")); 0679 } else if (role == "size") { 0680 descending->setText(i18nc("Sort descending", "Largest First")); 0681 ascending->setText(i18nc("Sort ascending", "Smallest First")); 0682 } else if (role == "modificationtime" || role == "creationtime" || role == "accesstime") { 0683 descending->setText(i18nc("Sort descending", "Newest First")); 0684 ascending->setText(i18nc("Sort ascending", "Oldest First")); 0685 } else if (role == "rating") { 0686 descending->setText(i18nc("Sort descending", "Highest First")); 0687 ascending->setText(i18nc("Sort ascending", "Lowest First")); 0688 } else { 0689 descending->setText(i18nc("Sort descending", "Descending")); 0690 ascending->setText(i18nc("Sort ascending", "Ascending")); 0691 } 0692 0693 slotSortOrderChanged(m_currentView->sortOrder()); 0694 } 0695 0696 void DolphinViewActionHandler::slotZoomLevelChanged(int current, int previous) 0697 { 0698 Q_UNUSED(previous) 0699 0700 QAction *zoomInAction = m_actionCollection->action(KStandardAction::name(KStandardAction::ZoomIn)); 0701 if (zoomInAction) { 0702 zoomInAction->setEnabled(current < ZoomLevelInfo::maximumLevel()); 0703 } 0704 0705 QAction *zoomOutAction = m_actionCollection->action(KStandardAction::name(KStandardAction::ZoomOut)); 0706 if (zoomOutAction) { 0707 zoomOutAction->setEnabled(current > ZoomLevelInfo::minimumLevel()); 0708 } 0709 } 0710 0711 void DolphinViewActionHandler::slotSortTriggered(QAction *action) 0712 { 0713 // The radiobuttons of the "Sort By"-menu are split between the main-menu 0714 // and several sub-menus. Because of this they don't have a common 0715 // action-group that assures an exclusive toggle-state between the main-menu 0716 // actions and the sub-menu-actions. If an action gets checked, it must 0717 // be assured that all other actions get unchecked, except the ascending/ 0718 // descending actions 0719 for (QAction *groupAction : std::as_const(m_sortByActions)) { 0720 KActionMenu *actionMenu = qobject_cast<KActionMenu *>(groupAction); 0721 if (actionMenu) { 0722 const auto actions = actionMenu->menu()->actions(); 0723 for (QAction *subAction : actions) { 0724 subAction->setChecked(false); 0725 } 0726 } else if (groupAction->actionGroup()) { 0727 groupAction->setChecked(false); 0728 } 0729 } 0730 action->setChecked(true); 0731 0732 // Apply the activated sort-role to the view 0733 const QByteArray role = action->data().toByteArray(); 0734 m_currentView->setSortRole(role); 0735 } 0736 0737 void DolphinViewActionHandler::slotAdjustViewProperties() 0738 { 0739 Q_EMIT actionBeingHandled(); 0740 QPointer<ViewPropertiesDialog> dialog = new ViewPropertiesDialog(m_currentView); 0741 dialog->exec(); 0742 delete dialog; 0743 } 0744 0745 void DolphinViewActionHandler::slotDuplicate() 0746 { 0747 if (m_currentView->selectedItemsCount() == 0) { 0748 Q_EMIT selectionModeChangeTriggered(true, SelectionMode::BottomBar::Contents::DuplicateContents); 0749 } else { 0750 Q_EMIT actionBeingHandled(); 0751 m_currentView->duplicateSelectedItems(); 0752 Q_EMIT selectionModeChangeTriggered(false); 0753 } 0754 } 0755 0756 void DolphinViewActionHandler::slotProperties() 0757 { 0758 KPropertiesDialog *dialog = nullptr; 0759 const KFileItemList list = m_currentView->selectedItems(); 0760 if (list.isEmpty()) { 0761 const QUrl url = m_currentView->url(); 0762 dialog = new KPropertiesDialog(url, m_currentView); 0763 } else { 0764 dialog = new KPropertiesDialog(list, m_currentView); 0765 } 0766 0767 dialog->setAttribute(Qt::WA_DeleteOnClose); 0768 dialog->show(); 0769 dialog->raise(); 0770 dialog->activateWindow(); 0771 } 0772 0773 void DolphinViewActionHandler::slotCopyPath() 0774 { 0775 if (m_currentView->selectedItemsCount() == 0) { 0776 Q_EMIT selectionModeChangeTriggered(true, SelectionMode::BottomBar::Contents::CopyLocationContents); 0777 } else { 0778 m_currentView->copyPathToClipboard(); 0779 Q_EMIT selectionModeChangeTriggered(false); 0780 } 0781 } 0782 0783 void DolphinViewActionHandler::slotSelectionChanged(const KFileItemList &selection) 0784 { 0785 QString basicActionsMenuText; 0786 if (selection.isEmpty()) { 0787 basicActionsMenuText = i18nc("@action:inmenu menu with actions like copy, paste, rename. The user's selection is empty when this text is shown.", 0788 "Actions for Current View"); 0789 } else { 0790 // clang-format off 0791 QFontMetrics fontMetrics = QMenu().fontMetrics(); 0792 // i18n: @action:inmenu menu with actions like copy, paste, rename. 0793 // %1 is a textual representation of the currently selected files or folders. This can be the name of 0794 // the file/files like "file1" or "file1, file2 and file3" or an aggregate like "8 Selected Folders". 0795 // If this sort of word puzzle can not be correctly translated in your language, translate it as "NULL" (without the quotes) 0796 // and a fallback will be used. 0797 basicActionsMenuText = i18n("Actions for %1", fileItemListToString(selection, fontMetrics.averageCharWidth() * 40, fontMetrics, ItemsState::Selected)); 0798 // clang-format on 0799 } 0800 0801 if (basicActionsMenuText == QStringLiteral("NULL")) { 0802 const KFileItemListProperties properties(selection); 0803 basicActionsMenuText = i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.", 0804 "Actions for One Selected Item", 0805 "Actions for %1 Selected Items", 0806 selection.count()); 0807 } 0808 0809 QAction *basicActionsMenu = m_actionCollection->action(QStringLiteral("basic_actions")); 0810 basicActionsMenu->setText(basicActionsMenuText); 0811 0812 // Add or remove contextual actions 0813 while (!basicActionsMenu->menu()->actions().constLast()->isSeparator()) { 0814 basicActionsMenu->menu()->removeAction(basicActionsMenu->menu()->actions().last()); 0815 } 0816 if (selection.count() == 1) { 0817 if (selection.first().isLink()) { 0818 basicActionsMenu->menu()->addAction(m_actionCollection->action(QStringLiteral("show_target"))); 0819 } 0820 if (selection.first().isDir()) { 0821 basicActionsMenu->menu()->addAction(m_actionCollection->action(QStringLiteral("add_to_places"))); 0822 } 0823 } 0824 } 0825 0826 #include "moc_dolphinviewactionhandler.cpp"