| 1 | /* |
| 2 | This file is part of the KDE libraries |
| 3 | SPDX-FileCopyrightText: 1999, 2000 Kurt Granroth <granroth@kde.org> |
| 4 | |
| 5 | SPDX-License-Identifier: LGPL-2.0-only |
| 6 | */ |
| 7 | |
| 8 | #ifndef KSTANDARDACTION_PRIVATE_H |
| 9 | #define KSTANDARDACTION_PRIVATE_H |
| 10 | |
| 11 | #include <QAction> |
| 12 | #include <QApplication> |
| 13 | |
| 14 | #include <KLazyLocalizedString> |
| 15 | #include <KLocalizedString> |
| 16 | #include <KStandardShortcut> |
| 17 | |
| 18 | #include <string> |
| 19 | |
| 20 | namespace KStandardAction |
| 21 | { |
| 22 | |
| 23 | // Helper class for storing raw data in static tables which can be used for QString instance |
| 24 | // creation at runtime without copying/converting to new memalloc'ed memory, as well as avoiding |
| 25 | // that way storing the strings directly as QStrings resulting in non-constexpr init code on |
| 26 | // library loading |
| 27 | struct RawStringData { |
| 28 | template<std::size_t StringSize> |
| 29 | constexpr inline RawStringData(const char16_t (&_data)[StringSize]) |
| 30 | : data(_data) |
| 31 | , size(std::char_traits<char16_t>::length(s: _data)) |
| 32 | { |
| 33 | } |
| 34 | constexpr inline RawStringData(std::nullptr_t) |
| 35 | { |
| 36 | } |
| 37 | constexpr inline RawStringData() = default; |
| 38 | |
| 39 | inline QString toString() const |
| 40 | { |
| 41 | if (!data) { |
| 42 | return QString(); |
| 43 | } |
| 44 | |
| 45 | return Qt::Literals::StringLiterals::operator""_s (str: data, size); |
| 46 | } |
| 47 | |
| 48 | private: |
| 49 | const char16_t *const data = nullptr; |
| 50 | const std::size_t size = 0; |
| 51 | }; |
| 52 | |
| 53 | struct KStandardActionInfo { |
| 54 | StandardAction id; |
| 55 | KStandardShortcut::StandardShortcut idAccel; |
| 56 | const RawStringData psName; |
| 57 | const KLazyLocalizedString psLabel; |
| 58 | const KLazyLocalizedString psToolTip; |
| 59 | const RawStringData psIconName; |
| 60 | }; |
| 61 | // clang-format off |
| 62 | static const KStandardActionInfo g_rgActionInfo[] = { |
| 63 | { .id: New, .idAccel: KStandardShortcut::New, .psName: u"file_new" , .psLabel: kli18n(text: "&New" ), .psToolTip: kli18n(text: "Create new document" ), .psIconName: u"document-new" }, |
| 64 | { .id: Open, .idAccel: KStandardShortcut::Open, .psName: u"file_open" , .psLabel: kli18n(text: "&Open…" ), .psToolTip: kli18n(text: "Open an existing document" ), .psIconName: u"document-open" }, |
| 65 | { .id: OpenRecent, .idAccel: KStandardShortcut::AccelNone, .psName: u"file_open_recent" , .psLabel: kli18n(text: "Open &Recent" ), .psToolTip: kli18n(text: "Open a document which was recently opened" ), .psIconName: u"document-open-recent" }, |
| 66 | { .id: Save, .idAccel: KStandardShortcut::Save, .psName: u"file_save" , .psLabel: kli18n(text: "&Save" ), .psToolTip: kli18n(text: "Save document" ), .psIconName: u"document-save" }, |
| 67 | { .id: SaveAs, .idAccel: KStandardShortcut::SaveAs, .psName: u"file_save_as" , .psLabel: kli18n(text: "Save &As…" ), .psToolTip: kli18n(text: "Save document under a new name" ), .psIconName: u"document-save-as" }, |
| 68 | { .id: Revert, .idAccel: KStandardShortcut::Revert, .psName: u"file_revert" , .psLabel: kli18n(text: "Re&vert" ), .psToolTip: kli18n(text: "Revert unsaved changes made to document" ), .psIconName: u"document-revert" }, |
| 69 | { .id: Close, .idAccel: KStandardShortcut::Close, .psName: u"file_close" , .psLabel: kli18n(text: "&Close" ), .psToolTip: kli18n(text: "Close document" ), .psIconName: u"document-close" }, |
| 70 | { .id: Print, .idAccel: KStandardShortcut::Print, .psName: u"file_print" , .psLabel: kli18n(text: "&Print…" ), .psToolTip: kli18n(text: "Print document" ), .psIconName: u"document-print" }, |
| 71 | { .id: PrintPreview, .idAccel: KStandardShortcut::PrintPreview, .psName: u"file_print_preview" , .psLabel: kli18n(text: "Print Previe&w" ), .psToolTip: kli18n(text: "Show a print preview of document" ), .psIconName: u"document-print-preview" }, |
| 72 | { .id: Mail, .idAccel: KStandardShortcut::Mail, .psName: u"file_mail" , .psLabel: kli18n(text: "&Mail…" ), .psToolTip: kli18n(text: "Send document by mail" ), .psIconName: u"mail-send" }, |
| 73 | { .id: Quit, .idAccel: KStandardShortcut::Quit, .psName: u"file_quit" , .psLabel: kli18n(text: "&Quit" ), .psToolTip: kli18n(text: "Quit application" ), .psIconName: u"application-exit" }, |
| 74 | |
| 75 | { .id: Undo, .idAccel: KStandardShortcut::Undo, .psName: u"edit_undo" , .psLabel: kli18n(text: "&Undo" ), .psToolTip: kli18n(text: "Undo last action" ), .psIconName: u"edit-undo" }, |
| 76 | { .id: Redo, .idAccel: KStandardShortcut::Redo, .psName: u"edit_redo" , .psLabel: kli18n(text: "Re&do" ), .psToolTip: kli18n(text: "Redo last undone action" ), .psIconName: u"edit-redo" }, |
| 77 | { .id: Cut, .idAccel: KStandardShortcut::Cut, .psName: u"edit_cut" , .psLabel: kli18n(text: "Cu&t" ), .psToolTip: kli18n(text: "Cut selection to clipboard" ), .psIconName: u"edit-cut" }, |
| 78 | { .id: Copy, .idAccel: KStandardShortcut::Copy, .psName: u"edit_copy" , .psLabel: kli18n(text: "&Copy" ), .psToolTip: kli18n(text: "Copy selection to clipboard" ), .psIconName: u"edit-copy" }, |
| 79 | { .id: Paste, .idAccel: KStandardShortcut::Paste, .psName: u"edit_paste" , .psLabel: kli18n(text: "&Paste" ), .psToolTip: kli18n(text: "Paste clipboard content" ), .psIconName: u"edit-paste" }, |
| 80 | { .id: Clear, .idAccel: KStandardShortcut::Clear, .psName: u"edit_clear" , .psLabel: kli18n(text: "C&lear" ), .psToolTip: {}, .psIconName: u"edit-clear" }, |
| 81 | { .id: SelectAll, .idAccel: KStandardShortcut::SelectAll, .psName: u"edit_select_all" , .psLabel: kli18n(text: "Select &All" ), .psToolTip: {}, .psIconName: u"edit-select-all" }, |
| 82 | { .id: Deselect, .idAccel: KStandardShortcut::Deselect, .psName: u"edit_deselect" , .psLabel: kli18n(text: "Dese&lect" ), .psToolTip: {}, .psIconName: u"edit-select-none" }, |
| 83 | { .id: Find, .idAccel: KStandardShortcut::Find, .psName: u"edit_find" , .psLabel: kli18n(text: "&Find…" ), .psToolTip: {}, .psIconName: u"edit-find" }, |
| 84 | { .id: FindNext, .idAccel: KStandardShortcut::FindNext, .psName: u"edit_find_next" , .psLabel: kli18n(text: "Find &Next" ), .psToolTip: {}, .psIconName: u"go-down-search" }, |
| 85 | { .id: FindPrev, .idAccel: KStandardShortcut::FindPrev, .psName: u"edit_find_prev" , .psLabel: kli18n(text: "Find Pre&vious" ), .psToolTip: {}, .psIconName: u"go-up-search" }, |
| 86 | { .id: Replace, .idAccel: KStandardShortcut::Replace, .psName: u"edit_replace" , .psLabel: kli18n(text: "&Replace…" ), .psToolTip: {}, .psIconName: u"edit-find-replace" }, |
| 87 | |
| 88 | { .id: ActualSize, .idAccel: KStandardShortcut::ActualSize, .psName: u"view_actual_size" , .psLabel: kli18n(text: "Zoom to &Actual Size" ), .psToolTip: kli18n(text: "View document at its actual size" ), .psIconName: u"zoom-original" }, |
| 89 | { .id: FitToPage, .idAccel: KStandardShortcut::FitToPage, .psName: u"view_fit_to_page" , .psLabel: kli18n(text: "&Fit to Page" ), .psToolTip: kli18n(text: "Zoom to fit page in window" ), .psIconName: u"zoom-fit-page" }, |
| 90 | { .id: FitToWidth, .idAccel: KStandardShortcut::FitToWidth, .psName: u"view_fit_to_width" , .psLabel: kli18n(text: "Fit to Page &Width" ), .psToolTip: kli18n(text: "Zoom to fit page width in window" ), .psIconName: u"zoom-fit-width" }, |
| 91 | { .id: FitToHeight, .idAccel: KStandardShortcut::FitToHeight, .psName: u"view_fit_to_height" , .psLabel: kli18n(text: "Fit to Page &Height" ), .psToolTip: kli18n(text: "Zoom to fit page height in window" ), .psIconName: u"zoom-fit-height" }, |
| 92 | { .id: ZoomIn, .idAccel: KStandardShortcut::ZoomIn, .psName: u"view_zoom_in" , .psLabel: kli18n(text: "Zoom &In" ), .psToolTip: {}, .psIconName: u"zoom-in" }, |
| 93 | { .id: ZoomOut, .idAccel: KStandardShortcut::ZoomOut, .psName: u"view_zoom_out" , .psLabel: kli18n(text: "Zoom &Out" ), .psToolTip: {}, .psIconName: u"zoom-out" }, |
| 94 | { .id: Zoom, .idAccel: KStandardShortcut::Zoom, .psName: u"view_zoom" , .psLabel: kli18n(text: "&Zoom…" ), .psToolTip: kli18n(text: "Select zoom level" ), .psIconName: u"zoom" }, |
| 95 | { .id: Redisplay, .idAccel: KStandardShortcut::Reload, .psName: u"view_redisplay" , .psLabel: kli18n(text: "&Refresh" ), .psToolTip: kli18n(text: "Refresh document" ), .psIconName: u"view-refresh" }, |
| 96 | |
| 97 | { .id: Up, .idAccel: KStandardShortcut::Up, .psName: u"go_up" , .psLabel: kli18n(text: "&Up" ), .psToolTip: kli18n(text: "Go up" ), .psIconName: u"go-up" }, |
| 98 | // The following three have special i18n() needs for sLabel |
| 99 | { .id: Back, .idAccel: KStandardShortcut::Back, .psName: u"go_back" , .psLabel: {}, .psToolTip: {}, .psIconName: u"go-previous" }, |
| 100 | { .id: Forward, .idAccel: KStandardShortcut::Forward, .psName: u"go_forward" , .psLabel: {}, .psToolTip: {}, .psIconName: u"go-next" }, |
| 101 | { .id: Home, .idAccel: KStandardShortcut::Home, .psName: u"go_home" , .psLabel: {}, .psToolTip: {}, .psIconName: u"go-home" }, |
| 102 | { .id: Prior, .idAccel: KStandardShortcut::Prior, .psName: u"go_previous" , .psLabel: kli18n(text: "&Previous Page" ), .psToolTip: kli18n(text: "Go to previous page" ), .psIconName: u"go-previous-view-page" }, |
| 103 | { .id: Next, .idAccel: KStandardShortcut::Next, .psName: u"go_next" , .psLabel: kli18n(text: "&Next Page" ), .psToolTip: kli18n(text: "Go to next page" ), .psIconName: u"go-next-view-page" }, |
| 104 | { .id: Goto, .idAccel: KStandardShortcut::Goto, .psName: u"go_goto" , .psLabel: kli18n(text: "&Go To…" ), .psToolTip: {}, .psIconName: {} }, |
| 105 | { .id: GotoPage, .idAccel: KStandardShortcut::GotoPage, .psName: u"go_goto_page" , .psLabel: kli18n(text: "&Go to Page…" ), .psToolTip: {}, .psIconName: u"go-jump" }, |
| 106 | { .id: GotoLine, .idAccel: KStandardShortcut::GotoLine, .psName: u"go_goto_line" , .psLabel: kli18n(text: "&Go to Line…" ), .psToolTip: {}, .psIconName: {} }, |
| 107 | { .id: FirstPage, .idAccel: KStandardShortcut::Begin, .psName: u"go_first" , .psLabel: kli18n(text: "&First Page" ), .psToolTip: kli18n(text: "Go to first page" ), .psIconName: u"go-first-view-page" }, |
| 108 | { .id: LastPage, .idAccel: KStandardShortcut::End, .psName: u"go_last" , .psLabel: kli18n(text: "&Last Page" ), .psToolTip: kli18n(text: "Go to last page" ), .psIconName: u"go-last-view-page" }, |
| 109 | { .id: DocumentBack, .idAccel: KStandardShortcut::DocumentBack, .psName: u"go_document_back" , .psLabel: kli18n(text: "&Back" ), .psToolTip: kli18n(text: "Go back in document" ), .psIconName: u"go-previous" }, |
| 110 | { .id: DocumentForward, .idAccel: KStandardShortcut::DocumentForward, .psName: u"go_document_forward" , .psLabel: kli18n(text: "&Forward" ), .psToolTip: kli18n(text: "Go forward in document" ), .psIconName: u"go-next" }, |
| 111 | |
| 112 | { .id: AddBookmark, .idAccel: KStandardShortcut::AddBookmark, .psName: u"bookmark_add" , .psLabel: kli18n(text: "&Add Bookmark" ), .psToolTip: {}, .psIconName: u"bookmark-new" }, |
| 113 | { .id: EditBookmarks, .idAccel: KStandardShortcut::EditBookmarks, .psName: u"bookmark_edit" , .psLabel: kli18n(text: "&Edit Bookmarks…" ), .psToolTip: {}, .psIconName: u"bookmarks-organize" }, |
| 114 | |
| 115 | { .id: Spelling, .idAccel: KStandardShortcut::Spelling, .psName: u"tools_spelling" , .psLabel: kli18n(text: "&Spelling…" ), .psToolTip: kli18n(text: "Check spelling in document" ), .psIconName: u"tools-check-spelling" }, |
| 116 | |
| 117 | { .id: ShowMenubar, .idAccel: KStandardShortcut::ShowMenubar, .psName: u"options_show_menubar" , .psLabel: kli18n(text: "Show &Menubar" ), .psToolTip: kli18n(text: "Show or hide menubar" ), .psIconName: u"show-menu" }, |
| 118 | { .id: ShowToolbar, .idAccel: KStandardShortcut::ShowToolbar, .psName: u"options_show_toolbar" , .psLabel: kli18n(text: "Show &Toolbar" ), .psToolTip: kli18n(text: "Show or hide toolbar" ), .psIconName: {} }, |
| 119 | { .id: ShowStatusbar, .idAccel: KStandardShortcut::ShowStatusbar, .psName: u"options_show_statusbar" , .psLabel: kli18n(text: "Show St&atusbar" ), .psToolTip: kli18n(text: "Show or hide statusbar" ), .psIconName: {} }, |
| 120 | { .id: FullScreen, .idAccel: KStandardShortcut::FullScreen, .psName: u"fullscreen" , .psLabel: kli18n(text: "F&ull Screen Mode" ), .psToolTip: {}, .psIconName: u"view-fullscreen" }, |
| 121 | { .id: KeyBindings, .idAccel: KStandardShortcut::KeyBindings, .psName: u"options_configure_keybinding" , .psLabel: kli18n(text: "Configure Keyboard S&hortcuts…" ), .psToolTip: {}, .psIconName: u"configure-shortcuts" }, |
| 122 | { .id: Preferences, .idAccel: KStandardShortcut::Preferences, .psName: u"options_configure" , .psLabel: kli18n(text: "&Configure %1…" ), .psToolTip: {}, .psIconName: u"configure" }, |
| 123 | { .id: ConfigureToolbars, .idAccel: KStandardShortcut::ConfigureToolbars, .psName: u"options_configure_toolbars" , .psLabel: kli18n(text: "Configure Tool&bars…" ), .psToolTip: {}, .psIconName: u"configure-toolbars" }, |
| 124 | { .id: ConfigureNotifications, .idAccel: KStandardShortcut::ConfigureNotifications, .psName: u"options_configure_notifications" , .psLabel: kli18n(text: "Configure &Notifications…" ), .psToolTip: {}, .psIconName: u"preferences-desktop-notification" }, |
| 125 | |
| 126 | // the idea here is that Contents is used in menus, and Help in dialogs, so both share the same |
| 127 | // shortcut |
| 128 | { .id: HelpContents, .idAccel: KStandardShortcut::Help, .psName: u"help_contents" , .psLabel: kli18n(text: "%1 &Handbook" ), .psToolTip: {}, .psIconName: u"help-contents" }, |
| 129 | { .id: WhatsThis, .idAccel: KStandardShortcut::WhatsThis, .psName: u"help_whats_this" , .psLabel: kli18n(text: "What's &This?" ), .psToolTip: {}, .psIconName: u"help-contextual" }, |
| 130 | { .id: ReportBug, .idAccel: KStandardShortcut::ReportBug, .psName: u"help_report_bug" , .psLabel: kli18n(text: "&Report Bug…" ), .psToolTip: {}, .psIconName: u"tools-report-bug" }, |
| 131 | { .id: SwitchApplicationLanguage, .idAccel: KStandardShortcut::SwitchApplicationLanguage, .psName: u"switch_application_language" , .psLabel: kli18n(text: "Configure &Language…" ), .psToolTip: {}, .psIconName: u"preferences-desktop-locale" }, |
| 132 | { .id: AboutApp, .idAccel: KStandardShortcut::AccelNone, .psName: u"help_about_app" , .psLabel: kli18n(text: "&About %1" ), .psToolTip: {}, .psIconName: nullptr }, |
| 133 | { .id: AboutKDE, .idAccel: KStandardShortcut::AccelNone, .psName: u"help_about_kde" , .psLabel: kli18n(text: "About &KDE" ), .psToolTip: {}, .psIconName: u"kde" }, |
| 134 | { .id: DeleteFile, .idAccel: KStandardShortcut::DeleteFile, .psName: u"deletefile" , .psLabel: kli18n(text: "&Delete" ), .psToolTip: {}, .psIconName: u"edit-delete" }, |
| 135 | { .id: RenameFile, .idAccel: KStandardShortcut::RenameFile, .psName: u"renamefile" , .psLabel: kli18n(text: "&Rename…" ), .psToolTip: {}, .psIconName: u"edit-rename" }, |
| 136 | { .id: MoveToTrash, .idAccel: KStandardShortcut::MoveToTrash, .psName: u"movetotrash" , .psLabel: kli18n(text: "&Move to Trash" ), .psToolTip: {}, .psIconName: u"trash-empty" }, |
| 137 | { .id: Donate, .idAccel: KStandardShortcut::Donate, .psName: u"help_donate" , .psLabel: kli18n(text: "&Donate" ), .psToolTip: {}, .psIconName: u"help-donate" }, |
| 138 | { .id: HamburgerMenu, .idAccel: KStandardShortcut::OpenMainMenu, .psName: u"hamburger_menu" , .psLabel: kli18n(text: "Open &Menu" ), .psToolTip: {}, .psIconName: u"application-menu" }, |
| 139 | { .id: ActionNone, .idAccel: KStandardShortcut::AccelNone, .psName: nullptr, .psLabel: {}, .psToolTip: {}, .psIconName: nullptr } |
| 140 | }; |
| 141 | // clang-format on |
| 142 | |
| 143 | inline const KStandardActionInfo *infoPtr(StandardAction id) |
| 144 | { |
| 145 | for (uint i = 0; g_rgActionInfo[i].id != ActionNone; i++) { |
| 146 | if (g_rgActionInfo[i].id == id) { |
| 147 | return &g_rgActionInfo[i]; |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | return nullptr; |
| 152 | } |
| 153 | |
| 154 | static inline QStringList internal_stdNames() |
| 155 | { |
| 156 | QStringList result; |
| 157 | |
| 158 | for (uint i = 0; g_rgActionInfo[i].id != ActionNone; i++) |
| 159 | if (!g_rgActionInfo[i].psLabel.isEmpty()) { |
| 160 | if (QByteArrayView(g_rgActionInfo[i].psLabel.untranslatedText()).contains(a: "%1" )) |
| 161 | // Prevents KLocalizedString::toString() from complaining about unsubstituted placeholder. |
| 162 | { |
| 163 | result.append(t: g_rgActionInfo[i].psLabel.subs(a: QString()).toString()); |
| 164 | } else { |
| 165 | result.append(t: g_rgActionInfo[i].psLabel.toString()); |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | return result; |
| 170 | } |
| 171 | |
| 172 | class AutomaticAction : public QAction |
| 173 | { |
| 174 | Q_OBJECT |
| 175 | |
| 176 | public: |
| 177 | AutomaticAction(const QIcon &icon, const QString &text, KStandardShortcut::StandardShortcut standardShortcut, const char *slot, QObject *parent); |
| 178 | public Q_SLOTS: |
| 179 | inline void cut() |
| 180 | { |
| 181 | invokeEditSlot(slot: "cut" ); |
| 182 | } |
| 183 | inline void copy() |
| 184 | { |
| 185 | invokeEditSlot(slot: "copy" ); |
| 186 | } |
| 187 | inline void paste() |
| 188 | { |
| 189 | invokeEditSlot(slot: "paste" ); |
| 190 | } |
| 191 | inline void clear() |
| 192 | { |
| 193 | invokeEditSlot(slot: "clear" ); |
| 194 | } |
| 195 | inline void selectAll() |
| 196 | { |
| 197 | invokeEditSlot(slot: "selectAll" ); |
| 198 | } |
| 199 | |
| 200 | void invokeEditSlot(const char *slot) |
| 201 | { |
| 202 | if (qApp->focusWidget()) { |
| 203 | QMetaObject::invokeMethod(qApp->focusWidget(), member: slot); |
| 204 | } |
| 205 | } |
| 206 | }; |
| 207 | |
| 208 | } |
| 209 | |
| 210 | #endif |
| 211 | |