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 (QByteArray(g_rgActionInfo[i].psLabel.untranslatedText()).contains(bv: "%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 | |