VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/globals/UIShortcutPool.cpp@ 102493

Last change on this file since 102493 was 98103, checked in by vboxsync, 20 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.2 KB
Line 
1/* $Id: UIShortcutPool.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIShortcutPool class implementation.
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* GUI includes: */
29#include "UICommon.h"
30#include "UIActionPool.h"
31#include "UIExtraDataManager.h"
32#include "UIShortcutPool.h"
33
34
35/* Namespaces: */
36using namespace UIExtraDataDefs;
37
38
39/*********************************************************************************************************************************
40* Class UIShortcut implementation. *
41*********************************************************************************************************************************/
42
43void UIShortcut::setScope(const QString &strScope)
44{
45 m_strScope = strScope;
46}
47
48const QString &UIShortcut::scope() const
49{
50 return m_strScope;
51}
52
53void UIShortcut::setDescription(const QString &strDescription)
54{
55 m_strDescription = strDescription;
56}
57
58const QString &UIShortcut::description() const
59{
60 return m_strDescription;
61}
62
63void UIShortcut::setSequences(const QList<QKeySequence> &sequences)
64{
65 m_sequences = sequences;
66}
67
68const QList<QKeySequence> &UIShortcut::sequences() const
69{
70 return m_sequences;
71}
72
73void UIShortcut::setDefaultSequence(const QKeySequence &defaultSequence)
74{
75 m_defaultSequence = defaultSequence;
76}
77
78const QKeySequence &UIShortcut::defaultSequence() const
79{
80 return m_defaultSequence;
81}
82
83void UIShortcut::setStandardSequence(const QKeySequence &standardSequence)
84{
85 m_standardSequence = standardSequence;
86}
87
88const QKeySequence &UIShortcut::standardSequence() const
89{
90 return m_standardSequence;
91}
92
93QString UIShortcut::primaryToNativeText() const
94{
95 return m_sequences.isEmpty() ? QString() : m_sequences.first().toString(QKeySequence::NativeText);
96}
97
98QString UIShortcut::primaryToPortableText() const
99{
100 return m_sequences.isEmpty() ? QString() : m_sequences.first().toString(QKeySequence::PortableText);
101}
102
103
104/*********************************************************************************************************************************
105* Class UIShortcutPool implementation. *
106*********************************************************************************************************************************/
107
108/* static */
109UIShortcutPool *UIShortcutPool::s_pInstance = 0;
110const QString UIShortcutPool::s_strShortcutKeyTemplate = QString("%1/%2");
111const QString UIShortcutPool::s_strShortcutKeyTemplateRuntime = s_strShortcutKeyTemplate.arg(GUI_Input_MachineShortcuts);
112
113void UIShortcutPool::create()
114{
115 /* Check that instance do NOT exists: */
116 if (s_pInstance)
117 return;
118
119 /* Create instance: */
120 new UIShortcutPool;
121
122 /* Prepare instance: */
123 s_pInstance->prepare();
124}
125
126void UIShortcutPool::destroy()
127{
128 /* Check that instance exists: */
129 if (!s_pInstance)
130 return;
131
132 /* Cleanup instance: */
133 s_pInstance->cleanup();
134
135 /* Delete instance: */
136 delete s_pInstance;
137}
138
139UIShortcut &UIShortcutPool::shortcut(UIActionPool *pActionPool, UIAction *pAction)
140{
141 /* Compose shortcut key: */
142 const QString strShortcutKey(s_strShortcutKeyTemplate.arg(pActionPool->shortcutsExtraDataID(),
143 pAction->shortcutExtraDataID()));
144 /* Return existing if any: */
145 if (m_shortcuts.contains(strShortcutKey))
146 return shortcut(strShortcutKey);
147 /* Create and return new one: */
148 UIShortcut &newShortcut = m_shortcuts[strShortcutKey];
149 newShortcut.setScope(pAction->shortcutScope());
150 newShortcut.setDescription(pAction->name());
151 const QKeySequence &defaultSequence = pAction->defaultShortcut(pActionPool->type());
152 const QKeySequence &standardSequence = pAction->standardShortcut(pActionPool->type());
153 newShortcut.setSequences(QList<QKeySequence>() << defaultSequence << standardSequence);
154 newShortcut.setDefaultSequence(defaultSequence);
155 newShortcut.setStandardSequence(standardSequence);
156 return newShortcut;
157}
158
159UIShortcut &UIShortcutPool::shortcut(const QString &strPoolID, const QString &strActionID)
160{
161 /* Return if present, autocreate if necessary: */
162 return shortcut(s_strShortcutKeyTemplate.arg(strPoolID, strActionID));
163}
164
165void UIShortcutPool::setOverrides(const QMap<QString, QString> &overrides)
166{
167 /* Iterate over all the overrides: */
168 const QList<QString> shortcutKeys = overrides.keys();
169 foreach (const QString &strShortcutKey, shortcutKeys)
170 {
171 /* Make no changes if there is no such shortcut: */
172 if (!m_shortcuts.contains(strShortcutKey))
173 continue;
174 /* Assign overridden sequences to the shortcut: */
175 m_shortcuts[strShortcutKey].setSequences(QList<QKeySequence>() << overrides[strShortcutKey]);
176 }
177 /* Save overrides: */
178 saveOverrides();
179}
180
181void UIShortcutPool::applyShortcuts(UIActionPool *pActionPool)
182{
183 /* For each the action of the passed action-pool: */
184 foreach (UIAction *pAction, pActionPool->actions())
185 {
186 /* Skip menu actions: */
187 if (pAction->type() == UIActionType_Menu)
188 continue;
189
190 /* Compose shortcut key: */
191 const QString strShortcutKey = s_strShortcutKeyTemplate.arg(pActionPool->shortcutsExtraDataID(),
192 pAction->shortcutExtraDataID());
193 /* If shortcut key is already known: */
194 if (m_shortcuts.contains(strShortcutKey))
195 {
196 /* Get corresponding shortcut: */
197 UIShortcut &existingShortcut = m_shortcuts[strShortcutKey];
198 /* Copy the scope from the action to the shortcut: */
199 existingShortcut.setScope(pAction->shortcutScope());
200 /* Copy the description from the action to the shortcut: */
201 existingShortcut.setDescription(pAction->name());
202 /* Copy the sequences from the shortcut to the action: */
203 pAction->setShortcuts(existingShortcut.sequences());
204 pAction->retranslateUi();
205 /* Copy default and standard sequences from the action to the shortcut: */
206 existingShortcut.setDefaultSequence(pAction->defaultShortcut(pActionPool->type()));
207 existingShortcut.setStandardSequence(pAction->standardShortcut(pActionPool->type()));
208 }
209 /* If shortcut key is NOT known yet: */
210 else
211 {
212 /* Create corresponding shortcut: */
213 UIShortcut &newShortcut = m_shortcuts[strShortcutKey];
214 /* Copy the action's default sequence to both the shortcut & the action: */
215 const QKeySequence &defaultSequence = pAction->defaultShortcut(pActionPool->type());
216 const QKeySequence &standardSequence = pAction->standardShortcut(pActionPool->type());
217 newShortcut.setSequences(QList<QKeySequence>() << defaultSequence << standardSequence);
218 newShortcut.setDefaultSequence(defaultSequence);
219 newShortcut.setStandardSequence(standardSequence);
220 pAction->setShortcuts(newShortcut.sequences());
221 pAction->retranslateUi();
222 /* Copy the description from the action to the shortcut: */
223 newShortcut.setScope(pAction->shortcutScope());
224 newShortcut.setDescription(pAction->name());
225 }
226 }
227}
228
229void UIShortcutPool::retranslateUi()
230{
231 /* Translate own defaults: */
232 m_shortcuts[s_strShortcutKeyTemplateRuntime.arg("PopupMenu")]
233 .setDescription(QApplication::translate("UIActionPool", "Popup Menu"));
234}
235
236void UIShortcutPool::sltReloadSelectorShortcuts()
237{
238 /* Clear selector shortcuts first: */
239 const QList<QString> shortcutKeyList = m_shortcuts.keys();
240 foreach (const QString &strShortcutKey, shortcutKeyList)
241 if (strShortcutKey.startsWith(GUI_Input_SelectorShortcuts))
242 m_shortcuts.remove(strShortcutKey);
243
244 /* Load selector defaults: */
245 loadDefaultsFor(GUI_Input_SelectorShortcuts);
246 /* Load selector overrides: */
247 loadOverridesFor(GUI_Input_SelectorShortcuts);
248
249 /* Notify manager shortcuts reloaded: */
250 emit sigManagerShortcutsReloaded();
251}
252
253void UIShortcutPool::sltReloadMachineShortcuts()
254{
255 /* Clear machine shortcuts first: */
256 const QList<QString> shortcutKeyList = m_shortcuts.keys();
257 foreach (const QString &strShortcutKey, shortcutKeyList)
258 if (strShortcutKey.startsWith(GUI_Input_MachineShortcuts))
259 m_shortcuts.remove(strShortcutKey);
260
261 /* Load machine defaults: */
262 loadDefaultsFor(GUI_Input_MachineShortcuts);
263 /* Load machine overrides: */
264 loadOverridesFor(GUI_Input_MachineShortcuts);
265
266 /* Notify runtime shortcuts reloaded: */
267 emit sigRuntimeShortcutsReloaded();
268}
269
270UIShortcutPool::UIShortcutPool()
271{
272 /* Prepare instance: */
273 if (!s_pInstance)
274 s_pInstance = this;
275}
276
277UIShortcutPool::~UIShortcutPool()
278{
279 /* Cleanup instance: */
280 if (s_pInstance == this)
281 s_pInstance = 0;
282}
283
284void UIShortcutPool::prepare()
285{
286 /* Load defaults: */
287 loadDefaults();
288 /* Load overrides: */
289 loadOverrides();
290 /* Prepare connections: */
291 prepareConnections();
292}
293
294void UIShortcutPool::prepareConnections()
295{
296 /* Connect to extra-data signals: */
297 connect(gEDataManager, &UIExtraDataManager::sigSelectorUIShortcutChange,
298 this, &UIShortcutPool::sltReloadSelectorShortcuts);
299 connect(gEDataManager, &UIExtraDataManager::sigRuntimeUIShortcutChange,
300 this, &UIShortcutPool::sltReloadMachineShortcuts);
301}
302
303void UIShortcutPool::loadDefaults()
304{
305 /* Load selector defaults: */
306 loadDefaultsFor(GUI_Input_SelectorShortcuts);
307 /* Load machine defaults: */
308 loadDefaultsFor(GUI_Input_MachineShortcuts);
309}
310
311void UIShortcutPool::loadDefaultsFor(const QString &strPoolExtraDataID)
312{
313 /* Default shortcuts for Selector UI: */
314 if (strPoolExtraDataID == GUI_Input_SelectorShortcuts)
315 {
316 /* Nothing for now.. */
317 }
318 /* Default shortcuts for Runtime UI: */
319 else if (strPoolExtraDataID == GUI_Input_MachineShortcuts)
320 {
321 /* Default shortcut for the Runtime Popup Menu: */
322 m_shortcuts.insert(s_strShortcutKeyTemplateRuntime.arg("PopupMenu"),
323 UIShortcut(QString(),
324 QApplication::translate("UIActionPool", "Popup Menu"),
325 QList<QKeySequence>() << QString("Home"),
326 QString("Home"),
327 QString()));
328 }
329}
330
331void UIShortcutPool::loadOverrides()
332{
333 /* Load selector overrides: */
334 loadOverridesFor(GUI_Input_SelectorShortcuts);
335 /* Load machine overrides: */
336 loadOverridesFor(GUI_Input_MachineShortcuts);
337}
338
339void UIShortcutPool::loadOverridesFor(const QString &strPoolExtraDataID)
340{
341 /* Compose shortcut key template: */
342 const QString strShortcutKeyTemplate(s_strShortcutKeyTemplate.arg(strPoolExtraDataID));
343 /* Iterate over all the overrides: */
344 const QStringList overrides = gEDataManager->shortcutOverrides(strPoolExtraDataID);
345 foreach (const QString &strKeyValuePair, overrides)
346 {
347 /* Make sure override structure is valid: */
348 int iDelimiterPosition = strKeyValuePair.indexOf('=');
349 if (iDelimiterPosition < 0)
350 continue;
351
352 /* Get shortcut ID/sequence: */
353 QString strShortcutExtraDataID = strKeyValuePair.left(iDelimiterPosition);
354 const QString strShortcutSequence = strKeyValuePair.right(strKeyValuePair.length() - iDelimiterPosition - 1);
355
356 // Hack for handling "Save" as "SaveState":
357 if (strShortcutExtraDataID == "Save")
358 strShortcutExtraDataID = "SaveState";
359
360 /* Compose corresponding shortcut key: */
361 const QString strShortcutKey(strShortcutKeyTemplate.arg(strShortcutExtraDataID));
362 /* Modify map with composed key/value: */
363 if (!m_shortcuts.contains(strShortcutKey))
364 m_shortcuts.insert(strShortcutKey,
365 UIShortcut(QString(),
366 QString(),
367 QList<QKeySequence>() << strShortcutSequence,
368 QString(),
369 QString()));
370 else
371 {
372 /* Get corresponding value: */
373 UIShortcut &shortcut = m_shortcuts[strShortcutKey];
374 /* Check if corresponding shortcut overridden by value: */
375 if (shortcut.primaryToPortableText().compare(strShortcutSequence, Qt::CaseInsensitive) != 0)
376 {
377 /* Shortcut unassigned? */
378 if (strShortcutSequence.compare("None", Qt::CaseInsensitive) == 0)
379 shortcut.setSequences(QList<QKeySequence>());
380 /* Or reassigned? */
381 else
382 shortcut.setSequences(QList<QKeySequence>() << strShortcutSequence);
383 }
384 }
385 }
386}
387
388void UIShortcutPool::saveOverrides()
389{
390 /* Load selector overrides: */
391 saveOverridesFor(GUI_Input_SelectorShortcuts);
392 /* Load machine overrides: */
393 saveOverridesFor(GUI_Input_MachineShortcuts);
394}
395
396void UIShortcutPool::saveOverridesFor(const QString &strPoolExtraDataID)
397{
398 /* Compose shortcut prefix: */
399 const QString strShortcutPrefix(s_strShortcutKeyTemplate.arg(strPoolExtraDataID, QString()));
400 /* Populate the list of all the known overrides: */
401 QStringList overrides;
402 const QList<QString> shortcutKeys = m_shortcuts.keys();
403 foreach (const QString &strShortcutKey, shortcutKeys)
404 {
405 /* Check if the key starts from the proper prefix: */
406 if (!strShortcutKey.startsWith(strShortcutPrefix))
407 continue;
408 /* Get corresponding shortcut: */
409 const UIShortcut &shortcut = m_shortcuts[strShortcutKey];
410 /* Check if the sequence for that shortcut differs from default or standard: */
411 if ( shortcut.sequences().contains(shortcut.defaultSequence())
412 || ( !shortcut.standardSequence().isEmpty()
413 && shortcut.sequences().contains(shortcut.standardSequence())))
414 continue;
415 /* Add the shortcut sequence into overrides list: */
416 overrides << QString("%1=%2").arg(QString(strShortcutKey).remove(strShortcutPrefix),
417 shortcut.primaryToPortableText());
418 }
419 /* Save overrides into the extra-data: */
420 uiCommon().virtualBox().SetExtraDataStringList(strPoolExtraDataID, overrides);
421}
422
423UIShortcut &UIShortcutPool::shortcut(const QString &strShortcutKey)
424{
425 return m_shortcuts[strShortcutKey];
426}
427
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle
ContactPrivacy/Do Not Sell My InfoTerms of Use