VirtualBox

Ignore:
Timestamp:
Mar 26, 2019 5:33:58 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
129596
Message:

FE/Qt: bugref:9241: VirtualBox Manager: Chooser pane: Move UIChooserAbstractModel to separate files.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
3 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r77702 r77891  
    613613        src/manager/UIWelcomePane.h \
    614614        src/manager/chooser/UIChooser.h \
     615        src/manager/chooser/UIChooserAbstractModel.h \
    615616        src/manager/chooser/UIChooserModel.h \
    616617        src/manager/chooser/UIChooserView.h \
     
    10391040        src/manager/UIWelcomePane.cpp \
    10401041        src/manager/chooser/UIChooser.cpp \
     1042        src/manager/chooser/UIChooserAbstractModel.cpp \
    10411043        src/manager/chooser/UIChooserModel.cpp \
    10421044        src/manager/chooser/UIChooserView.cpp \
  • trunk/src/VBox/Frontends/VirtualBox/src/manager/chooser/UIChooserAbstractModel.cpp

    r77890 r77891  
    1616 */
    1717
    18 /* Qt includes: */
    19 #include <QDrag>
    20 #include <QGraphicsScene>
    21 #include <QGraphicsSceneContextMenuEvent>
    22 #include <QGraphicsView>
    23 #include <QScrollBar>
    24 #include <QTimer>
    25 
    2618/* GUI includes: */
    27 #include "QIMessageBox.h"
    2819#include "VBoxGlobal.h"
    29 #include "UIActionPoolManager.h"
    3020#include "UIChooser.h"
    31 #include "UIChooserHandlerMouse.h"
    32 #include "UIChooserHandlerKeyboard.h"
    33 #include "UIChooserItemGroup.h"
    34 #include "UIChooserItemGlobal.h"
    35 #include "UIChooserItemMachine.h"
    36 #include "UIChooserModel.h"
     21#include "UIChooserAbstractModel.h"
    3722#include "UIChooserNode.h"
    3823#include "UIChooserNodeGroup.h"
    3924#include "UIChooserNodeGlobal.h"
    4025#include "UIChooserNodeMachine.h"
    41 #include "UIChooserView.h"
    4226#include "UIExtraDataManager.h"
    4327#include "UIMessageCenter.h"
    44 #include "UIModalWindowManager.h"
    45 #include "UIVirtualBoxManagerWidget.h"
    4628#include "UIVirtualBoxEventHandler.h"
    47 #include "UIWizardNewVM.h"
    48 
    49 /* COM includes: */
    50 #include "CExtPack.h"
    51 #include "CExtPackManager.h"
    5229
    5330/* Type defs: */
     
    631608
    632609/*********************************************************************************************************************************
    633 *   Class UIChooserModel implementation.                                                                                         *
    634 *********************************************************************************************************************************/
    635 
    636 UIChooserModel:: UIChooserModel(UIChooser *pParent)
    637     : UIChooserAbstractModel(pParent)
    638     , m_pChooser(pParent)
    639     , m_pScene(0)
    640     , m_pMouseHandler(0)
    641     , m_pKeyboardHandler(0)
    642     , m_pContextMenuGlobal(0)
    643     , m_pContextMenuGroup(0)
    644     , m_pContextMenuMachine(0)
    645     , m_iCurrentScrolledIndex(-1)
    646     , m_iScrollingTokenSize(30)
    647     , m_fIsScrollingInProgress(false)
    648     , m_pLookupTimer(0)
    649 {
    650     prepare();
    651 }
    652 
    653 UIChooserModel::~UIChooserModel()
    654 {
    655     cleanup();
    656 }
    657 
    658 void UIChooserModel::init()
    659 {
    660     /* Call to base-class: */
    661     UIChooserAbstractModel::init();
    662 
    663     /* Build tree for main root: */
    664     buildTreeForMainRoot();
    665     updateNavigation();
    666     updateLayout();
    667 
    668     /* Load last selected item: */
    669     loadLastSelectedItem();
    670 }
    671 
    672 void UIChooserModel::deinit()
    673 {
    674     /* Save last selected item: */
    675     saveLastSelectedItem();
    676 
    677     /* Unset current items: */
    678     unsetCurrentItems();
    679 
    680     /* Call to base-class: */
    681     UIChooserAbstractModel::deinit();
    682 }
    683 
    684 UIChooser *UIChooserModel::chooser() const
    685 {
    686     return m_pChooser;
    687 }
    688 
    689 UIActionPool *UIChooserModel::actionPool() const
    690 {
    691     return chooser()->actionPool();
    692 }
    693 
    694 QGraphicsScene *UIChooserModel::scene() const
    695 {
    696     return m_pScene;
    697 }
    698 
    699 UIChooserView *UIChooserModel::view()
    700 {
    701     if (!scene())
    702         return 0;
    703     UIChooserView *pChooserView = qobject_cast<UIChooserView*>(scene()->views()[0]);
    704     return pChooserView;
    705 }
    706 
    707 QPaintDevice *UIChooserModel::paintDevice() const
    708 {
    709     if (scene() && !scene()->views().isEmpty())
    710         return scene()->views().first();
    711     return 0;
    712 }
    713 
    714 QGraphicsItem *UIChooserModel::itemAt(const QPointF &position, const QTransform &deviceTransform /* = QTransform() */) const
    715 {
    716     return scene()->itemAt(position, deviceTransform);
    717 }
    718 
    719 void UIChooserModel::handleToolButtonClick(UIChooserItem *pItem)
    720 {
    721     switch (pItem->type())
    722     {
    723         case UIChooserItemType_Global:
    724             emit sigToolMenuRequested(UIToolClass_Global, pItem->mapToScene(QPointF(pItem->size().width(), 0)).toPoint());
    725             break;
    726         case UIChooserItemType_Machine:
    727             emit sigToolMenuRequested(UIToolClass_Machine, pItem->mapToScene(QPointF(pItem->size().width(), 0)).toPoint());
    728             break;
    729         default:
    730             break;
    731     }
    732 }
    733 
    734 void UIChooserModel::handlePinButtonClick(UIChooserItem *pItem)
    735 {
    736     switch (pItem->type())
    737     {
    738         case UIChooserItemType_Global:
    739             pItem->setFavorite(!pItem->isFavorite());
    740             break;
    741         default:
    742             break;
    743     }
    744 }
    745 
    746 void UIChooserModel::setCurrentItems(const QList<UIChooserItem*> &items)
    747 {
    748     /* Is there something changed? */
    749     if (m_currentItems == items)
    750         return;
    751 
    752     /* Remember old current-item list: */
    753     const QList<UIChooserItem*> oldCurrentItems = m_currentItems;
    754 
    755     /* Clear current current-item list: */
    756     m_currentItems.clear();
    757 
    758     /* Iterate over all the passed items: */
    759     foreach (UIChooserItem *pItem, items)
    760     {
    761         /* Add item to current list if navigation list contains it: */
    762         if (pItem && navigationList().contains(pItem))
    763             m_currentItems << pItem;
    764         else
    765             AssertMsgFailed(("Passed item is not in navigation list!"));
    766     }
    767 
    768     /* Is there something really changed? */
    769     if (oldCurrentItems == m_currentItems)
    770         return;
    771 
    772     /* Update all the old items (they are no longer selected): */
    773     foreach (UIChooserItem *pItem, oldCurrentItems)
    774         pItem->update();
    775     /* Update all the new items (they are selected now): */
    776     foreach (UIChooserItem *pItem, m_currentItems)
    777         pItem->update();
    778 
    779     /* Notify about selection changes: */
    780     emit sigSelectionChanged();
    781 }
    782 
    783 void UIChooserModel::setCurrentItem(UIChooserItem *pItem)
    784 {
    785     /* Call for wrapper above: */
    786     QList<UIChooserItem*> items;
    787     if (pItem)
    788         items << pItem;
    789     setCurrentItems(items);
    790 
    791     /* Move focus to current-item: */
    792     setFocusItem(currentItem());
    793 }
    794 
    795 void UIChooserModel::setCurrentItem(const QString &strDefinition)
    796 {
    797     /* Ignore if empty definition passed: */
    798     if (strDefinition.isEmpty())
    799         return;
    800 
    801     /* Parse definition: */
    802     UIChooserItem *pItem = 0;
    803     const QString strItemType = strDefinition.section('=', 0, 0);
    804     const QString strItemDescriptor = strDefinition.section('=', 1, -1);
    805     /* Its a group-item definition? */
    806     if (strItemType == "g")
    807     {
    808         /* Search for group-item with passed descriptor (name): */
    809         pItem = root()->searchForItem(strItemDescriptor,
    810                                       UIChooserItemSearchFlag_Group |
    811                                       UIChooserItemSearchFlag_ExactName);
    812     }
    813     /* Its a machine-item definition? */
    814     else if (strItemType == "m")
    815     {
    816         /* Check if machine-item with passed descriptor (name or id) registered: */
    817         CMachine comMachine = vboxGlobal().virtualBox().FindMachine(strItemDescriptor);
    818         if (!comMachine.isNull())
    819         {
    820             /* Search for machine-item with required name: */
    821             pItem = root()->searchForItem(comMachine.GetName(),
    822                                           UIChooserItemSearchFlag_Machine |
    823                                           UIChooserItemSearchFlag_ExactName);
    824         }
    825     }
    826 
    827     /* Make sure found item is in navigation list: */
    828     if (!pItem || !navigationList().contains(pItem))
    829         return;
    830 
    831     /* Call for wrapper above: */
    832     setCurrentItem(pItem);
    833 }
    834 
    835 void UIChooserModel::unsetCurrentItems()
    836 {
    837     /* Call for wrapper above: */
    838     setCurrentItem(0);
    839 }
    840 
    841 void UIChooserModel::addToCurrentItems(UIChooserItem *pItem)
    842 {
    843     /* Call for wrapper above: */
    844     setCurrentItems(QList<UIChooserItem*>(m_currentItems) << pItem);
    845 }
    846 
    847 void UIChooserModel::removeFromCurrentItems(UIChooserItem *pItem)
    848 {
    849     /* Prepare filtered list: */
    850     QList<UIChooserItem*> list(m_currentItems);
    851     list.removeAll(pItem);
    852     /* Call for wrapper above: */
    853     setCurrentItems(list);
    854 }
    855 
    856 UIChooserItem *UIChooserModel::currentItem() const
    857 {
    858     /* Return first of current items, if any: */
    859     return currentItems().isEmpty() ? 0 : currentItems().first();
    860 }
    861 
    862 const QList<UIChooserItem*> &UIChooserModel::currentItems() const
    863 {
    864     return m_currentItems;
    865 }
    866 
    867 UIVirtualMachineItem *UIChooserModel::currentMachineItem() const
    868 {
    869     /* Return first machine-item of the current-item: */
    870     return   currentItem() && currentItem()->firstMachineItem() && currentItem()->firstMachineItem()->node()
    871            ? currentItem()->firstMachineItem()->node()->toMachineNode()
    872            : 0;
    873 }
    874 
    875 QList<UIVirtualMachineItem*> UIChooserModel::currentMachineItems() const
    876 {
    877     /* Gather list of current unique machine-items: */
    878     QList<UIChooserItemMachine*> currentMachineItemList;
    879     UIChooserItemMachine::enumerateMachineItems(currentItems(), currentMachineItemList,
    880                                                 UIChooserItemMachineEnumerationFlag_Unique);
    881 
    882     /* Reintegrate machine-items into valid format: */
    883     QList<UIVirtualMachineItem*> currentMachineList;
    884     foreach (UIChooserItemMachine *pItem, currentMachineItemList)
    885         currentMachineList << pItem->node()->toMachineNode();
    886     return currentMachineList;
    887 }
    888 
    889 bool UIChooserModel::isGroupItemSelected() const
    890 {
    891     return currentItem() && currentItem()->type() == UIChooserItemType_Group;
    892 }
    893 
    894 bool UIChooserModel::isGlobalItemSelected() const
    895 {
    896     return currentItem() && currentItem()->type() == UIChooserItemType_Global;
    897 }
    898 
    899 bool UIChooserModel::isMachineItemSelected() const
    900 {
    901     return currentItem() && currentItem()->type() == UIChooserItemType_Machine;
    902 }
    903 
    904 bool UIChooserModel::isSingleGroupSelected() const
    905 {
    906     return    currentItems().size() == 1
    907            && currentItem()->type() == UIChooserItemType_Group;
    908 }
    909 
    910 bool UIChooserModel::isAllItemsOfOneGroupSelected() const
    911 {
    912     /* Make sure at least one item selected: */
    913     if (currentItems().isEmpty())
    914         return false;
    915 
    916     /* Determine the parent group of the first item: */
    917     UIChooserItem *pFirstParent = currentItem()->parentItem();
    918 
    919     /* Make sure this parent is not main root-item: */
    920     if (pFirstParent == root())
    921         return false;
    922 
    923     /* Enumerate current-item set: */
    924     QSet<UIChooserItem*> currentItemSet;
    925     foreach (UIChooserItem *pCurrentItem, currentItems())
    926         currentItemSet << pCurrentItem;
    927 
    928     /* Enumerate first parent children set: */
    929     QSet<UIChooserItem*> firstParentItemSet;
    930     foreach (UIChooserItem *pFirstParentItem, pFirstParent->items())
    931         firstParentItemSet << pFirstParentItem;
    932 
    933     /* Check if both sets contains the same: */
    934     return currentItemSet == firstParentItemSet;
    935 }
    936 
    937 UIChooserItem *UIChooserModel::findClosestUnselectedItem() const
    938 {
    939     /* Take the focus item (if any) as a starting point
    940      * and find the closest non-selected item. */
    941     UIChooserItem *pItem = focusItem();
    942     if (!pItem)
    943         pItem = currentItem();
    944     if (pItem)
    945     {
    946         int idxBefore = navigationList().indexOf(pItem) - 1;
    947         int idxAfter  = idxBefore + 2;
    948         while (idxBefore >= 0 || idxAfter < navigationList().size())
    949         {
    950             if (idxBefore >= 0)
    951             {
    952                 pItem = navigationList().at(idxBefore);
    953                 if (!currentItems().contains(pItem) && pItem->type() == UIChooserItemType_Machine)
    954                     return pItem;
    955                 --idxBefore;
    956             }
    957             if (idxAfter < navigationList().size())
    958             {
    959                 pItem = navigationList().at(idxAfter);
    960                 if (!currentItems().contains(pItem) && pItem->type() == UIChooserItemType_Machine)
    961                     return pItem;
    962                 ++idxAfter;
    963             }
    964         }
    965     }
    966     return 0;
    967 }
    968 
    969 void UIChooserModel::makeSureSomeItemIsSelected()
    970 {
    971     /* Make sure selection item list is never empty
    972      * if at least one item (for example 'focus') present: */
    973     if (!currentItem() && focusItem())
    974         setCurrentItem(focusItem());
    975 }
    976 
    977 void UIChooserModel::setFocusItem(UIChooserItem *pItem)
    978 {
    979     /* Make sure real focus unset: */
    980     clearRealFocus();
    981 
    982     /* Is there something changed? */
    983     if (m_pFocusItem == pItem)
    984         return;
    985 
    986     /* Remember old focus-item: */
    987     UIChooserItem *pOldFocusItem = m_pFocusItem;
    988 
    989     /* Set new focus-item: */
    990     m_pFocusItem = pItem;
    991 
    992     /* Disconnect old focus-item (if any): */
    993     if (pOldFocusItem)
    994         disconnect(pOldFocusItem, SIGNAL(destroyed(QObject*)), this, SLOT(sltFocusItemDestroyed()));
    995     /* Connect new focus-item (if any): */
    996     if (m_pFocusItem)
    997         connect(m_pFocusItem, SIGNAL(destroyed(QObject*)), this, SLOT(sltFocusItemDestroyed()));
    998 
    999     /* If dialog is visible and item exists => make it visible as well: */
    1000     if (view() && view()->window() && root())
    1001         if (view()->window()->isVisible() && pItem)
    1002             root()->makeSureItemIsVisible(pItem);
    1003 }
    1004 
    1005 UIChooserItem *UIChooserModel::focusItem() const
    1006 {
    1007     return m_pFocusItem;
    1008 }
    1009 
    1010 const QList<UIChooserItem*> &UIChooserModel::navigationList() const
    1011 {
    1012     return m_navigationList;
    1013 }
    1014 
    1015 void UIChooserModel::removeFromNavigationList(UIChooserItem *pItem)
    1016 {
    1017     AssertMsg(pItem, ("Passed item is invalid!"));
    1018     m_navigationList.removeAll(pItem);
    1019 }
    1020 
    1021 void UIChooserModel::updateNavigation()
    1022 {
    1023     m_navigationList.clear();
    1024     m_navigationList = createNavigationList(root());
    1025 }
    1026 
    1027 void UIChooserModel::performSearch(const QString &strSearchTerm, int iItemSearchFlags)
    1028 {
    1029     if (!invisibleRoot())
    1030         return;
    1031 
    1032     /* Currently we perform the search only for machines. when this to be changed make sure the disabled flags
    1033        of the other item types are also managed correctly: */
    1034 
    1035     QList<UIChooserNode*> allNodes = resetSearch();
    1036     if (strSearchTerm.isEmpty())
    1037         return;
    1038 
    1039     invisibleRoot()->searchForNodes(strSearchTerm, iItemSearchFlags, m_searchResults);
    1040 
    1041     foreach (UIChooserNode* pNode, allNodes)
    1042     {
    1043         if (!pNode)
    1044             continue;
    1045         pNode->setDisabled(!m_searchResults.contains(pNode));
    1046     }
    1047 
    1048     scrollToSearchResult(true);
    1049 }
    1050 
    1051 QList<UIChooserNode*> UIChooserModel::resetSearch()
    1052 {
    1053     QList<UIChooserNode*> allNodes;
    1054     /* Calling UIChooserNode::searchForNodes with an empty search string returns a list all nodes (of the whole treee) of the required type: */
    1055     invisibleRoot()->searchForNodes(QString(), UIChooserItemSearchFlag_Machine, allNodes);
    1056 
    1057     /* Reset the disabled flag of the node items first. */
    1058     foreach (UIChooserNode* pNode, allNodes)
    1059     {
    1060         if (!pNode)
    1061             continue;
    1062         pNode->setDisabled(false);
    1063     }
    1064     /* Reset the search result relate data: */
    1065     m_searchResults.clear();
    1066     m_iCurrentScrolledIndex = -1;
    1067     return allNodes;
    1068 }
    1069 
    1070 void UIChooserModel::scrollToSearchResult(bool fIsNext)
    1071 {
    1072     if (m_searchResults.isEmpty())
    1073     {
    1074         m_iCurrentScrolledIndex = -1;
    1075         if (view())
    1076             view()->setSearchResultsCount(m_searchResults.size(), m_iCurrentScrolledIndex);
    1077         return;
    1078     }
    1079 
    1080     if (fIsNext)
    1081     {
    1082         if (++m_iCurrentScrolledIndex >= m_searchResults.size())
    1083             m_iCurrentScrolledIndex = 0;
    1084     }
    1085     else
    1086     {
    1087         if (--m_iCurrentScrolledIndex < 0)
    1088             m_iCurrentScrolledIndex = m_searchResults.size() - 1;
    1089     }
    1090 
    1091     if (m_searchResults.at(m_iCurrentScrolledIndex))
    1092     {
    1093         UIChooserItem *pItem = m_searchResults.at(m_iCurrentScrolledIndex)->item();
    1094         if (pItem)
    1095         {
    1096             pItem->makeSureItsVisible();
    1097             setCurrentItem(pItem);
    1098         }
    1099     }
    1100 
    1101     /* Update the search widget's match count(s): */
    1102     if (view())
    1103         view()->setSearchResultsCount(m_searchResults.size(), m_iCurrentScrolledIndex);
    1104 }
    1105 
    1106 void UIChooserModel::setSearchWidgetVisible(bool fVisible)
    1107 {
    1108     if (view())
    1109         view()->setSearchWidgetVisible(fVisible);
    1110 }
    1111 
    1112 UIChooserItem *UIChooserModel::root() const
    1113 {
    1114     return m_pRoot.data();
    1115 }
    1116 
    1117 void UIChooserModel::startEditingGroupItemName()
    1118 {
    1119     sltEditGroupName();
    1120 }
    1121 
    1122 void UIChooserModel::activateMachineItem()
    1123 {
    1124     actionPool()->action(UIActionIndexST_M_Machine_M_StartOrShow)->activate(QAction::Trigger);
    1125 }
    1126 
    1127 void UIChooserModel::setCurrentDragObject(QDrag *pDragObject)
    1128 {
    1129     /* Make sure real focus unset: */
    1130     clearRealFocus();
    1131 
    1132     /* Remember new drag-object: */
    1133     m_pCurrentDragObject = pDragObject;
    1134     connect(m_pCurrentDragObject, SIGNAL(destroyed(QObject*)), this, SLOT(sltCurrentDragObjectDestroyed()));
    1135 }
    1136 
    1137 void UIChooserModel::lookFor(const QString &strLookupSymbol)
    1138 {
    1139     if (view())
    1140     {
    1141         view()->setSearchWidgetVisible(true);
    1142         view()->appendToSearchString(strLookupSymbol);
    1143     }
    1144 }
    1145 
    1146 bool UIChooserModel::isLookupInProgress() const
    1147 {
    1148     return m_pLookupTimer->isActive();
    1149 }
    1150 
    1151 void UIChooserModel::updateLayout()
    1152 {
    1153     if (!view() || !root())
    1154         return;
    1155 
    1156     /* Initialize variables: */
    1157     const QSize viewportSize = view()->size();
    1158     const int iViewportWidth = viewportSize.width();
    1159     const int iViewportHeight = viewportSize.height();
    1160 
    1161     /* Set root-item position: */
    1162     root()->setPos(0, 0);
    1163     /* Set root-item size: */
    1164     root()->resize(iViewportWidth, iViewportHeight);
    1165     /* Relayout root-item: */
    1166     root()->updateLayout();
    1167     /* Make sure root-item is shown: */
    1168     root()->show();
    1169 }
    1170 
    1171 void UIChooserModel::setGlobalItemHeightHint(int iHint)
    1172 {
    1173     /* Walk thrugh all the items of navigation list: */
    1174     foreach (UIChooserItem *pItem, navigationList())
    1175     {
    1176         /* And for each global item: */
    1177         if (pItem->type() == UIChooserItemType_Global)
    1178         {
    1179             /* Apply the height hint we have: */
    1180             UIChooserItemGlobal *pGlobalItem = pItem->toGlobalItem();
    1181             if (pGlobalItem)
    1182                 pGlobalItem->setHeightHint(iHint);
    1183         }
    1184     }
    1185 }
    1186 
    1187 void UIChooserModel::sltHandleViewResized()
    1188 {
    1189     /* Relayout: */
    1190     updateLayout();
    1191 }
    1192 
    1193 bool UIChooserModel::eventFilter(QObject *pWatched, QEvent *pEvent)
    1194 {
    1195     /* Process only scene events: */
    1196     if (pWatched != scene())
    1197         return QObject::eventFilter(pWatched, pEvent);
    1198 
    1199     /* Process only item focused by model: */
    1200     if (scene()->focusItem())
    1201         return QObject::eventFilter(pWatched, pEvent);
    1202 
    1203     /* Checking event-type: */
    1204     switch (pEvent->type())
    1205     {
    1206         /* Keyboard handler: */
    1207         case QEvent::KeyPress:
    1208             return m_pKeyboardHandler->handle(static_cast<QKeyEvent*>(pEvent), UIKeyboardEventType_Press);
    1209         case QEvent::KeyRelease:
    1210             return m_pKeyboardHandler->handle(static_cast<QKeyEvent*>(pEvent), UIKeyboardEventType_Release);
    1211         /* Mouse handler: */
    1212         case QEvent::GraphicsSceneMousePress:
    1213             return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_Press);
    1214         case QEvent::GraphicsSceneMouseRelease:
    1215             return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_Release);
    1216         case QEvent::GraphicsSceneMouseDoubleClick:
    1217             return m_pMouseHandler->handle(static_cast<QGraphicsSceneMouseEvent*>(pEvent), UIMouseEventType_DoubleClick);
    1218         /* Context-menu handler: */
    1219         case QEvent::GraphicsSceneContextMenu:
    1220             return processContextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent*>(pEvent));
    1221         /* Drag&drop scroll-event (drag-move) handler: */
    1222         case QEvent::GraphicsSceneDragMove:
    1223             return processDragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(pEvent));
    1224         /* Drag&drop scroll-event (drag-leave) handler: */
    1225         case QEvent::GraphicsSceneDragLeave:
    1226             return processDragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(pEvent));
    1227         default: break; /* Shut up MSC */
    1228     }
    1229 
    1230     /* Call to base-class: */
    1231     return QObject::eventFilter(pWatched, pEvent);
    1232 }
    1233 
    1234 void UIChooserModel::sltMachineRegistered(const QUuid &uId, const bool fRegistered)
    1235 {
    1236     /* Call to base-class: */
    1237     UIChooserAbstractModel::sltMachineRegistered(uId, fRegistered);
    1238 
    1239     /* Existing VM unregistered? */
    1240     if (!fRegistered)
    1241     {
    1242         /* Rebuild tree for main root: */
    1243         buildTreeForMainRoot();
    1244         updateNavigation();
    1245         updateLayout();
    1246 
    1247         /* Make sure current-item present, if possible: */
    1248         if (!currentItem() && !navigationList().isEmpty())
    1249             setCurrentItem(navigationList().first());
    1250         /* Make sure focus-item present, if possible: */
    1251         else if (!focusItem() && currentItem())
    1252             setFocusItem(currentItem());
    1253         /* Notify about current-item change: */
    1254         emit sigSelectionChanged();
    1255     }
    1256     /* New VM registered? */
    1257     else
    1258     {
    1259         /* Should we show this VM? */
    1260         if (gEDataManager->showMachineInVirtualBoxManagerChooser(uId))
    1261         {
    1262             /* Rebuild tree for main root: */
    1263             buildTreeForMainRoot();
    1264             updateNavigation();
    1265             updateLayout();
    1266 
    1267             /* Choose newly added item: */
    1268             CMachine comMachine = vboxGlobal().virtualBox().FindMachine(uId.toString());
    1269             setCurrentItem(root()->searchForItem(comMachine.GetName(),
    1270                                                  UIChooserItemSearchFlag_Machine |
    1271                                                  UIChooserItemSearchFlag_ExactName));
    1272         }
    1273     }
    1274 }
    1275 
    1276 void UIChooserModel::sltReloadMachine(const QUuid &uId)
    1277 {
    1278     /* Call to base-class: */
    1279     UIChooserAbstractModel::sltReloadMachine(uId);
    1280 
    1281     /* Show machine if we should: */
    1282     if (gEDataManager->showMachineInVirtualBoxManagerChooser(uId))
    1283     {
    1284         /* Rebuild tree for main root: */
    1285         buildTreeForMainRoot();
    1286         updateNavigation();
    1287         updateLayout();
    1288 
    1289         /* Choose newly added item: */
    1290         CMachine comMachine = vboxGlobal().virtualBox().FindMachine(uId.toString());
    1291         setCurrentItem(root()->searchForItem(comMachine.GetName(),
    1292                                              UIChooserItemSearchFlag_Machine |
    1293                                              UIChooserItemSearchFlag_ExactName));
    1294     }
    1295     else
    1296     {
    1297         /* Make sure at least one item selected after that: */
    1298         if (!currentItem() && !navigationList().isEmpty())
    1299             setCurrentItem(navigationList().first());
    1300     }
    1301 
    1302     /* Notify listeners about selection change: */
    1303     emit sigSelectionChanged();
    1304 }
    1305 
    1306 void UIChooserModel::sltFocusItemDestroyed()
    1307 {
    1308     AssertMsgFailed(("Focus item destroyed!"));
    1309 }
    1310 
    1311 void UIChooserModel::sltEditGroupName()
    1312 {
    1313     /* Check if action is enabled: */
    1314     if (!actionPool()->action(UIActionIndexST_M_Group_S_Rename)->isEnabled())
    1315         return;
    1316 
    1317     /* Only for single selected group: */
    1318     if (!isSingleGroupSelected())
    1319         return;
    1320 
    1321     /* Start editing group name: */
    1322     currentItem()->startEditing();
    1323 }
    1324 
    1325 void UIChooserModel::sltSortGroup()
    1326 {
    1327     /* Check if action is enabled: */
    1328     if (!actionPool()->action(UIActionIndexST_M_Group_S_Sort)->isEnabled())
    1329         return;
    1330 
    1331     /* Only for single selected group: */
    1332     if (!isSingleGroupSelected())
    1333         return;
    1334 
    1335     /* Sort group-node: */
    1336     sortNodes(currentItem()->node());
    1337 }
    1338 
    1339 void UIChooserModel::sltShowHideSearchWidget()
    1340 {
    1341     if (view())
    1342         setSearchWidgetVisible(!view()->isSearchWidgetVisible());
    1343 }
    1344 
    1345 void UIChooserModel::sltUngroupSelectedGroup()
    1346 {
    1347     /* Check if action is enabled: */
    1348     if (!actionPool()->action(UIActionIndexST_M_Group_S_Remove)->isEnabled())
    1349         return;
    1350 
    1351     /* Make sure focus item is of group type! */
    1352     AssertMsg(focusItem()->type() == UIChooserItemType_Group, ("This is not group-item!"));
    1353 
    1354     /* Check if we have collisions with our siblings: */
    1355     UIChooserItem *pFocusItem = focusItem();
    1356     UIChooserNode *pFocusNode = pFocusItem->node();
    1357     UIChooserItem *pParentItem = pFocusItem->parentItem();
    1358     UIChooserNode *pParentNode = pParentItem->node();
    1359     QList<UIChooserNode*> siblings = pParentNode->nodes();
    1360     QList<UIChooserNode*> toBeRenamed;
    1361     QList<UIChooserNode*> toBeRemoved;
    1362     foreach (UIChooserNode *pNode, pFocusNode->nodes())
    1363     {
    1364         QString strItemName = pNode->name();
    1365         UIChooserNode *pCollisionSibling = 0;
    1366         foreach (UIChooserNode *pSibling, siblings)
    1367             if (pSibling != pFocusNode && pSibling->name() == strItemName)
    1368                 pCollisionSibling = pSibling;
    1369         if (pCollisionSibling)
    1370         {
    1371             if (pNode->type() == UIChooserItemType_Machine)
    1372             {
    1373                 if (pCollisionSibling->type() == UIChooserItemType_Machine)
    1374                     toBeRemoved << pNode;
    1375                 else if (pCollisionSibling->type() == UIChooserItemType_Group)
    1376                 {
    1377                     msgCenter().cannotResolveCollisionAutomatically(strItemName, pParentNode->name());
    1378                     return;
    1379                 }
    1380             }
    1381             else if (pNode->type() == UIChooserItemType_Group)
    1382             {
    1383                 if (msgCenter().confirmAutomaticCollisionResolve(strItemName, pParentNode->name()))
    1384                     toBeRenamed << pNode;
    1385                 else
    1386                     return;
    1387             }
    1388         }
    1389     }
    1390 
    1391     /* Copy all the children into our parent: */
    1392     QList<UIChooserItem*> copiedItems;
    1393     foreach (UIChooserNode *pNode, pFocusNode->nodes())
    1394     {
    1395         if (toBeRemoved.contains(pNode))
    1396             continue;
    1397         switch (pNode->type())
    1398         {
    1399             case UIChooserItemType_Group:
    1400             {
    1401                 UIChooserNodeGroup *pGroupNode = new UIChooserNodeGroup(pParentNode,
    1402                                                                         pNode->toGroupNode(),
    1403                                                                         pParentNode->nodes().size());
    1404                 UIChooserItemGroup *pGroupItem = new UIChooserItemGroup(pParentItem, pGroupNode);
    1405                 if (toBeRenamed.contains(pNode))
    1406                     pGroupNode->setName(uniqueGroupName(pParentNode));
    1407                 copiedItems << pGroupItem;
    1408                 break;
    1409             }
    1410             case UIChooserItemType_Machine:
    1411             {
    1412                 UIChooserNodeMachine *pMachineNode = new UIChooserNodeMachine(pParentNode,
    1413                                                                               pNode->toMachineNode(),
    1414                                                                               pParentNode->nodes().size());
    1415                 UIChooserItemMachine *pMachineItem = new UIChooserItemMachine(pParentItem, pMachineNode);
    1416                 copiedItems << pMachineItem;
    1417                 break;
    1418             }
    1419             default:
    1420                 break;
    1421         }
    1422     }
    1423 
    1424     /* Delete focus group: */
    1425     delete pFocusNode;
    1426 
    1427     /* Notify about selection invalidated: */
    1428     emit sigSelectionInvalidated();
    1429 
    1430     /* And update model: */
    1431     updateNavigation();
    1432     updateLayout();
    1433     if (!copiedItems.isEmpty())
    1434     {
    1435         setCurrentItems(copiedItems);
    1436         setFocusItem(currentItem());
    1437     }
    1438     else
    1439         setCurrentItem(navigationList().first());
    1440     saveGroupSettings();
    1441 }
    1442 
    1443 void UIChooserModel::sltCreateNewMachine()
    1444 {
    1445     /* Check if action is enabled: */
    1446     if (!actionPool()->action(UIActionIndexST_M_Machine_S_New)->isEnabled())
    1447         return;
    1448 
    1449     /* Choose the parent: */
    1450     UIChooserItem *pGroup = 0;
    1451     if (isSingleGroupSelected())
    1452         pGroup = currentItem();
    1453     else if (!currentItems().isEmpty())
    1454         pGroup = currentItem()->parentItem();
    1455     QString strGroupName;
    1456     if (pGroup)
    1457         strGroupName = pGroup->fullName();
    1458 
    1459     /* Lock the action preventing cascade calls: */
    1460     actionPool()->action(UIActionIndexST_M_Welcome_S_New)->setEnabled(false);
    1461     actionPool()->action(UIActionIndexST_M_Machine_S_New)->setEnabled(false);
    1462     actionPool()->action(UIActionIndexST_M_Group_S_New)->setEnabled(false);
    1463 
    1464     /* Use the "safe way" to open stack of Mac OS X Sheets: */
    1465     QWidget *pWizardParent = windowManager().realParentWindow(chooser()->managerWidget());
    1466     UISafePointerWizardNewVM pWizard = new UIWizardNewVM(pWizardParent, strGroupName);
    1467     windowManager().registerNewParent(pWizard, pWizardParent);
    1468     pWizard->prepare();
    1469 
    1470     /* Execute wizard: */
    1471     pWizard->exec();
    1472     if (pWizard)
    1473         delete pWizard;
    1474 
    1475     /* Unlock the action allowing further calls: */
    1476     actionPool()->action(UIActionIndexST_M_Welcome_S_New)->setEnabled(true);
    1477     actionPool()->action(UIActionIndexST_M_Machine_S_New)->setEnabled(true);
    1478     actionPool()->action(UIActionIndexST_M_Group_S_New)->setEnabled(true);
    1479 }
    1480 
    1481 void UIChooserModel::sltGroupSelectedMachines()
    1482 {
    1483     /* Check if action is enabled: */
    1484     if (!actionPool()->action(UIActionIndexST_M_Machine_S_AddGroup)->isEnabled())
    1485         return;
    1486 
    1487     /* Create new group node in the current root: */
    1488     UIChooserNodeGroup *pNewGroupNode = new UIChooserNodeGroup(invisibleRoot(),
    1489                                                                false /* favorite */,
    1490                                                                invisibleRoot()->nodes().size() /* position */,
    1491                                                                uniqueGroupName(invisibleRoot()),
    1492                                                                true /* opened */);
    1493     UIChooserItemGroup *pNewGroupItem = new UIChooserItemGroup(root(), pNewGroupNode);
    1494 
    1495     /* Enumerate all the currently chosen items: */
    1496     QStringList busyGroupNames;
    1497     QStringList busyMachineNames;
    1498     QList<UIChooserItem*> selectedItems = currentItems();
    1499     foreach (UIChooserItem *pItem, selectedItems)
    1500     {
    1501         /* For each of known types: */
    1502         switch (pItem->type())
    1503         {
    1504             case UIChooserItemType_Group:
    1505             {
    1506                 /* Avoid name collisions: */
    1507                 if (busyGroupNames.contains(pItem->name()))
    1508                     break;
    1509                 /* Add name to busy: */
    1510                 busyGroupNames << pItem->name();
    1511                 /* Copy or move group-item: */
    1512                 UIChooserNodeGroup *pNewGroupSubNode = new UIChooserNodeGroup(pNewGroupNode,
    1513                                                                               pItem->node()->toGroupNode(),
    1514                                                                               pNewGroupNode->nodes().size());
    1515                 new UIChooserItemGroup(pNewGroupItem, pNewGroupSubNode);
    1516                 delete pItem->node();
    1517                 break;
    1518             }
    1519             case UIChooserItemType_Machine:
    1520             {
    1521                 /* Avoid name collisions: */
    1522                 if (busyMachineNames.contains(pItem->name()))
    1523                     break;
    1524                 /* Add name to busy: */
    1525                 busyMachineNames << pItem->name();
    1526                 /* Copy or move machine-item: */
    1527                 UIChooserNodeMachine *pNewMachineSubNode = new UIChooserNodeMachine(pNewGroupNode,
    1528                                                                                     pItem->node()->toMachineNode(),
    1529                                                                                     pNewGroupNode->nodes().size());
    1530                 new UIChooserItemMachine(pNewGroupItem, pNewMachineSubNode);
    1531                 delete pItem->node();
    1532                 break;
    1533             }
    1534         }
    1535     }
    1536 
    1537     /* Update model: */
    1538     wipeOutEmptyGroups();
    1539     updateNavigation();
    1540     updateLayout();
    1541     setCurrentItem(pNewGroupItem);
    1542     saveGroupSettings();
    1543 }
    1544 
    1545 void UIChooserModel::sltSortParentGroup()
    1546 {
    1547     /* Check if action is enabled: */
    1548     if (!actionPool()->action(UIActionIndexST_M_Machine_S_SortParent)->isEnabled())
    1549         return;
    1550 
    1551     /* Only if some item selected: */
    1552     if (!currentItem())
    1553         return;
    1554 
    1555     /* Sort parent group-node: */
    1556     sortNodes(currentItem()->parentItem()->node());
    1557 }
    1558 
    1559 void UIChooserModel::sltPerformRefreshAction()
    1560 {
    1561     /* Check if action is enabled: */
    1562     if (!actionPool()->action(UIActionIndexST_M_Group_S_Refresh)->isEnabled())
    1563         return;
    1564 
    1565     /* Gather list of current unique inaccessible machine-items: */
    1566     QList<UIChooserItemMachine*> inaccessibleMachineItemList;
    1567     UIChooserItemMachine::enumerateMachineItems(currentItems(), inaccessibleMachineItemList,
    1568                                                 UIChooserItemMachineEnumerationFlag_Unique |
    1569                                                 UIChooserItemMachineEnumerationFlag_Inaccessible);
    1570 
    1571     /* For each machine-item: */
    1572     UIChooserItem *pSelectedItem = 0;
    1573     foreach (UIChooserItemMachine *pItem, inaccessibleMachineItemList)
    1574     {
    1575         /* Recache: */
    1576         pItem->recache();
    1577         /* Become accessible? */
    1578         if (pItem->accessible())
    1579         {
    1580             /* Machine name: */
    1581             const QString strMachineName = ((UIChooserItem*)pItem)->name();
    1582             /* We should reload this machine: */
    1583             sltReloadMachine(pItem->id());
    1584             /* Select first of reloaded items: */
    1585             if (!pSelectedItem)
    1586                 pSelectedItem = root()->searchForItem(strMachineName,
    1587                                                       UIChooserItemSearchFlag_Machine |
    1588                                                       UIChooserItemSearchFlag_ExactName);
    1589         }
    1590     }
    1591 
    1592     /* Some item to be selected? */
    1593     if (pSelectedItem)
    1594     {
    1595         pSelectedItem->makeSureItsVisible();
    1596         setCurrentItem(pSelectedItem);
    1597     }
    1598 }
    1599 
    1600 void UIChooserModel::sltRemoveSelectedMachine()
    1601 {
    1602     /* Check if action is enabled: */
    1603     if (!actionPool()->action(UIActionIndexST_M_Machine_S_Remove)->isEnabled())
    1604         return;
    1605 
    1606     /* Enumerate all the selected machine-items: */
    1607     QList<UIChooserItemMachine*> selectedMachineItemList;
    1608     UIChooserItemMachine::enumerateMachineItems(currentItems(), selectedMachineItemList);
    1609     /* Enumerate all the existing machine-items: */
    1610     QList<UIChooserItemMachine*> existingMachineItemList;
    1611     UIChooserItemMachine::enumerateMachineItems(root()->items(), existingMachineItemList);
    1612 
    1613     /* Prepare arrays: */
    1614     QMap<QUuid, bool> verdicts;
    1615     QList<UIChooserItem*> itemsToRemove;
    1616     QList<QUuid> machinesToUnregister;
    1617 
    1618     /* For each selected machine-item: */
    1619     foreach (UIChooserItem *pItem, selectedMachineItemList)
    1620     {
    1621         /* Get machine-item id: */
    1622         QUuid uId = pItem->toMachineItem()->id();
    1623 
    1624         /* We already decided for that machine? */
    1625         if (verdicts.contains(uId))
    1626         {
    1627             /* To remove similar machine items? */
    1628             if (!verdicts[uId])
    1629                 itemsToRemove << pItem;
    1630             continue;
    1631         }
    1632 
    1633         /* Selected copy count: */
    1634         int iSelectedCopyCount = 0;
    1635         foreach (UIChooserItem *pSelectedItem, selectedMachineItemList)
    1636             if (pSelectedItem->toMachineItem()->id() == uId)
    1637                 ++iSelectedCopyCount;
    1638         /* Existing copy count: */
    1639         int iExistingCopyCount = 0;
    1640         foreach (UIChooserItem *pExistingItem, existingMachineItemList)
    1641             if (pExistingItem->toMachineItem()->id() == uId)
    1642                 ++iExistingCopyCount;
    1643         /* If selected copy count equal to existing copy count,
    1644          * we will propose ro unregister machine fully else
    1645          * we will just propose to remove selected items: */
    1646         bool fVerdict = iSelectedCopyCount == iExistingCopyCount;
    1647         verdicts.insert(uId, fVerdict);
    1648         if (fVerdict)
    1649             machinesToUnregister.append(uId);
    1650         else
    1651             itemsToRemove << pItem;
    1652     }
    1653 
    1654     /* If we have something to remove: */
    1655     if (!itemsToRemove.isEmpty())
    1656         removeItems(itemsToRemove);
    1657     /* If we have something to unregister: */
    1658     if (!machinesToUnregister.isEmpty())
    1659         unregisterMachines(machinesToUnregister);
    1660 }
    1661 
    1662 void UIChooserModel::sltStartScrolling()
    1663 {
    1664     /* Should we scroll? */
    1665     if (!m_fIsScrollingInProgress)
    1666         return;
    1667 
    1668     /* Reset scrolling progress: */
    1669     m_fIsScrollingInProgress = false;
    1670 
    1671     /* Get view/scrollbar: */
    1672     QGraphicsView *pView = view();
    1673     QScrollBar *pVerticalScrollBar = pView->verticalScrollBar();
    1674 
    1675     /* Convert mouse position to view co-ordinates: */
    1676     const QPoint mousePos = pView->mapFromGlobal(QCursor::pos());
    1677     /* Mouse position is at the top of view? */
    1678     if (mousePos.y() < m_iScrollingTokenSize && mousePos.y() > 0)
    1679     {
    1680         int iValue = mousePos.y();
    1681         if (!iValue) iValue = 1;
    1682         int iDelta = m_iScrollingTokenSize / iValue;
    1683         if (pVerticalScrollBar->value() > pVerticalScrollBar->minimum())
    1684         {
    1685             /* Backward scrolling: */
    1686             pVerticalScrollBar->setValue(pVerticalScrollBar->value() - 2 * iDelta);
    1687             m_fIsScrollingInProgress = true;
    1688             QTimer::singleShot(10, this, SLOT(sltStartScrolling()));
    1689         }
    1690     }
    1691     /* Mouse position is at the bottom of view? */
    1692     else if (mousePos.y() > pView->height() - m_iScrollingTokenSize && mousePos.y() < pView->height())
    1693     {
    1694         int iValue = pView->height() - mousePos.y();
    1695         if (!iValue) iValue = 1;
    1696         int iDelta = m_iScrollingTokenSize / iValue;
    1697         if (pVerticalScrollBar->value() < pVerticalScrollBar->maximum())
    1698         {
    1699             /* Forward scrolling: */
    1700             pVerticalScrollBar->setValue(pVerticalScrollBar->value() + 2 * iDelta);
    1701             m_fIsScrollingInProgress = true;
    1702             QTimer::singleShot(10, this, SLOT(sltStartScrolling()));
    1703         }
    1704     }
    1705 }
    1706 
    1707 void UIChooserModel::sltCurrentDragObjectDestroyed()
    1708 {
    1709     root()->resetDragToken();
    1710 }
    1711 
    1712 void UIChooserModel::sltEraseLookupTimer()
    1713 {
    1714     m_pLookupTimer->stop();
    1715     m_strLookupString = QString();
    1716 }
    1717 
    1718 void UIChooserModel::prepare()
    1719 {
    1720     prepareScene();
    1721     prepareLookup();
    1722     prepareContextMenu();
    1723     prepareHandlers();
    1724     prepareConnections();
    1725 }
    1726 
    1727 void UIChooserModel::prepareScene()
    1728 {
    1729     m_pScene = new QGraphicsScene(this);
    1730     if (m_pScene)
    1731         m_pScene->installEventFilter(this);
    1732 }
    1733 
    1734 void UIChooserModel::prepareLookup()
    1735 {
    1736     m_pLookupTimer = new QTimer(this);
    1737     if (m_pLookupTimer)
    1738     {
    1739         m_pLookupTimer->setInterval(1000);
    1740         m_pLookupTimer->setSingleShot(true);
    1741         connect(m_pLookupTimer, SIGNAL(timeout()), this, SLOT(sltEraseLookupTimer()));
    1742     }
    1743 }
    1744 
    1745 void UIChooserModel::prepareContextMenu()
    1746 {
    1747     /* Context menu for global(s): */
    1748     m_pContextMenuGlobal = new QMenu;
    1749     if (m_pContextMenuGlobal)
    1750     {
    1751         /* Check if Ext Pack is ready, some of actions my depend on it: */
    1752         CExtPack extPack = vboxGlobal().virtualBox().GetExtensionPackManager().Find(GUI_ExtPackName);
    1753         const bool fExtPackAccessible = !extPack.isNull() && extPack.GetUsable();
    1754 
    1755 #ifdef VBOX_WS_MAC
    1756         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndex_M_Application_S_About));
    1757         m_pContextMenuGlobal->addSeparator();
    1758         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndex_M_Application_S_Preferences));
    1759         m_pContextMenuGlobal->addSeparator();
    1760         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ImportAppliance));
    1761         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ExportAppliance));
    1762 # ifdef VBOX_GUI_WITH_EXTRADATA_MANAGER_UI
    1763         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ShowExtraDataManager));
    1764 # endif
    1765         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ShowVirtualMediumManager));
    1766         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ShowHostNetworkManager));
    1767         if (fExtPackAccessible)
    1768             m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ShowCloudProfileManager));
    1769 
    1770 #else /* !VBOX_WS_MAC */
    1771 
    1772         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndex_M_Application_S_Preferences));
    1773         m_pContextMenuGlobal->addSeparator();
    1774         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ImportAppliance));
    1775         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ExportAppliance));
    1776         m_pContextMenuGlobal->addSeparator();
    1777 # ifdef VBOX_GUI_WITH_EXTRADATA_MANAGER_UI
    1778         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ShowExtraDataManager));
    1779 # endif
    1780         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ShowVirtualMediumManager));
    1781         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ShowHostNetworkManager));
    1782         if (fExtPackAccessible)
    1783             m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndexST_M_File_S_ShowCloudProfileManager));
    1784 # ifdef VBOX_GUI_WITH_NETWORK_MANAGER
    1785         m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndex_M_Application_S_NetworkAccessManager));
    1786         if (gEDataManager->applicationUpdateEnabled())
    1787             m_pContextMenuGlobal->addAction(actionPool()->action(UIActionIndex_M_Application_S_CheckForUpdates));
    1788 # endif
    1789 #endif /* !VBOX_WS_MAC */
    1790     }
    1791 
    1792     /* Context menu for group(s): */
    1793     m_pContextMenuGroup = new QMenu;
    1794     if (m_pContextMenuGroup)
    1795     {
    1796         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_New));
    1797         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_Add));
    1798         m_pContextMenuGroup->addSeparator();
    1799         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_Rename));
    1800         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_Remove));
    1801         m_pContextMenuGroup->addSeparator();
    1802         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_M_StartOrShow));
    1803         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_T_Pause));
    1804         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_Reset));
    1805         m_pContextMenuGroup->addMenu(actionPool()->action(UIActionIndexST_M_Group_M_Close)->menu());
    1806         m_pContextMenuGroup->addSeparator();
    1807         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_Discard));
    1808         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_ShowLogDialog));
    1809         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_Refresh));
    1810         m_pContextMenuGroup->addSeparator();
    1811         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_ShowInFileManager));
    1812         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_CreateShortcut));
    1813         m_pContextMenuGroup->addSeparator();
    1814         m_pContextMenuGroup->addAction(actionPool()->action(UIActionIndexST_M_Group_S_Sort));
    1815     }
    1816 
    1817     /* Context menu for machine(s): */
    1818     m_pContextMenuMachine = new QMenu;
    1819     if (m_pContextMenuMachine)
    1820     {
    1821         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_Settings));
    1822         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_Clone));
    1823         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_Move));
    1824         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_ExportToOCI));
    1825         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_Remove));
    1826         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_AddGroup));
    1827         m_pContextMenuMachine->addSeparator();
    1828         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_M_StartOrShow));
    1829         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_T_Pause));
    1830         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_Reset));
    1831         m_pContextMenuMachine->addMenu(actionPool()->action(UIActionIndexST_M_Machine_M_Close)->menu());
    1832         m_pContextMenuMachine->addSeparator();
    1833         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_Discard));
    1834         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_ShowLogDialog));
    1835         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_Refresh));
    1836         m_pContextMenuMachine->addSeparator();
    1837         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_ShowInFileManager));
    1838         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_CreateShortcut));
    1839         m_pContextMenuMachine->addSeparator();
    1840         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_SortParent));
    1841         m_pContextMenuMachine->addAction(actionPool()->action(UIActionIndexST_M_Machine_S_Search));
    1842     }
    1843 }
    1844 
    1845 void UIChooserModel::prepareHandlers()
    1846 {
    1847     m_pMouseHandler = new UIChooserHandlerMouse(this);
    1848     m_pKeyboardHandler = new UIChooserHandlerKeyboard(this);
    1849 }
    1850 
    1851 void UIChooserModel::prepareConnections()
    1852 {
    1853     /* Setup parent connections: */
    1854     connect(this, SIGNAL(sigSelectionChanged()),
    1855             parent(), SIGNAL(sigSelectionChanged()));
    1856     connect(this, SIGNAL(sigSelectionInvalidated()),
    1857             parent(), SIGNAL(sigSelectionInvalidated()));
    1858     connect(this, SIGNAL(sigToggleStarted()),
    1859             parent(), SIGNAL(sigToggleStarted()));
    1860     connect(this, SIGNAL(sigToggleFinished()),
    1861             parent(), SIGNAL(sigToggleFinished()));
    1862 
    1863     /* Setup action connections: */
    1864     connect(actionPool()->action(UIActionIndexST_M_Welcome_S_New), SIGNAL(triggered()),
    1865             this, SLOT(sltCreateNewMachine()));
    1866     connect(actionPool()->action(UIActionIndexST_M_Group_S_New), SIGNAL(triggered()),
    1867             this, SLOT(sltCreateNewMachine()));
    1868     connect(actionPool()->action(UIActionIndexST_M_Machine_S_New), SIGNAL(triggered()),
    1869             this, SLOT(sltCreateNewMachine()));
    1870     connect(actionPool()->action(UIActionIndexST_M_Group_S_Rename), SIGNAL(triggered()),
    1871             this, SLOT(sltEditGroupName()));
    1872     connect(actionPool()->action(UIActionIndexST_M_Group_S_Remove), SIGNAL(triggered()),
    1873             this, SLOT(sltUngroupSelectedGroup()));
    1874     connect(actionPool()->action(UIActionIndexST_M_Machine_S_Remove), SIGNAL(triggered()),
    1875             this, SLOT(sltRemoveSelectedMachine()));
    1876     connect(actionPool()->action(UIActionIndexST_M_Machine_S_AddGroup), SIGNAL(triggered()),
    1877             this, SLOT(sltGroupSelectedMachines()));
    1878     connect(actionPool()->action(UIActionIndexST_M_Group_S_Refresh), SIGNAL(triggered()),
    1879             this, SLOT(sltPerformRefreshAction()));
    1880     connect(actionPool()->action(UIActionIndexST_M_Machine_S_Refresh), SIGNAL(triggered()),
    1881             this, SLOT(sltPerformRefreshAction()));
    1882     connect(actionPool()->action(UIActionIndexST_M_Machine_S_SortParent), SIGNAL(triggered()),
    1883             this, SLOT(sltSortParentGroup()));
    1884     connect(actionPool()->action(UIActionIndexST_M_Group_S_Sort), SIGNAL(triggered()),
    1885             this, SLOT(sltSortGroup()));
    1886     connect(actionPool()->action(UIActionIndexST_M_Machine_S_Search), SIGNAL(triggered()),
    1887             this, SLOT(sltShowHideSearchWidget()));
    1888 }
    1889 
    1890 void UIChooserModel::loadLastSelectedItem()
    1891 {
    1892     /* Load last selected item (choose first if unable to load): */
    1893     setCurrentItem(gEDataManager->selectorWindowLastItemChosen());
    1894     if (!currentItem() && !navigationList().isEmpty())
    1895         setCurrentItem(navigationList().first());
    1896 }
    1897 
    1898 void UIChooserModel::saveLastSelectedItem()
    1899 {
    1900     /* Save last selected item: */
    1901     gEDataManager->setSelectorWindowLastItemChosen(currentItem() ? currentItem()->definition() : QString());
    1902 }
    1903 
    1904 void UIChooserModel::cleanupHandlers()
    1905 {
    1906     delete m_pKeyboardHandler;
    1907     m_pKeyboardHandler = 0;
    1908     delete m_pMouseHandler;
    1909     m_pMouseHandler = 0;
    1910 }
    1911 
    1912 void UIChooserModel::cleanupContextMenu()
    1913 {
    1914     delete m_pContextMenuGlobal;
    1915     m_pContextMenuGlobal = 0;
    1916     delete m_pContextMenuGroup;
    1917     m_pContextMenuGroup = 0;
    1918     delete m_pContextMenuMachine;
    1919     m_pContextMenuMachine = 0;
    1920 }
    1921 
    1922 void UIChooserModel::cleanupLookup()
    1923 {
    1924     delete m_pLookupTimer;
    1925     m_pLookupTimer = 0;
    1926 }
    1927 
    1928 void UIChooserModel::cleanupScene()
    1929 {
    1930     delete m_pScene;
    1931     m_pScene = 0;
    1932 }
    1933 
    1934 void UIChooserModel::cleanup()
    1935 {
    1936     cleanupHandlers();
    1937     cleanupContextMenu();
    1938     cleanupLookup();
    1939     cleanupScene();
    1940 }
    1941 
    1942 bool UIChooserModel::processContextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent)
    1943 {
    1944     /* Whats the reason? */
    1945     switch (pEvent->reason())
    1946     {
    1947         case QGraphicsSceneContextMenuEvent::Mouse:
    1948         {
    1949             /* First of all we should look for an item under cursor: */
    1950             if (QGraphicsItem *pItem = itemAt(pEvent->scenePos()))
    1951             {
    1952                 /* If this item of known type? */
    1953                 switch (pItem->type())
    1954                 {
    1955                     case UIChooserItemType_Global:
    1956                     {
    1957                         /* Global context menu for global item cases: */
    1958                         popupContextMenu(UIGraphicsSelectorContextMenuType_Global, pEvent->screenPos());
    1959                         return true;
    1960                     }
    1961                     case UIChooserItemType_Group:
    1962                     {
    1963                         /* Get group-item: */
    1964                         UIChooserItem *pGroupItem = qgraphicsitem_cast<UIChooserItemGroup*>(pItem);
    1965                         /* Make sure thats not root: */
    1966                         if (pGroupItem->isRoot())
    1967                             return false;
    1968                         /* Is this group-item only the one selected? */
    1969                         if (currentItems().contains(pGroupItem) && currentItems().size() == 1)
    1970                         {
    1971                             /* Group context menu in that case: */
    1972                             popupContextMenu(UIGraphicsSelectorContextMenuType_Group, pEvent->screenPos());
    1973                             return true;
    1974                         }
    1975                     }
    1976                     RT_FALL_THRU();
    1977                     case UIChooserItemType_Machine:
    1978                     {
    1979                         /* Machine context menu for other Group/Machine cases: */
    1980                         popupContextMenu(UIGraphicsSelectorContextMenuType_Machine, pEvent->screenPos());
    1981                         return true;
    1982                     }
    1983                     default:
    1984                         break;
    1985                 }
    1986             }
    1987             return true;
    1988         }
    1989         case QGraphicsSceneContextMenuEvent::Keyboard:
    1990         {
    1991             /* Get first selected item: */
    1992             if (UIChooserItem *pItem = currentItem())
    1993             {
    1994                 /* If this item of known type? */
    1995                 switch (pItem->type())
    1996                 {
    1997                     case UIChooserItemType_Global:
    1998                     {
    1999                         /* Global context menu for global item cases: */
    2000                         popupContextMenu(UIGraphicsSelectorContextMenuType_Machine, pEvent->screenPos());
    2001                         return true;
    2002                     }
    2003                     case UIChooserItemType_Group:
    2004                     {
    2005                         /* Is this group-item only the one selected? */
    2006                         if (currentItems().size() == 1)
    2007                         {
    2008                             /* Group context menu in that case: */
    2009                             popupContextMenu(UIGraphicsSelectorContextMenuType_Group, pEvent->screenPos());
    2010                             return true;
    2011                         }
    2012                     }
    2013                     RT_FALL_THRU();
    2014                     case UIChooserItemType_Machine:
    2015                     {
    2016                         /* Machine context menu for other Group/Machine cases: */
    2017                         popupContextMenu(UIGraphicsSelectorContextMenuType_Machine, pEvent->screenPos());
    2018                         return true;
    2019                     }
    2020                     default:
    2021                         break;
    2022                 }
    2023             }
    2024             return true;
    2025         }
    2026         default:
    2027             break;
    2028     }
    2029     /* Pass others context menu events: */
    2030     return false;
    2031 }
    2032 
    2033 void UIChooserModel::popupContextMenu(UIGraphicsSelectorContextMenuType enmType, QPoint point)
    2034 {
    2035     /* Which type of context-menu requested? */
    2036     switch (enmType)
    2037     {
    2038         /* For global item? */
    2039         case UIGraphicsSelectorContextMenuType_Global:
    2040         {
    2041             m_pContextMenuGlobal->exec(point);
    2042             break;
    2043         }
    2044         /* For group? */
    2045         case UIGraphicsSelectorContextMenuType_Group:
    2046         {
    2047             m_pContextMenuGroup->exec(point);
    2048             break;
    2049         }
    2050         /* For machine(s)? */
    2051         case UIGraphicsSelectorContextMenuType_Machine:
    2052         {
    2053             m_pContextMenuMachine->exec(point);
    2054             break;
    2055         }
    2056     }
    2057 }
    2058 
    2059 void UIChooserModel::clearRealFocus()
    2060 {
    2061     /* Set the real focus to null: */
    2062     scene()->setFocusItem(0);
    2063 }
    2064 
    2065 QList<UIChooserItem*> UIChooserModel::createNavigationList(UIChooserItem *pItem)
    2066 {
    2067     /* Prepare navigation list: */
    2068     QList<UIChooserItem*> navigationItems;
    2069 
    2070     /* Iterate over all the global-items: */
    2071     foreach (UIChooserItem *pGlobalItem, pItem->items(UIChooserItemType_Global))
    2072         navigationItems << pGlobalItem;
    2073     /* Iterate over all the group-items: */
    2074     foreach (UIChooserItem *pGroupItem, pItem->items(UIChooserItemType_Group))
    2075     {
    2076         navigationItems << pGroupItem;
    2077         if (pGroupItem->toGroupItem()->isOpened())
    2078             navigationItems << createNavigationList(pGroupItem);
    2079     }
    2080     /* Iterate over all the machine-items: */
    2081     foreach (UIChooserItem *pMachineItem, pItem->items(UIChooserItemType_Machine))
    2082         navigationItems << pMachineItem;
    2083 
    2084     /* Return navigation list: */
    2085     return navigationItems;
    2086 }
    2087 
    2088 void UIChooserModel::buildTreeForMainRoot()
    2089 {
    2090     /* Cleanup previous tree if exists: */
    2091     delete m_pRoot;
    2092     m_pRoot = 0;
    2093 
    2094     /* Build whole tree for invisible root item: */
    2095     m_pRoot = new UIChooserItemGroup(scene(), invisibleRoot()->toGroupNode());
    2096 
    2097     /* Install root as event-filter for scene view,
    2098      * we need QEvent::Scroll events from it: */
    2099     root()->installEventFilterHelper(view());
    2100 }
    2101 
    2102 void UIChooserModel::removeItems(const QList<UIChooserItem*> &itemsToRemove)
    2103 {
    2104     /* Confirm machine-items removal: */
    2105     QStringList names;
    2106     foreach (UIChooserItem *pItem, itemsToRemove)
    2107         names << pItem->name();
    2108     if (!msgCenter().confirmMachineItemRemoval(names))
    2109         return;
    2110 
    2111     /* Remove all the passed nodes: */
    2112     foreach (UIChooserItem *pItem, itemsToRemove)
    2113         delete pItem->node();
    2114 
    2115     /* And update model: */
    2116     wipeOutEmptyGroups();
    2117     updateNavigation();
    2118     updateLayout();
    2119     if (!navigationList().isEmpty())
    2120         setCurrentItem(navigationList().first());
    2121     else
    2122         unsetCurrentItems();
    2123     saveGroupSettings();
    2124 }
    2125 
    2126 void UIChooserModel::unregisterMachines(const QList<QUuid> &ids)
    2127 {
    2128     /* Populate machine list: */
    2129     QList<CMachine> machines;
    2130     CVirtualBox vbox = vboxGlobal().virtualBox();
    2131     foreach (const QUuid &uId, ids)
    2132     {
    2133         CMachine machine = vbox.FindMachine(uId.toString());
    2134         if (!machine.isNull())
    2135             machines << machine;
    2136     }
    2137 
    2138     /* Confirm machine removal: */
    2139     int iResultCode = msgCenter().confirmMachineRemoval(machines);
    2140     if (iResultCode == AlertButton_Cancel)
    2141         return;
    2142 
    2143     /* Change selection to some close by item: */
    2144     setCurrentItem(findClosestUnselectedItem());
    2145 
    2146     /* For every selected item: */
    2147     for (int iMachineIndex = 0; iMachineIndex < machines.size(); ++iMachineIndex)
    2148     {
    2149         /* Get iterated machine: */
    2150         CMachine &machine = machines[iMachineIndex];
    2151         if (iResultCode == AlertButton_Choice1)
    2152         {
    2153             /* Unregister machine first: */
    2154             CMediumVector media = machine.Unregister(KCleanupMode_DetachAllReturnHardDisksOnly);
    2155             if (!machine.isOk())
    2156             {
    2157                 msgCenter().cannotRemoveMachine(machine);
    2158                 continue;
    2159             }
    2160             /* Prepare cleanup progress: */
    2161             CProgress progress = machine.DeleteConfig(media);
    2162             if (!machine.isOk())
    2163             {
    2164                 msgCenter().cannotRemoveMachine(machine);
    2165                 continue;
    2166             }
    2167             /* And show cleanup progress finally: */
    2168             msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_delete_90px.png");
    2169             if (!progress.isOk() || progress.GetResultCode() != 0)
    2170             {
    2171                 msgCenter().cannotRemoveMachine(machine, progress);
    2172                 continue;
    2173             }
    2174         }
    2175         else if (iResultCode == AlertButton_Choice2 || iResultCode == AlertButton_Ok)
    2176         {
    2177             /* Unregister machine first: */
    2178             CMediumVector media = machine.Unregister(KCleanupMode_DetachAllReturnHardDisksOnly);
    2179             if (!machine.isOk())
    2180             {
    2181                 msgCenter().cannotRemoveMachine(machine);
    2182                 continue;
    2183             }
    2184             /* Finally close all media, deliberately ignoring errors: */
    2185             foreach (CMedium medium, media)
    2186             {
    2187                 if (!medium.isNull())
    2188                     medium.Close();
    2189             }
    2190         }
    2191     }
    2192 }
    2193 
    2194 bool UIChooserModel::processDragMoveEvent(QGraphicsSceneDragDropEvent *pEvent)
    2195 {
    2196     /* Do we scrolling already? */
    2197     if (m_fIsScrollingInProgress)
    2198         return false;
    2199 
    2200     /* Get view: */
    2201     QGraphicsView *pView = view();
    2202 
    2203     /* Check scroll-area: */
    2204     const QPoint eventPoint = pView->mapFromGlobal(pEvent->screenPos());
    2205     if ((eventPoint.y() < m_iScrollingTokenSize) ||
    2206         (eventPoint.y() > pView->height() - m_iScrollingTokenSize))
    2207     {
    2208         /* Set scrolling in progress: */
    2209         m_fIsScrollingInProgress = true;
    2210         /* Start scrolling: */
    2211         QTimer::singleShot(200, this, SLOT(sltStartScrolling()));
    2212     }
    2213 
    2214     /* Pass event: */
    2215     return false;
    2216 }
    2217 
    2218 bool UIChooserModel::processDragLeaveEvent(QGraphicsSceneDragDropEvent *pEvent)
    2219 {
    2220     /* Event object is not required here: */
    2221     Q_UNUSED(pEvent);
    2222 
    2223     /* Make sure to stop scrolling as drag-leave event happened: */
    2224     if (m_fIsScrollingInProgress)
    2225         m_fIsScrollingInProgress = false;
    2226 
    2227     /* Pass event: */
    2228     return false;
    2229 }
    2230 
    2231 void UIChooserModel::sortNodes(UIChooserNode *pNode)
    2232 {
    2233     /* Sort nodes: */
    2234     pNode->sortNodes();
    2235 
    2236     /* Rebuild tree for main root: */
    2237     buildTreeForMainRoot();
    2238     updateNavigation();
    2239     updateLayout();
    2240 }
    2241 
    2242 
    2243 /*********************************************************************************************************************************
    2244610*   Class UIThreadGroupDefinitionSave implementation.                                                                            *
    2245611*********************************************************************************************************************************/
  • trunk/src/VBox/Frontends/VirtualBox/src/manager/chooser/UIChooserAbstractModel.h

    r77890 r77891  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UIChooserModel class declaration.
     3 * VBox Qt GUI - UIChooserAbstractModel class declaration.
    44 */
    55
     
    1616 */
    1717
    18 #ifndef FEQT_INCLUDED_SRC_manager_chooser_UIChooserModel_h
    19 #define FEQT_INCLUDED_SRC_manager_chooser_UIChooserModel_h
     18#ifndef FEQT_INCLUDED_SRC_manager_chooser_UIChooserAbstractModel_h
     19#define FEQT_INCLUDED_SRC_manager_chooser_UIChooserAbstractModel_h
    2020#ifndef RT_WITHOUT_PRAGMA_ONCE
    2121# pragma once
     
    2323
    2424/* Qt includes: */
    25 #include <QPointer>
    2625#include <QThread>
    27 #include <QUuid>
    2826
    2927/* GUI includes: */
    3028#include "UIChooserDefs.h"
    31 #include "UIExtraDataDefs.h"
    3229
    3330/* COM includes: */
     
    3532
    3633/* Forward declaration: */
    37 class QDrag;
    38 class UIActionPool;
     34class QUuid;
    3935class UIChooser;
    40 class UIChooserHandlerMouse;
    41 class UIChooserHandlerKeyboard;
    42 class UIChooserItem;
    4336class UIChooserNode;
    44 class UIChooserView;
    45 class UIVirtualMachineItem;
    4637class CMachine;
    47 
    48 
    49 /** Context-menu types. */
    50 enum UIGraphicsSelectorContextMenuType
    51 {
    52     UIGraphicsSelectorContextMenuType_Global,
    53     UIGraphicsSelectorContextMenuType_Group,
    54     UIGraphicsSelectorContextMenuType_Machine
    55 };
    5638
    5739
     
    215197
    216198
    217 /** UIChooserAbstractModel extension used as VM Chooser-pane model.
    218   * This class is used to operate on tree of visible tree items
    219   * representing VMs and their groups. */
    220 class UIChooserModel : public UIChooserAbstractModel
    221 {
    222     Q_OBJECT;
    223 
    224 signals:
    225 
    226     /** @name General stuff.
    227       * @{ */
    228         /** Notify listeners about tool menu popup request for certain @a enmClass and @a position. */
    229         void sigToolMenuRequested(UIToolClass enmClass, const QPoint &position);
    230     /** @} */
    231 
    232     /** @name Selection stuff.
    233       * @{ */
    234         /** Notifies about selection changed. */
    235         void sigSelectionChanged();
    236         /** Notifies about selection invalidated. */
    237         void sigSelectionInvalidated();
    238 
    239         /** Notifies about group toggling started. */
    240         void sigToggleStarted();
    241         /** Notifies about group toggling finished. */
    242         void sigToggleFinished();
    243     /** @} */
    244 
    245     /** @name Layout stuff.
    246       * @{ */
    247         /** Notifies about root item minimum width @a iHint changed. */
    248         void sigRootItemMinimumWidthHintChanged(int iHint);
    249     /** @} */
    250 
    251 public:
    252 
    253     /** Constructs Chooser-model passing @a pParent to the base-class. */
    254     UIChooserModel(UIChooser *pParent);
    255     /** Destructs Chooser-model. */
    256     virtual ~UIChooserModel() /* override */;
    257 
    258     /** @name General stuff.
    259       * @{ */
    260         /** Inits model. */
    261         void init();
    262         /** Deinits model. */
    263         void deinit();
    264 
    265         /** Returns the Chooser reference. */
    266         UIChooser *chooser() const;
    267         /** Returns the action-pool reference. */
    268         UIActionPool *actionPool() const;
    269         /** Returns the scene reference. */
    270         QGraphicsScene *scene() const;
    271         /** Returns the paint device reference. */
    272         QPaintDevice *paintDevice() const;
    273 
    274         /** Returns item at @a position, taking into account possible @a deviceTransform. */
    275         QGraphicsItem *itemAt(const QPointF &position, const QTransform &deviceTransform = QTransform()) const;
    276 
    277         /** Handles tool button click for certain @a pItem. */
    278         void handleToolButtonClick(UIChooserItem *pItem);
    279         /** Handles pin button click for certain @a pItem. */
    280         void handlePinButtonClick(UIChooserItem *pItem);
    281     /** @} */
    282 
    283     /** @name Selection stuff.
    284       * @{ */
    285         /** Sets a list of current @a items. */
    286         void setCurrentItems(const QList<UIChooserItem*> &items);
    287         /** Defines current @a pItem. */
    288         void setCurrentItem(UIChooserItem *pItem);
    289         /** Defines current item by @a definition. */
    290         void setCurrentItem(const QString &strDefinition);
    291         /** Unsets all current items. */
    292         void unsetCurrentItems();
    293 
    294         /** Adds @a pItem to list of current. */
    295         void addToCurrentItems(UIChooserItem *pItem);
    296         /** Removes @a pItem from list of current. */
    297         void removeFromCurrentItems(UIChooserItem *pItem);
    298 
    299         /** Returns current item. */
    300         UIChooserItem *currentItem() const;
    301         /** Returns a list of current items. */
    302         const QList<UIChooserItem*> &currentItems() const;
    303 
    304         /** Returns current machine item. */
    305         UIVirtualMachineItem *currentMachineItem() const;
    306         /** Returns a list of current machine items. */
    307         QList<UIVirtualMachineItem*> currentMachineItems() const;
    308 
    309         /** Returns whether group item is selected. */
    310         bool isGroupItemSelected() const;
    311         /** Returns whether global item is selected. */
    312         bool isGlobalItemSelected() const;
    313         /** Returns whether machine item is selected. */
    314         bool isMachineItemSelected() const;
    315 
    316         /** Returns whether single group is selected. */
    317         bool isSingleGroupSelected() const;
    318         /** Returns whether all machine items of one group is selected. */
    319         bool isAllItemsOfOneGroupSelected() const;
    320 
    321         /** Finds closest non-selected item. */
    322         UIChooserItem *findClosestUnselectedItem() const;
    323 
    324         /** Makes sure some item is selected. */
    325         void makeSureSomeItemIsSelected();
    326 
    327         /** Defines focus @a pItem. */
    328         void setFocusItem(UIChooserItem *pItem);
    329         /** Returns focus item. */
    330         UIChooserItem *focusItem() const;
    331     /** @} */
    332 
    333     /** @name Navigation stuff.
    334       * @{ */
    335         /** Returns navigation item list. */
    336         const QList<UIChooserItem*> &navigationList() const;
    337         /** Removes @a pItem from navigation list. */
    338         void removeFromNavigationList(UIChooserItem *pItem);
    339         /** Updates navigation list. */
    340         void updateNavigation();
    341     /** @} */
    342 
    343     /** @name Virtual Machine/Group search stuff.
    344       * @{ */
    345         /** Performs a search starting from the m_pInvisibleRootNode. */
    346         void performSearch(const QString &strSearchTerm, int iItemSearchFlags);
    347         /** Clean the search result data members and disables item's visual effects. Also returns a list of
    348           * all nodes which may be utilized by the calling code. */
    349         QList<UIChooserNode*> resetSearch();
    350         /** Scrolls to next/prev (wrt. @a fIsNext) search result. */
    351         void scrollToSearchResult(bool fIsNext);
    352         /** Shows/hides machine search widget. */
    353         void setSearchWidgetVisible(bool fVisible);
    354     /** @} */
    355 
    356     /** @name Children stuff.
    357       * @{ */
    358         /** Returns the root instance. */
    359         UIChooserItem *root() const;
    360 
    361         /** Starts editing group name. */
    362         void startEditingGroupItemName();
    363 
    364         /** Activates machine item. */
    365         void activateMachineItem();
    366 
    367         /** Defines current @a pDragObject. */
    368         void setCurrentDragObject(QDrag *pDragObject);
    369 
    370         /** Looks for item with certain @a strLookupSymbol. */
    371         void lookFor(const QString &strLookupSymbol);
    372         /** Returns whether looking is in progress. */
    373         bool isLookupInProgress() const;
    374     /** @} */
    375 
    376     /** @name Layout stuff.
    377       * @{ */
    378         /** Updates layout. */
    379         void updateLayout();
    380 
    381         /** Defines global item height @a iHint. */
    382         void setGlobalItemHeightHint(int iHint);
    383     /** @} */
    384 
    385 public slots:
    386 
    387     /** @name General stuff.
    388       * @{ */
    389         /** Handles Chooser-view resize. */
    390         void sltHandleViewResized();
    391     /** @} */
    392 
    393 protected:
    394 
    395     /** @name Event handling stuff.
    396       * @{ */
    397         /** Preprocesses Qt @a pEvent for passed @a pObject. */
    398         virtual bool eventFilter(QObject *pObject, QEvent *pEvent) /* override */;
    399     /** @} */
    400 
    401 protected slots:
    402 
    403     /** @name Main event handling stuff.
    404       * @{ */
    405         /** Handles machine registering/unregistering for machine with certain @a uId. */
    406         virtual void sltMachineRegistered(const QUuid &uId, const bool fRegistered) /* override */;
    407     /** @} */
    408 
    409     /** @name Children stuff.
    410       * @{ */
    411         /** Handles reload machine with certain @a uId request. */
    412         virtual void sltReloadMachine(const QUuid &uId) /* override */;
    413     /** @} */
    414 
    415 private slots:
    416 
    417     /** @name Selection stuff.
    418       * @{ */
    419         /** Handles focus item destruction. */
    420         void sltFocusItemDestroyed();
    421     /** @} */
    422 
    423     /** @name Children stuff.
    424       * @{ */
    425         /** Handles group rename request. */
    426         void sltEditGroupName();
    427         /** Handles group sort request. */
    428         void sltSortGroup();
    429         /** Handles machine search widget show/hide request. */
    430         void sltShowHideSearchWidget();
    431         /** Handles group destroy request. */
    432         void sltUngroupSelectedGroup();
    433 
    434         /** Handles create new machine request. */
    435         void sltCreateNewMachine();
    436         /** Handles group selected machines request. */
    437         void sltGroupSelectedMachines();
    438         /** Handles sort parent group request. */
    439         void sltSortParentGroup();
    440         /** Handles refresh request. */
    441         void sltPerformRefreshAction();
    442         /** Handles remove selected machine request. */
    443         void sltRemoveSelectedMachine();
    444 
    445         /** Handles D&D scrolling. */
    446         void sltStartScrolling();
    447         /** Handles D&D object destruction. */
    448         void sltCurrentDragObjectDestroyed();
    449 
    450         /** Handles request to erase lookup timer. */
    451         void sltEraseLookupTimer();
    452     /** @} */
    453 
    454 private:
    455 
    456     /** @name Prepare/Cleanup cascade.
    457       * @{ */
    458         /** Prepares all. */
    459         void prepare();
    460         /** Prepares scene. */
    461         void prepareScene();
    462         /** Prepares lookup. */
    463         void prepareLookup();
    464         /** Prepares context-menu. */
    465         void prepareContextMenu();
    466         /** Prepares handlers. */
    467         void prepareHandlers();
    468         /** Prepares connections. */
    469         void prepareConnections();
    470         /** Loads last selected items. */
    471         void loadLastSelectedItem();
    472 
    473         /** Saves last selected items. */
    474         void saveLastSelectedItem();
    475         /** Cleanups connections. */
    476         void cleanupHandlers();
    477         /** Cleanups context-menu. */
    478         void cleanupContextMenu();
    479         /** Cleanups lookup. */
    480         void cleanupLookup();
    481         /** Cleanups scene. */
    482         void cleanupScene();
    483         /** Cleanups all. */
    484         void cleanup();
    485     /** @} */
    486 
    487     /** @name General stuff.
    488       * @{ */
    489         /** Handles context-menu @a pEvent. */
    490         bool processContextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent);
    491         /** Popups context-menu of certain @a enmType in specified @a point. */
    492         void popupContextMenu(UIGraphicsSelectorContextMenuType enmType, QPoint point);
    493         /** Returns the reference of the first view of the scene(). */
    494         UIChooserView *view();
    495     /** @} */
    496 
    497     /** @name Selection stuff.
    498       * @{ */
    499         /** Clears real focus. */
    500         void clearRealFocus();
    501     /** @} */
    502 
    503     /** @name Navigation stuff.
    504       * @{ */
    505         /** Creates navigation list for passed root @a pItem. */
    506         QList<UIChooserItem*> createNavigationList(UIChooserItem *pItem);
    507     /** @} */
    508 
    509     /** @name Children stuff.
    510       * @{ */
    511         /** Build tree for main root. */
    512         void buildTreeForMainRoot();
    513 
    514         /** Removes machine @a items. */
    515         void removeItems(const QList<UIChooserItem*> &items);
    516         /** Unregisters virtual machines using list of @a ids. */
    517         void unregisterMachines(const QList<QUuid> &ids);
    518 
    519         /** Processes drag move @a pEvent. */
    520         bool processDragMoveEvent(QGraphicsSceneDragDropEvent *pEvent);
    521         /** Processes drag leave @a pEvent. */
    522         bool processDragLeaveEvent(QGraphicsSceneDragDropEvent *pEvent);
    523 
    524         /** Performs sorting for @a pNode. */
    525         void sortNodes(UIChooserNode *pNode);
    526     /** @} */
    527 
    528     /** @name General stuff.
    529       * @{ */
    530         /** Holds the Chooser reference. */
    531         UIChooser *m_pChooser;
    532 
    533         /** Holds the scene reference. */
    534         QGraphicsScene *m_pScene;
    535 
    536         /** Holds the mouse handler instance. */
    537         UIChooserHandlerMouse    *m_pMouseHandler;
    538         /** Holds the keyboard handler instance. */
    539         UIChooserHandlerKeyboard *m_pKeyboardHandler;
    540 
    541         /** Holds the global item context menu instance. */
    542         QMenu *m_pContextMenuGlobal;
    543         /** Holds the group item context menu instance. */
    544         QMenu *m_pContextMenuGroup;
    545         /** Holds the machine item context menu instance. */
    546         QMenu *m_pContextMenuMachine;
    547     /** @} */
    548 
    549     /** @name Selection stuff.
    550       * @{ */
    551         /** Holds the focus item reference. */
    552         QPointer<UIChooserItem>  m_pFocusItem;
    553     /** @} */
    554 
    555     /** @name Virtual Machine/Group search stuff.
    556       * @{ */
    557         /** Stores the results of the current search. */
    558         QList<UIChooserNode*> m_searchResults;
    559         /** Stores the index (within the m_searchResults) of the currently scrolled item. */
    560         int m_iCurrentScrolledIndex;
    561     /** @} */
    562 
    563     /** @name Children stuff.
    564       * @{ */
    565         /** Holds the root instance. */
    566         QPointer<UIChooserItem>  m_pRoot;
    567 
    568         /** Holds the navigation list. */
    569         QList<UIChooserItem*>  m_navigationList;
    570         QList<UIChooserItem*>  m_currentItems;
    571 
    572         /** Holds the current drag object instance. */
    573         QPointer<QDrag>  m_pCurrentDragObject;
    574         /** Holds the drag scrolling token size. */
    575         int              m_iScrollingTokenSize;
    576         /** Holds whether drag scrolling is in progress. */
    577         bool             m_fIsScrollingInProgress;
    578 
    579         /** Holds the item lookup timer instance. */
    580         QTimer  *m_pLookupTimer;
    581         /** Holds the item lookup string. */
    582         QString  m_strLookupString;
    583     /** @} */
    584 };
    585 
    586 
    587199/** QThread subclass allowing to save group definitions asynchronously. */
    588200class UIThreadGroupDefinitionSave : public QThread
     
    676288
    677289
    678 #endif /* !FEQT_INCLUDED_SRC_manager_chooser_UIChooserModel_h */
     290#endif /* !FEQT_INCLUDED_SRC_manager_chooser_UIChooserAbstractModel_h */
  • trunk/src/VBox/Frontends/VirtualBox/src/manager/chooser/UIChooserModel.cpp

    r77890 r77891  
    4444#include "UIModalWindowManager.h"
    4545#include "UIVirtualBoxManagerWidget.h"
    46 #include "UIVirtualBoxEventHandler.h"
    4746#include "UIWizardNewVM.h"
    4847
     
    5453typedef QSet<QString> UIStringSet;
    5554
    56 
    57 /*********************************************************************************************************************************
    58 *   Class UIChooserAbstractModel implementation.                                                                                 *
    59 *********************************************************************************************************************************/
    60 
    61 UIChooserAbstractModel:: UIChooserAbstractModel(UIChooser *pParent)
    62     : QObject(pParent)
    63     , m_pInvisibleRootNode(0)
    64 {
    65     prepare();
    66 }
    67 
    68 void UIChooserAbstractModel::init()
    69 {
    70     /* Load tree: */
    71     loadTree();
    72 }
    73 
    74 void UIChooserAbstractModel::deinit()
    75 {
    76     /* Currently we are not saving group descriptors
    77      * (which reflecting group toggle-state) on-the-fly,
    78      * so, for now we are additionally save group orders
    79      * when exiting application: */
    80     saveGroupOrders();
    81 
    82     /* Make sure all saving steps complete: */
    83     makeSureGroupDefinitionsSaveIsFinished();
    84     makeSureGroupOrdersSaveIsFinished();
    85 
    86     /* Delete tree: */
    87     delete m_pInvisibleRootNode;
    88     m_pInvisibleRootNode = 0;
    89 }
    90 
    91 UIChooserNode *UIChooserAbstractModel::invisibleRoot() const
    92 {
    93     return m_pInvisibleRootNode;
    94 }
    95 
    96 void UIChooserAbstractModel::wipeOutEmptyGroups()
    97 {
    98     wipeOutEmptyGroups(invisibleRoot());
    99 }
    100 
    101 /* static */
    102 QString UIChooserAbstractModel::uniqueGroupName(UIChooserNode *pRoot)
    103 {
    104     /* Enumerate all the group names: */
    105     QStringList groupNames;
    106     foreach (UIChooserNode *pNode, pRoot->nodes(UIChooserItemType_Group))
    107         groupNames << pNode->name();
    108 
    109     /* Prepare reg-exp: */
    110     const QString strMinimumName = tr("New group");
    111     const QString strShortTemplate = strMinimumName;
    112     const QString strFullTemplate = strShortTemplate + QString(" (\\d+)");
    113     const QRegExp shortRegExp(strShortTemplate);
    114     const QRegExp fullRegExp(strFullTemplate);
    115 
    116     /* Search for the maximum index: */
    117     int iMinimumPossibleNumber = 0;
    118     foreach (const QString &strName, groupNames)
    119     {
    120         if (shortRegExp.exactMatch(strName))
    121             iMinimumPossibleNumber = qMax(iMinimumPossibleNumber, 2);
    122         else if (fullRegExp.exactMatch(strName))
    123             iMinimumPossibleNumber = qMax(iMinimumPossibleNumber, fullRegExp.cap(1).toInt() + 1);
    124     }
    125 
    126     /* Prepare result: */
    127     QString strResult = strMinimumName;
    128     if (iMinimumPossibleNumber)
    129         strResult += " " + QString::number(iMinimumPossibleNumber);
    130     return strResult;
    131 }
    132 
    133 void UIChooserAbstractModel::saveGroupSettings()
    134 {
    135     emit sigGroupSavingStarted();
    136 }
    137 
    138 bool UIChooserAbstractModel::isGroupSavingInProgress() const
    139 {
    140     return    UIThreadGroupDefinitionSave::instance()
    141            || UIThreadGroupOrderSave::instance();
    142 }
    143 
    144 void UIChooserAbstractModel::sltMachineStateChanged(const QUuid &uId, const KMachineState)
    145 {
    146     /* Update machine-nodes with passed id: */
    147     invisibleRoot()->updateAllNodes(uId);
    148 }
    149 
    150 void UIChooserAbstractModel::sltMachineDataChanged(const QUuid &uId)
    151 {
    152     /* Update machine-nodes with passed id: */
    153     invisibleRoot()->updateAllNodes(uId);
    154 }
    155 
    156 void UIChooserAbstractModel::sltMachineRegistered(const QUuid &uId, const bool fRegistered)
    157 {
    158     /* Existing VM unregistered? */
    159     if (!fRegistered)
    160     {
    161         /* Remove machine-items with passed id: */
    162         invisibleRoot()->removeAllNodes(uId);
    163         /* Wipe out empty groups: */
    164         wipeOutEmptyGroups();
    165     }
    166     /* New VM registered? */
    167     else
    168     {
    169         /* Should we show this VM? */
    170         if (gEDataManager->showMachineInVirtualBoxManagerChooser(uId))
    171         {
    172             /* Add new machine-item: */
    173             CMachine comMachine = vboxGlobal().virtualBox().FindMachine(uId.toString());
    174             addMachineIntoTheTree(comMachine, true /* make it visible */);
    175         }
    176     }
    177 }
    178 
    179 void UIChooserAbstractModel::sltSessionStateChanged(const QUuid &uId, const KSessionState)
    180 {
    181     /* Update machine-nodes with passed id: */
    182     invisibleRoot()->updateAllNodes(uId);
    183 }
    184 
    185 void UIChooserAbstractModel::sltSnapshotChanged(const QUuid &uId, const QUuid &)
    186 {
    187     /* Update machine-nodes with passed id: */
    188     invisibleRoot()->updateAllNodes(uId);
    189 }
    190 
    191 void UIChooserAbstractModel::sltReloadMachine(const QUuid &uId)
    192 {
    193     /* Remove machine-items with passed id: */
    194     invisibleRoot()->removeAllNodes(uId);
    195     /* Wipe out empty groups: */
    196     wipeOutEmptyGroups();
    197 
    198     /* Should we show this VM? */
    199     if (gEDataManager->showMachineInVirtualBoxManagerChooser(uId))
    200     {
    201         /* Add new machine-item: */
    202         CMachine comMachine = vboxGlobal().virtualBox().FindMachine(uId.toString());
    203         addMachineIntoTheTree(comMachine, true /* make it visible */);
    204     }
    205 }
    206 
    207 void UIChooserAbstractModel::sltGroupSavingStart()
    208 {
    209     saveGroupDefinitions();
    210     saveGroupOrders();
    211 }
    212 
    213 void UIChooserAbstractModel::sltGroupDefinitionsSaveComplete()
    214 {
    215     makeSureGroupDefinitionsSaveIsFinished();
    216     emit sigGroupSavingStateChanged();
    217 }
    218 
    219 void UIChooserAbstractModel::sltGroupOrdersSaveComplete()
    220 {
    221     makeSureGroupOrdersSaveIsFinished();
    222     emit sigGroupSavingStateChanged();
    223 }
    224 
    225 void UIChooserAbstractModel::prepare()
    226 {
    227     prepareConnections();
    228 }
    229 
    230 void UIChooserAbstractModel::prepareConnections()
    231 {
    232     /* Setup parent connections: */
    233     connect(this, SIGNAL(sigGroupSavingStateChanged()),
    234             parent(), SIGNAL(sigGroupSavingStateChanged()));
    235 
    236     /* Setup global connections: */
    237     connect(gVBoxEvents, SIGNAL(sigMachineStateChange(QUuid, KMachineState)),
    238             this, SLOT(sltMachineStateChanged(QUuid, KMachineState)));
    239     connect(gVBoxEvents, SIGNAL(sigMachineDataChange(QUuid)),
    240             this, SLOT(sltMachineDataChanged(QUuid)));
    241     connect(gVBoxEvents, SIGNAL(sigMachineRegistered(QUuid, bool)),
    242             this, SLOT(sltMachineRegistered(QUuid, bool)));
    243     connect(gVBoxEvents, SIGNAL(sigSessionStateChange(QUuid, KSessionState)),
    244             this, SLOT(sltSessionStateChanged(QUuid, KSessionState)));
    245     connect(gVBoxEvents, SIGNAL(sigSnapshotTake(QUuid, QUuid)),
    246             this, SLOT(sltSnapshotChanged(QUuid, QUuid)));
    247     connect(gVBoxEvents, SIGNAL(sigSnapshotDelete(QUuid, QUuid)),
    248             this, SLOT(sltSnapshotChanged(QUuid, QUuid)));
    249     connect(gVBoxEvents, SIGNAL(sigSnapshotChange(QUuid, QUuid)),
    250             this, SLOT(sltSnapshotChanged(QUuid, QUuid)));
    251     connect(gVBoxEvents, SIGNAL(sigSnapshotRestore(QUuid, QUuid)),
    252             this, SLOT(sltSnapshotChanged(QUuid, QUuid)));
    253 
    254     /* Setup group saving connections: */
    255     connect(this, &UIChooserAbstractModel::sigGroupSavingStarted,
    256             this, &UIChooserAbstractModel::sltGroupSavingStart,
    257             Qt::QueuedConnection);
    258 }
    259 
    260 void UIChooserAbstractModel::loadTree()
    261 {
    262     /* Create invisible root group node: */
    263     m_pInvisibleRootNode = new UIChooserNodeGroup(0 /* parent */,
    264                                                   false /* favorite */,
    265                                                   0 /* position */,
    266                                                   QString() /* name */,
    267                                                   true /* opened */);
    268     if (invisibleRoot())
    269     {
    270         /* Create global node: */
    271         new UIChooserNodeGlobal(m_pInvisibleRootNode,
    272                                 isGlobalNodeFavorite(m_pInvisibleRootNode),
    273                                 0 /* position */,
    274                                 QString() /* tip */);
    275 
    276         /* Add all the approved machine nodes into the tree: */
    277         LogRelFlow(("UIChooserModel: Loading VMs...\n"));
    278         foreach (const CMachine &comMachine, vboxGlobal().virtualBox().GetMachines())
    279         {
    280             const QUuid uMachineID = comMachine.GetId();
    281             if (!uMachineID.isNull() && gEDataManager->showMachineInVirtualBoxManagerChooser(uMachineID))
    282                 addMachineIntoTheTree(comMachine);
    283         }
    284         LogRelFlow(("UIChooserModel: VMs loaded.\n"));
    285     }
    286 }
    287 
    288 void UIChooserAbstractModel::addMachineIntoTheTree(const CMachine &comMachine, bool fMakeItVisible /* = false */)
    289 {
    290     /* Make sure passed VM is not NULL: */
    291     if (comMachine.isNull())
    292         LogRelFlow(("UIChooserModel: ERROR: Passed VM is NULL!\n"));
    293     AssertReturnVoid(!comMachine.isNull());
    294 
    295     /* Which VM we are loading: */
    296     LogRelFlow(("UIChooserModel: Loading VM with ID={%s}...\n", toOldStyleUuid(comMachine.GetId()).toUtf8().constData()));
    297     /* Is that machine accessible? */
    298     if (comMachine.GetAccessible())
    299     {
    300         /* VM is accessible: */
    301         const QString strName = comMachine.GetName();
    302         LogRelFlow(("UIChooserModel:  VM {%s} is accessible.\n", strName.toUtf8().constData()));
    303         /* Which groups passed machine attached to? */
    304         const QVector<QString> groups = comMachine.GetGroups();
    305         const QStringList groupList = groups.toList();
    306         const QString strGroups = groupList.join(", ");
    307         LogRelFlow(("UIChooserModel:  VM {%s} has groups: {%s}.\n", strName.toUtf8().constData(),
    308                                                                     strGroups.toUtf8().constData()));
    309         foreach (QString strGroup, groups)
    310         {
    311             /* Remove last '/' if any: */
    312             if (strGroup.right(1) == "/")
    313                 strGroup.truncate(strGroup.size() - 1);
    314             /* Create machine-item with found group-item as parent: */
    315             LogRelFlow(("UIChooserModel:   Creating item for VM {%s} in group {%s}.\n", strName.toUtf8().constData(),
    316                                                                                         strGroup.toUtf8().constData()));
    317             createMachineNode(getGroupNode(strGroup, invisibleRoot(), fMakeItVisible), comMachine);
    318         }
    319         /* Update group definitions: */
    320         m_groups[toOldStyleUuid(comMachine.GetId())] = groupList;
    321     }
    322     /* Inaccessible machine: */
    323     else
    324     {
    325         /* VM is accessible: */
    326         LogRelFlow(("UIChooserModel:  VM {%s} is inaccessible.\n", toOldStyleUuid(comMachine.GetId()).toUtf8().constData()));
    327         /* Create machine-item with main-root group-item as parent: */
    328         createMachineNode(invisibleRoot(), comMachine);
    329     }
    330 }
    331 
    332 UIChooserNode *UIChooserAbstractModel::getGroupNode(const QString &strName, UIChooserNode *pParentNode, bool fAllGroupsOpened)
    333 {
    334     /* Check passed stuff: */
    335     if (pParentNode->name() == strName)
    336         return pParentNode;
    337 
    338     /* Prepare variables: */
    339     const QString strFirstSubName = strName.section('/', 0, 0);
    340     const QString strFirstSuffix = strName.section('/', 1, -1);
    341     const QString strSecondSubName = strFirstSuffix.section('/', 0, 0);
    342     const QString strSecondSuffix = strFirstSuffix.section('/', 1, -1);
    343 
    344     /* Passed group name equal to first sub-name: */
    345     if (pParentNode->name() == strFirstSubName)
    346     {
    347         /* Make sure first-suffix is NOT empty: */
    348         AssertMsg(!strFirstSuffix.isEmpty(), ("Invalid group name!"));
    349         /* Trying to get group node among our children: */
    350         foreach (UIChooserNode *pGroupNode, pParentNode->nodes(UIChooserItemType_Group))
    351         {
    352             if (pGroupNode->name() == strSecondSubName)
    353             {
    354                 UIChooserNode *pFoundNode = getGroupNode(strFirstSuffix, pGroupNode, fAllGroupsOpened);
    355                 if (UIChooserNodeGroup *pFoundGroupNode = pFoundNode->toGroupNode())
    356                     if (fAllGroupsOpened && pFoundGroupNode->isClosed())
    357                         pFoundGroupNode->open();
    358                 return pFoundNode;
    359             }
    360         }
    361     }
    362 
    363     /* Found nothing? Creating: */
    364     UIChooserNodeGroup *pNewGroupNode =
    365         new UIChooserNodeGroup(pParentNode,
    366                                false /* favorite */,
    367                                getDesiredPosition(pParentNode, UIChooserItemType_Group, strSecondSubName),
    368                                strSecondSubName,
    369                                fAllGroupsOpened || shouldBeGroupOpened(pParentNode, strSecondSubName));
    370     return strSecondSuffix.isEmpty() ? pNewGroupNode : getGroupNode(strFirstSuffix, pNewGroupNode, fAllGroupsOpened);
    371 }
    372 
    373 bool UIChooserAbstractModel::shouldBeGroupOpened(UIChooserNode *pParentNode, const QString &strName)
    374 {
    375     /* Read group definitions: */
    376     const QStringList definitions = gEDataManager->selectorWindowGroupsDefinitions(pParentNode->fullName());
    377     /* Return 'false' if no definitions found: */
    378     if (definitions.isEmpty())
    379         return false;
    380 
    381     /* Prepare required group definition reg-exp: */
    382     const QString strDefinitionTemplate = QString("g(\\S)*=%1").arg(strName);
    383     const QRegExp definitionRegExp(strDefinitionTemplate);
    384     /* For each the group definition: */
    385     foreach (const QString &strDefinition, definitions)
    386     {
    387         /* Check if this is required definition: */
    388         if (definitionRegExp.indexIn(strDefinition) == 0)
    389         {
    390             /* Get group descriptor: */
    391             const QString strDescriptor(definitionRegExp.cap(1));
    392             if (strDescriptor.contains('o'))
    393                 return true;
    394         }
    395     }
    396 
    397     /* Return 'false' by default: */
    398     return false;
    399 }
    400 
    401 void UIChooserAbstractModel::wipeOutEmptyGroups(UIChooserNode *pParent)
    402 {
    403     /* Cleanup all the group-items recursively first: */
    404     foreach (UIChooserNode *pNode, pParent->nodes(UIChooserItemType_Group))
    405         wipeOutEmptyGroups(pNode);
    406     /* If parent has no nodes: */
    407     if (!pParent->hasNodes())
    408     {
    409         /* If that is non-root item: */
    410         if (!pParent->isRoot())
    411         {
    412             /* Delete parent node and item: */
    413             delete pParent;
    414         }
    415     }
    416 }
    417 
    418 bool UIChooserAbstractModel::isGlobalNodeFavorite(UIChooserNode *pParentNode) const
    419 {
    420     /* Read group definitions: */
    421     const QStringList definitions = gEDataManager->selectorWindowGroupsDefinitions(pParentNode->fullName());
    422     /* Return 'false' if no definitions found: */
    423     if (definitions.isEmpty())
    424         return false;
    425 
    426     /* Prepare required group definition reg-exp: */
    427     const QString strDefinitionTemplate = QString("n(\\S)*=GLOBAL");
    428     const QRegExp definitionRegExp = QRegExp(strDefinitionTemplate);
    429     /* For each the group definition: */
    430     foreach (const QString &strDefinition, definitions)
    431     {
    432         /* Check if this is required definition: */
    433         if (definitionRegExp.indexIn(strDefinition) == 0)
    434         {
    435             /* Get group descriptor: */
    436             const QString strDescriptor(definitionRegExp.cap(1));
    437             if (strDescriptor.contains('f'))
    438                 return true;
    439         }
    440     }
    441 
    442     /* Return 'false' by default: */
    443     return false;
    444 }
    445 
    446 int UIChooserAbstractModel::getDesiredPosition(UIChooserNode *pParentNode, UIChooserItemType enmType, const QString &strName)
    447 {
    448     /* End of list (by default)? */
    449     int iNewNodeDesiredPosition = -1;
    450     /* Which position should be new node placed by definitions: */
    451     int iNewNodeDefinitionPosition = positionFromDefinitions(pParentNode, enmType, strName);
    452     /* If some position wanted: */
    453     if (iNewNodeDefinitionPosition != -1)
    454     {
    455         /* Start of list if some definition present: */
    456         iNewNodeDesiredPosition = 0;
    457         /* We have to check all the existing node positions: */
    458         QList<UIChooserNode*> nodes = pParentNode->nodes(enmType);
    459         for (int i = nodes.size() - 1; i >= 0; --i)
    460         {
    461             /* Get current node: */
    462             UIChooserNode *pNode = nodes[i];
    463             /* Which position should be current node placed by definitions? */
    464             QString strDefinitionName = pNode->type() == UIChooserItemType_Group ? pNode->name() :
    465                                         pNode->type() == UIChooserItemType_Machine ? toOldStyleUuid(pNode->toMachineNode()->id()) :
    466                                         QString();
    467             AssertMsg(!strDefinitionName.isEmpty(), ("Wrong definition name!"));
    468             int iNodeDefinitionPosition = positionFromDefinitions(pParentNode, enmType, strDefinitionName);
    469             /* If some position wanted: */
    470             if (iNodeDefinitionPosition != -1)
    471             {
    472                 AssertMsg(iNodeDefinitionPosition != iNewNodeDefinitionPosition, ("Incorrect definitions!"));
    473                 if (iNodeDefinitionPosition < iNewNodeDefinitionPosition)
    474                 {
    475                     iNewNodeDesiredPosition = i + 1;
    476                     break;
    477                 }
    478             }
    479         }
    480     }
    481     /* Return desired node position: */
    482     return iNewNodeDesiredPosition;
    483 }
    484 
    485 int UIChooserAbstractModel::positionFromDefinitions(UIChooserNode *pParentNode, UIChooserItemType enmType, const QString &strName)
    486 {
    487     /* Read group definitions: */
    488     const QStringList definitions = gEDataManager->selectorWindowGroupsDefinitions(pParentNode->fullName());
    489     /* Return 'false' if no definitions found: */
    490     if (definitions.isEmpty())
    491         return -1;
    492 
    493     /* Prepare definition reg-exp: */
    494     QString strDefinitionTemplateShort;
    495     QString strDefinitionTemplateFull;
    496     switch (enmType)
    497     {
    498         case UIChooserItemType_Group:
    499             strDefinitionTemplateShort = QString("^g(\\S)*=");
    500             strDefinitionTemplateFull = QString("^g(\\S)*=%1$").arg(strName);
    501             break;
    502         case UIChooserItemType_Machine:
    503             strDefinitionTemplateShort = QString("^m=");
    504             strDefinitionTemplateFull = QString("^m=%1$").arg(strName);
    505             break;
    506         default: return -1;
    507     }
    508     QRegExp definitionRegExpShort(strDefinitionTemplateShort);
    509     QRegExp definitionRegExpFull(strDefinitionTemplateFull);
    510 
    511     /* For each the definition: */
    512     int iDefinitionIndex = -1;
    513     foreach (const QString &strDefinition, definitions)
    514     {
    515         /* Check if this definition is of required type: */
    516         if (definitionRegExpShort.indexIn(strDefinition) == 0)
    517         {
    518             ++iDefinitionIndex;
    519             /* Check if this definition is exactly what we need: */
    520             if (definitionRegExpFull.indexIn(strDefinition) == 0)
    521                 return iDefinitionIndex;
    522         }
    523     }
    524 
    525     /* Return result: */
    526     return -1;
    527 }
    528 
    529 void UIChooserAbstractModel::createMachineNode(UIChooserNode *pParentNode, const CMachine &comMachine)
    530 {
    531     /* Create machine node: */
    532     new UIChooserNodeMachine(pParentNode,
    533                              false /* favorite */,
    534                              getDesiredPosition(pParentNode, UIChooserItemType_Machine, toOldStyleUuid(comMachine.GetId())),
    535                              comMachine);
    536 }
    537 
    538 void UIChooserAbstractModel::saveGroupDefinitions()
    539 {
    540     /* Make sure there is no group save activity: */
    541     if (UIThreadGroupDefinitionSave::instance())
    542         return;
    543 
    544     /* Prepare full group map: */
    545     QMap<QString, QStringList> groups;
    546     gatherGroupDefinitions(groups, invisibleRoot());
    547 
    548     /* Save information in other thread: */
    549     UIThreadGroupDefinitionSave::prepare();
    550     emit sigGroupSavingStateChanged();
    551     connect(UIThreadGroupDefinitionSave::instance(), SIGNAL(sigReload(QUuid)),
    552             this, SLOT(sltReloadMachine(QUuid)));
    553     UIThreadGroupDefinitionSave::instance()->configure(this, m_groups, groups);
    554     UIThreadGroupDefinitionSave::instance()->start();
    555     m_groups = groups;
    556 }
    557 
    558 void UIChooserAbstractModel::saveGroupOrders()
    559 {
    560     /* Make sure there is no group save activity: */
    561     if (UIThreadGroupOrderSave::instance())
    562         return;
    563 
    564     /* Prepare full group map: */
    565     QMap<QString, QStringList> groups;
    566     gatherGroupOrders(groups, invisibleRoot());
    567 
    568     /* Save information in other thread: */
    569     UIThreadGroupOrderSave::prepare();
    570     emit sigGroupSavingStateChanged();
    571     UIThreadGroupOrderSave::instance()->configure(this, groups);
    572     UIThreadGroupOrderSave::instance()->start();
    573 }
    574 
    575 void UIChooserAbstractModel::gatherGroupDefinitions(QMap<QString, QStringList> &definitions,
    576                                                     UIChooserNode *pParentGroup)
    577 {
    578     /* Iterate over all the machine-nodes: */
    579     foreach (UIChooserNode *pNode, pParentGroup->nodes(UIChooserItemType_Machine))
    580         if (UIChooserNodeMachine *pMachineNode = pNode->toMachineNode())
    581             if (pMachineNode->accessible())
    582                 definitions[toOldStyleUuid(pMachineNode->id())] << pParentGroup->fullName();
    583     /* Iterate over all the group-nodes: */
    584     foreach (UIChooserNode *pNode, pParentGroup->nodes(UIChooserItemType_Group))
    585         gatherGroupDefinitions(definitions, pNode);
    586 }
    587 
    588 void UIChooserAbstractModel::gatherGroupOrders(QMap<QString, QStringList> &orders,
    589                                                UIChooserNode *pParentItem)
    590 {
    591     /* Prepare extra-data key for current group: */
    592     const QString strExtraDataKey = pParentItem->fullName();
    593     /* Iterate over all the global-nodes: */
    594     foreach (UIChooserNode *pNode, pParentItem->nodes(UIChooserItemType_Global))
    595     {
    596         const QString strGlobalDescriptor(pNode->isFavorite() ? "nf" : "n");
    597         orders[strExtraDataKey] << QString("%1=GLOBAL").arg(strGlobalDescriptor);
    598     }
    599     /* Iterate over all the group-nodes: */
    600     foreach (UIChooserNode *pNode, pParentItem->nodes(UIChooserItemType_Group))
    601     {
    602         const QString strGroupDescriptor(pNode->toGroupNode()->isOpened() ? "go" : "gc");
    603         orders[strExtraDataKey] << QString("%1=%2").arg(strGroupDescriptor, pNode->name());
    604         gatherGroupOrders(orders, pNode);
    605     }
    606     /* Iterate over all the machine-nodes: */
    607     foreach (UIChooserNode *pNode, pParentItem->nodes(UIChooserItemType_Machine))
    608         orders[strExtraDataKey] << QString("m=%1").arg(toOldStyleUuid(pNode->toMachineNode()->id()));
    609 }
    610 
    611 void UIChooserAbstractModel::makeSureGroupDefinitionsSaveIsFinished()
    612 {
    613     /* Cleanup if necessary: */
    614     if (UIThreadGroupDefinitionSave::instance())
    615         UIThreadGroupDefinitionSave::cleanup();
    616 }
    617 
    618 void UIChooserAbstractModel::makeSureGroupOrdersSaveIsFinished()
    619 {
    620     /* Cleanup if necessary: */
    621     if (UIThreadGroupOrderSave::instance())
    622         UIThreadGroupOrderSave::cleanup();
    623 }
    624 
    625 /* static */
    626 QString UIChooserAbstractModel::toOldStyleUuid(const QUuid &uId)
    627 {
    628     return uId.toString().remove(QRegExp("[{}]"));
    629 }
    630 
    631 
    632 /*********************************************************************************************************************************
    633 *   Class UIChooserModel implementation.                                                                                         *
    634 *********************************************************************************************************************************/
    63555
    63656UIChooserModel:: UIChooserModel(UIChooser *pParent)
     
    22391659    updateLayout();
    22401660}
    2241 
    2242 
    2243 /*********************************************************************************************************************************
    2244 *   Class UIThreadGroupDefinitionSave implementation.                                                                            *
    2245 *********************************************************************************************************************************/
    2246 
    2247 /* static */
    2248 UIThreadGroupDefinitionSave *UIThreadGroupDefinitionSave::s_pInstance = 0;
    2249 
    2250 /* static */
    2251 UIThreadGroupDefinitionSave *UIThreadGroupDefinitionSave::instance()
    2252 {
    2253     return s_pInstance;
    2254 }
    2255 
    2256 /* static */
    2257 void UIThreadGroupDefinitionSave::prepare()
    2258 {
    2259     /* Make sure instance not prepared: */
    2260     if (s_pInstance)
    2261         return;
    2262 
    2263     /* Crate instance: */
    2264     new UIThreadGroupDefinitionSave;
    2265 }
    2266 
    2267 /* static */
    2268 void UIThreadGroupDefinitionSave::cleanup()
    2269 {
    2270     /* Make sure instance prepared: */
    2271     if (!s_pInstance)
    2272         return;
    2273 
    2274     /* Crate instance: */
    2275     delete s_pInstance;
    2276 }
    2277 
    2278 void UIThreadGroupDefinitionSave::configure(QObject *pParent,
    2279                                             const QMap<QString, QStringList> &oldLists,
    2280                                             const QMap<QString, QStringList> &newLists)
    2281 {
    2282     m_oldLists = oldLists;
    2283     m_newLists = newLists;
    2284     connect(this, SIGNAL(sigComplete()), pParent, SLOT(sltGroupDefinitionsSaveComplete()));
    2285 }
    2286 
    2287 UIThreadGroupDefinitionSave::UIThreadGroupDefinitionSave()
    2288 {
    2289     /* Assign instance: */
    2290     s_pInstance = this;
    2291 }
    2292 
    2293 UIThreadGroupDefinitionSave::~UIThreadGroupDefinitionSave()
    2294 {
    2295     /* Wait: */
    2296     wait();
    2297 
    2298     /* Erase instance: */
    2299     s_pInstance = 0;
    2300 }
    2301 
    2302 void UIThreadGroupDefinitionSave::run()
    2303 {
    2304     /* COM prepare: */
    2305     COMBase::InitializeCOM(false);
    2306 
    2307     /* For every particular machine ID: */
    2308     foreach (const QString &strId, m_newLists.keys())
    2309     {
    2310         /* Get new group list/set: */
    2311         const QStringList &newGroupList = m_newLists.value(strId);
    2312         const UIStringSet &newGroupSet = UIStringSet::fromList(newGroupList);
    2313         /* Get old group list/set: */
    2314         const QStringList &oldGroupList = m_oldLists.value(strId);
    2315         const UIStringSet &oldGroupSet = UIStringSet::fromList(oldGroupList);
    2316         /* Make sure group set changed: */
    2317         if (newGroupSet == oldGroupSet)
    2318             continue;
    2319 
    2320         /* The next steps are subsequent.
    2321          * Every of them is mandatory in order to continue
    2322          * with common cleanup in case of failure.
    2323          * We have to simulate a try-catch block. */
    2324         CSession session;
    2325         CMachine machine;
    2326         do
    2327         {
    2328             /* 1. Open session: */
    2329             session = vboxGlobal().openSession(QUuid(strId));
    2330             if (session.isNull())
    2331                 break;
    2332 
    2333             /* 2. Get session machine: */
    2334             machine = session.GetMachine();
    2335             if (machine.isNull())
    2336                 break;
    2337 
    2338             /* 3. Set new groups: */
    2339             machine.SetGroups(newGroupList.toVector());
    2340             if (!machine.isOk())
    2341             {
    2342                 msgCenter().cannotSetGroups(machine);
    2343                 break;
    2344             }
    2345 
    2346             /* 4. Save settings: */
    2347             machine.SaveSettings();
    2348             if (!machine.isOk())
    2349             {
    2350                 msgCenter().cannotSaveMachineSettings(machine);
    2351                 break;
    2352             }
    2353         } while (0);
    2354 
    2355         /* Cleanup if necessary: */
    2356         if (machine.isNull() || !machine.isOk())
    2357             emit sigReload(QUuid(strId));
    2358         if (!session.isNull())
    2359             session.UnlockMachine();
    2360     }
    2361 
    2362     /* Notify listeners about completeness: */
    2363     emit sigComplete();
    2364 
    2365     /* COM cleanup: */
    2366     COMBase::CleanupCOM();
    2367 }
    2368 
    2369 
    2370 /*********************************************************************************************************************************
    2371 *   Class UIThreadGroupOrderSave implementation.                                                                                 *
    2372 *********************************************************************************************************************************/
    2373 
    2374 /* static */
    2375 UIThreadGroupOrderSave *UIThreadGroupOrderSave::s_pInstance = 0;
    2376 
    2377 /* static */
    2378 UIThreadGroupOrderSave *UIThreadGroupOrderSave::instance()
    2379 {
    2380     return s_pInstance;
    2381 }
    2382 
    2383 /* static */
    2384 void UIThreadGroupOrderSave::prepare()
    2385 {
    2386     /* Make sure instance not prepared: */
    2387     if (s_pInstance)
    2388         return;
    2389 
    2390     /* Crate instance: */
    2391     new UIThreadGroupOrderSave;
    2392 }
    2393 
    2394 /* static */
    2395 void UIThreadGroupOrderSave::cleanup()
    2396 {
    2397     /* Make sure instance prepared: */
    2398     if (!s_pInstance)
    2399         return;
    2400 
    2401     /* Crate instance: */
    2402     delete s_pInstance;
    2403 }
    2404 
    2405 void UIThreadGroupOrderSave::configure(QObject *pParent,
    2406                                        const QMap<QString, QStringList> &groups)
    2407 {
    2408     m_groups = groups;
    2409     connect(this, SIGNAL(sigComplete()), pParent, SLOT(sltGroupOrdersSaveComplete()));
    2410 }
    2411 
    2412 UIThreadGroupOrderSave::UIThreadGroupOrderSave()
    2413 {
    2414     /* Assign instance: */
    2415     s_pInstance = this;
    2416 }
    2417 
    2418 UIThreadGroupOrderSave::~UIThreadGroupOrderSave()
    2419 {
    2420     /* Wait: */
    2421     wait();
    2422 
    2423     /* Erase instance: */
    2424     s_pInstance = 0;
    2425 }
    2426 
    2427 void UIThreadGroupOrderSave::run()
    2428 {
    2429     /* COM prepare: */
    2430     COMBase::InitializeCOM(false);
    2431 
    2432     /* Clear all the extra-data records related to group definitions: */
    2433     gEDataManager->clearSelectorWindowGroupsDefinitions();
    2434     /* For every particular group definition: */
    2435     foreach (const QString &strId, m_groups.keys())
    2436         gEDataManager->setSelectorWindowGroupsDefinitions(strId, m_groups[strId]);
    2437 
    2438     /* Notify listeners about completeness: */
    2439     emit sigComplete();
    2440 
    2441     /* COM cleanup: */
    2442     COMBase::CleanupCOM();
    2443 }
  • trunk/src/VBox/Frontends/VirtualBox/src/manager/chooser/UIChooserModel.h

    r77890 r77891  
    2424/* Qt includes: */
    2525#include <QPointer>
    26 #include <QThread>
    27 #include <QUuid>
    2826
    2927/* GUI includes: */
    30 #include "UIChooserDefs.h"
     28#include "UIChooserAbstractModel.h"
    3129#include "UIExtraDataDefs.h"
    32 
    33 /* COM includes: */
    34 #include "COMEnums.h"
    3530
    3631/* Forward declaration: */
     
    4439class UIChooserView;
    4540class UIVirtualMachineItem;
    46 class CMachine;
    4741
    4842
     
    5347    UIGraphicsSelectorContextMenuType_Group,
    5448    UIGraphicsSelectorContextMenuType_Machine
    55 };
    56 
    57 
    58 /** QObject extension used as VM Chooser-pane abstract model.
    59   * This class is used to load/save a tree of abstract invisible
    60   * nodes representing VMs and their groups from/to extra-data. */
    61 class UIChooserAbstractModel : public QObject
    62 {
    63     Q_OBJECT;
    64 
    65 signals:
    66 
    67     /** @name Group saving stuff.
    68       * @{ */
    69         /** Notifies about group saving started. */
    70         void sigGroupSavingStarted();
    71         /** Notifies about group saving state changed. */
    72         void sigGroupSavingStateChanged();
    73     /** @} */
    74 
    75 public:
    76 
    77     /** Constructs abstract Chooser-model passing @a pParent to the base-class. */
    78     UIChooserAbstractModel(UIChooser *pParent);
    79 
    80     /** @name General stuff.
    81       * @{ */
    82         /** Inits model. */
    83         void init();
    84         /** Deinits model. */
    85         void deinit();
    86     /** @} */
    87 
    88     /** @name Children stuff.
    89       * @{ */
    90         /** Returns invisible root node instance. */
    91         UIChooserNode *invisibleRoot() const;
    92 
    93         /** Wipes out empty groups. */
    94         void wipeOutEmptyGroups();
    95 
    96         /** Generates unique group name traversing recursively starting from @a pRoot. */
    97         static QString uniqueGroupName(UIChooserNode *pRoot);
    98     /** @} */
    99 
    100     /** @name Group saving stuff.
    101       * @{ */
    102         /** Commands to save group settings. */
    103         void saveGroupSettings();
    104         /** Returns whether group saving is in progress. */
    105         bool isGroupSavingInProgress() const;
    106     /** @} */
    107 
    108 protected slots:
    109 
    110     /** @name Main event handling stuff.
    111       * @{ */
    112         /** Handles machine @a enmState change for machine with certain @a uId. */
    113         virtual void sltMachineStateChanged(const QUuid &uId, const KMachineState enmState);
    114         /** Handles machine data change for machine with certain @a uId. */
    115         virtual void sltMachineDataChanged(const QUuid &uId);
    116         /** Handles machine registering/unregistering for machine with certain @a uId. */
    117         virtual void sltMachineRegistered(const QUuid &uId, const bool fRegistered);
    118         /** Handles session @a enmState change for machine with certain @a uId. */
    119         virtual void sltSessionStateChanged(const QUuid &uId, const KSessionState enmState);
    120         /** Handles snapshot change for machine/snapshot with certain @a uId / @a uSnapshotId. */
    121         virtual void sltSnapshotChanged(const QUuid &uId, const QUuid &uSnapshotId);
    122     /** @} */
    123 
    124     /** @name Children stuff.
    125       * @{ */
    126         /** Handles reload machine with certain @a uId request. */
    127         virtual void sltReloadMachine(const QUuid &uId);
    128     /** @} */
    129 
    130 private slots:
    131 
    132     /** @name Group saving stuff.
    133       * @{ */
    134         /** Handles request to start group saving. */
    135         void sltGroupSavingStart();
    136         /** Handles group definition saving complete. */
    137         void sltGroupDefinitionsSaveComplete();
    138         /** Handles group order saving complete. */
    139         void sltGroupOrdersSaveComplete();
    140     /** @} */
    141 
    142 private:
    143 
    144     /** @name Prepare/Cleanup cascade.
    145       * @{ */
    146         /** Prepares all. */
    147         void prepare();
    148         /** Prepares connections. */
    149         void prepareConnections();
    150     /** @} */
    151 
    152     /** @name Children stuff.
    153       * @{ */
    154         /** Loads tree. */
    155         void loadTree();
    156         /** Adds machine item based on certain @a comMachine and optionally @a fMakeItVisible. */
    157         void addMachineIntoTheTree(const CMachine &comMachine, bool fMakeItVisible = false);
    158         /** Acquires group node, creates one if necessary.
    159           * @param  strName           Brings the name of group we looking for.
    160           * @param  pParentNode       Brings the parent we starting to look for a group from.
    161           * @param  fAllGroupsOpened  Brings whether we should open all the groups till the required one. */
    162         UIChooserNode *getGroupNode(const QString &strName, UIChooserNode *pParentNode, bool fAllGroupsOpened);
    163         /** Returns whether group with certain @a strName should be opened, searching starting from the passed @a pParentItem. */
    164         bool shouldBeGroupOpened(UIChooserNode *pParentNode, const QString &strName);
    165 
    166         /** Wipes out empty groups starting from @a pParentItem. */
    167         void wipeOutEmptyGroups(UIChooserNode *pParentNode);
    168 
    169         /** Returns whether global node within the @a pParentNode is favorite. */
    170         bool isGlobalNodeFavorite(UIChooserNode *pParentNode) const;
    171 
    172         /** Acquires desired position for a child of @a pParentNode with specified @a enmType and @a strName. */
    173         int getDesiredPosition(UIChooserNode *pParentNode, UIChooserItemType enmType, const QString &strName);
    174         /** Acquires saved position for a child of @a pParentNode with specified @a enmType and @a strName. */
    175         int positionFromDefinitions(UIChooserNode *pParentNode, UIChooserItemType enmType, const QString &strName);
    176 
    177         /** Creates machine node based on certain @a comMachine as a child of specified @a pParentNode. */
    178         void createMachineNode(UIChooserNode *pParentNode, const CMachine &comMachine);
    179     /** @} */
    180 
    181     /** @name Group saving stuff.
    182       * @{ */
    183         /** Saves group definitions. */
    184         void saveGroupDefinitions();
    185         /** Saves group orders. */
    186         void saveGroupOrders();
    187 
    188         /** Gathers group @a definitions of @a pParentGroup. */
    189         void gatherGroupDefinitions(QMap<QString, QStringList> &definitions, UIChooserNode *pParentGroup);
    190         /** Gathers group @a orders of @a pParentGroup. */
    191         void gatherGroupOrders(QMap<QString, QStringList> &orders, UIChooserNode *pParentItem);
    192 
    193         /** Makes sure group definitions saving is finished. */
    194         void makeSureGroupDefinitionsSaveIsFinished();
    195         /** Makes sure group orders saving is finished. */
    196         void makeSureGroupOrdersSaveIsFinished();
    197 
    198         /** Returns QString representation for passed @a uId, wiping out {} symbols.
    199           * @note  Required for backward compatibility after QString=>QUuid change. */
    200         static QString toOldStyleUuid(const QUuid &uId);
    201     /** @} */
    202 
    203     /** @name Children stuff.
    204       * @{ */
    205         /** Holds the invisible root node instance. */
    206         UIChooserNode *m_pInvisibleRootNode;
    207     /** @} */
    208 
    209     /** @name Group saving stuff.
    210       * @{ */
    211         /** Holds the consolidated map of group definitions/orders. */
    212         QMap<QString, QStringList>  m_groups;
    213     /** @} */
    21449};
    21550
     
    585420
    586421
    587 /** QThread subclass allowing to save group definitions asynchronously. */
    588 class UIThreadGroupDefinitionSave : public QThread
    589 {
    590     Q_OBJECT;
    591 
    592 signals:
    593 
    594     /** Notifies about machine with certain @a uId to be reloaded. */
    595     void sigReload(const QUuid &uId);
    596 
    597     /** Notifies about task is complete. */
    598     void sigComplete();
    599 
    600 public:
    601 
    602     /** Returns group saving thread instance. */
    603     static UIThreadGroupDefinitionSave* instance();
    604     /** Prepares group saving thread instance. */
    605     static void prepare();
    606     /** Cleanups group saving thread instance. */
    607     static void cleanup();
    608 
    609     /** Configures @a groups saving thread with corresponding @a pListener.
    610       * @param  oldLists  Brings the old definition list to be compared.
    611       * @param  newLists  Brings the new definition list to be saved. */
    612     void configure(QObject *pParent,
    613                    const QMap<QString, QStringList> &oldLists,
    614                    const QMap<QString, QStringList> &newLists);
    615 
    616 protected:
    617 
    618     /** Constructs group saving thread. */
    619     UIThreadGroupDefinitionSave();
    620     /** Destructs group saving thread. */
    621     virtual ~UIThreadGroupDefinitionSave() /* override */;
    622 
    623     /** Contains a thread task to be executed. */
    624     void run();
    625 
    626     /** Holds the singleton instance. */
    627     static UIThreadGroupDefinitionSave *s_pInstance;
    628 
    629     /** Holds the map of group definitions to be compared. */
    630     QMap<QString, QStringList> m_oldLists;
    631     /** Holds the map of group definitions to be saved. */
    632     QMap<QString, QStringList> m_newLists;
    633 };
    634 
    635 
    636 /** QThread subclass allowing to save group order asynchronously. */
    637 class UIThreadGroupOrderSave : public QThread
    638 {
    639     Q_OBJECT;
    640 
    641 signals:
    642 
    643     /** Notifies about task is complete. */
    644     void sigComplete();
    645 
    646 public:
    647 
    648     /** Returns group saving thread instance. */
    649     static UIThreadGroupOrderSave *instance();
    650     /** Prepares group saving thread instance. */
    651     static void prepare();
    652     /** Cleanups group saving thread instance. */
    653     static void cleanup();
    654 
    655     /** Configures group saving thread with corresponding @a pListener.
    656       * @param  groups  Brings the groups to be saved. */
    657     void configure(QObject *pListener,
    658                    const QMap<QString, QStringList> &groups);
    659 
    660 protected:
    661 
    662     /** Constructs group saving thread. */
    663     UIThreadGroupOrderSave();
    664     /** Destructs group saving thread. */
    665     virtual ~UIThreadGroupOrderSave() /* override */;
    666 
    667     /** Contains a thread task to be executed. */
    668     virtual void run() /* override */;
    669 
    670     /** Holds the singleton instance. */
    671     static UIThreadGroupOrderSave *s_pInstance;
    672 
    673     /** Holds the map of groups to be saved. */
    674     QMap<QString, QStringList>  m_groups;
    675 };
    676 
    677 
    678422#endif /* !FEQT_INCLUDED_SRC_manager_chooser_UIChooserModel_h */
Note: See TracChangeset for help on using the changeset viewer.

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