1 /**************************************************************************
2 * Otter Browser: Web browser controlled by the user, not vice-versa.
3 * Copyright (C) 2013 - 2018 Michal Dutkiewicz aka Emdek <michal@emdek.pl>
4 * Copyright (C) 2014 - 2015 Piotr Wójcik <chocimier@tlen.pl>
5 * Copyright (C) 2015 Jan Bajer aka bajasoft <jbajer@gmail.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 **************************************************************************/
21 
22 #include "ActionsManager.h"
23 #include "JsonSettings.h"
24 #include "SessionsManager.h"
25 #include "ThemesManager.h"
26 
27 #include <QtCore/QJsonArray>
28 #include <QtCore/QJsonObject>
29 #include <QtCore/QMetaEnum>
30 #include <QtCore/QTextStream>
31 #include <QtGui/QKeySequence>
32 
33 namespace Otter
34 {
35 
operator ==(const KeyboardProfile::Action & other) const36 bool KeyboardProfile::Action::operator ==(const KeyboardProfile::Action &other) const
37 {
38 	return (shortcuts == other.shortcuts && parameters == other.parameters && action == other.action);
39 }
40 
KeyboardProfile(const QString & identifier,LoadMode mode)41 KeyboardProfile::KeyboardProfile(const QString &identifier, LoadMode mode) : Addon(),
42 	m_identifier(identifier),
43 	m_isModified(false)
44 {
45 	if (identifier.isEmpty())
46 	{
47 		return;
48 	}
49 
50 	const JsonSettings settings(SessionsManager::getReadableDataPath(QLatin1String("keyboard/") + identifier + QLatin1String(".json")));
51 	const QStringList comments(settings.getComment().split(QLatin1Char('\n')));
52 
53 	for (int i = 0; i < comments.count(); ++i)
54 	{
55 		const QString key(comments.at(i).section(QLatin1Char(':'), 0, 0).trimmed());
56 		const QString value(comments.at(i).section(QLatin1Char(':'), 1).trimmed());
57 
58 		if (key == QLatin1String("Title"))
59 		{
60 			m_title = value;
61 		}
62 		else if (key == QLatin1String("Description"))
63 		{
64 			m_description = value;
65 		}
66 		else if (key == QLatin1String("Author"))
67 		{
68 			m_author = value;
69 		}
70 		else if (key == QLatin1String("Version"))
71 		{
72 			m_version = value;
73 		}
74 	}
75 
76 	if (mode == MetaDataOnlyMode)
77 	{
78 		return;
79 	}
80 
81 	const QJsonArray contextsArray(settings.array());
82 	const bool areSingleKeyShortcutsAllowed((mode == FullMode) ? true : SettingsManager::getOption(SettingsManager::Browser_EnableSingleKeyShortcutsOption).toBool());
83 
84 	for (int i = 0; i < contextsArray.count(); ++i)
85 	{
86 		const QJsonArray actionsArray(contextsArray.at(i).toObject().value(QLatin1String("actions")).toArray());
87 		QVector<Action> definitions;
88 		definitions.reserve(actionsArray.count());
89 
90 		for (int j = 0; j < actionsArray.count(); ++j)
91 		{
92 			const QJsonObject actionObject(actionsArray.at(j).toObject());
93 			const int action(ActionsManager::getActionIdentifier(actionObject.value(QLatin1String("action")).toString()));
94 
95 			if (action < 0)
96 			{
97 				continue;
98 			}
99 
100 			const QJsonArray shortcutsArray(actionObject.value(QLatin1String("shortcuts")).toArray());
101 			QVector<QKeySequence> shortcuts;
102 			shortcuts.reserve(shortcutsArray.count());
103 
104 			for (int k = 0; k < shortcutsArray.count(); ++k)
105 			{
106 				const QKeySequence shortcut(shortcutsArray.at(k).toString());
107 
108 				if (shortcut.isEmpty() || (!areSingleKeyShortcutsAllowed && !ActionsManager::isShortcutAllowed(shortcut, ActionsManager::DisallowSingleKeyShortcutCheck, false)))
109 				{
110 					continue;
111 				}
112 
113 				shortcuts.append(shortcut);
114 			}
115 
116 			if (shortcuts.isEmpty())
117 			{
118 				continue;
119 			}
120 
121 			KeyboardProfile::Action definition;
122 			definition.shortcuts = shortcuts;
123 			definition.parameters = actionObject.value(QLatin1String("parameters")).toVariant().toMap();
124 			definition.action = action;
125 
126 			definitions.append(definition);
127 		}
128 
129 		m_definitions[ActionsManager::GenericContext] = definitions;
130 	}
131 }
132 
setTitle(const QString & title)133 void KeyboardProfile::setTitle(const QString &title)
134 {
135 	if (title != m_title)
136 	{
137 		m_title = title;
138 		m_isModified = true;
139 	}
140 }
141 
setDescription(const QString & description)142 void KeyboardProfile::setDescription(const QString &description)
143 {
144 	if (description != m_description)
145 	{
146 		m_description = description;
147 		m_isModified = true;
148 	}
149 }
150 
setAuthor(const QString & author)151 void KeyboardProfile::setAuthor(const QString &author)
152 {
153 	if (author != m_author)
154 	{
155 		m_author = author;
156 		m_isModified = true;
157 	}
158 }
159 
setVersion(const QString & version)160 void KeyboardProfile::setVersion(const QString &version)
161 {
162 	if (version != m_version)
163 	{
164 		m_version = version;
165 		m_isModified = true;
166 	}
167 }
168 
setDefinitions(const QHash<int,QVector<KeyboardProfile::Action>> & definitions)169 void KeyboardProfile::setDefinitions(const QHash<int, QVector<KeyboardProfile::Action> > &definitions)
170 {
171 	if (definitions != m_definitions)
172 	{
173 		m_definitions = definitions;
174 		m_isModified = true;
175 	}
176 }
177 
setModified(bool isModified)178 void KeyboardProfile::setModified(bool isModified)
179 {
180 	m_isModified = isModified;
181 }
182 
getName() const183 QString KeyboardProfile::getName() const
184 {
185 	return m_identifier;
186 }
187 
getTitle() const188 QString KeyboardProfile::getTitle() const
189 {
190 	return (m_title.isEmpty() ? QCoreApplication::translate("Otter::KeyboardProfile", "(Untitled)") : m_title);
191 }
192 
getDescription() const193 QString KeyboardProfile::getDescription() const
194 {
195 	return m_description;
196 }
197 
getAuthor() const198 QString KeyboardProfile::getAuthor() const
199 {
200 	return m_author;
201 }
202 
getVersion() const203 QString KeyboardProfile::getVersion() const
204 {
205 	return m_version;
206 }
207 
getDefinitions() const208 QHash<int, QVector<KeyboardProfile::Action> > KeyboardProfile::getDefinitions() const
209 {
210 	return m_definitions;
211 }
212 
isModified() const213 bool KeyboardProfile::isModified() const
214 {
215 	return m_isModified;
216 }
217 
save()218 bool KeyboardProfile::save()
219 {
220 	JsonSettings settings(SessionsManager::getWritableDataPath(QLatin1String("keyboard/") + m_identifier + QLatin1String(".json")));
221 	QString comment;
222 	QTextStream stream(&comment);
223 	stream.setCodec("UTF-8");
224 	stream << QLatin1String("Title: ") << (m_title.isEmpty() ? QT_TR_NOOP("(Untitled)") : m_title) << QLatin1Char('\n');
225 	stream << QLatin1String("Description: ") << m_description << QLatin1Char('\n');
226 	stream << QLatin1String("Type: keyboard-profile\n");
227 	stream << QLatin1String("Author: ") << m_author << QLatin1Char('\n');
228 	stream << QLatin1String("Version: ") << m_version;
229 
230 	settings.setComment(comment);
231 
232 	QJsonArray contextsArray;
233 	QHash<int, QVector<KeyboardProfile::Action> >::const_iterator contextsIterator;
234 
235 	for (contextsIterator = m_definitions.begin(); contextsIterator != m_definitions.end(); ++contextsIterator)
236 	{
237 		QJsonArray actionsArray;
238 
239 		for (int i = 0; i < contextsIterator.value().count(); ++i)
240 		{
241 			const KeyboardProfile::Action &action(contextsIterator.value().at(i));
242 			QJsonArray shortcutsArray;
243 
244 			for (int j = 0; j < action.shortcuts.count(); ++j)
245 			{
246 				shortcutsArray.append(action.shortcuts.at(j).toString());
247 			}
248 
249 			QJsonObject actionObject{{QLatin1String("action"), ActionsManager::getActionName(action.action)}, {QLatin1String("shortcuts"), shortcutsArray}};
250 
251 			if (!action.parameters.isEmpty())
252 			{
253 				actionObject.insert(QLatin1String("parameters"), QJsonObject::fromVariantMap(action.parameters));
254 			}
255 
256 			actionsArray.append(actionObject);
257 		}
258 
259 		contextsArray.append(QJsonObject({{QLatin1String("context"), QLatin1String("Generic")}, {QLatin1String("actions"), actionsArray}}));
260 	}
261 
262 	settings.setArray(contextsArray);
263 
264 	const bool result(settings.save());
265 
266 	if (result)
267 	{
268 		m_isModified = false;
269 	}
270 
271 	return result;
272 }
273 
274 ActionsManager* ActionsManager::m_instance(nullptr);
275 QMap<int, QVector<QKeySequence> > ActionsManager::m_shortcuts;
276 QMultiMap<int, QPair<QVariantMap, QVector<QKeySequence> > > ActionsManager::m_extraShortcuts;
277 QVector<QKeySequence> ActionsManager::m_disallowedShortcuts;
278 QVector<ActionsManager::ActionDefinition> ActionsManager::m_definitions;
279 int ActionsManager::m_actionIdentifierEnumerator(0);
280 
ActionsManager(QObject * parent)281 ActionsManager::ActionsManager(QObject *parent) : QObject(parent),
282 	m_reloadTimer(0)
283 {
284 	m_definitions.reserve(ActionsManager::OtherAction);
285 
286 	registerAction(RunMacroAction, QT_TRANSLATE_NOOP("actions", "Run Macro"), QT_TRANSLATE_NOOP("actions", "Run Arbitrary List of Actions"), {}, ActionDefinition::ApplicationScope, ActionDefinition::RequiresParameters);
287 	registerAction(SetOptionAction, QT_TRANSLATE_NOOP("actions", "Set Option"), QT_TRANSLATE_NOOP("actions", "Set, Reset or Toggle Option"), {}, ActionDefinition::ApplicationScope, ActionDefinition::RequiresParameters);
288 	registerAction(NewTabAction, QT_TRANSLATE_NOOP("actions", "New Tab"), {}, ThemesManager::createIcon(QLatin1String("tab-new")), ActionDefinition::MainWindowScope);
289 	registerAction(NewTabPrivateAction, QT_TRANSLATE_NOOP("actions", "New Private Tab"), {}, ThemesManager::createIcon(QLatin1String("tab-new-private")), ActionDefinition::MainWindowScope);
290 	registerAction(NewWindowAction, QT_TRANSLATE_NOOP("actions", "New Window"), {}, ThemesManager::createIcon(QLatin1String("window-new")), ActionDefinition::ApplicationScope);
291 	registerAction(NewWindowPrivateAction, QT_TRANSLATE_NOOP("actions", "New Private Window"), {}, ThemesManager::createIcon(QLatin1String("window-new-private")), ActionDefinition::ApplicationScope);
292 	registerAction(OpenAction, QT_TRANSLATE_NOOP("actions", "Open…"), {}, ThemesManager::createIcon(QLatin1String("document-open")), ActionDefinition::MainWindowScope);
293 	registerAction(SaveAction, QT_TRANSLATE_NOOP("actions", "Save…"), {}, ThemesManager::createIcon(QLatin1String("document-save")), ActionDefinition::WindowScope);
294 	registerAction(CloneTabAction, QT_TRANSLATE_NOOP("actions", "Clone Tab"), {}, {}, ActionDefinition::WindowScope);
295 	registerAction(PeekTabAction, QT_TRANSLATE_NOOP("actions", "Peek Tab"), {}, {}, ActionDefinition::MainWindowScope);
296 	registerAction(PinTabAction, QT_TRANSLATE_NOOP("actions", "Pin Tab"), {}, {}, ActionDefinition::WindowScope);
297 	registerAction(DetachTabAction, QT_TRANSLATE_NOOP("actions", "Detach Tab"), {}, {}, ActionDefinition::WindowScope);
298 	registerAction(MaximizeTabAction, QT_TRANSLATE_NOOP("actions", "Maximize"), QT_TRANSLATE_NOOP("actions", "Maximize Tab"), {}, ActionDefinition::WindowScope);
299 	registerAction(MinimizeTabAction, QT_TRANSLATE_NOOP("actions", "Minimize"), QT_TRANSLATE_NOOP("actions", "Minimize Tab"), {}, ActionDefinition::WindowScope);
300 	registerAction(RestoreTabAction, QT_TRANSLATE_NOOP("actions", "Restore"), QT_TRANSLATE_NOOP("actions", "Restore Tab"), {}, ActionDefinition::WindowScope);
301 	registerAction(AlwaysOnTopTabAction, QT_TRANSLATE_NOOP("actions", "Stay on Top"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsCheckableFlag));
302 	registerAction(ClearTabHistoryAction, QT_TRANSLATE_NOOP("actions", "Clear Tab History"), QT_TRANSLATE_NOOP("actions", "Remove Local Tab History"), {}, ActionDefinition::WindowScope, ActionDefinition::NoFlags, ActionsManager::ActionDefinition::NavigationCategory);
303 	registerAction(PurgeTabHistoryAction, QT_TRANSLATE_NOOP("actions", "Purge Tab History"), QT_TRANSLATE_NOOP("actions", "Remove Local and Global Tab History"), {}, ActionDefinition::WindowScope, ActionDefinition::IsDeprecatedFlag, ActionsManager::ActionDefinition::NavigationCategory);
304 	registerAction(MuteTabMediaAction, QT_TRANSLATE_NOOP("actions", "Mute Tab Media"), {}, ThemesManager::createIcon(QLatin1String("audio-volume-muted")), ActionDefinition::WindowScope);
305 	registerAction(SuspendTabAction, QT_TRANSLATE_NOOP("actions", "Suspend Tab"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::NoFlags);
306 	registerAction(CloseTabAction, QT_TRANSLATE_NOOP("actions", "Close Tab"), {}, ThemesManager::createIcon(QLatin1String("tab-close")), ActionDefinition::WindowScope);
307 	registerAction(CloseOtherTabsAction, QT_TRANSLATE_NOOP("actions", "Close Other Tabs"), {}, ThemesManager::createIcon(QLatin1String("tab-close-other")), ActionDefinition::MainWindowScope);
308 	registerAction(ClosePrivateTabsAction, QT_TRANSLATE_NOOP("actions", "Close All Private Tabs"), QT_TRANSLATE_NOOP("actions", "Close All Private Tabs in Current Window"), {}, ActionDefinition::MainWindowScope, ActionDefinition::NoFlags);
309 	registerAction(ClosePrivateTabsPanicAction, QT_TRANSLATE_NOOP("actions", "Close Private Tabs and Windows"), {}, {}, ActionDefinition::ApplicationScope);
310 	registerAction(ReopenTabAction, QT_TRANSLATE_NOOP("actions", "Reopen Previously Closed Tab"), {}, {}, ActionDefinition::MainWindowScope, ActionDefinition::NoFlags);
311 	registerAction(MaximizeAllAction, QT_TRANSLATE_NOOP("actions", "Maximize All"), {}, {}, ActionDefinition::MainWindowScope);
312 	registerAction(MinimizeAllAction, QT_TRANSLATE_NOOP("actions", "Minimize All"), {}, {}, ActionDefinition::MainWindowScope);
313 	registerAction(RestoreAllAction, QT_TRANSLATE_NOOP("actions", "Restore All"), {}, {}, ActionDefinition::MainWindowScope);
314 	registerAction(CascadeAllAction, QT_TRANSLATE_NOOP("actions", "Cascade"), {}, {}, ActionDefinition::MainWindowScope);
315 	registerAction(TileAllAction, QT_TRANSLATE_NOOP("actions", "Tile"), {}, {}, ActionDefinition::MainWindowScope);
316 	registerAction(CloseWindowAction, QT_TRANSLATE_NOOP("actions", "Close Window"), {}, {}, ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
317 	registerAction(ReopenWindowAction, QT_TRANSLATE_NOOP("actions", "Reopen Previously Closed Window"), {}, {}, ActionDefinition::ApplicationScope, ActionDefinition::NoFlags);
318 	registerAction(SessionsAction, QT_TRANSLATE_NOOP("actions", "Manage Sessions…"), {}, {}, ActionDefinition::ApplicationScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
319 	registerAction(SaveSessionAction, QT_TRANSLATE_NOOP("actions", "Save Current Session…"), {}, {}, ActionDefinition::ApplicationScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
320 	registerAction(OpenUrlAction, QT_TRANSLATE_NOOP("actions", "Open URL"), {}, {}, ActionDefinition::MainWindowScope, ActionDefinition::RequiresParameters);
321 	registerAction(OpenLinkAction, QT_TRANSLATE_NOOP("actions", "Open"), {}, ThemesManager::createIcon(QLatin1String("document-open")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::LinkCategory);
322 	registerAction(OpenLinkInCurrentTabAction, QT_TRANSLATE_NOOP("actions", "Open in This Tab"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::LinkCategory);
323 	registerAction(OpenLinkInNewTabAction, QT_TRANSLATE_NOOP("actions", "Open in New Tab"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::LinkCategory);
324 	registerAction(OpenLinkInNewTabBackgroundAction, QT_TRANSLATE_NOOP("actions", "Open in New Background Tab"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::LinkCategory);
325 	registerAction(OpenLinkInNewWindowAction, QT_TRANSLATE_NOOP("actions", "Open in New Window"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::LinkCategory);
326 	registerAction(OpenLinkInNewWindowBackgroundAction, QT_TRANSLATE_NOOP("actions", "Open in New Background Window"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::LinkCategory);
327 	registerAction(OpenLinkInNewPrivateTabAction, QT_TRANSLATE_NOOP("actions", "Open in New Private Tab"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::LinkCategory);
328 	registerAction(OpenLinkInNewPrivateTabBackgroundAction, QT_TRANSLATE_NOOP("actions", "Open in New Private Background Tab"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::LinkCategory);
329 	registerAction(OpenLinkInNewPrivateWindowAction, QT_TRANSLATE_NOOP("actions", "Open in New Private Window"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::LinkCategory);
330 	registerAction(OpenLinkInNewPrivateWindowBackgroundAction, QT_TRANSLATE_NOOP("actions", "Open in New Private Background Window"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::LinkCategory);
331 	registerAction(CopyLinkToClipboardAction, QT_TRANSLATE_NOOP("actions", "Copy Link to Clipboard"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::LinkCategory);
332 	registerAction(BookmarkLinkAction, QT_TRANSLATE_NOOP("actions", "Bookmark Link…"), {}, ThemesManager::createIcon(QLatin1String("bookmark-new")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::LinkCategory);
333 	registerAction(SaveLinkToDiskAction, QT_TRANSLATE_NOOP("actions", "Save Link Target As…"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::LinkCategory);
334 	registerAction(SaveLinkToDownloadsAction, QT_TRANSLATE_NOOP("actions", "Save to Downloads"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::LinkCategory);
335 	registerAction(OpenSelectionAsLinkAction, QT_TRANSLATE_NOOP("actions", "Go to This Address"), {}, {}, ActionDefinition::WindowScope);
336 	registerAction(OpenFrameAction, QT_TRANSLATE_NOOP("actions", "Open"), QT_TRANSLATE_NOOP("actions", "Open Frame"), {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::FrameCategory);
337 	registerAction(OpenFrameInCurrentTabAction, QT_TRANSLATE_NOOP("actions", "Open"), QT_TRANSLATE_NOOP("actions", "Open Frame in This Tab"), {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::FrameCategory);
338 	registerAction(OpenFrameInNewTabAction, QT_TRANSLATE_NOOP("actions", "Open in New Tab"), QT_TRANSLATE_NOOP("actions", "Open Frame in New Tab"), {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::FrameCategory);
339 	registerAction(OpenFrameInNewTabBackgroundAction, QT_TRANSLATE_NOOP("actions", "Open in New Background Tab"), QT_TRANSLATE_NOOP("actions", "Open Frame in New Background Tab"), {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::FrameCategory);
340 	registerAction(CopyFrameLinkToClipboardAction, QT_TRANSLATE_NOOP("actions", "Copy Frame Link to Clipboard"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::FrameCategory);
341 	registerAction(ReloadFrameAction, QT_TRANSLATE_NOOP("actions", "Reload"), QT_TRANSLATE_NOOP("actions", "Reload Frame"), {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::FrameCategory);
342 	registerAction(ViewFrameSourceAction, QT_TRANSLATE_NOOP("actions", "View Frame Source"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::FrameCategory);
343 	registerAction(OpenImageAction, QT_TRANSLATE_NOOP("actions", "Open Image"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::ImageCategory);
344 	registerAction(OpenImageInNewTabAction, QT_TRANSLATE_NOOP("actions", "Open Image In New Tab"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::ImageCategory);
345 	registerAction(OpenImageInNewTabBackgroundAction, QT_TRANSLATE_NOOP("actions", "Open Image in New Background Tab"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::ImageCategory);
346 	registerAction(SaveImageToDiskAction, QT_TRANSLATE_NOOP("actions", "Save Image…"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::ImageCategory);
347 	registerAction(CopyImageToClipboardAction, QT_TRANSLATE_NOOP("actions", "Copy Image to Clipboard"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::ImageCategory);
348 	registerAction(CopyImageUrlToClipboardAction, QT_TRANSLATE_NOOP("actions", "Copy Image Link to Clipboard"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::ImageCategory);
349 	registerAction(ReloadImageAction, QT_TRANSLATE_NOOP("actions", "Reload Image"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::ImageCategory);
350 	registerAction(ImagePropertiesAction, QT_TRANSLATE_NOOP("actions", "Image Properties…"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::ImageCategory);
351 	registerAction(SaveMediaToDiskAction, QT_TRANSLATE_NOOP("actions", "Save Media…"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::MediaCategory);
352 	registerAction(CopyMediaUrlToClipboardAction, QT_TRANSLATE_NOOP("actions", "Copy Media Link to Clipboard"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::MediaCategory);
353 	registerAction(MediaControlsAction, QT_TRANSLATE_NOOP("actions", "Show Controls"), QT_TRANSLATE_NOOP("actions", "Show Media Controls"), {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsCheckableFlag), ActionDefinition::MediaCategory);
354 	registerAction(MediaLoopAction, QT_TRANSLATE_NOOP("actions", "Looping"), QT_TRANSLATE_NOOP("actions", "Playback Looping"), {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsCheckableFlag), ActionDefinition::MediaCategory);
355 	registerAction(MediaPlayPauseAction, QT_TRANSLATE_NOOP("actions", "Play"), QT_TRANSLATE_NOOP("actions", "Play Media"), ThemesManager::createIcon(QLatin1String("media-playback-start")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::MediaCategory);
356 	registerAction(MediaMuteAction, QT_TRANSLATE_NOOP("actions", "Mute"), QT_TRANSLATE_NOOP("actions", "Mute Media"), ThemesManager::createIcon(QLatin1String("audio-volume-muted")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::MediaCategory);
357 	registerAction(MediaPlaybackRateAction, QT_TRANSLATE_NOOP("actions", "Playback Rate"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsCheckableFlag, ActionDefinition::MediaCategory);
358 	registerAction(FillPasswordAction, QT_TRANSLATE_NOOP("actions", "Log In"), {}, ThemesManager::createIcon(QLatin1String("fill-password")), ActionDefinition::WindowScope, ActionDefinition::NoFlags, ActionDefinition::PageCategory);
359 	registerAction(GoAction, QT_TRANSLATE_NOOP("actions", "Go"), QT_TRANSLATE_NOOP("actions", "Go to URL"), ThemesManager::createIcon(QLatin1String("go-jump-locationbar")), ActionDefinition::MainWindowScope);
360 	registerAction(GoBackAction, QT_TRANSLATE_NOOP("actions", "Back"), QT_TRANSLATE_NOOP("actions", "Go Back"), ThemesManager::createIcon(QLatin1String("go-previous")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::NavigationCategory);
361 	registerAction(GoForwardAction, QT_TRANSLATE_NOOP("actions", "Forward"), QT_TRANSLATE_NOOP("actions", "Go Forward"), ThemesManager::createIcon(QLatin1String("go-next")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::NavigationCategory);
362 	registerAction(GoToHistoryIndexAction, QT_TRANSLATE_NOOP("actions", "Go to History Entry"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::RequiresParameters, ActionDefinition::NavigationCategory);
363 	registerAction(GoToPageAction, QT_TRANSLATE_NOOP("actions", "Go to Page or Search"), {}, {}, ActionDefinition::MainWindowScope);
364 	registerAction(GoToHomePageAction, QT_TRANSLATE_NOOP("actions", "Go to Home Page"), {}, ThemesManager::createIcon(QLatin1String("go-home")), ActionDefinition::MainWindowScope);
365 	registerAction(GoToParentDirectoryAction, QT_TRANSLATE_NOOP("actions", "Go to Parent Directory"), {}, {}, ActionDefinition::WindowScope);
366 	registerAction(RewindAction, QT_TRANSLATE_NOOP("actions", "Rewind"), QT_TRANSLATE_NOOP("actions", "Rewind History"), ThemesManager::createIcon(QLatin1String("go-first")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::NavigationCategory);
367 	registerAction(FastForwardAction, QT_TRANSLATE_NOOP("actions", "Fast Forward"), {}, ThemesManager::createIcon(QLatin1String("go-last")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::NavigationCategory);
368 	registerAction(RemoveHistoryIndexAction, QT_TRANSLATE_NOOP("actions", "Remove History Entry"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::RequiresParameters, ActionDefinition::NavigationCategory);
369 	registerAction(StopAction, QT_TRANSLATE_NOOP("actions", "Stop"), {}, ThemesManager::createIcon(QLatin1String("process-stop")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::NavigationCategory);
370 	registerAction(StopScheduledReloadAction, QT_TRANSLATE_NOOP("actions", "Stop Scheduled Page Reload"), {}, {}, ActionDefinition::WindowScope);
371 	registerAction(StopAllAction, QT_TRANSLATE_NOOP("actions", "Stop All Pages"), {}, ThemesManager::createIcon(QLatin1String("process-stop")), ActionDefinition::MainWindowScope);
372 	registerAction(ReloadAction, QT_TRANSLATE_NOOP("actions", "Reload"), {}, ThemesManager::createIcon(QLatin1String("view-refresh")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::NavigationCategory);
373 	registerAction(ReloadOrStopAction, QT_TRANSLATE_NOOP("actions", "Reload"), QT_TRANSLATE_NOOP("actions", "Reload or Stop"), ThemesManager::createIcon(QLatin1String("view-refresh")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::NavigationCategory);
374 	registerAction(ReloadAndBypassCacheAction, QT_TRANSLATE_NOOP("actions", "Reload and Bypass Cache"), {}, {}, ActionDefinition::WindowScope);
375 	registerAction(ReloadAllAction, QT_TRANSLATE_NOOP("actions", "Reload All Tabs"), {}, ThemesManager::createIcon(QLatin1String("view-refresh")), ActionDefinition::MainWindowScope);
376 	registerAction(ScheduleReloadAction, QT_TRANSLATE_NOOP("actions", "Schedule Page Reload"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsCheckableFlag));
377 	registerAction(ContextMenuAction, QT_TRANSLATE_NOOP("actions", "Show Context Menu"), {}, {}, ActionDefinition::WindowScope);
378 	registerAction(UndoAction, QT_TRANSLATE_NOOP("actions", "Undo"), {}, ThemesManager::createIcon(QLatin1String("edit-undo")), ActionDefinition::EditorScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
379 	registerAction(RedoAction, QT_TRANSLATE_NOOP("actions", "Redo"), {}, ThemesManager::createIcon(QLatin1String("edit-redo")), ActionDefinition::EditorScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
380 	registerAction(CutAction, QT_TRANSLATE_NOOP("actions", "Cut"), {}, ThemesManager::createIcon(QLatin1String("edit-cut")), ActionDefinition::EditorScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
381 	registerAction(CopyAction, QT_TRANSLATE_NOOP("actions", "Copy"), {}, ThemesManager::createIcon(QLatin1String("edit-copy")), ActionDefinition::EditorScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
382 	registerAction(CopyPlainTextAction, QT_TRANSLATE_NOOP("actions", "Copy as Plain Text"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag), ActionDefinition::EditingCategory);
383 	registerAction(CopyAddressAction, QT_TRANSLATE_NOOP("actions", "Copy Address"), {}, {}, ActionDefinition::WindowScope);
384 	registerAction(CopyToNoteAction, QT_TRANSLATE_NOOP("actions", "Copy to Note"), {}, {}, ActionDefinition::EditorScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
385 	registerAction(PasteAction, QT_TRANSLATE_NOOP("actions", "Paste"), {}, ThemesManager::createIcon(QLatin1String("edit-paste")), ActionDefinition::EditorScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
386 	registerAction(PasteAndGoAction, QT_TRANSLATE_NOOP("actions", "Paste and Go"), {}, {}, ActionDefinition::WindowScope);
387 	registerAction(DeleteAction, QT_TRANSLATE_NOOP("actions", "Delete"), {}, ThemesManager::createIcon(QLatin1String("edit-delete")), ActionDefinition::EditorScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
388 	registerAction(SelectAllAction, QT_TRANSLATE_NOOP("actions", "Select All"), {}, ThemesManager::createIcon(QLatin1String("edit-select-all")), ActionDefinition::EditorScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
389 	registerAction(UnselectAction, QT_TRANSLATE_NOOP("actions", "Deselect"), {}, {}, ActionDefinition::EditorScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
390 	registerAction(ClearAllAction, QT_TRANSLATE_NOOP("actions", "Clear All"), {}, {}, ActionDefinition::EditorScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
391 	registerAction(CheckSpellingAction, QT_TRANSLATE_NOOP("actions", "Check Spelling"), {}, {}, ActionDefinition::EditorScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsCheckableFlag), ActionDefinition::EditingCategory);
392 	registerAction(FindAction, QT_TRANSLATE_NOOP("actions", "Find…"), {}, ThemesManager::createIcon(QLatin1String("edit-find")), ActionDefinition::WindowScope);
393 	registerAction(FindNextAction, QT_TRANSLATE_NOOP("actions", "Find Next"), {}, ThemesManager::createIcon(QLatin1String("go-down")), ActionDefinition::WindowScope);
394 	registerAction(FindPreviousAction, QT_TRANSLATE_NOOP("actions", "Find Previous"), {}, ThemesManager::createIcon(QLatin1String("go-up")), ActionDefinition::WindowScope);
395 	registerAction(QuickFindAction, QT_TRANSLATE_NOOP("actions", "Quick Find"), {}, {}, ActionDefinition::WindowScope);
396 	registerAction(SearchAction, QT_TRANSLATE_NOOP("actions", "Search"), {}, ThemesManager::createIcon(QLatin1String("edit-find")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
397 	registerAction(CreateSearchAction, QT_TRANSLATE_NOOP("actions", "Create Search…"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::EditingCategory);
398 	registerAction(ZoomInAction, QT_TRANSLATE_NOOP("actions", "Zoom In"), {}, ThemesManager::createIcon(QLatin1String("zoom-in")), ActionDefinition::WindowScope);
399 	registerAction(ZoomOutAction, QT_TRANSLATE_NOOP("actions", "Zoom Out"), {}, ThemesManager::createIcon(QLatin1String("zoom-out")), ActionDefinition::WindowScope);
400 	registerAction(ZoomOriginalAction, QT_TRANSLATE_NOOP("actions", "Zoom Original"), {}, ThemesManager::createIcon(QLatin1String("zoom-original")), ActionDefinition::WindowScope);
401 	registerAction(ScrollToStartAction, QT_TRANSLATE_NOOP("actions", "Go to Start of the Page"), {}, {}, ActionDefinition::WindowScope);
402 	registerAction(ScrollToEndAction, QT_TRANSLATE_NOOP("actions", "Go to the End of the Page"), {}, {}, ActionDefinition::WindowScope);
403 	registerAction(ScrollPageUpAction, QT_TRANSLATE_NOOP("actions", "Page Up"), {}, {}, ActionDefinition::WindowScope);
404 	registerAction(ScrollPageDownAction, QT_TRANSLATE_NOOP("actions", "Page Down"), {}, {}, ActionDefinition::WindowScope);
405 	registerAction(ScrollPageLeftAction, QT_TRANSLATE_NOOP("actions", "Page Left"), {}, {}, ActionDefinition::WindowScope);
406 	registerAction(ScrollPageRightAction, QT_TRANSLATE_NOOP("actions", "Page Right"), {}, {}, ActionDefinition::WindowScope);
407 	registerAction(StartDragScrollAction, QT_TRANSLATE_NOOP("actions", "Enter Drag Scroll Mode"), {}, {}, ActionDefinition::WindowScope);
408 	registerAction(StartMoveScrollAction, QT_TRANSLATE_NOOP("actions", "Enter Move Scroll Mode"), {}, {}, ActionDefinition::WindowScope);
409 	registerAction(EndScrollAction, QT_TRANSLATE_NOOP("actions", "Exit Scroll Mode"), {}, {}, ActionDefinition::WindowScope);
410 	registerAction(PrintAction, QT_TRANSLATE_NOOP("actions", "Print…"), {}, ThemesManager::createIcon(QLatin1String("document-print")), ActionDefinition::WindowScope);
411 	registerAction(PrintPreviewAction, QT_TRANSLATE_NOOP("actions", "Print Preview"), {}, ThemesManager::createIcon(QLatin1String("document-print-preview")), ActionDefinition::WindowScope);
412 	registerAction(TakeScreenshotAction, QT_TRANSLATE_NOOP("actions", "Take Screenshot"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::NoFlags);
413 	registerAction(ActivateAddressFieldAction, QT_TRANSLATE_NOOP("actions", "Activate Address Field"), {}, {}, ActionDefinition::MainWindowScope);
414 	registerAction(ActivateSearchFieldAction, QT_TRANSLATE_NOOP("actions", "Activate Search Field"), {}, {}, ActionDefinition::MainWindowScope);
415 	registerAction(ActivateContentAction, QT_TRANSLATE_NOOP("actions", "Activate Content"), {}, {}, ActionDefinition::WindowScope);
416 	registerAction(ActivatePreviouslyUsedTabAction, QT_TRANSLATE_NOOP("actions", "Go to Previously Used Tab"), {}, {}, ActionDefinition::MainWindowScope);
417 	registerAction(ActivateLeastRecentlyUsedTabAction, QT_TRANSLATE_NOOP("actions", "Go to Least Recently Used Tab"), {}, {}, ActionDefinition::MainWindowScope);
418 	registerAction(ActivateTabAction, QT_TRANSLATE_NOOP("actions", "Activate Tab"), {}, {}, ActionDefinition::MainWindowScope, ActionDefinition::RequiresParameters);
419 	registerAction(ActivateTabOnLeftAction, QT_TRANSLATE_NOOP("actions", "Go to Tab on Left"), {}, {}, ActionDefinition::MainWindowScope);
420 	registerAction(ActivateTabOnRightAction, QT_TRANSLATE_NOOP("actions", "Go to Tab on Right"), {}, {}, ActionDefinition::MainWindowScope);
421 	registerAction(ActivateWindowAction, QT_TRANSLATE_NOOP("actions", "Activate Window"), {}, {}, ActionDefinition::ApplicationScope, ActionDefinition::RequiresParameters);
422 	registerAction(BookmarksAction, QT_TRANSLATE_NOOP("actions", "Manage Bookmarks"), {}, ThemesManager::createIcon(QLatin1String("bookmarks-organize")), ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
423 	registerAction(BookmarkPageAction, QT_TRANSLATE_NOOP("actions", "Bookmark Page…"), {}, ThemesManager::createIcon(QLatin1String("bookmark-new")), ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::PageCategory);
424 	registerAction(BookmarkAllOpenPagesAction, QT_TRANSLATE_NOOP("actions", "Bookmark All Open Pages"), {}, {}, ActionDefinition::MainWindowScope);
425 	registerAction(OpenBookmarkAction, QT_TRANSLATE_NOOP("actions", "Open Bookmark"), {}, {}, ActionDefinition::MainWindowScope, ActionDefinition::RequiresParameters);
426 	registerAction(QuickBookmarkAccessAction, QT_TRANSLATE_NOOP("actions", "Quick Bookmark Access"), {}, {}, ActionDefinition::MainWindowScope);
427 	registerAction(CookiesAction, QT_TRANSLATE_NOOP("actions", "Cookies"), {}, ThemesManager::createIcon(QLatin1String("cookies")), ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
428 	registerAction(LoadPluginsAction, QT_TRANSLATE_NOOP("actions", "Load All Plugins on the Page"), {}, ThemesManager::createIcon(QLatin1String("preferences-plugin")), ActionDefinition::WindowScope, ActionDefinition::NoFlags);
429 	registerAction(EnableJavaScriptAction, QT_TRANSLATE_NOOP("actions", "Enable JavaScript"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsCheckableFlag), ActionDefinition::PageCategory);
430 	registerAction(EnableReferrerAction, QT_TRANSLATE_NOOP("actions", "Enable Referrer"), {}, {}, ActionDefinition::WindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsCheckableFlag), ActionDefinition::PageCategory);
431 	registerAction(ViewSourceAction, QT_TRANSLATE_NOOP("actions", "View Source"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::NoFlags, ActionDefinition::NavigationCategory);
432 	registerAction(InspectPageAction, QT_TRANSLATE_NOOP("actions", "Inspect Page"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsCheckableFlag);
433 	registerAction(InspectElementAction, QT_TRANSLATE_NOOP("actions", "Inspect Element…"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::NoFlags);
434 	registerAction(WorkOfflineAction, QT_TRANSLATE_NOOP("actions", "Work Offline"), {}, {}, ActionDefinition::ApplicationScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsCheckableFlag));
435 	registerAction(FullScreenAction, QT_TRANSLATE_NOOP("actions", "Full Screen"), {}, ThemesManager::createIcon(QLatin1String("view-fullscreen")), ActionDefinition::MainWindowScope);
436 	registerAction(ShowTabSwitcherAction, QT_TRANSLATE_NOOP("actions", "Show Tab Switcher"), {}, {}, ActionDefinition::MainWindowScope);
437 	registerAction(ShowToolBarAction, QT_TRANSLATE_NOOP("actions", "Show Toolbar"), {}, {}, ActionDefinition::MainWindowScope, (ActionDefinition::IsCheckableFlag | ActionDefinition::RequiresParameters));
438 	registerAction(ShowMenuBarAction, QT_TRANSLATE_NOOP("actions", "Show Menubar"), {}, {}, ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag | ActionDefinition::IsCheckableFlag));
439 	registerAction(ShowTabBarAction, QT_TRANSLATE_NOOP("actions", "Show Tabbar"), {}, {}, ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag | ActionDefinition::IsCheckableFlag));
440 	registerAction(ShowSidebarAction, QT_TRANSLATE_NOOP("actions", "Show Sidebar"), {}, ThemesManager::createIcon(QLatin1String("sidebar-show")), ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsDeprecatedFlag | ActionDefinition::IsCheckableFlag));
441 	registerAction(ShowErrorConsoleAction, QT_TRANSLATE_NOOP("actions", "Show Error Console"), {}, {}, ActionDefinition::MainWindowScope, (ActionDefinition::IsDeprecatedFlag | ActionDefinition::IsCheckableFlag));
442 	registerAction(LockToolBarsAction, QT_TRANSLATE_NOOP("actions", "Lock Toolbars"), {}, {}, ActionDefinition::ApplicationScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsCheckableFlag));
443 	registerAction(ResetToolBarsAction, QT_TRANSLATE_NOOP("actions", "Reset to Defaults…"), QT_TRANSLATE_NOOP("actions", "Reset Toolbars to Defaults…"), {}, ActionDefinition::ApplicationScope);
444 	registerAction(ShowPanelAction, QT_TRANSLATE_NOOP("actions", "Show Panel"), QT_TRANSLATE_NOOP("actions", "Show Specified Panel in Sidebar"), {}, ActionDefinition::MainWindowScope);
445 	registerAction(OpenPanelAction, QT_TRANSLATE_NOOP("actions", "Open Panel as Tab"), QT_TRANSLATE_NOOP("actions", "Open Curent Sidebar Panel as Tab"), ThemesManager::createIcon(QLatin1String("arrow-right")), ActionDefinition::MainWindowScope);
446 	registerAction(ContentBlockingAction, QT_TRANSLATE_NOOP("actions", "Content Blocking…"), {}, ThemesManager::createIcon(QLatin1String("content-blocking")), ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
447 	registerAction(HistoryAction, QT_TRANSLATE_NOOP("actions", "View History"), {}, ThemesManager::createIcon(QLatin1String("view-history")), ActionDefinition::MainWindowScope);
448 	registerAction(ClearHistoryAction, QT_TRANSLATE_NOOP("actions", "Clear History…"), {}, ThemesManager::createIcon(QLatin1String("edit-clear-history")), ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
449 	registerAction(AddonsAction, QT_TRANSLATE_NOOP("actions", "Addons"), {}, ThemesManager::createIcon(QLatin1String("preferences-plugin")), ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
450 	registerAction(NotesAction, QT_TRANSLATE_NOOP("actions", "Notes"), {}, ThemesManager::createIcon(QLatin1String("notes")), ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
451 	registerAction(PasswordsAction, QT_TRANSLATE_NOOP("actions", "Passwords"), {}, ThemesManager::createIcon(QLatin1String("dialog-password")), ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
452 	registerAction(TransfersAction, QT_TRANSLATE_NOOP("actions", "Downloads"), {}, ThemesManager::createIcon(QLatin1String("transfers")), ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
453 	registerAction(PreferencesAction, QT_TRANSLATE_NOOP("actions", "Preferences…"), {}, {}, ActionDefinition::MainWindowScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
454 	registerAction(WebsitePreferencesAction, QT_TRANSLATE_NOOP("actions", "Website Preferences…"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::IsEnabledFlag, ActionDefinition::PageCategory);
455 	registerAction(QuickPreferencesAction, QT_TRANSLATE_NOOP("actions", "Quick Preferences"), {}, {}, ActionDefinition::WindowScope);
456 	registerAction(ResetQuickPreferencesAction, QT_TRANSLATE_NOOP("actions", "Reset Options"), {}, {}, ActionDefinition::WindowScope, ActionDefinition::NoFlags);
457 	registerAction(WebsiteInformationAction, QT_TRANSLATE_NOOP("actions", "Website Information…"), {}, {}, ActionDefinition::WindowScope);
458 	registerAction(WebsiteCertificateInformationAction, QT_TRANSLATE_NOOP("actions", "Website Certificate Information…"), {}, {}, ActionDefinition::WindowScope);
459 	registerAction(SwitchApplicationLanguageAction, QT_TRANSLATE_NOOP("actions", "Switch Application Language…"), {}, ThemesManager::createIcon(QLatin1String("preferences-desktop-locale")), ActionDefinition::ApplicationScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
460 	registerAction(CheckForUpdatesAction, QT_TRANSLATE_NOOP("actions", "Check for Updates…"), {}, {}, ActionDefinition::ApplicationScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
461 	registerAction(DiagnosticReportAction, QT_TRANSLATE_NOOP("actions", "Diagnostic Report…"), {}, {}, ActionDefinition::ApplicationScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
462 	registerAction(AboutApplicationAction, QT_TRANSLATE_NOOP("actions", "About Otter…"), {}, ThemesManager::createIcon(QLatin1String("otter-browser"), false), ActionDefinition::ApplicationScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
463 	registerAction(AboutQtAction, QT_TRANSLATE_NOOP("actions", "About Qt…"), {}, ThemesManager::createIcon(QLatin1String("qt")), ActionDefinition::ApplicationScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
464 	registerAction(ExitAction, QT_TRANSLATE_NOOP("actions", "Exit"), {}, ThemesManager::createIcon(QLatin1String("application-exit")), ActionDefinition::ApplicationScope, (ActionDefinition::IsEnabledFlag | ActionDefinition::IsImmutableFlag));
465 
466 	connect(SettingsManager::getInstance(), &SettingsManager::optionChanged, this, &ActionsManager::handleOptionChanged);
467 }
468 
createInstance()469 void ActionsManager::createInstance()
470 {
471 	if (!m_instance)
472 	{
473 		m_instance = new ActionsManager(QCoreApplication::instance());
474 		m_actionIdentifierEnumerator = ActionsManager::staticMetaObject.indexOfEnumerator(QLatin1String("ActionIdentifier").data());
475 
476 		loadProfiles();
477 	}
478 }
479 
timerEvent(QTimerEvent * event)480 void ActionsManager::timerEvent(QTimerEvent *event)
481 {
482 	if (event->timerId() == m_reloadTimer)
483 	{
484 		killTimer(m_reloadTimer);
485 
486 		m_reloadTimer = 0;
487 
488 		loadProfiles();
489 	}
490 }
491 
loadProfiles()492 void ActionsManager::loadProfiles()
493 {
494 	m_shortcuts.clear();
495 	m_extraShortcuts.clear();
496 
497 	QVector<QKeySequence> allShortcuts;
498 	const QStringList profiles(SettingsManager::getOption(SettingsManager::Browser_KeyboardShortcutsProfilesOrderOption).toStringList());
499 
500 	for (int i = 0; i < profiles.count(); ++i)
501 	{
502 		const QHash<int, QVector<KeyboardProfile::Action> > definitions(KeyboardProfile(profiles.at(i)).getDefinitions());
503 		QHash<int, QVector<KeyboardProfile::Action> >::const_iterator iterator;
504 
505 		for (iterator = definitions.constBegin(); iterator != definitions.constEnd(); ++iterator)
506 		{
507 			for (int j = 0; j < iterator.value().count(); ++j)
508 			{
509 				const KeyboardProfile::Action definition(iterator.value().at(j));
510 				QVector<QKeySequence> shortcuts;
511 
512 				if (definition.parameters.isEmpty() && m_shortcuts.contains(definition.action))
513 				{
514 					shortcuts = m_shortcuts[definition.action];
515 				}
516 				else if (!definition.parameters.isEmpty() && m_extraShortcuts.contains(definition.action))
517 				{
518 					const QList<QPair<QVariantMap, QVector<QKeySequence> > > extraDefinitions(m_extraShortcuts.values(definition.action));
519 
520 					for (int k = 0; k < extraDefinitions.count(); ++k)
521 					{
522 						if (extraDefinitions.at(k).first == definition.parameters)
523 						{
524 							shortcuts = extraDefinitions.at(k).second;
525 
526 							break;
527 						}
528 					}
529 				}
530 
531 				for (int k = 0; k < definition.shortcuts.count(); ++k)
532 				{
533 					const QKeySequence shortcut(definition.shortcuts.at(k));
534 
535 					if (!allShortcuts.contains(shortcut))
536 					{
537 						shortcuts.append(shortcut);
538 						allShortcuts.append(shortcut);
539 					}
540 				}
541 
542 				if (!shortcuts.isEmpty())
543 				{
544 					if (definition.parameters.isEmpty())
545 					{
546 						m_shortcuts[definition.action] = shortcuts;
547 					}
548 					else
549 					{
550 						m_extraShortcuts.insert(definition.action, {definition.parameters, shortcuts});
551 					}
552 				}
553 			}
554 		}
555 	}
556 
557 	emit m_instance->shortcutsChanged();
558 }
559 
registerAction(int identifier,const QString & text,const QString & description,const QIcon & icon,ActionDefinition::ActionScope scope,ActionDefinition::ActionFlags flags,ActionDefinition::ActionCategory category)560 void ActionsManager::registerAction(int identifier, const QString &text, const QString &description, const QIcon &icon, ActionDefinition::ActionScope scope, ActionDefinition::ActionFlags flags, ActionDefinition::ActionCategory category)
561 {
562 	ActionsManager::ActionDefinition action;
563 	action.description = description;
564 	action.defaultState.text = text;
565 	action.defaultState.icon = icon;
566 	action.defaultState.isEnabled = flags.testFlag(ActionDefinition::IsEnabledFlag);
567 	action.identifier = identifier;
568 	action.flags = flags;
569 	action.category = category;
570 	action.scope = scope;
571 
572 	m_definitions.append(action);
573 }
574 
handleOptionChanged(int identifier)575 void ActionsManager::handleOptionChanged(int identifier)
576 {
577 	switch (identifier)
578 	{
579 		case SettingsManager::Browser_EnableSingleKeyShortcutsOption:
580 		case SettingsManager::Browser_KeyboardShortcutsProfilesOrderOption:
581 			if (m_reloadTimer == 0)
582 			{
583 				m_reloadTimer = startTimer(250);
584 			}
585 
586 			break;
587 		default:
588 			break;
589 	}
590 }
591 
getInstance()592 ActionsManager* ActionsManager::getInstance()
593 {
594 	return m_instance;
595 }
596 
createReport()597 QString ActionsManager::createReport()
598 {
599 	QString report;
600 	QTextStream stream(&report);
601 	stream.setFieldAlignment(QTextStream::AlignLeft);
602 	stream << QLatin1String("Keyboard Shortcuts:\n");
603 
604 	for (int i = 0; i < m_definitions.count(); ++i)
605 	{
606 		if (m_shortcuts.contains(i))
607 		{
608 			const QVector<QKeySequence> shortcuts(m_shortcuts[i]);
609 
610 			stream << QLatin1Char('\t');
611 			stream.setFieldWidth(30);
612 			stream << getActionName(i);
613 			stream.setFieldWidth(20);
614 
615 			for (int j = 0; j < shortcuts.count(); ++j)
616 			{
617 				stream << shortcuts.at(j).toString(QKeySequence::PortableText);
618 			}
619 
620 			stream.setFieldWidth(0);
621 			stream << QLatin1Char('\n');
622 		}
623 
624 		if (m_extraShortcuts.contains(i))
625 		{
626 			const QList<QPair<QVariantMap, QVector<QKeySequence> > > definitions(m_extraShortcuts.values(i));
627 
628 			if (!m_shortcuts.contains(i))
629 			{
630 				stream << QLatin1Char('\t');
631 				stream.setFieldWidth(30);
632 				stream << getActionName(i);
633 				stream.setFieldWidth(0);
634 				stream << QLatin1Char('\n');
635 			}
636 
637 			for (int j = 0; j < definitions.count(); ++j)
638 			{
639 				const QVector<QKeySequence> shortcuts(definitions.at(j).second);
640 
641 				stream << QLatin1Char('\t');
642 				stream.setFieldWidth(30);
643 				stream << QLatin1Char(' ') + QJsonDocument(QJsonObject::fromVariantMap(definitions.at(j).first)).toJson(QJsonDocument::Compact);
644 				stream.setFieldWidth(20);
645 
646 				for (int k = 0; k < shortcuts.count(); ++k)
647 				{
648 					stream << shortcuts.at(k).toString(QKeySequence::PortableText);
649 				}
650 
651 				stream.setFieldWidth(0);
652 				stream << QLatin1Char('\n');
653 			}
654 		}
655 	}
656 
657 	stream << QLatin1Char('\n');
658 
659 	return report;
660 }
661 
getActionName(int identifier)662 QString ActionsManager::getActionName(int identifier)
663 {
664 	QString name(ActionsManager::staticMetaObject.enumerator(m_actionIdentifierEnumerator).valueToKey(identifier));
665 
666 	if (!name.isEmpty())
667 	{
668 		name.chop(6);
669 
670 		return name;
671 	}
672 
673 	return {};
674 }
675 
getActionShortcut(int identifier,const QVariantMap & parameters)676 QKeySequence ActionsManager::getActionShortcut(int identifier, const QVariantMap &parameters)
677 {
678 	if (parameters.isEmpty() && m_shortcuts.contains(identifier))
679 	{
680 		return m_shortcuts[identifier].first();
681 	}
682 
683 	if (!parameters.isEmpty() && m_extraShortcuts.contains(identifier))
684 	{
685 		const QList<QPair<QVariantMap, QVector<QKeySequence> > > definitions(m_extraShortcuts.values(identifier));
686 
687 		for (int i = 0; i < definitions.count(); ++i)
688 		{
689 			if (definitions.at(i).first == parameters)
690 			{
691 				return definitions.at(i).second.first();
692 			}
693 		}
694 	}
695 
696 	return QKeySequence();
697 }
698 
getActionDefinitions()699 QVector<ActionsManager::ActionDefinition> ActionsManager::getActionDefinitions()
700 {
701 	return m_definitions;
702 }
703 
getShortcutDefinitions()704 QVector<KeyboardProfile::Action> ActionsManager::getShortcutDefinitions()
705 {
706 	QVector<KeyboardProfile::Action> definitions;
707 	definitions.reserve(m_shortcuts.count() + m_extraShortcuts.count());
708 
709 	QMap<int, QVector<QKeySequence> >::iterator shortcutsIterator;
710 
711 	for (shortcutsIterator = m_shortcuts.begin(); shortcutsIterator != m_shortcuts.end(); ++shortcutsIterator)
712 	{
713 		KeyboardProfile::Action definition;
714 		definition.shortcuts = shortcutsIterator.value();
715 		definition.action = shortcutsIterator.key();
716 
717 		definitions.append(definition);
718 	}
719 
720 	QMultiMap<int, QPair<QVariantMap, QVector<QKeySequence> > >::iterator extraShortcutsIterator;
721 
722 	for (extraShortcutsIterator = m_extraShortcuts.begin(); extraShortcutsIterator != m_extraShortcuts.end(); ++extraShortcutsIterator)
723 	{
724 		KeyboardProfile::Action definition;
725 		definition.parameters = extraShortcutsIterator.value().first;
726 		definition.shortcuts = extraShortcutsIterator.value().second;
727 		definition.action = extraShortcutsIterator.key();
728 
729 		definitions.append(definition);
730 	}
731 
732 	return definitions;
733 }
734 
getActionDefinition(int identifier)735 ActionsManager::ActionDefinition ActionsManager::getActionDefinition(int identifier)
736 {
737 	if (identifier < 0 || identifier >= m_definitions.count())
738 	{
739 		return ActionsManager::ActionDefinition();
740 	}
741 
742 	return m_definitions[identifier];
743 }
744 
getActionIdentifier(const QString & name)745 int ActionsManager::getActionIdentifier(const QString &name)
746 {
747 	if (!name.endsWith(QLatin1String("Action")))
748 	{
749 		return ActionsManager::staticMetaObject.enumerator(m_actionIdentifierEnumerator).keyToValue((name + QLatin1String("Action")).toLatin1());
750 	}
751 
752 	return ActionsManager::staticMetaObject.enumerator(m_actionIdentifierEnumerator).keyToValue(name.toLatin1());
753 }
754 
isShortcutAllowed(const QKeySequence & shortcut,ShortcutCheck check,bool areSingleKeyShortcutsAllowed)755 bool ActionsManager::isShortcutAllowed(const QKeySequence &shortcut, ShortcutCheck check, bool areSingleKeyShortcutsAllowed)
756 {
757 	if (shortcut.isEmpty())
758 	{
759 		return false;
760 	}
761 
762 	if ((check == AllChecks || check == DisallowSingleKeyShortcutCheck) && (!areSingleKeyShortcutsAllowed && (shortcut[0] == Qt::Key_Plus || !shortcut.toString(QKeySequence::PortableText).contains(QLatin1Char('+'))) && shortcut[0] != Qt::Key_Delete && !(shortcut[0] >= Qt::Key_F1 && shortcut[0] <= Qt::Key_F35)))
763 	{
764 		return false;
765 	}
766 
767 	if (check == AllChecks || check == DisallowStandardShortcutCheck)
768 	{
769 		if (m_disallowedShortcuts.isEmpty())
770 		{
771 			m_disallowedShortcuts = {QKeySequence(QKeySequence::Copy), QKeySequence(QKeySequence::Cut), QKeySequence(QKeySequence::Delete), QKeySequence(QKeySequence::Paste), QKeySequence(QKeySequence::Redo), QKeySequence(QKeySequence::SelectAll), QKeySequence(QKeySequence::Undo)};
772 		}
773 
774 		if (m_disallowedShortcuts.contains(shortcut))
775 		{
776 			return false;
777 		}
778 	}
779 
780 	return true;
781 }
782 
783 }
784