Changeset 77890 in vbox for trunk/src/VBox
- Timestamp:
- Mar 26, 2019 5:16:28 PM (6 years ago)
- svn:sync-xref-src-repo-rev:
- 129595
- Location:
- trunk/src/VBox/Frontends/VirtualBox/src/manager/chooser
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/manager/chooser/UIChooserItemMachine.cpp
r77847 r77890 419 419 false /* favorite */, 420 420 parentItem()->node()->nodes().size(), 421 UIChooserModel::uniqueGroupName(parentItem() ),421 UIChooserModel::uniqueGroupName(parentItem()->node()), 422 422 true /* true */); 423 423 UIChooserItemGroup *pNewGroupItem = new UIChooserItemGroup(parentItem(), pNewGroupNode); -
trunk/src/VBox/Frontends/VirtualBox/src/manager/chooser/UIChooserModel.cpp
r77847 r77890 56 56 57 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 /********************************************************************************************************************************* 58 633 * Class UIChooserModel implementation. * 59 634 *********************************************************************************************************************************/ 60 635 61 636 UIChooserModel:: UIChooserModel(UIChooser *pParent) 62 : QObject(pParent)637 : UIChooserAbstractModel(pParent) 63 638 , m_pChooser(pParent) 64 639 , m_pScene(0) … … 69 644 , m_pContextMenuMachine(0) 70 645 , m_iCurrentScrolledIndex(-1) 71 , m_pInvisibleRootNode(0)72 646 , m_iScrollingTokenSize(30) 73 647 , m_fIsScrollingInProgress(false) … … 84 658 void UIChooserModel::init() 85 659 { 86 /* Load tree: */87 loadTree();660 /* Call to base-class: */ 661 UIChooserAbstractModel::init(); 88 662 89 663 /* Build tree for main root: */ … … 101 675 saveLastSelectedItem(); 102 676 103 /* Currently we are not saving group descriptors104 * (which reflecting group toggle-state) on-the-fly,105 * so, for now we are additionally save group orders106 * when exiting application: */107 saveGroupOrders();108 109 /* Make sure all saving steps complete: */110 makeSureGroupDefinitionsSaveIsFinished();111 makeSureGroupOrdersSaveIsFinished();112 113 677 /* Unset current items: */ 114 678 unsetCurrentItems(); 115 679 116 /* Delete tree: */ 117 delete m_pInvisibleRootNode; 118 m_pInvisibleRootNode = 0; 680 /* Call to base-class: */ 681 UIChooserAbstractModel::deinit(); 119 682 } 120 683 … … 464 1027 void UIChooserModel::performSearch(const QString &strSearchTerm, int iItemSearchFlags) 465 1028 { 466 if (! m_pInvisibleRootNode)1029 if (!invisibleRoot()) 467 1030 return; 468 1031 … … 474 1037 return; 475 1038 476 m_pInvisibleRootNode->searchForNodes(strSearchTerm, iItemSearchFlags, m_searchResults);1039 invisibleRoot()->searchForNodes(strSearchTerm, iItemSearchFlags, m_searchResults); 477 1040 478 1041 foreach (UIChooserNode* pNode, allNodes) … … 490 1053 QList<UIChooserNode*> allNodes; 491 1054 /* Calling UIChooserNode::searchForNodes with an empty search string returns a list all nodes (of the whole treee) of the required type: */ 492 m_pInvisibleRootNode->searchForNodes(QString(), UIChooserItemSearchFlag_Machine, allNodes);1055 invisibleRoot()->searchForNodes(QString(), UIChooserItemSearchFlag_Machine, allNodes); 493 1056 494 1057 /* Reset the disabled flag of the node items first. */ … … 547 1110 } 548 1111 549 UIChooserNode *UIChooserModel::invisibleRoot() const550 {551 return m_pInvisibleRootNode;552 }553 554 1112 UIChooserItem *UIChooserModel::root() const 555 1113 { … … 560 1118 { 561 1119 sltEditGroupName(); 562 }563 564 void UIChooserModel::wipeOutEmptyGroups()565 {566 wipeOutEmptyGroups(invisibleRoot());567 1120 } 568 1121 … … 594 1147 { 595 1148 return m_pLookupTimer->isActive(); 596 }597 598 /* static */599 QString UIChooserModel::uniqueGroupName(UIChooserItem *pRoot)600 {601 /* Enumerate all the group names: */602 QStringList groupNames;603 foreach (UIChooserItem *pItem, pRoot->items(UIChooserItemType_Group))604 groupNames << pItem->name();605 606 /* Prepare reg-exp: */607 const QString strMinimumName = tr("New group");608 const QString strShortTemplate = strMinimumName;609 const QString strFullTemplate = strShortTemplate + QString(" (\\d+)");610 const QRegExp shortRegExp(strShortTemplate);611 const QRegExp fullRegExp(strFullTemplate);612 613 /* Search for the maximum index: */614 int iMinimumPossibleNumber = 0;615 foreach (const QString &strName, groupNames)616 {617 if (shortRegExp.exactMatch(strName))618 iMinimumPossibleNumber = qMax(iMinimumPossibleNumber, 2);619 else if (fullRegExp.exactMatch(strName))620 iMinimumPossibleNumber = qMax(iMinimumPossibleNumber, fullRegExp.cap(1).toInt() + 1);621 }622 623 /* Prepare result: */624 QString strResult = strMinimumName;625 if (iMinimumPossibleNumber)626 strResult += " " + QString::number(iMinimumPossibleNumber);627 return strResult;628 1149 } 629 1150 … … 662 1183 } 663 1184 } 664 }665 666 void UIChooserModel::saveGroupSettings()667 {668 emit sigGroupSavingStarted();669 }670 671 bool UIChooserModel::isGroupSavingInProgress() const672 {673 return UIThreadGroupDefinitionSave::instance()674 || UIThreadGroupOrderSave::instance();675 1185 } 676 1186 … … 722 1232 } 723 1233 724 void UIChooserModel::sltMachineStateChanged(const QUuid &uId, const KMachineState)725 {726 /* Update machine-nodes with passed id: */727 invisibleRoot()->updateAllNodes(uId);728 }729 730 void UIChooserModel::sltMachineDataChanged(const QUuid &uId)731 {732 /* Update machine-nodes with passed id: */733 invisibleRoot()->updateAllNodes(uId);734 }735 736 1234 void UIChooserModel::sltMachineRegistered(const QUuid &uId, const bool fRegistered) 737 1235 { 738 /* New VM registered? */ 739 if (fRegistered) 740 { 741 /* Show machine if we should: */ 742 CMachine comMachine = vboxGlobal().virtualBox().FindMachine(uId.toString()); 743 if (gEDataManager->showMachineInVirtualBoxManagerChooser(uId)) 744 { 745 /* Add new machine-item: */ 746 addMachineIntoTheTree(comMachine, true /* make it visible */); 747 748 /* Rebuild tree for main root: */ 749 buildTreeForMainRoot(); 750 updateNavigation(); 751 updateLayout(); 752 753 /* Choose newly added item: */ 754 setCurrentItem(root()->searchForItem(comMachine.GetName(), 755 UIChooserItemSearchFlag_Machine | 756 UIChooserItemSearchFlag_ExactName)); 757 } 758 } 1236 /* Call to base-class: */ 1237 UIChooserAbstractModel::sltMachineRegistered(uId, fRegistered); 1238 759 1239 /* Existing VM unregistered? */ 760 else 761 { 762 /* Remove machine-items with passed id: */ 763 invisibleRoot()->removeAllNodes(uId.toString()); 764 /* Wipe out empty groups: */ 765 wipeOutEmptyGroups(); 766 1240 if (!fRegistered) 1241 { 767 1242 /* Rebuild tree for main root: */ 768 1243 buildTreeForMainRoot(); … … 779 1254 emit sigSelectionChanged(); 780 1255 } 781 } 782 783 void UIChooserModel::sltSessionStateChanged(const QUuid &uId, const KSessionState) 784 { 785 /* Update machine-nodes with passed id: */ 786 invisibleRoot()->updateAllNodes(uId); 787 } 788 789 void UIChooserModel::sltSnapshotChanged(const QUuid &uId, const QUuid &) 790 { 791 /* Update machine-nodes with passed id: */ 792 invisibleRoot()->updateAllNodes(uId); 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(); 793 1304 } 794 1305 … … 893 1404 UIChooserItemGroup *pGroupItem = new UIChooserItemGroup(pParentItem, pGroupNode); 894 1405 if (toBeRenamed.contains(pNode)) 895 pGroupNode->setName(uniqueGroupName(pParent Item));1406 pGroupNode->setName(uniqueGroupName(pParentNode)); 896 1407 copiedItems << pGroupItem; 897 1408 break; … … 978 1489 false /* favorite */, 979 1490 invisibleRoot()->nodes().size() /* position */, 980 uniqueGroupName( root()),1491 uniqueGroupName(invisibleRoot()), 981 1492 true /* opened */); 982 1493 UIChooserItemGroup *pNewGroupItem = new UIChooserItemGroup(root(), pNewGroupNode); … … 1032 1543 } 1033 1544 1034 void UIChooserModel::sltReloadMachine(const QUuid &uId)1035 {1036 /* Remove all the nodes first: */1037 invisibleRoot()->removeAllNodes(uId);1038 /* Wipe out empty groups: */1039 wipeOutEmptyGroups();1040 1041 /* Show machine if we should: */1042 CMachine comMachine = vboxGlobal().virtualBox().FindMachine(uId.toString());1043 if (gEDataManager->showMachineInVirtualBoxManagerChooser(uId))1044 {1045 /* Add new machine-item: */1046 addMachineIntoTheTree(comMachine);1047 1048 /* Rebuild tree for main root: */1049 buildTreeForMainRoot();1050 updateNavigation();1051 updateLayout();1052 1053 /* Choose newly added item: */1054 setCurrentItem(root()->searchForItem(comMachine.GetName(),1055 UIChooserItemSearchFlag_Machine |1056 UIChooserItemSearchFlag_ExactName));1057 }1058 else1059 {1060 /* Make sure at least one item selected after that: */1061 if (!currentItem() && !navigationList().isEmpty())1062 setCurrentItem(navigationList().first());1063 }1064 1065 /* Notify listeners about selection change: */1066 emit sigSelectionChanged();1067 }1068 1069 1545 void UIChooserModel::sltSortParentGroup() 1070 1546 { … … 1240 1716 } 1241 1717 1242 void UIChooserModel::sltGroupSavingStart()1243 {1244 saveGroupDefinitions();1245 saveGroupOrders();1246 }1247 1248 void UIChooserModel::sltGroupDefinitionsSaveComplete()1249 {1250 makeSureGroupDefinitionsSaveIsFinished();1251 emit sigGroupSavingStateChanged();1252 }1253 1254 void UIChooserModel::sltGroupOrdersSaveComplete()1255 {1256 makeSureGroupOrdersSaveIsFinished();1257 emit sigGroupSavingStateChanged();1258 }1259 1260 1718 void UIChooserModel::prepare() 1261 1719 { 1262 /* Prepare scene: */1263 1720 prepareScene(); 1264 1265 /* Prepare lookup: */1266 1721 prepareLookup(); 1267 1268 /* Prepare context-menu: */1269 1722 prepareContextMenu(); 1270 1271 /* Prepare handlers: */1272 1723 prepareHandlers(); 1273 1274 /* Prepare connections: */1275 1724 prepareConnections(); 1276 1725 } … … 1411 1860 connect(this, SIGNAL(sigToggleFinished()), 1412 1861 parent(), SIGNAL(sigToggleFinished())); 1413 connect(this, SIGNAL(sigGroupSavingStateChanged()),1414 parent(), SIGNAL(sigGroupSavingStateChanged()));1415 1416 /* Setup global connections: */1417 connect(gVBoxEvents, SIGNAL(sigMachineStateChange(QUuid, KMachineState)),1418 this, SLOT(sltMachineStateChanged(QUuid, KMachineState)));1419 connect(gVBoxEvents, SIGNAL(sigMachineDataChange(QUuid)),1420 this, SLOT(sltMachineDataChanged(QUuid)));1421 connect(gVBoxEvents, SIGNAL(sigMachineRegistered(QUuid, bool)),1422 this, SLOT(sltMachineRegistered(QUuid, bool)));1423 connect(gVBoxEvents, SIGNAL(sigSessionStateChange(QUuid, KSessionState)),1424 this, SLOT(sltSessionStateChanged(QUuid, KSessionState)));1425 connect(gVBoxEvents, SIGNAL(sigSnapshotTake(QUuid, QUuid)),1426 this, SLOT(sltSnapshotChanged(QUuid, QUuid)));1427 connect(gVBoxEvents, SIGNAL(sigSnapshotDelete(QUuid, QUuid)),1428 this, SLOT(sltSnapshotChanged(QUuid, QUuid)));1429 connect(gVBoxEvents, SIGNAL(sigSnapshotChange(QUuid, QUuid)),1430 this, SLOT(sltSnapshotChanged(QUuid, QUuid)));1431 connect(gVBoxEvents, SIGNAL(sigSnapshotRestore(QUuid, QUuid)),1432 this, SLOT(sltSnapshotChanged(QUuid, QUuid)));1433 1862 1434 1863 /* Setup action connections: */ … … 1457 1886 connect(actionPool()->action(UIActionIndexST_M_Machine_S_Search), SIGNAL(triggered()), 1458 1887 this, SLOT(sltShowHideSearchWidget())); 1459 1460 /* Setup group saving connections: */1461 connect(this, &UIChooserModel::sigGroupSavingStarted,1462 this, &UIChooserModel::sltGroupSavingStart,1463 Qt::QueuedConnection);1464 1888 } 1465 1889 … … 1510 1934 void UIChooserModel::cleanup() 1511 1935 { 1512 /* Cleanup handlers: */1513 1936 cleanupHandlers(); 1514 1515 /* Prepare context-menu: */1516 1937 cleanupContextMenu(); 1517 1518 /* Cleanup lookup: */1519 1938 cleanupLookup(); 1520 1521 /* Cleanup scene: */1522 1939 cleanupScene(); 1523 1940 } … … 1669 2086 } 1670 2087 1671 void UIChooserModel::loadTree()1672 {1673 /* Create invisible root group node: */1674 m_pInvisibleRootNode = new UIChooserNodeGroup(0 /* parent */,1675 false /* favorite */,1676 0 /* position */,1677 QString() /* name */,1678 true /* opened */);1679 if (invisibleRoot())1680 {1681 /* Create global node: */1682 new UIChooserNodeGlobal(m_pInvisibleRootNode,1683 isGlobalNodeFavorite(m_pInvisibleRootNode),1684 0 /* position */,1685 QString() /* tip */);1686 1687 /* Add all the approved machine nodes into the tree: */1688 LogRelFlow(("UIChooserModel: Loading VMs...\n"));1689 foreach (const CMachine &comMachine, vboxGlobal().virtualBox().GetMachines())1690 {1691 const QUuid uMachineID = comMachine.GetId();1692 if (!uMachineID.isNull() && gEDataManager->showMachineInVirtualBoxManagerChooser(uMachineID))1693 addMachineIntoTheTree(comMachine);1694 }1695 LogRelFlow(("UIChooserModel: VMs loaded.\n"));1696 }1697 }1698 1699 void UIChooserModel::addMachineIntoTheTree(const CMachine &comMachine, bool fMakeItVisible /* = false */)1700 {1701 /* Make sure passed VM is not NULL: */1702 if (comMachine.isNull())1703 LogRelFlow(("UIChooserModel: ERROR: Passed VM is NULL!\n"));1704 AssertReturnVoid(!comMachine.isNull());1705 1706 /* Which VM we are loading: */1707 LogRelFlow(("UIChooserModel: Loading VM with ID={%s}...\n", toOldStyleUuid(comMachine.GetId()).toUtf8().constData()));1708 /* Is that machine accessible? */1709 if (comMachine.GetAccessible())1710 {1711 /* VM is accessible: */1712 const QString strName = comMachine.GetName();1713 LogRelFlow(("UIChooserModel: VM {%s} is accessible.\n", strName.toUtf8().constData()));1714 /* Which groups passed machine attached to? */1715 const QVector<QString> groups = comMachine.GetGroups();1716 const QStringList groupList = groups.toList();1717 const QString strGroups = groupList.join(", ");1718 LogRelFlow(("UIChooserModel: VM {%s} has groups: {%s}.\n", strName.toUtf8().constData(),1719 strGroups.toUtf8().constData()));1720 foreach (QString strGroup, groups)1721 {1722 /* Remove last '/' if any: */1723 if (strGroup.right(1) == "/")1724 strGroup.truncate(strGroup.size() - 1);1725 /* Create machine-item with found group-item as parent: */1726 LogRelFlow(("UIChooserModel: Creating item for VM {%s} in group {%s}.\n", strName.toUtf8().constData(),1727 strGroup.toUtf8().constData()));1728 createMachineNode(getGroupNode(strGroup, invisibleRoot(), fMakeItVisible), comMachine);1729 }1730 /* Update group definitions: */1731 m_groups[toOldStyleUuid(comMachine.GetId())] = groupList;1732 }1733 /* Inaccessible machine: */1734 else1735 {1736 /* VM is accessible: */1737 LogRelFlow(("UIChooserModel: VM {%s} is inaccessible.\n", toOldStyleUuid(comMachine.GetId()).toUtf8().constData()));1738 /* Create machine-item with main-root group-item as parent: */1739 createMachineNode(invisibleRoot(), comMachine);1740 }1741 }1742 1743 UIChooserNode *UIChooserModel::getGroupNode(const QString &strName, UIChooserNode *pParentNode, bool fAllGroupsOpened)1744 {1745 /* Check passed stuff: */1746 if (pParentNode->name() == strName)1747 return pParentNode;1748 1749 /* Prepare variables: */1750 const QString strFirstSubName = strName.section('/', 0, 0);1751 const QString strFirstSuffix = strName.section('/', 1, -1);1752 const QString strSecondSubName = strFirstSuffix.section('/', 0, 0);1753 const QString strSecondSuffix = strFirstSuffix.section('/', 1, -1);1754 1755 /* Passed group name equal to first sub-name: */1756 if (pParentNode->name() == strFirstSubName)1757 {1758 /* Make sure first-suffix is NOT empty: */1759 AssertMsg(!strFirstSuffix.isEmpty(), ("Invalid group name!"));1760 /* Trying to get group node among our children: */1761 foreach (UIChooserNode *pGroupNode, pParentNode->nodes(UIChooserItemType_Group))1762 {1763 if (pGroupNode->name() == strSecondSubName)1764 {1765 UIChooserNode *pFoundNode = getGroupNode(strFirstSuffix, pGroupNode, fAllGroupsOpened);1766 if (UIChooserNodeGroup *pFoundGroupNode = pFoundNode->toGroupNode())1767 if (fAllGroupsOpened && pFoundGroupNode->isClosed())1768 pFoundGroupNode->open();1769 return pFoundNode;1770 }1771 }1772 }1773 1774 /* Found nothing? Creating: */1775 UIChooserNodeGroup *pNewGroupNode =1776 new UIChooserNodeGroup(pParentNode,1777 false /* favorite */,1778 getDesiredPosition(pParentNode, UIChooserItemType_Group, strSecondSubName),1779 strSecondSubName,1780 fAllGroupsOpened || shouldBeGroupOpened(pParentNode, strSecondSubName));1781 return strSecondSuffix.isEmpty() ? pNewGroupNode : getGroupNode(strFirstSuffix, pNewGroupNode, fAllGroupsOpened);1782 }1783 1784 bool UIChooserModel::shouldBeGroupOpened(UIChooserNode *pParentNode, const QString &strName)1785 {1786 /* Read group definitions: */1787 const QStringList definitions = gEDataManager->selectorWindowGroupsDefinitions(pParentNode->fullName());1788 /* Return 'false' if no definitions found: */1789 if (definitions.isEmpty())1790 return false;1791 1792 /* Prepare required group definition reg-exp: */1793 const QString strDefinitionTemplate = QString("g(\\S)*=%1").arg(strName);1794 const QRegExp definitionRegExp(strDefinitionTemplate);1795 /* For each the group definition: */1796 foreach (const QString &strDefinition, definitions)1797 {1798 /* Check if this is required definition: */1799 if (definitionRegExp.indexIn(strDefinition) == 0)1800 {1801 /* Get group descriptor: */1802 const QString strDescriptor(definitionRegExp.cap(1));1803 if (strDescriptor.contains('o'))1804 return true;1805 }1806 }1807 1808 /* Return 'false' by default: */1809 return false;1810 }1811 1812 void UIChooserModel::wipeOutEmptyGroups(UIChooserNode *pParent)1813 {1814 /* Cleanup all the group-items recursively first: */1815 foreach (UIChooserNode *pNode, pParent->nodes(UIChooserItemType_Group))1816 wipeOutEmptyGroups(pNode);1817 /* If parent has no nodes: */1818 if (!pParent->hasNodes())1819 {1820 /* If that is non-root item: */1821 if (!pParent->isRoot())1822 {1823 /* Delete parent node and item: */1824 delete pParent;1825 }1826 }1827 }1828 1829 bool UIChooserModel::isGlobalNodeFavorite(UIChooserNode *pParentNode) const1830 {1831 /* Read group definitions: */1832 const QStringList definitions = gEDataManager->selectorWindowGroupsDefinitions(pParentNode->fullName());1833 /* Return 'false' if no definitions found: */1834 if (definitions.isEmpty())1835 return false;1836 1837 /* Prepare required group definition reg-exp: */1838 const QString strDefinitionTemplate = QString("n(\\S)*=GLOBAL");1839 const QRegExp definitionRegExp = QRegExp(strDefinitionTemplate);1840 /* For each the group definition: */1841 foreach (const QString &strDefinition, definitions)1842 {1843 /* Check if this is required definition: */1844 if (definitionRegExp.indexIn(strDefinition) == 0)1845 {1846 /* Get group descriptor: */1847 const QString strDescriptor(definitionRegExp.cap(1));1848 if (strDescriptor.contains('f'))1849 return true;1850 }1851 }1852 1853 /* Return 'false' by default: */1854 return false;1855 }1856 1857 int UIChooserModel::getDesiredPosition(UIChooserNode *pParentNode, UIChooserItemType enmType, const QString &strName)1858 {1859 /* End of list (by default)? */1860 int iNewNodeDesiredPosition = -1;1861 /* Which position should be new node placed by definitions: */1862 int iNewNodeDefinitionPosition = positionFromDefinitions(pParentNode, enmType, strName);1863 /* If some position wanted: */1864 if (iNewNodeDefinitionPosition != -1)1865 {1866 /* Start of list if some definition present: */1867 iNewNodeDesiredPosition = 0;1868 /* We have to check all the existing node positions: */1869 QList<UIChooserNode*> nodes = pParentNode->nodes(enmType);1870 for (int i = nodes.size() - 1; i >= 0; --i)1871 {1872 /* Get current node: */1873 UIChooserNode *pNode = nodes[i];1874 /* Which position should be current node placed by definitions? */1875 QString strDefinitionName = pNode->type() == UIChooserItemType_Group ? pNode->name() :1876 pNode->type() == UIChooserItemType_Machine ? toOldStyleUuid(pNode->toMachineNode()->id()) :1877 QString();1878 AssertMsg(!strDefinitionName.isEmpty(), ("Wrong definition name!"));1879 int iNodeDefinitionPosition = positionFromDefinitions(pParentNode, enmType, strDefinitionName);1880 /* If some position wanted: */1881 if (iNodeDefinitionPosition != -1)1882 {1883 AssertMsg(iNodeDefinitionPosition != iNewNodeDefinitionPosition, ("Incorrect definitions!"));1884 if (iNodeDefinitionPosition < iNewNodeDefinitionPosition)1885 {1886 iNewNodeDesiredPosition = i + 1;1887 break;1888 }1889 }1890 }1891 }1892 /* Return desired node position: */1893 return iNewNodeDesiredPosition;1894 }1895 1896 int UIChooserModel::positionFromDefinitions(UIChooserNode *pParentNode, UIChooserItemType enmType, const QString &strName)1897 {1898 /* Read group definitions: */1899 const QStringList definitions = gEDataManager->selectorWindowGroupsDefinitions(pParentNode->fullName());1900 /* Return 'false' if no definitions found: */1901 if (definitions.isEmpty())1902 return -1;1903 1904 /* Prepare definition reg-exp: */1905 QString strDefinitionTemplateShort;1906 QString strDefinitionTemplateFull;1907 switch (enmType)1908 {1909 case UIChooserItemType_Group:1910 strDefinitionTemplateShort = QString("^g(\\S)*=");1911 strDefinitionTemplateFull = QString("^g(\\S)*=%1$").arg(strName);1912 break;1913 case UIChooserItemType_Machine:1914 strDefinitionTemplateShort = QString("^m=");1915 strDefinitionTemplateFull = QString("^m=%1$").arg(strName);1916 break;1917 default: return -1;1918 }1919 QRegExp definitionRegExpShort(strDefinitionTemplateShort);1920 QRegExp definitionRegExpFull(strDefinitionTemplateFull);1921 1922 /* For each the definition: */1923 int iDefinitionIndex = -1;1924 foreach (const QString &strDefinition, definitions)1925 {1926 /* Check if this definition is of required type: */1927 if (definitionRegExpShort.indexIn(strDefinition) == 0)1928 {1929 ++iDefinitionIndex;1930 /* Check if this definition is exactly what we need: */1931 if (definitionRegExpFull.indexIn(strDefinition) == 0)1932 return iDefinitionIndex;1933 }1934 }1935 1936 /* Return result: */1937 return -1;1938 }1939 1940 void UIChooserModel::createMachineNode(UIChooserNode *pParentNode, const CMachine &comMachine)1941 {1942 /* Create machine node: */1943 new UIChooserNodeMachine(pParentNode,1944 false /* favorite */,1945 getDesiredPosition(pParentNode, UIChooserItemType_Machine, toOldStyleUuid(comMachine.GetId())),1946 comMachine);1947 }1948 1949 2088 void UIChooserModel::buildTreeForMainRoot() 1950 2089 { … … 2101 2240 } 2102 2241 2103 void UIChooserModel::saveGroupDefinitions()2104 {2105 /* Make sure there is no group save activity: */2106 if (UIThreadGroupDefinitionSave::instance())2107 return;2108 2109 /* Prepare full group map: */2110 QMap<QString, QStringList> groups;2111 gatherGroupDefinitions(groups, invisibleRoot());2112 2113 /* Save information in other thread: */2114 UIThreadGroupDefinitionSave::prepare();2115 emit sigGroupSavingStateChanged();2116 connect(UIThreadGroupDefinitionSave::instance(), SIGNAL(sigReload(QUuid)),2117 this, SLOT(sltReloadMachine(QUuid)));2118 UIThreadGroupDefinitionSave::instance()->configure(this, m_groups, groups);2119 UIThreadGroupDefinitionSave::instance()->start();2120 m_groups = groups;2121 }2122 2123 void UIChooserModel::saveGroupOrders()2124 {2125 /* Make sure there is no group save activity: */2126 if (UIThreadGroupOrderSave::instance())2127 return;2128 2129 /* Prepare full group map: */2130 QMap<QString, QStringList> groups;2131 gatherGroupOrders(groups, invisibleRoot());2132 2133 /* Save information in other thread: */2134 UIThreadGroupOrderSave::prepare();2135 emit sigGroupSavingStateChanged();2136 UIThreadGroupOrderSave::instance()->configure(this, groups);2137 UIThreadGroupOrderSave::instance()->start();2138 }2139 2140 void UIChooserModel::gatherGroupDefinitions(QMap<QString, QStringList> &definitions,2141 UIChooserNode *pParentGroup)2142 {2143 /* Iterate over all the machine-nodes: */2144 foreach (UIChooserNode *pNode, pParentGroup->nodes(UIChooserItemType_Machine))2145 if (UIChooserNodeMachine *pMachineNode = pNode->toMachineNode())2146 if (pMachineNode->accessible())2147 definitions[toOldStyleUuid(pMachineNode->id())] << pParentGroup->fullName();2148 /* Iterate over all the group-nodes: */2149 foreach (UIChooserNode *pNode, pParentGroup->nodes(UIChooserItemType_Group))2150 gatherGroupDefinitions(definitions, pNode);2151 }2152 2153 void UIChooserModel::gatherGroupOrders(QMap<QString, QStringList> &orders,2154 UIChooserNode *pParentItem)2155 {2156 /* Prepare extra-data key for current group: */2157 const QString strExtraDataKey = pParentItem->fullName();2158 /* Iterate over all the global-nodes: */2159 foreach (UIChooserNode *pNode, pParentItem->nodes(UIChooserItemType_Global))2160 {2161 const QString strGlobalDescriptor(pNode->isFavorite() ? "nf" : "n");2162 orders[strExtraDataKey] << QString("%1=GLOBAL").arg(strGlobalDescriptor);2163 }2164 /* Iterate over all the group-nodes: */2165 foreach (UIChooserNode *pNode, pParentItem->nodes(UIChooserItemType_Group))2166 {2167 const QString strGroupDescriptor(pNode->toGroupNode()->isOpened() ? "go" : "gc");2168 orders[strExtraDataKey] << QString("%1=%2").arg(strGroupDescriptor, pNode->name());2169 gatherGroupOrders(orders, pNode);2170 }2171 /* Iterate over all the machine-nodes: */2172 foreach (UIChooserNode *pNode, pParentItem->nodes(UIChooserItemType_Machine))2173 orders[strExtraDataKey] << QString("m=%1").arg(toOldStyleUuid(pNode->toMachineNode()->id()));2174 }2175 2176 void UIChooserModel::makeSureGroupDefinitionsSaveIsFinished()2177 {2178 /* Cleanup if necessary: */2179 if (UIThreadGroupDefinitionSave::instance())2180 UIThreadGroupDefinitionSave::cleanup();2181 }2182 2183 void UIChooserModel::makeSureGroupOrdersSaveIsFinished()2184 {2185 /* Cleanup if necessary: */2186 if (UIThreadGroupOrderSave::instance())2187 UIThreadGroupOrderSave::cleanup();2188 }2189 2190 /* static */2191 QString UIChooserModel::toOldStyleUuid(const QUuid &uId)2192 {2193 return uId.toString().remove(QRegExp("[{}]"));2194 }2195 2196 2242 2197 2243 /********************************************************************************************************************************* -
trunk/src/VBox/Frontends/VirtualBox/src/manager/chooser/UIChooserModel.h
r77847 r77890 56 56 57 57 58 /** QObject extension used as VM Chooser-pane model: */ 59 class UIChooserModel : public QObject 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 /** @} */ 214 }; 215 216 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 60 221 { 61 222 Q_OBJECT; … … 86 247 /** Notifies about root item minimum width @a iHint changed. */ 87 248 void sigRootItemMinimumWidthHintChanged(int iHint); 88 /** @} */89 90 /** @name Group saving stuff.91 * @{ */92 /** Notifies about group saving started. */93 void sigGroupSavingStarted();94 /** Notifies about group saving state changed. */95 void sigGroupSavingStateChanged();96 249 /** @} */ 97 250 … … 203 356 /** @name Children stuff. 204 357 * @{ */ 205 /** Returns invisible root node instance. */206 UIChooserNode *invisibleRoot() const;207 208 358 /** Returns the root instance. */ 209 359 UIChooserItem *root() const; … … 211 361 /** Starts editing group name. */ 212 362 void startEditingGroupItemName(); 213 214 /** Wipes out empty groups. */215 void wipeOutEmptyGroups();216 363 217 364 /** Activates machine item. */ … … 225 372 /** Returns whether looking is in progress. */ 226 373 bool isLookupInProgress() const; 227 228 /** Generates unique group name traversing recursively starting from @a pRoot. */229 static QString uniqueGroupName(UIChooserItem *pRoot);230 374 /** @} */ 231 375 … … 239 383 /** @} */ 240 384 241 /** @name Group saving stuff.242 * @{ */243 /** Commands to save group settings. */244 void saveGroupSettings();245 /** Returns whether group saving is in progress. */246 bool isGroupSavingInProgress() const;247 /** @} */248 249 385 public slots: 250 386 … … 263 399 /** @} */ 264 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 265 415 private slots: 266 267 /** @name Main event handling stuff.268 * @{ */269 /** Handles machine @a enmState change for machine with certain @a uId. */270 void sltMachineStateChanged(const QUuid &uId, const KMachineState enmState);271 /** Handles machine data change for machine with certain @a uId. */272 void sltMachineDataChanged(const QUuid &uId);273 /** Handles machine registering/unregistering for machine with certain @a uId. */274 void sltMachineRegistered(const QUuid &uId, const bool fRegistered);275 /** Handles session @a enmState change for machine with certain @a uId. */276 void sltSessionStateChanged(const QUuid &uId, const KSessionState enmState);277 /** Handles snapshot change for machine/snapshot with certain @a uId / @a uSnapshotId. */278 void sltSnapshotChanged(const QUuid &uId, const QUuid &uSnapshotId);279 /** @} */280 416 281 417 /** @name Selection stuff. … … 300 436 /** Handles group selected machines request. */ 301 437 void sltGroupSelectedMachines(); 302 /** Handles reload machine with certain @a uId request. */303 void sltReloadMachine(const QUuid &uId);304 438 /** Handles sort parent group request. */ 305 439 void sltSortParentGroup(); … … 316 450 /** Handles request to erase lookup timer. */ 317 451 void sltEraseLookupTimer(); 318 /** @} */319 320 /** @name Group saving stuff.321 * @{ */322 /** Handles request to start group saving. */323 void sltGroupSavingStart();324 /** Handles group definition saving complete. */325 void sltGroupDefinitionsSaveComplete();326 /** Handles group order saving complete. */327 void sltGroupOrdersSaveComplete();328 452 /** @} */ 329 453 … … 385 509 /** @name Children stuff. 386 510 * @{ */ 387 /** Loads tree. */388 void loadTree();389 /** Adds machine item based on certain @a comMachine and optionally @a fMakeItVisible. */390 void addMachineIntoTheTree(const CMachine &comMachine, bool fMakeItVisible = false);391 /** Acquires group node, creates one if necessary.392 * @param strName Brings the name of group we looking for.393 * @param pParentNode Brings the parent we starting to look for a group from.394 * @param fAllGroupsOpened Brings whether we should open all the groups till the required one. */395 UIChooserNode *getGroupNode(const QString &strName, UIChooserNode *pParentNode, bool fAllGroupsOpened);396 /** Returns whether group with certain @a strName should be opened, searching starting from the passed @a pParentItem. */397 bool shouldBeGroupOpened(UIChooserNode *pParentNode, const QString &strName);398 399 /** Wipes out empty groups starting from @a pParentItem. */400 void wipeOutEmptyGroups(UIChooserNode *pParentNode);401 402 /** Returns whether global node within the @a pParentNode is favorite. */403 bool isGlobalNodeFavorite(UIChooserNode *pParentNode) const;404 405 /** Acquires desired position for a child of @a pParentNode with specified @a enmType and @a strName. */406 int getDesiredPosition(UIChooserNode *pParentNode, UIChooserItemType enmType, const QString &strName);407 /** Acquires saved position for a child of @a pParentNode with specified @a enmType and @a strName. */408 int positionFromDefinitions(UIChooserNode *pParentNode, UIChooserItemType enmType, const QString &strName);409 410 /** Creates machine node based on certain @a comMachine as a child of specified @a pParentNode. */411 void createMachineNode(UIChooserNode *pParentNode, const CMachine &comMachine);412 413 511 /** Build tree for main root. */ 414 512 void buildTreeForMainRoot(); … … 426 524 /** Performs sorting for @a pNode. */ 427 525 void sortNodes(UIChooserNode *pNode); 428 /** @} */429 430 /** @name Group saving stuff.431 * @{ */432 /** Saves group definitions. */433 void saveGroupDefinitions();434 /** Saves group orders. */435 void saveGroupOrders();436 437 /** Gathers group @a definitions of @a pParentGroup. */438 void gatherGroupDefinitions(QMap<QString, QStringList> &definitions, UIChooserNode *pParentGroup);439 /** Gathers group @a orders of @a pParentGroup. */440 void gatherGroupOrders(QMap<QString, QStringList> &orders, UIChooserNode *pParentItem);441 442 /** Makes sure group definitions saving is finished. */443 void makeSureGroupDefinitionsSaveIsFinished();444 /** Makes sure group orders saving is finished. */445 void makeSureGroupOrdersSaveIsFinished();446 447 /** Returns QString representation for passed @a uId, wiping out {} symbols.448 * @note Required for backward compatibility after QString=>QUuid change. */449 static QString toOldStyleUuid(const QUuid &uId);450 526 /** @} */ 451 527 … … 487 563 /** @name Children stuff. 488 564 * @{ */ 489 /** Holds the invisible root node instance. */490 UIChooserNode *m_pInvisibleRootNode;491 492 565 /** Holds the root instance. */ 493 566 QPointer<UIChooserItem> m_pRoot; … … 509 582 QString m_strLookupString; 510 583 /** @} */ 511 512 /** @name Group saving stuff.513 * @{ */514 /** Holds the consolidated map of group definitions/orders. */515 QMap<QString, QStringList> m_groups;516 /** @} */517 584 }; 518 585
Note:
See TracChangeset
for help on using the changeset viewer.