VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/UIWindowMenuManager.cpp

Last change on this file was 104394, checked in by vboxsync, 5 weeks ago

FE/Qt. bugref:10622. Using new UITranslationEventListener in the UIWindowMenuManager class.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.0 KB
RevLine 
[32789]1/* $Id: UIWindowMenuManager.cpp 104394 2024-04-22 13:07:03Z vboxsync $ */
2/** @file
[52727]3 * VBox Qt GUI - UIWindowMenuManager class implementation.
[32789]4 */
5
6/*
[98103]7 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
[32789]8 *
[96407]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
[32789]26 */
27
[57890]28/* Qt includes: */
[94066]29#include <QActionGroup>
[76606]30#include <QApplication>
31#include <QMenu>
[32789]32
[57891]33/* GUI includes: */
[104394]34#include "UITranslationEventListener.h"
[76606]35#include "UIWindowMenuManager.h"
[57891]36
37/* Other VBox includes: */
38#include <iprt/assert.h>
39
[52730]40
[57890]41/** QObject extension
42 * used as Mac OS X 'Window' menu helper. */
[57891]43class UIMenuHelper : public QObject
[32789]44{
45 Q_OBJECT;
46
47public:
[57890]48
[57891]49 /** Constructs menu-helper on the basis of passed @a windows. */
[72166]50 UIMenuHelper(const QList<QWidget*> &windows);
[57890]51 /** Destructs menu-helper. */
[93990]52 virtual ~UIMenuHelper() RT_OVERRIDE;
[32789]53
[57890]54 /** Returns 'Window' menu. */
[72166]55 QMenu *menu() const { return m_pWindowMenu; }
[32789]56
[57891]57 /** Adds @a pWindow into 'Window' menu. */
[72166]58 QAction *addWindow(QWidget *pWindow);
[57891]59 /** Removes @a pWindow from 'Window' menu. */
[72166]60 void removeWindow(QWidget *pWindow);
[32789]61
[57890]62 /** Handles translation event. */
[103977]63 virtual void retranslateUi();
[57891]64
65 /** Updates toggle action states according to passed @a pActiveWindow. */
[72166]66 void updateStatus(QWidget *pActiveWindow);
[32789]67
68private slots:
69
[57890]70 /** Handles request to minimize active-window. */
[72166]71 void sltMinimizeActiveWindow();
[57890]72
73 /** Handles request to raise sender window. */
[72166]74 void sltRaiseSender();
[32789]75
76private:
77
[57890]78 /** Holds the 'Window' menu instance. */
[72166]79 QMenu *m_pWindowMenu;
[57890]80 /** Holds the action group instance. */
[72166]81 QActionGroup *m_pGroup;
[57890]82 /** Holds the 'Minimize' action instance. */
[72166]83 QAction *m_pMinimizeAction;
[57890]84 /** Holds the hash of the registered menu-helper instances. */
[72166]85 QHash<QWidget*, QAction*> m_windows;
[32789]86};
87
[62471]88
[57891]89/*********************************************************************************************************************************
[72166]90* Class UIMenuHelper implementation. *
91*********************************************************************************************************************************/
92
93UIMenuHelper::UIMenuHelper(const QList<QWidget*> &windows)
94{
95 /* Prepare 'Window' menu: */
96 m_pWindowMenu = new QMenu;
97
98 /* Prepare action group: */
99 m_pGroup = new QActionGroup(this);
100 m_pGroup->setExclusive(true);
101
102 /* Prepare 'Minimize' action: */
103 m_pMinimizeAction = new QAction(this);
104 m_pWindowMenu->addAction(m_pMinimizeAction);
105 connect(m_pMinimizeAction, SIGNAL(triggered(bool)),
106 this, SLOT(sltMinimizeActiveWindow()));
107
108 /* Make sure all already available windows are
109 * properly registered within this menu: */
110 for (int i = 0; i < windows.size(); ++i)
111 addWindow(windows.at(i));
112
113 /* Apply language settings: */
114 retranslateUi();
115}
116
117UIMenuHelper::~UIMenuHelper()
118{
119 /* Cleanup 'Window' menu: */
120 delete m_pWindowMenu;
121
122 /* Cleanup actions: */
123 qDeleteAll(m_windows);
124}
125
126QAction *UIMenuHelper::addWindow(QWidget *pWindow)
127{
128 QAction *pAction = 0;
129 if ( pWindow
130 && !m_windows.contains(pWindow))
131 {
132 if (m_windows.size() < 2)
133 m_pWindowMenu->addSeparator();
134
135 /* The main window always first: */
136 pAction = new QAction(this);
137 pAction->setText(pWindow->windowTitle());
138 pAction->setMenuRole(QAction::NoRole);
139 pAction->setData(QVariant::fromValue(pWindow));
140 pAction->setCheckable(true);
141
142 /* The first registered one is always
143 * considered as the main window: */
144 if (m_windows.size() == 0)
145 pAction->setShortcut(QKeySequence("Ctrl+0"));
146 m_pGroup->addAction(pAction);
147 connect(pAction, SIGNAL(triggered(bool)),
148 this, SLOT(sltRaiseSender()));
149 m_pWindowMenu->addAction(pAction);
150 m_windows[pWindow] = pAction;
151 }
152 return pAction;
153}
154
155void UIMenuHelper::removeWindow(QWidget *pWindow)
156{
157 if (m_windows.contains(pWindow))
158 {
159 delete m_windows.value(pWindow);
160 m_windows.remove(pWindow);
161 }
162}
163
164void UIMenuHelper::retranslateUi()
165{
166 /* Translate menu: */
167 m_pWindowMenu->setTitle(QApplication::translate("UIActionPool", "&Window"));
168
169 /* Translate menu 'Minimize' action: */
170 m_pMinimizeAction->setText(QApplication::translate("UIActionPool", "&Minimize"));
171 m_pMinimizeAction->setShortcut(QKeySequence("Ctrl+M"));
172
173 /* Translate other menu-actions: */
174 foreach (QAction *pAction, m_windows.values())
175 {
176 /* Get corresponding window from action's data: */
177 QWidget *pWindow = pAction->data().value<QWidget*>();
178 /* Use the window's title as the action's text: */
179 pAction->setText(pWindow->windowTitle());
180 }
181}
182
183void UIMenuHelper::updateStatus(QWidget *pActiveWindow)
184{
185 /* 'Minimize' action is enabled if there is active-window: */
186 m_pMinimizeAction->setEnabled(pActiveWindow != 0);
187
188 /* If there is active-window: */
189 if (pActiveWindow)
190 {
191 /* Toggle corresponding action on: */
192 if (m_windows.contains(pActiveWindow))
193 m_windows.value(pActiveWindow)->setChecked(true);
194 }
195 /* If there is no active-window: */
196 else
197 {
198 /* Make sure corresponding action toggled off: */
199 if (QAction *pChecked = m_pGroup->checkedAction())
200 pChecked->setChecked(false);
201 }
202}
203
204void UIMenuHelper::sltMinimizeActiveWindow()
205{
206 if (QWidget *pActiveWindow = qApp->activeWindow())
207 pActiveWindow->showMinimized();
208}
209
210void UIMenuHelper::sltRaiseSender()
211{
212 AssertReturnVoid(sender());
213 if (QAction *pAction = qobject_cast<QAction*>(sender()))
214 {
215 if (QWidget *pWidget = pAction->data().value<QWidget*>())
216 {
217 pWidget->show();
218 pWidget->raise();
219 pWidget->activateWindow();
220 }
221 }
222}
223
224
225/*********************************************************************************************************************************
[57891]226* Class UIWindowMenuManager implementation. *
227*********************************************************************************************************************************/
228
[57890]229/* static */
[72166]230UIWindowMenuManager* UIWindowMenuManager::s_pInstance = 0;
[32789]231
[57890]232/* static */
[57897]233void UIWindowMenuManager::create()
[32789]234{
[57897]235 /* Make sure 'Window' menu Manager is not created: */
[72166]236 AssertReturnVoid(!s_pInstance);
[32789]237
[57897]238 /* Create 'Window' menu Manager: */
239 new UIWindowMenuManager;
[32789]240}
241
[57890]242/* static */
[32789]243void UIWindowMenuManager::destroy()
244{
[57891]245 /* Make sure 'Window' menu Manager is created: */
[72166]246 AssertPtrReturnVoid(s_pInstance);
[57891]247
248 /* Delete 'Window' menu Manager: */
[72166]249 delete s_pInstance;
[32789]250}
251
252QMenu *UIWindowMenuManager::createMenu(QWidget *pWindow)
253{
[57891]254 /* Create helper: */
255 UIMenuHelper *pHelper = new UIMenuHelper(m_windows);
256 /* Register it: */
[32789]257 m_helpers[pWindow] = pHelper;
258
[57891]259 /* Return menu of created helper: */
[32789]260 return pHelper->menu();
261}
262
263void UIWindowMenuManager::destroyMenu(QWidget *pWindow)
264{
[57891]265 /* If window is registered: */
[32789]266 if (m_helpers.contains(pWindow))
267 {
[57891]268 /* Delete helper: */
269 delete m_helpers.value(pWindow);
270 /* Unregister it: */
[32789]271 m_helpers.remove(pWindow);
272 }
273}
274
275void UIWindowMenuManager::addWindow(QWidget *pWindow)
276{
[57891]277 /* Register window: */
278 m_windows.append(pWindow);
279 /* Add window to all menus we have: */
[57894]280 foreach (UIMenuHelper *pHelper, m_helpers.values())
281 pHelper->addWindow(pWindow);
[32789]282}
283
284void UIWindowMenuManager::removeWindow(QWidget *pWindow)
285{
[57891]286 /* Remove window from all menus we have: */
[57894]287 foreach (UIMenuHelper *pHelper, m_helpers.values())
288 pHelper->removeWindow(pWindow);
[57891]289 /* Unregister window: */
290 m_windows.removeAll(pWindow);
[32789]291}
292
[104394]293void UIWindowMenuManager::sltRetranslateUI()
[32789]294{
[57891]295 /* Translate all the helpers: */
[57894]296 foreach (UIMenuHelper *pHelper, m_helpers.values())
297 pHelper->retranslateUi();
[32789]298}
299
[72166]300UIWindowMenuManager::UIWindowMenuManager()
301{
302 /* Assign instance: */
303 s_pInstance = this;
304
305 /* Install global event-filter: */
306 qApp->installEventFilter(this);
[104394]307 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
308 this, &UIWindowMenuManager::sltRetranslateUI);
[72166]309}
310
311UIWindowMenuManager::~UIWindowMenuManager()
312{
313 /* Cleanup all helpers: */
314 qDeleteAll(m_helpers);
315
316 /* Unassign instance: */
317 s_pInstance = 0;
318}
319
[57891]320bool UIWindowMenuManager::eventFilter(QObject *pObject, QEvent *pEvent)
[32789]321{
[57891]322 /* Acquire event type: */
323 const QEvent::Type type = pEvent->type();
324
[69260]325#ifdef VBOX_OSE /// @todo Do we still need it?
[72166]326 // WORKAROUND:
327 // Stupid Qt: Qt doesn't check if a window is minimized when a command is
328 // executed. This leads to strange behaviour. The minimized window is
329 // partly restored, but not usable. As a workaround we raise the parent
330 // window before we let execute the command.
331 // Note: fixed in our local Qt build since 4.7.0.
[57891]332 if (pObject && type == QEvent::Show)
[32789]333 {
[57891]334 QWidget *pWidget = qobject_cast<QWidget*>(pObject);
335 if ( pWidget
336 && pWidget->parentWidget()
[32789]337 && pWidget->parentWidget()->isMinimized())
338 {
339 pWidget->parentWidget()->show();
340 pWidget->parentWidget()->raise();
341 pWidget->parentWidget()->activateWindow();
342 }
343 }
[68315]344#endif /* VBOX_OSE */
[57891]345
[32789]346 /* We need to track several events which leads to different window
347 * activation and change the menu items in that case. */
348 if ( type == QEvent::ActivationChange
349 || type == QEvent::WindowActivate
350 || type == QEvent::WindowDeactivate
351 || type == QEvent::WindowStateChange
352 || type == QEvent::Show
353 || type == QEvent::Close
354 || type == QEvent::Hide)
355 {
[57891]356 QWidget *pActiveWindow = qApp->activeWindow();
[57894]357 foreach (UIMenuHelper *pHelper, m_helpers.values())
358 pHelper->updateStatus(pActiveWindow);
[32789]359 }
360
[57895]361 /* Besides our own retranslation, we should also retranslate
362 * everything on any registered widget title change event: */
363 if (pObject && type == QEvent::WindowTitleChange)
364 {
365 QWidget *pWidget = qobject_cast<QWidget*>(pObject);
366 if (pWidget && m_helpers.contains(pWidget))
[104394]367 sltRetranslateUI();
[57895]368 }
369
[57891]370 /* Call to base-class: */
[104394]371 return QObject::eventFilter(pObject, pEvent);
[32789]372}
373
[72166]374
[32789]375#include "UIWindowMenuManager.moc"
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use