VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/manager/tools/UIToolsModel.cpp@ 103977

Last change on this file since 103977 was 103710, checked in by vboxsync, 11 months ago

FE/Qt: Get rid of unwanted UICommon includes across whole the GUI.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.8 KB
Line 
1/* $Id: UIToolsModel.cpp 103710 2024-03-06 16:53:27Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIToolsModel class implementation.
4 */
5
6/*
7 * Copyright (C) 2012-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/* Qt includes: */
29#include <QGraphicsScene>
30#include <QGraphicsSceneContextMenuEvent>
31#include <QGraphicsSceneMouseEvent>
32#include <QGraphicsView>
33#include <QScrollBar>
34#include <QTimer>
35
36/* GUI includes: */
37#include "QIMessageBox.h"
38#include "UIActionPoolManager.h"
39#include "UIIconPool.h"
40#include "UILoggingDefs.h"
41#include "UITools.h"
42#include "UIToolsHandlerMouse.h"
43#include "UIToolsHandlerKeyboard.h"
44#include "UIToolsModel.h"
45#include "UIExtraDataDefs.h"
46#include "UIExtraDataManager.h"
47#include "UIMessageCenter.h"
48#include "UIModalWindowManager.h"
49#include "UIVirtualBoxManagerWidget.h"
50#include "UIVirtualBoxEventHandler.h"
51
52/* COM includes: */
53#include "CExtPack.h"
54#include "CExtPackManager.h"
55
56/* Qt includes: */
57#include <QParallelAnimationGroup>
58
59/* Type defs: */
60typedef QSet<QString> UIStringSet;
61
62
63UIToolsModel::UIToolsModel(UIToolClass enmClass, UITools *pParent)
64 : QIWithRetranslateUI3<QObject>(pParent)
65 , m_enmClass(enmClass)
66 , m_pTools(pParent)
67 , m_pScene(0)
68 , m_pMouseHandler(0)
69 , m_pKeyboardHandler(0)
70 , m_fItemsEnabled(true)
71{
72 prepare();
73}
74
75UIToolsModel::~UIToolsModel()
76{
77 cleanup();
78}
79
80void UIToolsModel::init()
81{
82 /* Update linked values: */
83 updateLayout();
84 updateNavigation();
85 sltItemMinimumWidthHintChanged();
86 sltItemMinimumHeightHintChanged();
87
88 /* Load settings: */
89 loadSettings();
90}
91
92UITools *UIToolsModel::tools() const
93{
94 return m_pTools;
95}
96
97UIActionPool *UIToolsModel::actionPool() const
98{
99 return tools() ? tools()->actionPool() : 0;
100}
101
102QGraphicsScene *UIToolsModel::scene() const
103{
104 return m_pScene;
105}
106
107QPaintDevice *UIToolsModel::paintDevice() const
108{
109 if (scene() && !scene()->views().isEmpty())
110 return scene()->views().first();
111 return 0;
112}
113
114QGraphicsItem *UIToolsModel::itemAt(const QPointF &position, const QTransform &deviceTransform /* = QTransform() */) const
115{
116 return scene() ? scene()->itemAt(position, deviceTransform) : 0;
117}
118
119void UIToolsModel::setToolsType(UIToolType enmType)
120{
121 if (!currentItem() || currentItem()->itemType() != enmType)
122 {
123 foreach (UIToolsItem *pItem, items())
124 if (pItem->itemType() == enmType)
125 {
126 setCurrentItem(pItem);
127 break;
128 }
129 }
130}
131
132UIToolType UIToolsModel::toolsType() const
133{
134 return currentItem() ? currentItem()->itemType() : UIToolType_Invalid;
135}
136
137void UIToolsModel::setItemsEnabled(bool fEnabled)
138{
139 if (m_fItemsEnabled != fEnabled)
140 {
141 m_fItemsEnabled = fEnabled;
142 foreach (UIToolsItem *pItem, items())
143 pItem->setEnabled(m_fItemsEnabled);
144 }
145}
146
147bool UIToolsModel::isItemsEnabled() const
148{
149 return m_fItemsEnabled;
150}
151
152void UIToolsModel::setRestrictedToolTypes(const QList<UIToolType> &types)
153{
154 if (m_restrictedToolTypes != types)
155 {
156 m_restrictedToolTypes = types;
157 foreach (UIToolsItem *pItem, items())
158 pItem->setVisible(!m_restrictedToolTypes.contains(pItem->itemType()));
159 updateLayout();
160 updateNavigation();
161 sltItemMinimumWidthHintChanged();
162 sltItemMinimumHeightHintChanged();
163 }
164}
165
166QList<UIToolType> UIToolsModel::restrictedToolTypes() const
167{
168 return m_restrictedToolTypes;
169}
170
171void UIToolsModel::close()
172{
173 emit sigClose();
174}
175
176void UIToolsModel::setCurrentItem(UIToolsItem *pItem)
177{
178 /* Is there something changed? */
179 if (m_pCurrentItem == pItem)
180 return;
181
182 /* Remember old current-item: */
183 UIToolsItem *pOldCurrentItem = m_pCurrentItem;
184
185 /* If there is item: */
186 if (pItem)
187 {
188 /* Set this item as current: */
189 m_pCurrentItem = pItem;
190
191 /* Load last tool types: */
192 UIToolType enmTypeGlobal, enmTypeMachine;
193 loadLastToolTypes(enmTypeGlobal, enmTypeMachine);
194
195 /* Depending on tool class: */
196 switch (m_enmClass)
197 {
198 case UIToolClass_Global: enmTypeGlobal = m_pCurrentItem->itemType(); break;
199 case UIToolClass_Machine: enmTypeMachine = m_pCurrentItem->itemType(); break;
200 default: break;
201 }
202
203 /* Save selected items data: */
204 const QList<UIToolType> currentTypes = QList<UIToolType>() << enmTypeGlobal << enmTypeMachine;
205 LogRel2(("GUI: UIToolsModel: Saving tool items as: Global=%d, Machine=%d\n",
206 (int)enmTypeGlobal, (int)enmTypeMachine));
207 gEDataManager->setToolsPaneLastItemsChosen(currentTypes);
208 }
209 /* Otherwise reset current item: */
210 else
211 m_pCurrentItem = 0;
212
213 /* Update old item (if any): */
214 if (pOldCurrentItem)
215 pOldCurrentItem->update();
216 /* Update new item (if any): */
217 if (m_pCurrentItem)
218 m_pCurrentItem->update();
219
220 /* Notify about selection change: */
221 emit sigSelectionChanged(toolsType());
222
223 /* Move focus to current-item: */
224 setFocusItem(currentItem());
225
226 /* Adjust corrresponding actions finally: */
227 const UIToolType enmType = currentItem() ? currentItem()->itemType() : UIToolType_Welcome;
228 QMap<UIToolType, UIAction*> actions;
229 actions[UIToolType_Welcome] = actionPool()->action(UIActionIndexMN_M_File_M_Tools_T_WelcomeScreen);
230 actions[UIToolType_Extensions] = actionPool()->action(UIActionIndexMN_M_File_M_Tools_T_ExtensionPackManager);
231 actions[UIToolType_Media] = actionPool()->action(UIActionIndexMN_M_File_M_Tools_T_VirtualMediaManager);
232 actions[UIToolType_Network] = actionPool()->action(UIActionIndexMN_M_File_M_Tools_T_NetworkManager);
233 actions[UIToolType_Cloud] = actionPool()->action(UIActionIndexMN_M_File_M_Tools_T_CloudProfileManager);
234 actions[UIToolType_VMActivityOverview] = actionPool()->action(UIActionIndexMN_M_File_M_Tools_T_VMActivityOverview);
235 if (actions.contains(enmType))
236 actions.value(enmType)->setChecked(true);
237}
238
239UIToolsItem *UIToolsModel::currentItem() const
240{
241 return m_pCurrentItem;
242}
243
244void UIToolsModel::setFocusItem(UIToolsItem *pItem)
245{
246 /* Always make sure real focus unset: */
247 scene()->setFocusItem(0);
248
249 /* Is there something changed? */
250 if (m_pFocusItem == pItem)
251 return;
252
253 /* Remember old focus-item: */
254 UIToolsItem *pOldFocusItem = m_pFocusItem;
255
256 /* If there is item: */
257 if (pItem)
258 {
259 /* Set this item to focus if navigation list contains it: */
260 if (navigationList().contains(pItem))
261 m_pFocusItem = pItem;
262 /* Otherwise it's error: */
263 else
264 AssertMsgFailed(("Passed item is not in navigation list!"));
265 }
266 /* Otherwise reset focus item: */
267 else
268 m_pFocusItem = 0;
269
270 /* Disconnect old focus-item (if any): */
271 if (pOldFocusItem)
272 disconnect(pOldFocusItem, &UIToolsItem::destroyed, this, &UIToolsModel::sltFocusItemDestroyed);
273 /* Connect new focus-item (if any): */
274 if (m_pFocusItem)
275 connect(m_pFocusItem.data(), &UIToolsItem::destroyed, this, &UIToolsModel::sltFocusItemDestroyed);
276
277 /* Notify about focus change: */
278 emit sigFocusChanged();
279}
280
281UIToolsItem *UIToolsModel::focusItem() const
282{
283 return m_pFocusItem;
284}
285
286const QList<UIToolsItem*> &UIToolsModel::navigationList() const
287{
288 return m_navigationList;
289}
290
291void UIToolsModel::removeFromNavigationList(UIToolsItem *pItem)
292{
293 AssertMsg(pItem, ("Passed item is invalid!"));
294 m_navigationList.removeAll(pItem);
295}
296
297void UIToolsModel::updateNavigation()
298{
299 /* Clear list initially: */
300 m_navigationList.clear();
301
302 /* Enumerate the children: */
303 foreach (UIToolsItem *pItem, items())
304 if (pItem->isVisible())
305 m_navigationList << pItem;
306}
307
308QList<UIToolsItem*> UIToolsModel::items() const
309{
310 return m_items;
311}
312
313UIToolsItem *UIToolsModel::item(UIToolType enmType) const
314{
315 foreach (UIToolsItem *pItem, items())
316 if (pItem->itemType() == enmType)
317 return pItem;
318 return 0;
319}
320
321void UIToolsModel::updateLayout()
322{
323 /* Prepare variables: */
324 const int iMargin = data(ToolsModelData_Margin).toInt();
325 const int iSpacing = data(ToolsModelData_Spacing).toInt();
326 const QSize viewportSize = scene()->views()[0]->viewport()->size();
327 const int iViewportWidth = viewportSize.width();
328 int iVerticalIndent = iMargin;
329
330 /* Layout the children: */
331 foreach (UIToolsItem *pItem, items())
332 {
333 /* Make sure item visible: */
334 if (!pItem->isVisible())
335 continue;
336
337 /* Set item position: */
338 pItem->setPos(iMargin, iVerticalIndent);
339 /* Set root-item size: */
340 pItem->resize(iViewportWidth, pItem->minimumHeightHint());
341 /* Make sure item is shown: */
342 pItem->show();
343 /* Advance vertical indent: */
344 iVerticalIndent += (pItem->minimumHeightHint() + iSpacing);
345 }
346}
347
348void UIToolsModel::sltItemMinimumWidthHintChanged()
349{
350 /* Prepare variables: */
351 const int iMargin = data(ToolsModelData_Margin).toInt();
352
353 /* Calculate maximum horizontal width: */
354 int iMinimumWidthHint = 0;
355 iMinimumWidthHint += 2 * iMargin;
356 foreach (UIToolsItem *pItem, items())
357 iMinimumWidthHint = qMax(iMinimumWidthHint, pItem->minimumWidthHint());
358
359 /* Notify listeners: */
360 emit sigItemMinimumWidthHintChanged(iMinimumWidthHint);
361}
362
363void UIToolsModel::sltItemMinimumHeightHintChanged()
364{
365 /* Prepare variables: */
366 const int iMargin = data(ToolsModelData_Margin).toInt();
367 const int iSpacing = data(ToolsModelData_Spacing).toInt();
368
369 /* Calculate summary vertical height: */
370 int iMinimumHeightHint = 0;
371 iMinimumHeightHint += 2 * iMargin;
372 foreach (UIToolsItem *pItem, items())
373 if (pItem->isVisible())
374 iMinimumHeightHint += (pItem->minimumHeightHint() + iSpacing);
375 iMinimumHeightHint -= iSpacing;
376
377 /* Notify listeners: */
378 emit sigItemMinimumHeightHintChanged(iMinimumHeightHint);
379}
380
381bool UIToolsModel::eventFilter(QObject *pWatched, QEvent *pEvent)
382{
383 /* Process only scene events: */
384 if (pWatched != scene())
385 return QIWithRetranslateUI3<QObject>::eventFilter(pWatched, pEvent);
386
387 /* Process only item focused by model: */
388 if (scene()->focusItem())
389 return QIWithRetranslateUI3<QObject>::eventFilter(pWatched, pEvent);
390
391 /* Do not handle disabled items: */
392 if (!currentItem()->isEnabled())
393 return QIWithRetranslateUI3<QObject>::eventFilter(pWatched, pEvent);
394
395 /* Checking event-type: */
396 switch (pEvent->type())
397 {
398 /* Keyboard handler: */
399 case QEvent::KeyPress:
400 return m_pKeyboardHandler->handle(static_cast<QKeyEvent*>(pEvent), UIKeyboardEventType_Press);
401 case QEvent::KeyRelease:
402 return m_pKeyboardHandler->handle(static_cast<QKeyEvent*>(pEvent), UIKeyboardEventType_Release);
403 /* Mouse handler: */
404 case QEvent::GraphicsSceneMousePress:
405 return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_Press);
406 case QEvent::GraphicsSceneMouseRelease:
407 return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_Release);
408 /* Shut up MSC: */
409 default: break;
410 }
411
412 /* Call to base-class: */
413 return QIWithRetranslateUI3<QObject>::eventFilter(pWatched, pEvent);
414}
415
416void UIToolsModel::retranslateUi()
417{
418 foreach (UIToolsItem *pItem, m_items)
419 {
420 switch (pItem->itemType())
421 {
422 case UIToolType_Welcome: pItem->reconfigure(tr("Welcome")); break;
423 case UIToolType_Extensions: pItem->reconfigure(tr("Extensions")); break;
424 case UIToolType_Media: pItem->reconfigure(tr("Media")); break;
425 case UIToolType_Network: pItem->reconfigure(tr("Network")); break;
426 case UIToolType_Cloud: pItem->reconfigure(tr("Cloud")); break;
427 case UIToolType_VMActivityOverview: pItem->reconfigure(tr("Activities")); break;
428 case UIToolType_Details: pItem->reconfigure(tr("Details")); break;
429 case UIToolType_Snapshots: pItem->reconfigure(tr("Snapshots")); break;
430 case UIToolType_Logs: pItem->reconfigure(tr("Logs")); break;
431 case UIToolType_VMActivity: pItem->reconfigure(tr("Activity")); break;
432 case UIToolType_FileManager: pItem->reconfigure(tr("File Manager")); break;
433 default: break;
434 }
435 }
436}
437
438void UIToolsModel::sltFocusItemDestroyed()
439{
440 AssertMsgFailed(("Focus item destroyed!"));
441}
442
443void UIToolsModel::prepare()
444{
445 /* Prepare scene: */
446 prepareScene();
447 /* Prepare items: */
448 prepareItems();
449 /* Prepare handlers: */
450 prepareHandlers();
451 /* Apply language settings: */
452 retranslateUi();
453}
454
455void UIToolsModel::prepareScene()
456{
457 m_pScene = new QGraphicsScene(this);
458 if (m_pScene)
459 m_pScene->installEventFilter(this);
460}
461
462void UIToolsModel::prepareItems()
463{
464 /* Depending on tool class: */
465 switch (m_enmClass)
466 {
467 case UIToolClass_Global:
468 {
469 /* Welcome: */
470 m_items << new UIToolsItem(scene(), UIToolClass_Global, UIToolType_Welcome, QString(),
471 UIIconPool::iconSet(":/welcome_screen_24px.png",
472 ":/welcome_screen_24px.png"));
473
474 /* Extensions: */
475 m_items << new UIToolsItem(scene(), UIToolClass_Global, UIToolType_Extensions, QString(),
476 UIIconPool::iconSet(":/extension_pack_manager_24px.png",
477 ":/extension_pack_manager_disabled_24px.png"));
478
479 /* Media: */
480 m_items << new UIToolsItem(scene(), UIToolClass_Global, UIToolType_Media, QString(),
481 UIIconPool::iconSet(":/media_manager_24px.png",
482 ":/media_manager_disabled_24px.png"));
483
484 /* Network: */
485 m_items << new UIToolsItem(scene(), UIToolClass_Global, UIToolType_Network, QString(),
486 UIIconPool::iconSet(":/host_iface_manager_24px.png",
487 ":/host_iface_manager_disabled_24px.png"));
488
489 /* Cloud: */
490 m_items << new UIToolsItem(scene(), UIToolClass_Global, UIToolType_Cloud, QString(),
491 UIIconPool::iconSet(":/cloud_profile_manager_24px.png",
492 ":/cloud_profile_manager_disabled_24px.png"));
493
494 /* Activities: */
495 m_items << new UIToolsItem(scene(), UIToolClass_Global, UIToolType_VMActivityOverview, QString(),
496 UIIconPool::iconSet(":/resources_monitor_24px.png",
497 ":/resources_monitor_disabled_24px.png"));
498
499 break;
500 }
501 case UIToolClass_Machine:
502 {
503 /* Details: */
504 m_items << new UIToolsItem(scene(), UIToolClass_Machine, UIToolType_Details, QString(),
505 UIIconPool::iconSet(":/machine_details_manager_24px.png",
506 ":/machine_details_manager_disabled_24px.png"));
507
508 /* Snapshots: */
509 m_items << new UIToolsItem(scene(), UIToolClass_Machine, UIToolType_Snapshots, QString(),
510 UIIconPool::iconSet(":/snapshot_manager_24px.png",
511 ":/snapshot_manager_disabled_24px.png"));
512
513 /* Logs: */
514 m_items << new UIToolsItem(scene(), UIToolClass_Machine, UIToolType_Logs, QString(),
515 UIIconPool::iconSet(":/vm_show_logs_24px.png",
516 ":/vm_show_logs_disabled_24px.png"));
517
518 /* Activity: */
519 m_items << new UIToolsItem(scene(), UIToolClass_Machine, UIToolType_VMActivity, QString(),
520 UIIconPool::iconSet(":/performance_monitor_24px.png",
521 ":/performance_monitor_disabled_24px.png"));
522
523 /* File Manager: */
524 m_items << new UIToolsItem(scene(), UIToolClass_Machine, UIToolType_FileManager, QString(),
525 UIIconPool::iconSet(":/file_manager_24px.png",
526 ":/file_manager_disabled_24px.png"));
527
528 break;
529 }
530 default:
531 break;
532 }
533}
534
535void UIToolsModel::prepareHandlers()
536{
537 m_pMouseHandler = new UIToolsHandlerMouse(this);
538 m_pKeyboardHandler = new UIToolsHandlerKeyboard(this);
539}
540
541void UIToolsModel::loadSettings()
542{
543 /* Load last tool types: */
544 UIToolType enmTypeGlobal, enmTypeMachine;
545 loadLastToolTypes(enmTypeGlobal, enmTypeMachine);
546
547 /* Depending on tool class: */
548 UIToolsItem *pCurrentItem = 0;
549 switch (m_enmClass)
550 {
551 case UIToolClass_Global:
552 {
553 foreach (UIToolsItem *pItem, items())
554 if (pItem->itemType() == enmTypeGlobal)
555 pCurrentItem = pItem;
556 if (!pCurrentItem)
557 pCurrentItem = item(UIToolType_Welcome);
558 break;
559 }
560 case UIToolClass_Machine:
561 {
562 foreach (UIToolsItem *pItem, items())
563 if (pItem->itemType() == enmTypeMachine)
564 pCurrentItem = pItem;
565 if (!pCurrentItem)
566 pCurrentItem = item(UIToolType_Details);
567 break;
568 }
569 default:
570 break;
571 }
572 setCurrentItem(pCurrentItem);
573}
574
575/* static */
576void UIToolsModel::loadLastToolTypes(UIToolType &enmTypeGlobal, UIToolType &enmTypeMachine)
577{
578 /* Load selected items data: */
579 const QList<UIToolType> data = gEDataManager->toolsPaneLastItemsChosen();
580 enmTypeGlobal = data.value(0);
581 if (!UIToolStuff::isTypeOfClass(enmTypeGlobal, UIToolClass_Global))
582 enmTypeGlobal = UIToolType_Welcome;
583 enmTypeMachine = data.value(1);
584 if (!UIToolStuff::isTypeOfClass(enmTypeMachine, UIToolClass_Machine))
585 enmTypeMachine = UIToolType_Details;
586 LogRel2(("GUI: UIToolsModel: Restoring tool items as: Global=%d, Machine=%d\n",
587 (int)enmTypeGlobal, (int)enmTypeMachine));
588}
589
590void UIToolsModel::cleanupHandlers()
591{
592 delete m_pKeyboardHandler;
593 m_pKeyboardHandler = 0;
594 delete m_pMouseHandler;
595 m_pMouseHandler = 0;
596}
597
598void UIToolsModel::cleanupItems()
599{
600 foreach (UIToolsItem *pItem, m_items)
601 delete pItem;
602 m_items.clear();
603}
604
605void UIToolsModel::cleanupScene()
606{
607 delete m_pScene;
608 m_pScene = 0;
609}
610
611void UIToolsModel::cleanup()
612{
613 /* Cleanup handlers: */
614 cleanupHandlers();
615 /* Cleanup items: */
616 cleanupItems();
617 /* Cleanup scene: */
618 cleanupScene();
619}
620
621QVariant UIToolsModel::data(int iKey) const
622{
623 /* Provide other members with required data: */
624 switch (iKey)
625 {
626 /* Layout hints: */
627 case ToolsModelData_Margin: return 0;
628 case ToolsModelData_Spacing: return 1;
629
630 /* Default: */
631 default: break;
632 }
633 return QVariant();
634}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette