[42529] | 1 | /* $Id: UIChooserAbstractModel.cpp 103362 2024-02-14 16:50:56Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[77892] | 3 | * VBox Qt GUI - UIChooserAbstractModel class implementation.
|
---|
[42529] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2012-2023 Oracle and/or its affiliates.
|
---|
[42529] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[42529] | 26 | */
|
---|
| 27 |
|
---|
[84436] | 28 | /* Qt includes: */
|
---|
[93996] | 29 | #include <QRegularExpression>
|
---|
[84436] | 30 | #include <QThread>
|
---|
| 31 |
|
---|
[42529] | 32 | /* GUI includes: */
|
---|
[79365] | 33 | #include "UICommon.h"
|
---|
[76606] | 34 | #include "UIChooser.h"
|
---|
[77891] | 35 | #include "UIChooserAbstractModel.h"
|
---|
[77636] | 36 | #include "UIChooserNode.h"
|
---|
| 37 | #include "UIChooserNodeGroup.h"
|
---|
[77638] | 38 | #include "UIChooserNodeGlobal.h"
|
---|
[77636] | 39 | #include "UIChooserNodeMachine.h"
|
---|
[83705] | 40 | #include "UICloudNetworkingStuff.h"
|
---|
[76606] | 41 | #include "UIExtraDataManager.h"
|
---|
| 42 | #include "UIMessageCenter.h"
|
---|
[91094] | 43 | #include "UINotificationCenter.h"
|
---|
[86795] | 44 | #include "UIProgressTaskReadCloudMachineList.h"
|
---|
[76606] | 45 | #include "UIVirtualBoxEventHandler.h"
|
---|
[83706] | 46 | #include "UIVirtualMachineItemCloud.h"
|
---|
[42529] | 47 |
|
---|
[82944] | 48 | /* COM includes: */
|
---|
[84059] | 49 | #include "CCloudMachine.h"
|
---|
| 50 | #include "CCloudProfile.h"
|
---|
| 51 | #include "CCloudProvider.h"
|
---|
[82944] | 52 | #include "CMachine.h"
|
---|
| 53 |
|
---|
[42722] | 54 | /* Type defs: */
|
---|
| 55 | typedef QSet<QString> UIStringSet;
|
---|
| 56 |
|
---|
[58867] | 57 |
|
---|
[84436] | 58 | /** QThread subclass allowing to save group settings asynchronously. */
|
---|
| 59 | class UIThreadGroupSettingsSave : public QThread
|
---|
| 60 | {
|
---|
| 61 | Q_OBJECT;
|
---|
| 62 |
|
---|
| 63 | signals:
|
---|
| 64 |
|
---|
| 65 | /** Notifies about machine with certain @a uMachineId to be reloaded. */
|
---|
| 66 | void sigReload(const QUuid &uMachineId);
|
---|
| 67 |
|
---|
| 68 | /** Notifies about task is complete. */
|
---|
| 69 | void sigComplete();
|
---|
| 70 |
|
---|
| 71 | public:
|
---|
| 72 |
|
---|
| 73 | /** Returns group settings saving thread instance. */
|
---|
| 74 | static UIThreadGroupSettingsSave *instance();
|
---|
| 75 | /** Prepares group settings saving thread instance. */
|
---|
| 76 | static void prepare();
|
---|
| 77 | /** Cleanups group settings saving thread instance. */
|
---|
| 78 | static void cleanup();
|
---|
| 79 |
|
---|
| 80 | /** Configures @a group settings saving thread with corresponding @a pListener.
|
---|
| 81 | * @param oldLists Brings the old settings list to be compared.
|
---|
| 82 | * @param newLists Brings the new settings list to be saved. */
|
---|
| 83 | void configure(QObject *pParent,
|
---|
| 84 | const QMap<QString, QStringList> &oldLists,
|
---|
| 85 | const QMap<QString, QStringList> &newLists);
|
---|
| 86 |
|
---|
| 87 | protected:
|
---|
| 88 |
|
---|
| 89 | /** Constructs group settings saving thread. */
|
---|
| 90 | UIThreadGroupSettingsSave();
|
---|
| 91 | /** Destructs group settings saving thread. */
|
---|
[93990] | 92 | virtual ~UIThreadGroupSettingsSave() RT_OVERRIDE;
|
---|
[84436] | 93 |
|
---|
| 94 | /** Contains a thread task to be executed. */
|
---|
[93990] | 95 | virtual void run() RT_OVERRIDE;
|
---|
[84436] | 96 |
|
---|
| 97 | /** Holds the singleton instance. */
|
---|
| 98 | static UIThreadGroupSettingsSave *s_pInstance;
|
---|
| 99 |
|
---|
| 100 | /** Holds the map of group settings to be compared. */
|
---|
| 101 | QMap<QString, QStringList> m_oldLists;
|
---|
| 102 | /** Holds the map of group settings to be saved. */
|
---|
| 103 | QMap<QString, QStringList> m_newLists;
|
---|
| 104 | };
|
---|
| 105 |
|
---|
| 106 |
|
---|
| 107 | /** QThread subclass allowing to save group definitions asynchronously. */
|
---|
| 108 | class UIThreadGroupDefinitionsSave : public QThread
|
---|
| 109 | {
|
---|
| 110 | Q_OBJECT;
|
---|
| 111 |
|
---|
| 112 | signals:
|
---|
| 113 |
|
---|
| 114 | /** Notifies about task is complete. */
|
---|
| 115 | void sigComplete();
|
---|
| 116 |
|
---|
| 117 | public:
|
---|
| 118 |
|
---|
| 119 | /** Returns group definitions saving thread instance. */
|
---|
| 120 | static UIThreadGroupDefinitionsSave *instance();
|
---|
| 121 | /** Prepares group definitions saving thread instance. */
|
---|
| 122 | static void prepare();
|
---|
| 123 | /** Cleanups group definitions saving thread instance. */
|
---|
| 124 | static void cleanup();
|
---|
| 125 |
|
---|
| 126 | /** Configures group definitions saving thread with corresponding @a pListener.
|
---|
| 127 | * @param lists Brings definitions lists to be saved. */
|
---|
| 128 | void configure(QObject *pListener,
|
---|
| 129 | const QMap<QString, QStringList> &lists);
|
---|
| 130 |
|
---|
| 131 | protected:
|
---|
| 132 |
|
---|
| 133 | /** Constructs group definitions saving thread. */
|
---|
| 134 | UIThreadGroupDefinitionsSave();
|
---|
| 135 | /** Destructs group definitions saving thread. */
|
---|
[93990] | 136 | virtual ~UIThreadGroupDefinitionsSave() RT_OVERRIDE;
|
---|
[84436] | 137 |
|
---|
| 138 | /** Contains a thread task to be executed. */
|
---|
[93990] | 139 | virtual void run() RT_OVERRIDE;
|
---|
[84436] | 140 |
|
---|
| 141 | /** Holds the singleton instance. */
|
---|
| 142 | static UIThreadGroupDefinitionsSave *s_pInstance;
|
---|
| 143 |
|
---|
| 144 | /** Holds the map of group definitions to be saved. */
|
---|
| 145 | QMap<QString, QStringList> m_lists;
|
---|
| 146 | };
|
---|
| 147 |
|
---|
| 148 |
|
---|
[74184] | 149 | /*********************************************************************************************************************************
|
---|
[84436] | 150 | * Class UIThreadGroupSettingsSave implementation. *
|
---|
| 151 | *********************************************************************************************************************************/
|
---|
| 152 |
|
---|
| 153 | /* static */
|
---|
| 154 | UIThreadGroupSettingsSave *UIThreadGroupSettingsSave::s_pInstance = 0;
|
---|
| 155 |
|
---|
| 156 | /* static */
|
---|
| 157 | UIThreadGroupSettingsSave *UIThreadGroupSettingsSave::instance()
|
---|
| 158 | {
|
---|
| 159 | return s_pInstance;
|
---|
| 160 | }
|
---|
| 161 |
|
---|
| 162 | /* static */
|
---|
| 163 | void UIThreadGroupSettingsSave::prepare()
|
---|
| 164 | {
|
---|
| 165 | /* Make sure instance is not prepared: */
|
---|
| 166 | if (s_pInstance)
|
---|
| 167 | return;
|
---|
| 168 |
|
---|
| 169 | /* Crate instance: */
|
---|
| 170 | new UIThreadGroupSettingsSave;
|
---|
| 171 | }
|
---|
| 172 |
|
---|
| 173 | /* static */
|
---|
| 174 | void UIThreadGroupSettingsSave::cleanup()
|
---|
| 175 | {
|
---|
| 176 | /* Make sure instance is prepared: */
|
---|
| 177 | if (!s_pInstance)
|
---|
| 178 | return;
|
---|
| 179 |
|
---|
| 180 | /* Delete instance: */
|
---|
| 181 | delete s_pInstance;
|
---|
| 182 | }
|
---|
| 183 |
|
---|
| 184 | void UIThreadGroupSettingsSave::configure(QObject *pParent,
|
---|
| 185 | const QMap<QString, QStringList> &oldLists,
|
---|
| 186 | const QMap<QString, QStringList> &newLists)
|
---|
| 187 | {
|
---|
| 188 | m_oldLists = oldLists;
|
---|
| 189 | m_newLists = newLists;
|
---|
| 190 | UIChooserAbstractModel *pChooserAbstractModel = qobject_cast<UIChooserAbstractModel*>(pParent);
|
---|
| 191 | AssertPtrReturnVoid(pChooserAbstractModel);
|
---|
| 192 | {
|
---|
| 193 | connect(this, &UIThreadGroupSettingsSave::sigComplete,
|
---|
| 194 | pChooserAbstractModel, &UIChooserAbstractModel::sltGroupSettingsSaveComplete);
|
---|
| 195 | }
|
---|
| 196 | }
|
---|
| 197 |
|
---|
| 198 | UIThreadGroupSettingsSave::UIThreadGroupSettingsSave()
|
---|
| 199 | {
|
---|
| 200 | /* Assign instance: */
|
---|
| 201 | s_pInstance = this;
|
---|
| 202 | }
|
---|
| 203 |
|
---|
| 204 | UIThreadGroupSettingsSave::~UIThreadGroupSettingsSave()
|
---|
| 205 | {
|
---|
| 206 | /* Make sure thread work is complete: */
|
---|
| 207 | wait();
|
---|
| 208 |
|
---|
| 209 | /* Erase instance: */
|
---|
| 210 | s_pInstance = 0;
|
---|
| 211 | }
|
---|
| 212 |
|
---|
| 213 | void UIThreadGroupSettingsSave::run()
|
---|
| 214 | {
|
---|
| 215 | /* COM prepare: */
|
---|
| 216 | COMBase::InitializeCOM(false);
|
---|
| 217 |
|
---|
| 218 | /* For every particular machine ID: */
|
---|
| 219 | foreach (const QString &strId, m_newLists.keys())
|
---|
| 220 | {
|
---|
| 221 | /* Get new group list/set: */
|
---|
| 222 | const QStringList &newGroupList = m_newLists.value(strId);
|
---|
[94029] | 223 | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
---|
| 224 | const UIStringSet newGroupSet(newGroupList.begin(), newGroupList.end());
|
---|
| 225 | #else
|
---|
[84436] | 226 | const UIStringSet &newGroupSet = UIStringSet::fromList(newGroupList);
|
---|
[94029] | 227 | #endif
|
---|
[84436] | 228 | /* Get old group list/set: */
|
---|
| 229 | const QStringList &oldGroupList = m_oldLists.value(strId);
|
---|
[94029] | 230 | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
---|
| 231 | const UIStringSet oldGroupSet(oldGroupList.begin(), oldGroupList.end());
|
---|
| 232 | #else
|
---|
[84436] | 233 | const UIStringSet &oldGroupSet = UIStringSet::fromList(oldGroupList);
|
---|
[94029] | 234 | #endif
|
---|
[84436] | 235 | /* Make sure group set changed: */
|
---|
| 236 | if (newGroupSet == oldGroupSet)
|
---|
| 237 | continue;
|
---|
| 238 |
|
---|
| 239 | /* The next steps are subsequent.
|
---|
| 240 | * Every of them is mandatory in order to continue
|
---|
| 241 | * with common cleanup in case of failure.
|
---|
| 242 | * We have to simulate a try-catch block. */
|
---|
| 243 | CSession comSession;
|
---|
| 244 | CMachine comMachine;
|
---|
| 245 | do
|
---|
| 246 | {
|
---|
| 247 | /* 1. Open session: */
|
---|
| 248 | comSession = uiCommon().openSession(QUuid(strId));
|
---|
| 249 | if (comSession.isNull())
|
---|
| 250 | break;
|
---|
| 251 |
|
---|
| 252 | /* 2. Get session machine: */
|
---|
| 253 | comMachine = comSession.GetMachine();
|
---|
| 254 | if (comMachine.isNull())
|
---|
| 255 | break;
|
---|
| 256 |
|
---|
| 257 | /* 3. Set new groups: */
|
---|
| 258 | comMachine.SetGroups(newGroupList.toVector());
|
---|
| 259 | if (!comMachine.isOk())
|
---|
| 260 | {
|
---|
| 261 | msgCenter().cannotSetGroups(comMachine);
|
---|
| 262 | break;
|
---|
| 263 | }
|
---|
| 264 |
|
---|
| 265 | /* 4. Save settings: */
|
---|
| 266 | comMachine.SaveSettings();
|
---|
| 267 | if (!comMachine.isOk())
|
---|
| 268 | {
|
---|
| 269 | msgCenter().cannotSaveMachineSettings(comMachine);
|
---|
| 270 | break;
|
---|
| 271 | }
|
---|
| 272 | } while (0);
|
---|
| 273 |
|
---|
| 274 | /* Cleanup if necessary: */
|
---|
| 275 | if (comMachine.isNull() || !comMachine.isOk())
|
---|
| 276 | emit sigReload(QUuid(strId));
|
---|
| 277 | if (!comSession.isNull())
|
---|
| 278 | comSession.UnlockMachine();
|
---|
| 279 | }
|
---|
| 280 |
|
---|
| 281 | /* Notify listeners about completeness: */
|
---|
| 282 | emit sigComplete();
|
---|
| 283 |
|
---|
| 284 | /* COM cleanup: */
|
---|
| 285 | COMBase::CleanupCOM();
|
---|
| 286 | }
|
---|
| 287 |
|
---|
| 288 |
|
---|
| 289 | /*********************************************************************************************************************************
|
---|
| 290 | * Class UIThreadGroupDefinitionsSave implementation. *
|
---|
| 291 | *********************************************************************************************************************************/
|
---|
| 292 |
|
---|
| 293 | /* static */
|
---|
| 294 | UIThreadGroupDefinitionsSave *UIThreadGroupDefinitionsSave::s_pInstance = 0;
|
---|
| 295 |
|
---|
| 296 | /* static */
|
---|
| 297 | UIThreadGroupDefinitionsSave *UIThreadGroupDefinitionsSave::instance()
|
---|
| 298 | {
|
---|
| 299 | return s_pInstance;
|
---|
| 300 | }
|
---|
| 301 |
|
---|
| 302 | /* static */
|
---|
| 303 | void UIThreadGroupDefinitionsSave::prepare()
|
---|
| 304 | {
|
---|
| 305 | /* Make sure instance is not prepared: */
|
---|
| 306 | if (s_pInstance)
|
---|
| 307 | return;
|
---|
| 308 |
|
---|
| 309 | /* Crate instance: */
|
---|
| 310 | new UIThreadGroupDefinitionsSave;
|
---|
| 311 | }
|
---|
| 312 |
|
---|
| 313 | /* static */
|
---|
| 314 | void UIThreadGroupDefinitionsSave::cleanup()
|
---|
| 315 | {
|
---|
| 316 | /* Make sure instance is prepared: */
|
---|
| 317 | if (!s_pInstance)
|
---|
| 318 | return;
|
---|
| 319 |
|
---|
| 320 | /* Delete instance: */
|
---|
| 321 | delete s_pInstance;
|
---|
| 322 | }
|
---|
| 323 |
|
---|
| 324 | void UIThreadGroupDefinitionsSave::configure(QObject *pParent,
|
---|
| 325 | const QMap<QString, QStringList> &groups)
|
---|
| 326 | {
|
---|
| 327 | m_lists = groups;
|
---|
| 328 | UIChooserAbstractModel *pChooserAbstractModel = qobject_cast<UIChooserAbstractModel*>(pParent);
|
---|
| 329 | AssertPtrReturnVoid(pChooserAbstractModel);
|
---|
| 330 | {
|
---|
| 331 | connect(this, &UIThreadGroupDefinitionsSave::sigComplete,
|
---|
| 332 | pChooserAbstractModel, &UIChooserAbstractModel::sltGroupDefinitionsSaveComplete);
|
---|
| 333 | }
|
---|
| 334 | }
|
---|
| 335 |
|
---|
| 336 | UIThreadGroupDefinitionsSave::UIThreadGroupDefinitionsSave()
|
---|
| 337 | {
|
---|
| 338 | /* Assign instance: */
|
---|
| 339 | s_pInstance = this;
|
---|
| 340 | }
|
---|
| 341 |
|
---|
| 342 | UIThreadGroupDefinitionsSave::~UIThreadGroupDefinitionsSave()
|
---|
| 343 | {
|
---|
| 344 | /* Make sure thread work is complete: */
|
---|
| 345 | wait();
|
---|
| 346 |
|
---|
| 347 | /* Erase instance: */
|
---|
| 348 | s_pInstance = 0;
|
---|
| 349 | }
|
---|
| 350 |
|
---|
| 351 | void UIThreadGroupDefinitionsSave::run()
|
---|
| 352 | {
|
---|
| 353 | /* COM prepare: */
|
---|
| 354 | COMBase::InitializeCOM(false);
|
---|
| 355 |
|
---|
[88585] | 356 | /* Acquire a list of known group definition keys: */
|
---|
| 357 | QStringList knownKeys = gEDataManager->knownMachineGroupDefinitionKeys();
|
---|
| 358 | /* For every group definition to be saved: */
|
---|
[84436] | 359 | foreach (const QString &strId, m_lists.keys())
|
---|
[88585] | 360 | {
|
---|
| 361 | /* Save definition only if there is a change: */
|
---|
| 362 | if (gEDataManager->machineGroupDefinitions(strId) != m_lists.value(strId))
|
---|
| 363 | gEDataManager->setMachineGroupDefinitions(strId, m_lists.value(strId));
|
---|
| 364 | /* Remove it from known keys: */
|
---|
| 365 | knownKeys.removeAll(strId);
|
---|
| 366 | }
|
---|
| 367 | /* Wipe out rest of known group definitions: */
|
---|
| 368 | foreach (const QString strId, knownKeys)
|
---|
| 369 | gEDataManager->setMachineGroupDefinitions(strId, QStringList());
|
---|
[84436] | 370 |
|
---|
| 371 | /* Notify listeners about completeness: */
|
---|
| 372 | emit sigComplete();
|
---|
| 373 |
|
---|
| 374 | /* COM cleanup: */
|
---|
| 375 | COMBase::CleanupCOM();
|
---|
| 376 | }
|
---|
| 377 |
|
---|
| 378 |
|
---|
| 379 | /*********************************************************************************************************************************
|
---|
[77890] | 380 | * Class UIChooserAbstractModel implementation. *
|
---|
| 381 | *********************************************************************************************************************************/
|
---|
| 382 |
|
---|
[86788] | 383 | UIChooserAbstractModel::UIChooserAbstractModel(UIChooser *pParent)
|
---|
[77890] | 384 | : QObject(pParent)
|
---|
[77892] | 385 | , m_pParent(pParent)
|
---|
[77890] | 386 | , m_pInvisibleRootNode(0)
|
---|
[102838] | 387 | , m_fKeepCloudNodesUpdated(false)
|
---|
[77890] | 388 | {
|
---|
| 389 | prepare();
|
---|
| 390 | }
|
---|
| 391 |
|
---|
[86788] | 392 | UIChooserAbstractModel::~UIChooserAbstractModel()
|
---|
| 393 | {
|
---|
| 394 | cleanup();
|
---|
| 395 | }
|
---|
| 396 |
|
---|
[77890] | 397 | void UIChooserAbstractModel::init()
|
---|
| 398 | {
|
---|
[83689] | 399 | /* Create invisible root group node: */
|
---|
| 400 | m_pInvisibleRootNode = new UIChooserNodeGroup(0 /* parent */,
|
---|
| 401 | 0 /* position */,
|
---|
[86742] | 402 | QUuid() /* id */,
|
---|
[83689] | 403 | QString() /* name */,
|
---|
[86742] | 404 | UIChooserNodeGroupType_Local,
|
---|
| 405 | true /* opened */);
|
---|
[83689] | 406 | if (invisibleRoot())
|
---|
| 407 | {
|
---|
| 408 | /* Link root to this model: */
|
---|
| 409 | invisibleRoot()->setModel(this);
|
---|
| 410 |
|
---|
| 411 | /* Create global node: */
|
---|
[83690] | 412 | new UIChooserNodeGlobal(invisibleRoot() /* parent */,
|
---|
[84610] | 413 | 0 /* position */,
|
---|
[84434] | 414 | shouldGlobalNodeBeFavorite(invisibleRoot()),
|
---|
[83689] | 415 | QString() /* tip */);
|
---|
| 416 |
|
---|
[85036] | 417 | /* Reload local tree: */
|
---|
| 418 | reloadLocalTree();
|
---|
| 419 | /* Reload cloud tree: */
|
---|
| 420 | reloadCloudTree();
|
---|
[83689] | 421 | }
|
---|
[77890] | 422 | }
|
---|
| 423 |
|
---|
| 424 | void UIChooserAbstractModel::deinit()
|
---|
| 425 | {
|
---|
| 426 | /* Make sure all saving steps complete: */
|
---|
[84423] | 427 | makeSureGroupSettingsSaveIsFinished();
|
---|
[84424] | 428 | makeSureGroupDefinitionsSaveIsFinished();
|
---|
[77890] | 429 | }
|
---|
| 430 |
|
---|
| 431 | void UIChooserAbstractModel::wipeOutEmptyGroups()
|
---|
| 432 | {
|
---|
[77892] | 433 | wipeOutEmptyGroupsStartingFrom(invisibleRoot());
|
---|
[77890] | 434 | }
|
---|
| 435 |
|
---|
[84545] | 436 | QStringList UIChooserAbstractModel::possibleGroupNodeNamesForMachineNodeToMove(const QUuid &uId)
|
---|
| 437 | {
|
---|
| 438 | /* Search for all the machine nodes with passed ID: */
|
---|
| 439 | QList<UIChooserNode*> machineNodes;
|
---|
[84598] | 440 | invisibleRoot()->searchForNodes(uId.toString(),
|
---|
[84545] | 441 | UIChooserItemSearchFlag_Machine | UIChooserItemSearchFlag_ExactId,
|
---|
| 442 | machineNodes);
|
---|
| 443 |
|
---|
| 444 | /* Return group nodes starting from root one: */
|
---|
| 445 | return gatherPossibleGroupNodeNames(invisibleRoot(), machineNodes);
|
---|
| 446 | }
|
---|
| 447 |
|
---|
[84557] | 448 | QStringList UIChooserAbstractModel::possibleGroupNodeNamesForGroupNodeToMove(const QString &strFullName)
|
---|
| 449 | {
|
---|
| 450 | /* Search for all the group nodes with passed full-name: */
|
---|
| 451 | QList<UIChooserNode*> groupNodes;
|
---|
| 452 | invisibleRoot()->searchForNodes(strFullName,
|
---|
[86744] | 453 | UIChooserItemSearchFlag_LocalGroup | UIChooserItemSearchFlag_FullName,
|
---|
[84557] | 454 | groupNodes);
|
---|
| 455 |
|
---|
| 456 | /* Return group nodes starting from root one: */
|
---|
| 457 | return gatherPossibleGroupNodeNames(invisibleRoot(), groupNodes);
|
---|
| 458 | }
|
---|
| 459 |
|
---|
[77890] | 460 | /* static */
|
---|
| 461 | QString UIChooserAbstractModel::uniqueGroupName(UIChooserNode *pRoot)
|
---|
| 462 | {
|
---|
| 463 | /* Enumerate all the group names: */
|
---|
| 464 | QStringList groupNames;
|
---|
[83672] | 465 | foreach (UIChooserNode *pNode, pRoot->nodes(UIChooserNodeType_Group))
|
---|
[77890] | 466 | groupNames << pNode->name();
|
---|
| 467 |
|
---|
| 468 | /* Prepare reg-exp: */
|
---|
| 469 | const QString strMinimumName = tr("New group");
|
---|
| 470 | const QString strShortTemplate = strMinimumName;
|
---|
| 471 | const QString strFullTemplate = strShortTemplate + QString(" (\\d+)");
|
---|
[103362] | 472 | const QRegularExpression shortRegExp(strShortTemplate);
|
---|
| 473 | const QRegularExpression fullRegExp(strFullTemplate);
|
---|
[77890] | 474 |
|
---|
| 475 | /* Search for the maximum index: */
|
---|
| 476 | int iMinimumPossibleNumber = 0;
|
---|
| 477 | foreach (const QString &strName, groupNames)
|
---|
| 478 | {
|
---|
[103362] | 479 | const QRegularExpressionMatch mtShort = shortRegExp.match(strName);
|
---|
| 480 | const QRegularExpressionMatch mtFull = fullRegExp.match(strName);
|
---|
| 481 | if (mtShort.hasMatch())
|
---|
[77890] | 482 | iMinimumPossibleNumber = qMax(iMinimumPossibleNumber, 2);
|
---|
[103362] | 483 | else if (mtFull.hasMatch())
|
---|
| 484 | iMinimumPossibleNumber = qMax(iMinimumPossibleNumber, mtFull.captured(1).toInt() + 1);
|
---|
[77890] | 485 | }
|
---|
| 486 |
|
---|
[77892] | 487 | /* Prepare/return result: */
|
---|
[77890] | 488 | QString strResult = strMinimumName;
|
---|
| 489 | if (iMinimumPossibleNumber)
|
---|
| 490 | strResult += " " + QString::number(iMinimumPossibleNumber);
|
---|
| 491 | return strResult;
|
---|
| 492 | }
|
---|
| 493 |
|
---|
[84625] | 494 | void UIChooserAbstractModel::performSearch(const QString &strSearchTerm, int iSearchFlags)
|
---|
[77948] | 495 | {
|
---|
| 496 | /* Make sure invisible root exists: */
|
---|
| 497 | AssertPtrReturnVoid(invisibleRoot());
|
---|
| 498 |
|
---|
| 499 | /* Currently we perform the search only for machines, when this to be changed make
|
---|
| 500 | * sure the disabled flags of the other item types are also managed correctly. */
|
---|
| 501 |
|
---|
| 502 | /* Reset the search first to erase the disabled flag,
|
---|
| 503 | * this also returns a full list of all machine nodes: */
|
---|
| 504 | const QList<UIChooserNode*> nodes = resetSearch();
|
---|
| 505 |
|
---|
| 506 | /* Stop here if no search conditions specified: */
|
---|
| 507 | if (strSearchTerm.isEmpty())
|
---|
| 508 | return;
|
---|
| 509 |
|
---|
| 510 | /* Search for all the nodes matching required condition: */
|
---|
[84625] | 511 | invisibleRoot()->searchForNodes(strSearchTerm, iSearchFlags, m_searchResults);
|
---|
[77948] | 512 |
|
---|
| 513 | /* Assign/reset the disabled flag for required nodes: */
|
---|
| 514 | foreach (UIChooserNode *pNode, nodes)
|
---|
| 515 | {
|
---|
[84625] | 516 | AssertPtrReturnVoid(pNode);
|
---|
[77948] | 517 | pNode->setDisabled(!m_searchResults.contains(pNode));
|
---|
| 518 | }
|
---|
| 519 | }
|
---|
| 520 |
|
---|
| 521 | QList<UIChooserNode*> UIChooserAbstractModel::resetSearch()
|
---|
| 522 | {
|
---|
| 523 | /* Prepare resulting nodes: */
|
---|
| 524 | QList<UIChooserNode*> nodes;
|
---|
| 525 |
|
---|
| 526 | /* Make sure invisible root exists: */
|
---|
| 527 | AssertPtrReturn(invisibleRoot(), nodes);
|
---|
| 528 |
|
---|
[84625] | 529 | /* Calling UIChooserNode::searchForNodes with an empty search term
|
---|
[77948] | 530 | * returns a list all nodes (of the whole tree) of the required type: */
|
---|
| 531 | invisibleRoot()->searchForNodes(QString(), UIChooserItemSearchFlag_Machine, nodes);
|
---|
| 532 |
|
---|
| 533 | /* Reset the disabled flag of the nodes first: */
|
---|
| 534 | foreach (UIChooserNode *pNode, nodes)
|
---|
| 535 | {
|
---|
[84625] | 536 | AssertPtrReturn(pNode, nodes);
|
---|
[77948] | 537 | pNode->setDisabled(false);
|
---|
| 538 | }
|
---|
| 539 |
|
---|
| 540 | /* Reset the search result related data: */
|
---|
| 541 | m_searchResults.clear();
|
---|
| 542 |
|
---|
[84625] | 543 | /* Return nodes: */
|
---|
[77948] | 544 | return nodes;
|
---|
| 545 | }
|
---|
| 546 |
|
---|
| 547 | QList<UIChooserNode*> UIChooserAbstractModel::searchResult() const
|
---|
| 548 | {
|
---|
| 549 | return m_searchResults;
|
---|
| 550 | }
|
---|
| 551 |
|
---|
[84420] | 552 | void UIChooserAbstractModel::saveGroups()
|
---|
[77890] | 553 | {
|
---|
[88586] | 554 | emit sigSaveSettings();
|
---|
[77890] | 555 | }
|
---|
| 556 |
|
---|
| 557 | bool UIChooserAbstractModel::isGroupSavingInProgress() const
|
---|
| 558 | {
|
---|
[84423] | 559 | return UIThreadGroupSettingsSave::instance()
|
---|
[84424] | 560 | || UIThreadGroupDefinitionsSave::instance();
|
---|
[77890] | 561 | }
|
---|
| 562 |
|
---|
[83900] | 563 | /* static */
|
---|
| 564 | QString UIChooserAbstractModel::toOldStyleUuid(const QUuid &uId)
|
---|
| 565 | {
|
---|
[93996] | 566 | return uId.toString().remove(QRegularExpression("[{}]"));
|
---|
[83900] | 567 | }
|
---|
| 568 |
|
---|
[84376] | 569 | /* static */
|
---|
[84412] | 570 | QString UIChooserAbstractModel::prefixToString(UIChooserNodeDataPrefixType enmType)
|
---|
[84376] | 571 | {
|
---|
[84412] | 572 | switch (enmType)
|
---|
[84376] | 573 | {
|
---|
| 574 | /* Global nodes: */
|
---|
[84598] | 575 | case UIChooserNodeDataPrefixType_Global: return "n";
|
---|
[84376] | 576 | /* Machine nodes: */
|
---|
[84598] | 577 | case UIChooserNodeDataPrefixType_Machine: return "m";
|
---|
[84376] | 578 | /* Group nodes: */
|
---|
[84412] | 579 | case UIChooserNodeDataPrefixType_Local: return "g";
|
---|
| 580 | case UIChooserNodeDataPrefixType_Provider: return "p";
|
---|
| 581 | case UIChooserNodeDataPrefixType_Profile: return "a";
|
---|
[84376] | 582 | }
|
---|
| 583 | return QString();
|
---|
| 584 | }
|
---|
| 585 |
|
---|
[84412] | 586 | /* static */
|
---|
| 587 | QString UIChooserAbstractModel::optionToString(UIChooserNodeDataOptionType enmType)
|
---|
| 588 | {
|
---|
| 589 | switch (enmType)
|
---|
| 590 | {
|
---|
| 591 | /* Global nodes: */
|
---|
| 592 | case UIChooserNodeDataOptionType_GlobalFavorite: return "f";
|
---|
| 593 | /* Group nodes: */
|
---|
| 594 | case UIChooserNodeDataOptionType_GroupOpened: return "o";
|
---|
| 595 | }
|
---|
| 596 | return QString();
|
---|
| 597 | }
|
---|
| 598 |
|
---|
| 599 | /* static */
|
---|
| 600 | QString UIChooserAbstractModel::valueToString(UIChooserNodeDataValueType enmType)
|
---|
| 601 | {
|
---|
| 602 | switch (enmType)
|
---|
| 603 | {
|
---|
| 604 | /* Global nodes: */
|
---|
| 605 | case UIChooserNodeDataValueType_GlobalDefault: return "GLOBAL";
|
---|
| 606 | }
|
---|
| 607 | return QString();
|
---|
| 608 | }
|
---|
| 609 |
|
---|
[102838] | 610 | void UIChooserAbstractModel::setKeepCloudNodesUpdated(bool fUpdate)
|
---|
| 611 | {
|
---|
| 612 | /* Make sure something changed: */
|
---|
| 613 | if (m_fKeepCloudNodesUpdated == fUpdate)
|
---|
| 614 | return;
|
---|
| 615 |
|
---|
| 616 | /* Holds the value: */
|
---|
| 617 | m_fKeepCloudNodesUpdated = fUpdate;
|
---|
| 618 |
|
---|
[103021] | 619 | /* Update all the real cloud machine items: */
|
---|
| 620 | foreach (UIChooserNode *pNode, enumerateCloudMachineNodes())
|
---|
[102838] | 621 | {
|
---|
| 622 | AssertReturnVoid(pNode && pNode->type() == UIChooserNodeType_Machine);
|
---|
| 623 | UIChooserNodeMachine *pMachineNode = pNode->toMachineNode();
|
---|
[103021] | 624 | AssertPtrReturnVoid(pMachineNode);
|
---|
[102838] | 625 | if (pMachineNode->cacheType() != UIVirtualMachineItemType_CloudReal)
|
---|
| 626 | continue;
|
---|
| 627 | UIVirtualMachineItemCloud *pCloudMachineItem = pMachineNode->cache()->toCloud();
|
---|
[103021] | 628 | AssertPtrReturnVoid(pCloudMachineItem);
|
---|
[102838] | 629 | pCloudMachineItem->setUpdateRequiredByGlobalReason(m_fKeepCloudNodesUpdated);
|
---|
| 630 | if (m_fKeepCloudNodesUpdated)
|
---|
| 631 | pCloudMachineItem->updateInfoAsync(false /* delayed? */);
|
---|
| 632 | }
|
---|
| 633 | }
|
---|
| 634 |
|
---|
[86731] | 635 | void UIChooserAbstractModel::insertCloudEntityKey(const UICloudEntityKey &key)
|
---|
[86631] | 636 | {
|
---|
[86796] | 637 | // printf("Cloud entity with key %s being updated..\n", key.toString().toUtf8().constData());
|
---|
[86731] | 638 | m_cloudEntityKeysBeingUpdated.insert(key);
|
---|
[86655] | 639 | emit sigCloudUpdateStateChanged();
|
---|
[86631] | 640 | }
|
---|
| 641 |
|
---|
[86731] | 642 | void UIChooserAbstractModel::removeCloudEntityKey(const UICloudEntityKey &key)
|
---|
[86631] | 643 | {
|
---|
[86796] | 644 | // printf("Cloud entity with key %s is updated!\n", key.toString().toUtf8().constData());
|
---|
[86731] | 645 | m_cloudEntityKeysBeingUpdated.remove(key);
|
---|
[86655] | 646 | emit sigCloudUpdateStateChanged();
|
---|
[86631] | 647 | }
|
---|
| 648 |
|
---|
[86731] | 649 | bool UIChooserAbstractModel::containsCloudEntityKey(const UICloudEntityKey &key) const
|
---|
[86631] | 650 | {
|
---|
[86731] | 651 | return m_cloudEntityKeysBeingUpdated.contains(key);
|
---|
[86631] | 652 | }
|
---|
| 653 |
|
---|
[86734] | 654 | bool UIChooserAbstractModel::isCloudProfileUpdateInProgress() const
|
---|
[86655] | 655 | {
|
---|
[86734] | 656 | /* Compose RE for profile: */
|
---|
[103362] | 657 | const QRegularExpression re("^/[^/]+/[^/]+$");
|
---|
[86734] | 658 | /* Check whether keys match profile RE: */
|
---|
| 659 | foreach (const UICloudEntityKey &key, m_cloudEntityKeysBeingUpdated)
|
---|
| 660 | {
|
---|
[103362] | 661 | const QRegularExpressionMatch mt = re.match(key.toString());
|
---|
| 662 | if (mt.hasMatch())
|
---|
[86734] | 663 | return true;
|
---|
| 664 | }
|
---|
| 665 | /* False by default: */
|
---|
| 666 | return false;
|
---|
[86655] | 667 | }
|
---|
| 668 |
|
---|
[103023] | 669 | QList<UIVirtualMachineItemCloud*> UIChooserAbstractModel::cloudMachineItems() const
|
---|
| 670 | {
|
---|
| 671 | QList<UIVirtualMachineItemCloud*> items;
|
---|
| 672 | foreach (UIChooserNode *pNode, enumerateCloudMachineNodes())
|
---|
| 673 | {
|
---|
| 674 | AssertReturn(pNode && pNode->type() == UIChooserNodeType_Machine, items);
|
---|
| 675 | UIChooserNodeMachine *pMachineNode = pNode->toMachineNode();
|
---|
| 676 | AssertPtrReturn(pMachineNode, items);
|
---|
| 677 | if (pMachineNode->cacheType() != UIVirtualMachineItemType_CloudReal)
|
---|
| 678 | continue;
|
---|
| 679 | UIVirtualMachineItemCloud *pCloudMachineItem = pMachineNode->cache()->toCloud();
|
---|
| 680 | AssertPtrReturn(pCloudMachineItem, items);
|
---|
| 681 | items << pCloudMachineItem;
|
---|
| 682 | }
|
---|
| 683 | return items;
|
---|
| 684 | }
|
---|
| 685 |
|
---|
[86748] | 686 | void UIChooserAbstractModel::sltHandleCloudMachineRefreshStarted()
|
---|
[84598] | 687 | {
|
---|
[86748] | 688 | /* Acquire sender: */
|
---|
[84598] | 689 | UIVirtualMachineItem *pCache = qobject_cast<UIVirtualMachineItem*>(sender());
|
---|
| 690 | AssertPtrReturnVoid(pCache);
|
---|
[86748] | 691 |
|
---|
| 692 | /* Acquire sender's ID: */
|
---|
| 693 | const QUuid uId = pCache->id();
|
---|
| 694 |
|
---|
| 695 | /* Search for a first machine node with passed ID: */
|
---|
| 696 | UIChooserNode *pMachineNode = searchMachineNode(invisibleRoot(), uId);
|
---|
| 697 |
|
---|
[86786] | 698 | /* Insert cloud machine key into a list of keys currently being updated: */
|
---|
| 699 | const UICloudEntityKey guiCloudMachineKey = UICloudEntityKey(pMachineNode->parentNode()->parentNode()->name(),
|
---|
| 700 | pMachineNode->parentNode()->name(),
|
---|
| 701 | pMachineNode->toMachineNode()->id());
|
---|
| 702 | insertCloudEntityKey(guiCloudMachineKey);
|
---|
[84598] | 703 | }
|
---|
| 704 |
|
---|
[86748] | 705 | void UIChooserAbstractModel::sltHandleCloudMachineRefreshFinished()
|
---|
| 706 | {
|
---|
| 707 | /* Acquire sender: */
|
---|
| 708 | UIVirtualMachineItem *pCache = qobject_cast<UIVirtualMachineItem*>(sender());
|
---|
| 709 | AssertPtrReturnVoid(pCache);
|
---|
| 710 |
|
---|
| 711 | /* Acquire sender's ID: */
|
---|
| 712 | const QUuid uId = pCache->id();
|
---|
| 713 |
|
---|
| 714 | /* Search for a first machine node with passed ID: */
|
---|
| 715 | UIChooserNode *pMachineNode = searchMachineNode(invisibleRoot(), uId);
|
---|
| 716 |
|
---|
[86786] | 717 | /* Remove cloud machine key from the list of keys currently being updated: */
|
---|
| 718 | const UICloudEntityKey guiCloudMachineKey = UICloudEntityKey(pMachineNode->parentNode()->parentNode()->name(),
|
---|
| 719 | pMachineNode->parentNode()->name(),
|
---|
| 720 | pMachineNode->toMachineNode()->id());
|
---|
| 721 | removeCloudEntityKey(guiCloudMachineKey);
|
---|
[86748] | 722 |
|
---|
| 723 | /* Notify listeners: */
|
---|
| 724 | emit sigCloudMachineStateChange(uId);
|
---|
| 725 | }
|
---|
| 726 |
|
---|
[84598] | 727 | void UIChooserAbstractModel::sltGroupSettingsSaveComplete()
|
---|
| 728 | {
|
---|
| 729 | makeSureGroupSettingsSaveIsFinished();
|
---|
| 730 | emit sigGroupSavingStateChanged();
|
---|
| 731 | }
|
---|
| 732 |
|
---|
| 733 | void UIChooserAbstractModel::sltGroupDefinitionsSaveComplete()
|
---|
| 734 | {
|
---|
| 735 | makeSureGroupDefinitionsSaveIsFinished();
|
---|
| 736 | emit sigGroupSavingStateChanged();
|
---|
| 737 | }
|
---|
| 738 |
|
---|
[84186] | 739 | void UIChooserAbstractModel::sltLocalMachineStateChanged(const QUuid &uMachineId, const KMachineState)
|
---|
[77890] | 740 | {
|
---|
| 741 | /* Update machine-nodes with passed id: */
|
---|
[77909] | 742 | invisibleRoot()->updateAllNodes(uMachineId);
|
---|
[77890] | 743 | }
|
---|
| 744 |
|
---|
[84186] | 745 | void UIChooserAbstractModel::sltLocalMachineDataChanged(const QUuid &uMachineId)
|
---|
[77890] | 746 | {
|
---|
| 747 | /* Update machine-nodes with passed id: */
|
---|
[77909] | 748 | invisibleRoot()->updateAllNodes(uMachineId);
|
---|
[77890] | 749 | }
|
---|
| 750 |
|
---|
[86572] | 751 | void UIChooserAbstractModel::sltLocalMachineRegistrationChanged(const QUuid &uMachineId, const bool fRegistered)
|
---|
[77890] | 752 | {
|
---|
| 753 | /* Existing VM unregistered? */
|
---|
| 754 | if (!fRegistered)
|
---|
| 755 | {
|
---|
| 756 | /* Remove machine-items with passed id: */
|
---|
[77909] | 757 | invisibleRoot()->removeAllNodes(uMachineId);
|
---|
[77890] | 758 | /* Wipe out empty groups: */
|
---|
| 759 | wipeOutEmptyGroups();
|
---|
| 760 | }
|
---|
| 761 | /* New VM registered? */
|
---|
| 762 | else
|
---|
| 763 | {
|
---|
| 764 | /* Should we show this VM? */
|
---|
[77909] | 765 | if (gEDataManager->showMachineInVirtualBoxManagerChooser(uMachineId))
|
---|
[77890] | 766 | {
|
---|
| 767 | /* Add new machine-item: */
|
---|
[79365] | 768 | const CMachine comMachine = uiCommon().virtualBox().FindMachine(uMachineId.toString());
|
---|
[92028] | 769 | if (comMachine.isNotNull())
|
---|
| 770 | addLocalMachineIntoTheTree(comMachine, true /* make it visible */);
|
---|
[77890] | 771 | }
|
---|
| 772 | }
|
---|
| 773 | }
|
---|
| 774 |
|
---|
[97605] | 775 | void UIChooserAbstractModel::sltLocalMachineGroupsChanged(const QUuid &uMachineId)
|
---|
| 776 | {
|
---|
| 777 | /* Skip VM if restricted: */
|
---|
| 778 | if (!gEDataManager->showMachineInVirtualBoxManagerChooser(uMachineId))
|
---|
| 779 | return;
|
---|
| 780 |
|
---|
| 781 | /* Search for cached group list: */
|
---|
| 782 | const QStringList oldGroupList = m_groups.value(toOldStyleUuid(uMachineId));
|
---|
| 783 | //printf("Old groups for VM with ID=%s: %s\n",
|
---|
| 784 | // uMachineId.toString().toUtf8().constData(),
|
---|
| 785 | // oldGroupList.join(", ").toUtf8().constData());
|
---|
| 786 |
|
---|
| 787 | /* Search for existing registered machine: */
|
---|
| 788 | const CMachine comMachine = uiCommon().virtualBox().FindMachine(uMachineId.toString());
|
---|
| 789 | if (comMachine.isNull())
|
---|
| 790 | return;
|
---|
| 791 | /* Look for a new group list: */
|
---|
| 792 | const QStringList newGroupList = comMachine.GetGroups().toList();
|
---|
| 793 | //printf("New groups for VM with ID=%s: %s\n",
|
---|
| 794 | // uMachineId.toString().toUtf8().constData(),
|
---|
| 795 | // newGroupList.join(", ").toUtf8().constData());
|
---|
| 796 |
|
---|
| 797 | /* Re-register VM if required: */
|
---|
[97606] | 798 | QSet<QString> newGroupSet(newGroupList.begin(), newGroupList.end());
|
---|
| 799 | QSet<QString> oldGroupSet(oldGroupList.begin(), oldGroupList.end());
|
---|
| 800 | if (newGroupSet != oldGroupSet)
|
---|
[97605] | 801 | {
|
---|
| 802 | sltLocalMachineRegistrationChanged(uMachineId, false);
|
---|
| 803 | sltLocalMachineRegistrationChanged(uMachineId, true);
|
---|
| 804 | }
|
---|
| 805 | }
|
---|
| 806 |
|
---|
[86605] | 807 | void UIChooserAbstractModel::sltSessionStateChanged(const QUuid &uMachineId, const KSessionState)
|
---|
| 808 | {
|
---|
| 809 | /* Update machine-nodes with passed id: */
|
---|
| 810 | invisibleRoot()->updateAllNodes(uMachineId);
|
---|
| 811 | }
|
---|
| 812 |
|
---|
| 813 | void UIChooserAbstractModel::sltSnapshotChanged(const QUuid &uMachineId, const QUuid &)
|
---|
| 814 | {
|
---|
| 815 | /* Update machine-nodes with passed id: */
|
---|
| 816 | invisibleRoot()->updateAllNodes(uMachineId);
|
---|
| 817 | }
|
---|
| 818 |
|
---|
| 819 | void UIChooserAbstractModel::sltHandleCloudProviderUninstall(const QUuid &uProviderId)
|
---|
| 820 | {
|
---|
[90698] | 821 | /* First of all, stop all cloud updates: */
|
---|
| 822 | stopCloudUpdates();
|
---|
[86756] | 823 |
|
---|
[86746] | 824 | /* Search and delete corresponding cloud provider node if present: */
|
---|
| 825 | delete searchProviderNode(uProviderId);
|
---|
[86605] | 826 | }
|
---|
| 827 |
|
---|
| 828 | void UIChooserAbstractModel::sltReloadMachine(const QUuid &uMachineId)
|
---|
| 829 | {
|
---|
| 830 | /* Remove machine-items with passed id: */
|
---|
| 831 | invisibleRoot()->removeAllNodes(uMachineId);
|
---|
| 832 | /* Wipe out empty groups: */
|
---|
| 833 | wipeOutEmptyGroups();
|
---|
| 834 |
|
---|
| 835 | /* Should we show this VM? */
|
---|
| 836 | if (gEDataManager->showMachineInVirtualBoxManagerChooser(uMachineId))
|
---|
| 837 | {
|
---|
| 838 | /* Add new machine-item: */
|
---|
| 839 | const CMachine comMachine = uiCommon().virtualBox().FindMachine(uMachineId.toString());
|
---|
| 840 | addLocalMachineIntoTheTree(comMachine, true /* make it visible */);
|
---|
| 841 | }
|
---|
| 842 | }
|
---|
| 843 |
|
---|
[94086] | 844 | void UIChooserAbstractModel::sltCommitData()
|
---|
[88681] | 845 | {
|
---|
[94085] | 846 | /* Finally, stop all cloud updates: */
|
---|
| 847 | stopCloudUpdates(true /* forced? */);
|
---|
[94086] | 848 | }
|
---|
[94085] | 849 |
|
---|
[94086] | 850 | void UIChooserAbstractModel::sltDetachCOM()
|
---|
| 851 | {
|
---|
[88681] | 852 | /* Delete tree: */
|
---|
| 853 | delete m_pInvisibleRootNode;
|
---|
| 854 | m_pInvisibleRootNode = 0;
|
---|
| 855 | }
|
---|
| 856 |
|
---|
[86608] | 857 | void UIChooserAbstractModel::sltCloudMachineUnregistered(const QString &strProviderShortName,
|
---|
| 858 | const QString &strProfileName,
|
---|
| 859 | const QUuid &uId)
|
---|
[86573] | 860 | {
|
---|
| 861 | /* Search for profile node: */
|
---|
[86665] | 862 | UIChooserNode *pProfileNode = searchProfileNode(strProviderShortName, strProfileName);
|
---|
[86606] | 863 | if (!pProfileNode)
|
---|
| 864 | return;
|
---|
[86573] | 865 |
|
---|
[86608] | 866 | /* Remove machine-item with passed uId: */
|
---|
| 867 | pProfileNode->removeAllNodes(uId);
|
---|
[86573] | 868 |
|
---|
[86608] | 869 | /* If there are no items left => add fake cloud VM node: */
|
---|
| 870 | if (pProfileNode->nodes(UIChooserNodeType_Machine).isEmpty())
|
---|
[86664] | 871 | createCloudMachineNode(pProfileNode, UIFakeCloudVirtualMachineItemState_Done);
|
---|
[86573] | 872 | }
|
---|
| 873 |
|
---|
[86611] | 874 | void UIChooserAbstractModel::sltCloudMachinesUnregistered(const QString &strProviderShortName,
|
---|
| 875 | const QString &strProfileName,
|
---|
| 876 | const QList<QUuid> &ids)
|
---|
| 877 | {
|
---|
| 878 | /* Search for profile node: */
|
---|
[86665] | 879 | UIChooserNode *pProfileNode = searchProfileNode(strProviderShortName, strProfileName);
|
---|
[86611] | 880 | if (!pProfileNode)
|
---|
| 881 | return;
|
---|
| 882 |
|
---|
| 883 | /* Remove machine-items with passed id: */
|
---|
| 884 | foreach (const QUuid &uId, ids)
|
---|
| 885 | pProfileNode->removeAllNodes(uId);
|
---|
| 886 |
|
---|
| 887 | /* If there are no items left => add fake cloud VM node: */
|
---|
| 888 | if (pProfileNode->nodes(UIChooserNodeType_Machine).isEmpty())
|
---|
[86664] | 889 | createCloudMachineNode(pProfileNode, UIFakeCloudVirtualMachineItemState_Done);
|
---|
[86611] | 890 | }
|
---|
| 891 |
|
---|
[86608] | 892 | void UIChooserAbstractModel::sltCloudMachineRegistered(const QString &strProviderShortName,
|
---|
| 893 | const QString &strProfileName,
|
---|
| 894 | const CCloudMachine &comMachine)
|
---|
[83705] | 895 | {
|
---|
[84598] | 896 | /* Search for profile node: */
|
---|
[86665] | 897 | UIChooserNode *pProfileNode = searchProfileNode(strProviderShortName, strProfileName);
|
---|
[86606] | 898 | if (!pProfileNode)
|
---|
| 899 | return;
|
---|
[83920] | 900 |
|
---|
[86678] | 901 | /* Compose corresponding group path: */
|
---|
| 902 | const QString strGroup = QString("/%1/%2").arg(strProviderShortName, strProfileName);
|
---|
| 903 | /* Make sure there is no VM with such ID already: */
|
---|
| 904 | QUuid uId;
|
---|
| 905 | if (!cloudMachineId(comMachine, uId))
|
---|
| 906 | return;
|
---|
| 907 | if (checkIfNodeContainChildWithId(pProfileNode, uId))
|
---|
| 908 | return;
|
---|
[86608] | 909 | /* Add new machine-item: */
|
---|
[86665] | 910 | addCloudMachineIntoTheTree(strGroup, comMachine, true /* make it visible? */);
|
---|
[83930] | 911 |
|
---|
[86608] | 912 | /* Delete fake node if present: */
|
---|
[86665] | 913 | delete searchFakeNode(pProfileNode);
|
---|
[83705] | 914 | }
|
---|
| 915 |
|
---|
[86611] | 916 | void UIChooserAbstractModel::sltCloudMachinesRegistered(const QString &strProviderShortName,
|
---|
| 917 | const QString &strProfileName,
|
---|
| 918 | const QVector<CCloudMachine> &machines)
|
---|
| 919 | {
|
---|
| 920 | /* Search for profile node: */
|
---|
[86665] | 921 | UIChooserNode *pProfileNode = searchProfileNode(strProviderShortName, strProfileName);
|
---|
[86611] | 922 | if (!pProfileNode)
|
---|
| 923 | return;
|
---|
| 924 |
|
---|
[86678] | 925 | /* Compose corresponding group path: */
|
---|
[86665] | 926 | const QString strGroup = QString("/%1/%2").arg(strProviderShortName, strProfileName);
|
---|
[86611] | 927 | foreach (const CCloudMachine &comMachine, machines)
|
---|
[86678] | 928 | {
|
---|
| 929 | /* Make sure there is no VM with such ID already: */
|
---|
| 930 | QUuid uId;
|
---|
| 931 | if (!cloudMachineId(comMachine, uId))
|
---|
| 932 | continue;
|
---|
| 933 | if (checkIfNodeContainChildWithId(pProfileNode, uId))
|
---|
| 934 | continue;
|
---|
| 935 | /* Add new machine-item: */
|
---|
[86665] | 936 | addCloudMachineIntoTheTree(strGroup, comMachine, false /* make it visible? */);
|
---|
[86678] | 937 | }
|
---|
[86611] | 938 |
|
---|
| 939 | /* Delete fake node if present: */
|
---|
[86665] | 940 | delete searchFakeNode(pProfileNode);
|
---|
[86611] | 941 | }
|
---|
| 942 |
|
---|
[86795] | 943 | void UIChooserAbstractModel::sltHandleReadCloudMachineListTaskComplete()
|
---|
[83008] | 944 | {
|
---|
[86795] | 945 | /* Parse task result: */
|
---|
| 946 | UIProgressTaskReadCloudMachineList *pSender = qobject_cast<UIProgressTaskReadCloudMachineList*>(sender());
|
---|
| 947 | AssertPtrReturnVoid(pSender);
|
---|
| 948 | const UICloudEntityKey guiCloudProfileKey = pSender->cloudProfileKey();
|
---|
| 949 | const QVector<CCloudMachine> machines = pSender->machines();
|
---|
[86910] | 950 | const QString strErrorMessage = pSender->errorMessage();
|
---|
[86795] | 951 |
|
---|
| 952 | /* Delete task: */
|
---|
| 953 | delete pSender;
|
---|
| 954 |
|
---|
| 955 | /* Check whether this task was expected: */
|
---|
| 956 | if (!containsCloudEntityKey(guiCloudProfileKey))
|
---|
[83008] | 957 | return;
|
---|
| 958 |
|
---|
[86803] | 959 | /* Search for provider node separately, it can be removed already: */
|
---|
| 960 | UIChooserNode *pProviderNode = searchProviderNode(guiCloudProfileKey.m_strProviderShortName);
|
---|
| 961 | if (pProviderNode)
|
---|
[83276] | 962 | {
|
---|
[86803] | 963 | /* Search for profile node separately, it can be hidden at all: */
|
---|
| 964 | UIChooserNode *pProfileNode = searchProfileNode(pProviderNode, guiCloudProfileKey.m_strProfileName);
|
---|
| 965 | if (pProfileNode)
|
---|
| 966 | {
|
---|
| 967 | /* Compose old set of machine IDs: */
|
---|
| 968 | QSet<QUuid> oldIDs;
|
---|
| 969 | foreach (UIChooserNode *pNode, pProfileNode->nodes(UIChooserNodeType_Machine))
|
---|
| 970 | {
|
---|
| 971 | AssertPtrReturnVoid(pNode);
|
---|
| 972 | UIChooserNodeMachine *pNodeMachine = pNode->toMachineNode();
|
---|
| 973 | AssertPtrReturnVoid(pNodeMachine);
|
---|
| 974 | if (pNodeMachine->cacheType() != UIVirtualMachineItemType_CloudReal)
|
---|
| 975 | continue;
|
---|
| 976 | oldIDs << pNodeMachine->id();
|
---|
| 977 | }
|
---|
| 978 | /* Compose new set of machine IDs and map of machines: */
|
---|
| 979 | QSet<QUuid> newIDs;
|
---|
| 980 | QMap<QUuid, CCloudMachine> newMachines;
|
---|
| 981 | foreach (const CCloudMachine &comMachine, machines)
|
---|
| 982 | {
|
---|
| 983 | QUuid uId;
|
---|
| 984 | AssertReturnVoid(cloudMachineId(comMachine, uId));
|
---|
| 985 | newMachines[uId] = comMachine;
|
---|
| 986 | newIDs << uId;
|
---|
| 987 | }
|
---|
[86611] | 988 |
|
---|
[86803] | 989 | /* Calculate set of unregistered/registered IDs: */
|
---|
| 990 | const QSet<QUuid> unregisteredIDs = oldIDs - newIDs;
|
---|
| 991 | const QSet<QUuid> registeredIDs = newIDs - oldIDs;
|
---|
| 992 | QVector<CCloudMachine> registeredMachines;
|
---|
| 993 | foreach (const QUuid &uId, registeredIDs)
|
---|
| 994 | registeredMachines << newMachines.value(uId);
|
---|
[86611] | 995 |
|
---|
[86803] | 996 | /* Remove unregistered cloud VM nodes: */
|
---|
| 997 | if (!unregisteredIDs.isEmpty())
|
---|
[94029] | 998 | {
|
---|
| 999 | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
---|
| 1000 | QList<QUuid> listUnregisteredIDs(unregisteredIDs.begin(), unregisteredIDs.end());
|
---|
| 1001 | #else
|
---|
| 1002 | QList<QUuid> listUnregisteredIDs = unregisteredIDs.toList();
|
---|
| 1003 | #endif
|
---|
[86803] | 1004 | sltCloudMachinesUnregistered(guiCloudProfileKey.m_strProviderShortName,
|
---|
| 1005 | guiCloudProfileKey.m_strProfileName,
|
---|
[94029] | 1006 | listUnregisteredIDs);
|
---|
| 1007 | }
|
---|
[86803] | 1008 | /* Add registered cloud VM nodes: */
|
---|
| 1009 | if (!registeredMachines.isEmpty())
|
---|
| 1010 | sltCloudMachinesRegistered(guiCloudProfileKey.m_strProviderShortName,
|
---|
| 1011 | guiCloudProfileKey.m_strProfileName,
|
---|
| 1012 | registeredMachines);
|
---|
| 1013 | /* If we changed nothing and have nothing currently: */
|
---|
| 1014 | if (unregisteredIDs.isEmpty() && newIDs.isEmpty())
|
---|
| 1015 | {
|
---|
| 1016 | /* We should update at least fake cloud machine node: */
|
---|
| 1017 | UIChooserNode *pFakeNode = searchFakeNode(pProfileNode);
|
---|
| 1018 | AssertPtrReturnVoid(pFakeNode);
|
---|
[86910] | 1019 | UIVirtualMachineItemCloud *pFakeMachineItem = pFakeNode->toMachineNode()->cache()->toCloud();
|
---|
| 1020 | AssertPtrReturnVoid(pFakeMachineItem);
|
---|
| 1021 | pFakeMachineItem->setFakeCloudItemState(UIFakeCloudVirtualMachineItemState_Done);
|
---|
| 1022 | pFakeMachineItem->setFakeCloudItemErrorMessage(strErrorMessage);
|
---|
[86909] | 1023 | if (pFakeNode->item())
|
---|
| 1024 | pFakeNode->item()->updateItem();
|
---|
[86803] | 1025 | }
|
---|
| 1026 | }
|
---|
[86708] | 1027 | }
|
---|
[86630] | 1028 |
|
---|
[86731] | 1029 | /* Remove cloud entity key from the list of keys currently being updated: */
|
---|
[86795] | 1030 | removeCloudEntityKey(guiCloudProfileKey);
|
---|
[103023] | 1031 |
|
---|
| 1032 | /* Notify listeners: */
|
---|
| 1033 | emit sigCloudProfileStateChange(guiCloudProfileKey.m_strProviderShortName,
|
---|
| 1034 | guiCloudProfileKey.m_strProfileName);
|
---|
[83008] | 1035 | }
|
---|
| 1036 |
|
---|
[86544] | 1037 | void UIChooserAbstractModel::sltHandleCloudProfileManagerCumulativeChange()
|
---|
[85038] | 1038 | {
|
---|
| 1039 | /* Reload cloud tree: */
|
---|
| 1040 | reloadCloudTree();
|
---|
| 1041 | }
|
---|
| 1042 |
|
---|
[86787] | 1043 | void UIChooserAbstractModel::createReadCloudMachineListTask(const UICloudEntityKey &guiCloudProfileKey, bool fWithRefresh)
|
---|
| 1044 | {
|
---|
[86795] | 1045 | /* Do not create task if already registered: */
|
---|
| 1046 | if (containsCloudEntityKey(guiCloudProfileKey))
|
---|
| 1047 | return;
|
---|
| 1048 |
|
---|
| 1049 | /* Create task: */
|
---|
| 1050 | UIProgressTaskReadCloudMachineList *pTask = new UIProgressTaskReadCloudMachineList(this,
|
---|
| 1051 | guiCloudProfileKey,
|
---|
| 1052 | fWithRefresh);
|
---|
| 1053 | if (pTask)
|
---|
| 1054 | {
|
---|
[86804] | 1055 | /* It's easy to find child by name later: */
|
---|
| 1056 | pTask->setObjectName(guiCloudProfileKey.toString());
|
---|
| 1057 |
|
---|
[86795] | 1058 | /* Insert cloud profile key into a list of keys currently being updated: */
|
---|
| 1059 | insertCloudEntityKey(guiCloudProfileKey);
|
---|
| 1060 |
|
---|
| 1061 | /* Connect and start it finally: */
|
---|
| 1062 | connect(pTask, &UIProgressTaskReadCloudMachineList::sigProgressFinished,
|
---|
| 1063 | this, &UIChooserAbstractModel::sltHandleReadCloudMachineListTaskComplete);
|
---|
| 1064 | pTask->start();
|
---|
| 1065 | }
|
---|
[86787] | 1066 | }
|
---|
| 1067 |
|
---|
[88586] | 1068 | void UIChooserAbstractModel::sltSaveSettings()
|
---|
[86786] | 1069 | {
|
---|
| 1070 | saveGroupSettings();
|
---|
| 1071 | saveGroupDefinitions();
|
---|
| 1072 | }
|
---|
| 1073 |
|
---|
[77890] | 1074 | void UIChooserAbstractModel::prepare()
|
---|
| 1075 | {
|
---|
| 1076 | prepareConnections();
|
---|
| 1077 | }
|
---|
| 1078 |
|
---|
| 1079 | void UIChooserAbstractModel::prepareConnections()
|
---|
| 1080 | {
|
---|
[88586] | 1081 | /* UICommon connections: */
|
---|
[94086] | 1082 | connect(&uiCommon(), &UICommon::sigAskToCommitData,
|
---|
| 1083 | this, &UIChooserAbstractModel::sltCommitData);
|
---|
[88681] | 1084 | connect(&uiCommon(), &UICommon::sigAskToDetachCOM,
|
---|
| 1085 | this, &UIChooserAbstractModel::sltDetachCOM);
|
---|
[86608] | 1086 | connect(&uiCommon(), &UICommon::sigCloudMachineUnregistered,
|
---|
| 1087 | this, &UIChooserAbstractModel::sltCloudMachineUnregistered);
|
---|
[83858] | 1088 | connect(&uiCommon(), &UICommon::sigCloudMachineRegistered,
|
---|
[86573] | 1089 | this, &UIChooserAbstractModel::sltCloudMachineRegistered);
|
---|
[83858] | 1090 |
|
---|
[86788] | 1091 | /* Global connections: */
|
---|
[77892] | 1092 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineStateChange,
|
---|
[84186] | 1093 | this, &UIChooserAbstractModel::sltLocalMachineStateChanged);
|
---|
[77892] | 1094 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineDataChange,
|
---|
[84186] | 1095 | this, &UIChooserAbstractModel::sltLocalMachineDataChanged);
|
---|
[77892] | 1096 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineRegistered,
|
---|
[86572] | 1097 | this, &UIChooserAbstractModel::sltLocalMachineRegistrationChanged);
|
---|
[97605] | 1098 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineGroupsChange,
|
---|
| 1099 | this, &UIChooserAbstractModel::sltLocalMachineGroupsChanged);
|
---|
[77892] | 1100 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigSessionStateChange,
|
---|
| 1101 | this, &UIChooserAbstractModel::sltSessionStateChanged);
|
---|
| 1102 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigSnapshotTake,
|
---|
| 1103 | this, &UIChooserAbstractModel::sltSnapshotChanged);
|
---|
| 1104 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigSnapshotDelete,
|
---|
| 1105 | this, &UIChooserAbstractModel::sltSnapshotChanged);
|
---|
| 1106 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigSnapshotChange,
|
---|
| 1107 | this, &UIChooserAbstractModel::sltSnapshotChanged);
|
---|
| 1108 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigSnapshotRestore,
|
---|
| 1109 | this, &UIChooserAbstractModel::sltSnapshotChanged);
|
---|
[86077] | 1110 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigCloudProviderListChanged,
|
---|
[86544] | 1111 | this, &UIChooserAbstractModel::sltHandleCloudProfileManagerCumulativeChange);
|
---|
[86545] | 1112 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigCloudProfileRegistered,
|
---|
| 1113 | this, &UIChooserAbstractModel::sltHandleCloudProfileManagerCumulativeChange);
|
---|
| 1114 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigCloudProfileChanged,
|
---|
| 1115 | this, &UIChooserAbstractModel::sltHandleCloudProfileManagerCumulativeChange);
|
---|
[86077] | 1116 | connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigCloudProviderUninstall,
|
---|
| 1117 | this, &UIChooserAbstractModel::sltHandleCloudProviderUninstall);
|
---|
[77890] | 1118 |
|
---|
[88586] | 1119 | /* Settings saving connections: */
|
---|
| 1120 | connect(this, &UIChooserAbstractModel::sigSaveSettings,
|
---|
| 1121 | this, &UIChooserAbstractModel::sltSaveSettings,
|
---|
[77890] | 1122 | Qt::QueuedConnection);
|
---|
[85038] | 1123 |
|
---|
[86788] | 1124 | /* Extra-data connections: */
|
---|
[85038] | 1125 | connect(gEDataManager, &UIExtraDataManager::sigCloudProfileManagerRestrictionChange,
|
---|
[86544] | 1126 | this, &UIChooserAbstractModel::sltHandleCloudProfileManagerCumulativeChange);
|
---|
[77890] | 1127 | }
|
---|
| 1128 |
|
---|
[86788] | 1129 | void UIChooserAbstractModel::cleanupConnections()
|
---|
| 1130 | {
|
---|
[88652] | 1131 | /* Group saving connections: */
|
---|
[88586] | 1132 | disconnect(this, &UIChooserAbstractModel::sigSaveSettings,
|
---|
| 1133 | this, &UIChooserAbstractModel::sltSaveSettings);
|
---|
[86788] | 1134 | }
|
---|
| 1135 |
|
---|
| 1136 | void UIChooserAbstractModel::cleanup()
|
---|
| 1137 | {
|
---|
| 1138 | cleanupConnections();
|
---|
| 1139 | }
|
---|
| 1140 |
|
---|
[85036] | 1141 | void UIChooserAbstractModel::reloadLocalTree()
|
---|
| 1142 | {
|
---|
| 1143 | LogRelFlow(("UIChooserAbstractModel: Loading local VMs...\n"));
|
---|
| 1144 |
|
---|
| 1145 | /* Acquire VBox: */
|
---|
| 1146 | const CVirtualBox comVBox = uiCommon().virtualBox();
|
---|
| 1147 |
|
---|
| 1148 | /* Acquire existing local machines: */
|
---|
| 1149 | const QVector<CMachine> machines = comVBox.GetMachines();
|
---|
| 1150 | /* Show error message if necessary: */
|
---|
| 1151 | if (!comVBox.isOk())
|
---|
[91094] | 1152 | UINotificationMessage::cannotAcquireVirtualBoxParameter(comVBox);
|
---|
[85036] | 1153 | else
|
---|
| 1154 | {
|
---|
| 1155 | /* Iterate through existing machines: */
|
---|
| 1156 | foreach (const CMachine &comMachine, machines)
|
---|
| 1157 | {
|
---|
| 1158 | /* Skip if we have nothing to populate (wtf happened?): */
|
---|
| 1159 | if (comMachine.isNull())
|
---|
| 1160 | continue;
|
---|
| 1161 |
|
---|
| 1162 | /* Get machine ID: */
|
---|
| 1163 | const QUuid uMachineID = comMachine.GetId();
|
---|
| 1164 | /* Show error message if necessary: */
|
---|
| 1165 | if (!comMachine.isOk())
|
---|
| 1166 | {
|
---|
[91094] | 1167 | UINotificationMessage::cannotAcquireMachineParameter(comMachine);
|
---|
[85036] | 1168 | continue;
|
---|
| 1169 | }
|
---|
| 1170 |
|
---|
| 1171 | /* Skip if we have nothing to show (wtf happened?): */
|
---|
| 1172 | if (uMachineID.isNull())
|
---|
| 1173 | continue;
|
---|
| 1174 |
|
---|
| 1175 | /* Skip if machine is restricted from being shown: */
|
---|
| 1176 | if (!gEDataManager->showMachineInVirtualBoxManagerChooser(uMachineID))
|
---|
| 1177 | continue;
|
---|
| 1178 |
|
---|
| 1179 | /* Add machine into tree: */
|
---|
| 1180 | addLocalMachineIntoTheTree(comMachine);
|
---|
| 1181 | }
|
---|
| 1182 | }
|
---|
| 1183 |
|
---|
| 1184 | LogRelFlow(("UIChooserAbstractModel: Local VMs loaded.\n"));
|
---|
| 1185 | }
|
---|
| 1186 |
|
---|
| 1187 | void UIChooserAbstractModel::reloadCloudTree()
|
---|
| 1188 | {
|
---|
| 1189 | LogRelFlow(("UIChooserAbstractModel: Loading cloud providers/profiles...\n"));
|
---|
| 1190 |
|
---|
[85038] | 1191 | /* Wipe out existing cloud providers first.
|
---|
| 1192 | * This is quite rude, in future we need to reimplement it more wise.. */
|
---|
| 1193 | foreach (UIChooserNode *pNode, invisibleRoot()->nodes(UIChooserNodeType_Group))
|
---|
| 1194 | {
|
---|
| 1195 | AssertPtrReturnVoid(pNode);
|
---|
| 1196 | UIChooserNodeGroup *pGroupNode = pNode->toGroupNode();
|
---|
| 1197 | AssertPtrReturnVoid(pGroupNode);
|
---|
| 1198 | if (pGroupNode->groupType() == UIChooserNodeGroupType_Provider)
|
---|
| 1199 | delete pNode;
|
---|
| 1200 | }
|
---|
| 1201 |
|
---|
[85037] | 1202 | /* Acquire Cloud Profile Manager restrictions: */
|
---|
| 1203 | const QStringList restrictions = gEDataManager->cloudProfileManagerRestrictions();
|
---|
| 1204 |
|
---|
[85036] | 1205 | /* Iterate through existing providers: */
|
---|
| 1206 | foreach (CCloudProvider comCloudProvider, listCloudProviders())
|
---|
| 1207 | {
|
---|
| 1208 | /* Skip if we have nothing to populate: */
|
---|
| 1209 | if (comCloudProvider.isNull())
|
---|
| 1210 | continue;
|
---|
| 1211 |
|
---|
[86077] | 1212 | /* Acquire provider id: */
|
---|
| 1213 | QUuid uProviderId;
|
---|
| 1214 | if (!cloudProviderId(comCloudProvider, uProviderId))
|
---|
| 1215 | continue;
|
---|
| 1216 |
|
---|
[85036] | 1217 | /* Acquire provider short name: */
|
---|
| 1218 | QString strProviderShortName;
|
---|
| 1219 | if (!cloudProviderShortName(comCloudProvider, strProviderShortName))
|
---|
| 1220 | continue;
|
---|
| 1221 |
|
---|
[85037] | 1222 | /* Make sure this provider isn't restricted: */
|
---|
| 1223 | const QString strProviderPath = QString("/%1").arg(strProviderShortName);
|
---|
| 1224 | if (restrictions.contains(strProviderPath))
|
---|
| 1225 | continue;
|
---|
| 1226 |
|
---|
[85036] | 1227 | /* Acquire list of profiles: */
|
---|
| 1228 | const QVector<CCloudProfile> profiles = listCloudProfiles(comCloudProvider);
|
---|
| 1229 | if (profiles.isEmpty())
|
---|
| 1230 | continue;
|
---|
| 1231 |
|
---|
| 1232 | /* Add provider group node: */
|
---|
| 1233 | UIChooserNodeGroup *pProviderNode =
|
---|
| 1234 | new UIChooserNodeGroup(invisibleRoot() /* parent */,
|
---|
| 1235 | getDesiredNodePosition(invisibleRoot(),
|
---|
| 1236 | UIChooserNodeDataPrefixType_Provider,
|
---|
| 1237 | strProviderShortName),
|
---|
[86742] | 1238 | uProviderId,
|
---|
| 1239 | strProviderShortName,
|
---|
| 1240 | UIChooserNodeGroupType_Provider,
|
---|
[85036] | 1241 | shouldGroupNodeBeOpened(invisibleRoot(),
|
---|
| 1242 | UIChooserNodeDataPrefixType_Provider,
|
---|
[86742] | 1243 | strProviderShortName));
|
---|
[85036] | 1244 |
|
---|
| 1245 | /* Iterate through provider's profiles: */
|
---|
| 1246 | foreach (CCloudProfile comCloudProfile, profiles)
|
---|
| 1247 | {
|
---|
| 1248 | /* Skip if we have nothing to populate: */
|
---|
| 1249 | if (comCloudProfile.isNull())
|
---|
| 1250 | continue;
|
---|
| 1251 |
|
---|
| 1252 | /* Acquire profile name: */
|
---|
| 1253 | QString strProfileName;
|
---|
| 1254 | if (!cloudProfileName(comCloudProfile, strProfileName))
|
---|
| 1255 | continue;
|
---|
| 1256 |
|
---|
[85037] | 1257 | /* Make sure this profile isn't restricted: */
|
---|
| 1258 | const QString strProfilePath = QString("/%1/%2").arg(strProviderShortName, strProfileName);
|
---|
| 1259 | if (restrictions.contains(strProfilePath))
|
---|
| 1260 | continue;
|
---|
| 1261 |
|
---|
[85036] | 1262 | /* Add profile sub-group node: */
|
---|
| 1263 | UIChooserNodeGroup *pProfileNode =
|
---|
| 1264 | new UIChooserNodeGroup(pProviderNode /* parent */,
|
---|
| 1265 | getDesiredNodePosition(pProviderNode,
|
---|
| 1266 | UIChooserNodeDataPrefixType_Profile,
|
---|
| 1267 | strProfileName),
|
---|
[86742] | 1268 | QUuid() /* id */,
|
---|
| 1269 | strProfileName,
|
---|
| 1270 | UIChooserNodeGroupType_Profile,
|
---|
[85036] | 1271 | shouldGroupNodeBeOpened(pProviderNode,
|
---|
| 1272 | UIChooserNodeDataPrefixType_Profile,
|
---|
[86742] | 1273 | strProfileName));
|
---|
[85036] | 1274 |
|
---|
| 1275 | /* Add fake cloud VM item: */
|
---|
[86664] | 1276 | createCloudMachineNode(pProfileNode, UIFakeCloudVirtualMachineItemState_Loading);
|
---|
[85036] | 1277 |
|
---|
[86795] | 1278 | /* Create read cloud machine list task: */
|
---|
[86786] | 1279 | const UICloudEntityKey guiCloudProfileKey = UICloudEntityKey(strProviderShortName, strProfileName);
|
---|
[86787] | 1280 | createReadCloudMachineListTask(guiCloudProfileKey, true /* with refresh? */);
|
---|
[85036] | 1281 | }
|
---|
| 1282 | }
|
---|
| 1283 |
|
---|
| 1284 | LogRelFlow(("UIChooserAbstractModel: Cloud providers/profiles loaded.\n"));
|
---|
| 1285 | }
|
---|
| 1286 |
|
---|
[83698] | 1287 | void UIChooserAbstractModel::addLocalMachineIntoTheTree(const CMachine &comMachine,
|
---|
| 1288 | bool fMakeItVisible /* = false */)
|
---|
[77890] | 1289 | {
|
---|
| 1290 | /* Make sure passed VM is not NULL: */
|
---|
| 1291 | if (comMachine.isNull())
|
---|
[83698] | 1292 | LogRelFlow(("UIChooserModel: ERROR: Passed local VM is NULL!\n"));
|
---|
[77890] | 1293 | AssertReturnVoid(!comMachine.isNull());
|
---|
| 1294 |
|
---|
| 1295 | /* Which VM we are loading: */
|
---|
[83705] | 1296 | const QUuid uId = comMachine.GetId();
|
---|
[83698] | 1297 | LogRelFlow(("UIChooserModel: Loading local VM with ID={%s}...\n",
|
---|
[83705] | 1298 | toOldStyleUuid(uId).toUtf8().constData()));
|
---|
[84598] | 1299 |
|
---|
[77890] | 1300 | /* Is that machine accessible? */
|
---|
| 1301 | if (comMachine.GetAccessible())
|
---|
| 1302 | {
|
---|
[83698] | 1303 | /* Acquire VM name: */
|
---|
[77890] | 1304 | const QString strName = comMachine.GetName();
|
---|
[83698] | 1305 | LogRelFlow(("UIChooserModel: Local VM {%s} is accessible.\n", strName.toUtf8().constData()));
|
---|
[77890] | 1306 | /* Which groups passed machine attached to? */
|
---|
| 1307 | const QVector<QString> groups = comMachine.GetGroups();
|
---|
| 1308 | const QStringList groupList = groups.toList();
|
---|
| 1309 | const QString strGroups = groupList.join(", ");
|
---|
[83698] | 1310 | LogRelFlow(("UIChooserModel: Local VM {%s} has groups: {%s}.\n",
|
---|
| 1311 | strName.toUtf8().constData(), strGroups.toUtf8().constData()));
|
---|
[77890] | 1312 | foreach (QString strGroup, groups)
|
---|
| 1313 | {
|
---|
| 1314 | /* Remove last '/' if any: */
|
---|
| 1315 | if (strGroup.right(1) == "/")
|
---|
| 1316 | strGroup.truncate(strGroup.size() - 1);
|
---|
| 1317 | /* Create machine-item with found group-item as parent: */
|
---|
[83698] | 1318 | LogRelFlow(("UIChooserModel: Creating node for local VM {%s} in group {%s}.\n",
|
---|
| 1319 | strName.toUtf8().constData(), strGroup.toUtf8().constData()));
|
---|
| 1320 | createLocalMachineNode(getLocalGroupNode(strGroup, invisibleRoot(), fMakeItVisible), comMachine);
|
---|
[77890] | 1321 | }
|
---|
[84423] | 1322 | /* Update group settings: */
|
---|
[83705] | 1323 | m_groups[toOldStyleUuid(uId)] = groupList;
|
---|
[77890] | 1324 | }
|
---|
| 1325 | /* Inaccessible machine: */
|
---|
| 1326 | else
|
---|
| 1327 | {
|
---|
| 1328 | /* VM is accessible: */
|
---|
[83698] | 1329 | LogRelFlow(("UIChooserModel: Local VM {%s} is inaccessible.\n",
|
---|
[83705] | 1330 | toOldStyleUuid(uId).toUtf8().constData()));
|
---|
[77890] | 1331 | /* Create machine-item with main-root group-item as parent: */
|
---|
[83698] | 1332 | createLocalMachineNode(invisibleRoot(), comMachine);
|
---|
[77890] | 1333 | }
|
---|
| 1334 | }
|
---|
| 1335 |
|
---|
[83705] | 1336 | void UIChooserAbstractModel::addCloudMachineIntoTheTree(const QString &strGroup,
|
---|
| 1337 | const CCloudMachine &comMachine,
|
---|
| 1338 | bool fMakeItVisible /* = false */)
|
---|
| 1339 | {
|
---|
| 1340 | /* Make sure passed VM is not NULL: */
|
---|
| 1341 | if (comMachine.isNull())
|
---|
| 1342 | LogRelFlow(("UIChooserModel: ERROR: Passed cloud VM is NULL!\n"));
|
---|
| 1343 | AssertReturnVoid(!comMachine.isNull());
|
---|
| 1344 |
|
---|
| 1345 | /* Which VM we are loading: */
|
---|
| 1346 | const QUuid uId = comMachine.GetId();
|
---|
| 1347 | LogRelFlow(("UIChooserModel: Loading cloud VM with ID={%s}...\n",
|
---|
| 1348 | toOldStyleUuid(uId).toUtf8().constData()));
|
---|
[84598] | 1349 |
|
---|
[83705] | 1350 | /* Acquire VM name: */
|
---|
| 1351 | QString strName = comMachine.GetName();
|
---|
| 1352 | if (strName.isEmpty())
|
---|
| 1353 | strName = uId.toString();
|
---|
| 1354 | LogRelFlow(("UIChooserModel: Creating node for cloud VM {%s} in group {%s}.\n",
|
---|
| 1355 | strName.toUtf8().constData(), strGroup.toUtf8().constData()));
|
---|
| 1356 | /* Create machine-item with found group-item as parent: */
|
---|
| 1357 | createCloudMachineNode(getCloudGroupNode(strGroup, invisibleRoot(), fMakeItVisible), comMachine);
|
---|
[84423] | 1358 | /* Update group settings: */
|
---|
[83705] | 1359 | const QStringList groupList(strGroup);
|
---|
| 1360 | m_groups[toOldStyleUuid(uId)] = groupList;
|
---|
| 1361 | }
|
---|
| 1362 |
|
---|
[83698] | 1363 | UIChooserNode *UIChooserAbstractModel::getLocalGroupNode(const QString &strName, UIChooserNode *pParentNode, bool fAllGroupsOpened)
|
---|
[77890] | 1364 | {
|
---|
| 1365 | /* Check passed stuff: */
|
---|
| 1366 | if (pParentNode->name() == strName)
|
---|
| 1367 | return pParentNode;
|
---|
| 1368 |
|
---|
| 1369 | /* Prepare variables: */
|
---|
| 1370 | const QString strFirstSubName = strName.section('/', 0, 0);
|
---|
| 1371 | const QString strFirstSuffix = strName.section('/', 1, -1);
|
---|
| 1372 | const QString strSecondSubName = strFirstSuffix.section('/', 0, 0);
|
---|
| 1373 | const QString strSecondSuffix = strFirstSuffix.section('/', 1, -1);
|
---|
| 1374 |
|
---|
| 1375 | /* Passed group name equal to first sub-name: */
|
---|
| 1376 | if (pParentNode->name() == strFirstSubName)
|
---|
| 1377 | {
|
---|
| 1378 | /* Make sure first-suffix is NOT empty: */
|
---|
| 1379 | AssertMsg(!strFirstSuffix.isEmpty(), ("Invalid group name!"));
|
---|
| 1380 | /* Trying to get group node among our children: */
|
---|
[84400] | 1381 | foreach (UIChooserNode *pNode, pParentNode->nodes(UIChooserNodeType_Group))
|
---|
[77890] | 1382 | {
|
---|
[84400] | 1383 | AssertPtrReturn(pNode, 0);
|
---|
| 1384 | UIChooserNodeGroup *pGroupNode = pNode->toGroupNode();
|
---|
| 1385 | AssertPtrReturn(pGroupNode, 0);
|
---|
| 1386 | if ( pGroupNode->groupType() == UIChooserNodeGroupType_Local
|
---|
| 1387 | && pNode->name() == strSecondSubName)
|
---|
[77890] | 1388 | {
|
---|
[84400] | 1389 | UIChooserNode *pFoundNode = getLocalGroupNode(strFirstSuffix, pNode, fAllGroupsOpened);
|
---|
[77890] | 1390 | if (UIChooserNodeGroup *pFoundGroupNode = pFoundNode->toGroupNode())
|
---|
| 1391 | if (fAllGroupsOpened && pFoundGroupNode->isClosed())
|
---|
| 1392 | pFoundGroupNode->open();
|
---|
| 1393 | return pFoundNode;
|
---|
| 1394 | }
|
---|
| 1395 | }
|
---|
| 1396 | }
|
---|
| 1397 |
|
---|
| 1398 | /* Found nothing? Creating: */
|
---|
| 1399 | UIChooserNodeGroup *pNewGroupNode =
|
---|
| 1400 | new UIChooserNodeGroup(pParentNode,
|
---|
[84415] | 1401 | getDesiredNodePosition(pParentNode,
|
---|
| 1402 | UIChooserNodeDataPrefixType_Local,
|
---|
| 1403 | strSecondSubName),
|
---|
[86742] | 1404 | QUuid() /* id */,
|
---|
| 1405 | strSecondSubName,
|
---|
| 1406 | UIChooserNodeGroupType_Local,
|
---|
[84434] | 1407 | fAllGroupsOpened || shouldGroupNodeBeOpened(pParentNode,
|
---|
| 1408 | UIChooserNodeDataPrefixType_Local,
|
---|
[86742] | 1409 | strSecondSubName));
|
---|
[83698] | 1410 | return strSecondSuffix.isEmpty() ? pNewGroupNode : getLocalGroupNode(strFirstSuffix, pNewGroupNode, fAllGroupsOpened);
|
---|
[77890] | 1411 | }
|
---|
| 1412 |
|
---|
[83705] | 1413 | UIChooserNode *UIChooserAbstractModel::getCloudGroupNode(const QString &strName, UIChooserNode *pParentNode, bool fAllGroupsOpened)
|
---|
| 1414 | {
|
---|
| 1415 | /* Check passed stuff: */
|
---|
| 1416 | if (pParentNode->name() == strName)
|
---|
| 1417 | return pParentNode;
|
---|
| 1418 |
|
---|
| 1419 | /* Prepare variables: */
|
---|
| 1420 | const QString strFirstSubName = strName.section('/', 0, 0);
|
---|
| 1421 | const QString strFirstSuffix = strName.section('/', 1, -1);
|
---|
| 1422 | const QString strSecondSubName = strFirstSuffix.section('/', 0, 0);
|
---|
| 1423 |
|
---|
| 1424 | /* Passed group name equal to first sub-name: */
|
---|
| 1425 | if (pParentNode->name() == strFirstSubName)
|
---|
| 1426 | {
|
---|
| 1427 | /* Make sure first-suffix is NOT empty: */
|
---|
| 1428 | AssertMsg(!strFirstSuffix.isEmpty(), ("Invalid group name!"));
|
---|
| 1429 | /* Trying to get group node among our children: */
|
---|
[84400] | 1430 | foreach (UIChooserNode *pNode, pParentNode->nodes(UIChooserNodeType_Group))
|
---|
[83705] | 1431 | {
|
---|
[84400] | 1432 | AssertPtrReturn(pNode, 0);
|
---|
| 1433 | UIChooserNodeGroup *pGroupNode = pNode->toGroupNode();
|
---|
| 1434 | AssertPtrReturn(pGroupNode, 0);
|
---|
| 1435 | if ( ( pGroupNode->groupType() == UIChooserNodeGroupType_Provider
|
---|
| 1436 | || pGroupNode->groupType() == UIChooserNodeGroupType_Profile)
|
---|
| 1437 | && pNode->name() == strSecondSubName)
|
---|
[83705] | 1438 | {
|
---|
[84400] | 1439 | UIChooserNode *pFoundNode = getCloudGroupNode(strFirstSuffix, pNode, fAllGroupsOpened);
|
---|
[83705] | 1440 | if (UIChooserNodeGroup *pFoundGroupNode = pFoundNode->toGroupNode())
|
---|
| 1441 | if (fAllGroupsOpened && pFoundGroupNode->isClosed())
|
---|
| 1442 | pFoundGroupNode->open();
|
---|
| 1443 | return pFoundNode;
|
---|
| 1444 | }
|
---|
| 1445 | }
|
---|
| 1446 | }
|
---|
| 1447 |
|
---|
| 1448 | /* Found nothing? Returning parent: */
|
---|
| 1449 | AssertFailedReturn(pParentNode);
|
---|
| 1450 | }
|
---|
| 1451 |
|
---|
[84434] | 1452 | bool UIChooserAbstractModel::shouldGroupNodeBeOpened(UIChooserNode *pParentNode,
|
---|
| 1453 | UIChooserNodeDataPrefixType enmDataType,
|
---|
| 1454 | const QString &strName) const
|
---|
[77890] | 1455 | {
|
---|
| 1456 | /* Read group definitions: */
|
---|
[88585] | 1457 | const QStringList definitions = gEDataManager->machineGroupDefinitions(pParentNode->fullName());
|
---|
[77890] | 1458 | /* Return 'false' if no definitions found: */
|
---|
| 1459 | if (definitions.isEmpty())
|
---|
| 1460 | return false;
|
---|
| 1461 |
|
---|
| 1462 | /* Prepare required group definition reg-exp: */
|
---|
[84434] | 1463 | const QString strNodePrefix = prefixToString(enmDataType);
|
---|
[84412] | 1464 | const QString strNodeOptionOpened = optionToString(UIChooserNodeDataOptionType_GroupOpened);
|
---|
[84434] | 1465 | const QString strDefinitionTemplate = QString("%1(\\S)*=%2").arg(strNodePrefix, strName);
|
---|
[103362] | 1466 | const QRegularExpression re(strDefinitionTemplate);
|
---|
[77890] | 1467 | /* For each the group definition: */
|
---|
| 1468 | foreach (const QString &strDefinition, definitions)
|
---|
| 1469 | {
|
---|
| 1470 | /* Check if this is required definition: */
|
---|
[103362] | 1471 | const QRegularExpressionMatch mt = re.match(strDefinition);
|
---|
| 1472 | if (mt.capturedStart() == 0)
|
---|
[77890] | 1473 | {
|
---|
| 1474 | /* Get group descriptor: */
|
---|
[103362] | 1475 | const QString strDescriptor = mt.captured(1);
|
---|
[84376] | 1476 | if (strDescriptor.contains(strNodeOptionOpened))
|
---|
[77890] | 1477 | return true;
|
---|
| 1478 | }
|
---|
| 1479 | }
|
---|
| 1480 |
|
---|
| 1481 | /* Return 'false' by default: */
|
---|
| 1482 | return false;
|
---|
| 1483 | }
|
---|
| 1484 |
|
---|
[84434] | 1485 | bool UIChooserAbstractModel::shouldGlobalNodeBeFavorite(UIChooserNode *pParentNode) const
|
---|
[77890] | 1486 | {
|
---|
| 1487 | /* Read group definitions: */
|
---|
[88585] | 1488 | const QStringList definitions = gEDataManager->machineGroupDefinitions(pParentNode->fullName());
|
---|
[77890] | 1489 | /* Return 'false' if no definitions found: */
|
---|
| 1490 | if (definitions.isEmpty())
|
---|
| 1491 | return false;
|
---|
| 1492 |
|
---|
| 1493 | /* Prepare required group definition reg-exp: */
|
---|
[84412] | 1494 | const QString strNodePrefix = prefixToString(UIChooserNodeDataPrefixType_Global);
|
---|
| 1495 | const QString strNodeOptionFavorite = optionToString(UIChooserNodeDataOptionType_GlobalFavorite);
|
---|
| 1496 | const QString strNodeValueDefault = valueToString(UIChooserNodeDataValueType_GlobalDefault);
|
---|
[84376] | 1497 | const QString strDefinitionTemplate = QString("%1(\\S)*=%2").arg(strNodePrefix, strNodeValueDefault);
|
---|
[103362] | 1498 | const QRegularExpression re(strDefinitionTemplate);
|
---|
[77890] | 1499 | /* For each the group definition: */
|
---|
| 1500 | foreach (const QString &strDefinition, definitions)
|
---|
| 1501 | {
|
---|
| 1502 | /* Check if this is required definition: */
|
---|
[103362] | 1503 | const QRegularExpressionMatch mt = re.match(strDefinition);
|
---|
| 1504 | if (mt.capturedStart() == 0)
|
---|
[77890] | 1505 | {
|
---|
| 1506 | /* Get group descriptor: */
|
---|
[103362] | 1507 | const QString strDescriptor = mt.captured(1);
|
---|
[84376] | 1508 | if (strDescriptor.contains(strNodeOptionFavorite))
|
---|
[77890] | 1509 | return true;
|
---|
| 1510 | }
|
---|
| 1511 | }
|
---|
| 1512 |
|
---|
| 1513 | /* Return 'false' by default: */
|
---|
| 1514 | return false;
|
---|
| 1515 | }
|
---|
| 1516 |
|
---|
[84434] | 1517 | void UIChooserAbstractModel::wipeOutEmptyGroupsStartingFrom(UIChooserNode *pParent)
|
---|
| 1518 | {
|
---|
[84598] | 1519 | /* Cleanup all the group children recursively first: */
|
---|
[84434] | 1520 | foreach (UIChooserNode *pNode, pParent->nodes(UIChooserNodeType_Group))
|
---|
| 1521 | wipeOutEmptyGroupsStartingFrom(pNode);
|
---|
[84598] | 1522 | /* If parent isn't root and has no nodes: */
|
---|
| 1523 | if (!pParent->isRoot() && !pParent->hasNodes())
|
---|
[84434] | 1524 | {
|
---|
[84598] | 1525 | /* Delete parent node and item: */
|
---|
| 1526 | delete pParent;
|
---|
[84434] | 1527 | }
|
---|
| 1528 | }
|
---|
| 1529 |
|
---|
[84415] | 1530 | int UIChooserAbstractModel::getDesiredNodePosition(UIChooserNode *pParentNode,
|
---|
| 1531 | UIChooserNodeDataPrefixType enmDataType,
|
---|
| 1532 | const QString &strName)
|
---|
[77890] | 1533 | {
|
---|
| 1534 | /* End of list (by default)? */
|
---|
| 1535 | int iNewNodeDesiredPosition = -1;
|
---|
| 1536 | /* Which position should be new node placed by definitions: */
|
---|
[84415] | 1537 | const int iNewNodeDefinitionPosition = getDefinedNodePosition(pParentNode, enmDataType, strName);
|
---|
[77909] | 1538 |
|
---|
[84598] | 1539 | /* If some position defined: */
|
---|
[77890] | 1540 | if (iNewNodeDefinitionPosition != -1)
|
---|
| 1541 | {
|
---|
| 1542 | /* Start of list if some definition present: */
|
---|
| 1543 | iNewNodeDesiredPosition = 0;
|
---|
| 1544 | /* We have to check all the existing node positions: */
|
---|
[84415] | 1545 | UIChooserNodeType enmType = UIChooserNodeType_Any;
|
---|
| 1546 | switch (enmDataType)
|
---|
| 1547 | {
|
---|
| 1548 | case UIChooserNodeDataPrefixType_Global: enmType = UIChooserNodeType_Global; break;
|
---|
| 1549 | case UIChooserNodeDataPrefixType_Machine: enmType = UIChooserNodeType_Machine; break;
|
---|
| 1550 | case UIChooserNodeDataPrefixType_Local:
|
---|
| 1551 | case UIChooserNodeDataPrefixType_Provider:
|
---|
| 1552 | case UIChooserNodeDataPrefixType_Profile: enmType = UIChooserNodeType_Group; break;
|
---|
| 1553 | }
|
---|
| 1554 | const QList<UIChooserNode*> nodes = pParentNode->nodes(enmType);
|
---|
[77890] | 1555 | for (int i = nodes.size() - 1; i >= 0; --i)
|
---|
| 1556 | {
|
---|
| 1557 | /* Get current node: */
|
---|
[83946] | 1558 | UIChooserNode *pNode = nodes.at(i);
|
---|
| 1559 | AssertPtrReturn(pNode, iNewNodeDesiredPosition);
|
---|
[77890] | 1560 | /* Which position should be current node placed by definitions? */
|
---|
[84415] | 1561 | UIChooserNodeDataPrefixType enmNodeDataType = UIChooserNodeDataPrefixType_Global;
|
---|
| 1562 | QString strDefinitionName;
|
---|
| 1563 | switch (pNode->type())
|
---|
| 1564 | {
|
---|
| 1565 | case UIChooserNodeType_Machine:
|
---|
| 1566 | {
|
---|
| 1567 | enmNodeDataType = UIChooserNodeDataPrefixType_Machine;
|
---|
| 1568 | strDefinitionName = toOldStyleUuid(pNode->toMachineNode()->id());
|
---|
| 1569 | break;
|
---|
| 1570 | }
|
---|
| 1571 | case UIChooserNodeType_Group:
|
---|
| 1572 | {
|
---|
| 1573 | /* Cast to group node: */
|
---|
| 1574 | UIChooserNodeGroup *pGroupNode = pNode->toGroupNode();
|
---|
| 1575 | AssertPtrReturn(pGroupNode, iNewNodeDesiredPosition);
|
---|
| 1576 | switch (pGroupNode->groupType())
|
---|
| 1577 | {
|
---|
| 1578 | case UIChooserNodeGroupType_Local: enmNodeDataType = UIChooserNodeDataPrefixType_Local; break;
|
---|
| 1579 | case UIChooserNodeGroupType_Provider: enmNodeDataType = UIChooserNodeDataPrefixType_Provider; break;
|
---|
| 1580 | case UIChooserNodeGroupType_Profile: enmNodeDataType = UIChooserNodeDataPrefixType_Profile; break;
|
---|
| 1581 | default: break;
|
---|
| 1582 | }
|
---|
| 1583 | strDefinitionName = pNode->name();
|
---|
| 1584 | break;
|
---|
| 1585 | }
|
---|
| 1586 | default:
|
---|
| 1587 | break;
|
---|
| 1588 | }
|
---|
[84598] | 1589 | /* If some position defined: */
|
---|
[84415] | 1590 | const int iNodeDefinitionPosition = getDefinedNodePosition(pParentNode, enmNodeDataType, strDefinitionName);
|
---|
[77890] | 1591 | if (iNodeDefinitionPosition != -1)
|
---|
| 1592 | {
|
---|
[83946] | 1593 | AssertReturn(iNodeDefinitionPosition != iNewNodeDefinitionPosition, iNewNodeDesiredPosition);
|
---|
[77890] | 1594 | if (iNodeDefinitionPosition < iNewNodeDefinitionPosition)
|
---|
| 1595 | {
|
---|
| 1596 | iNewNodeDesiredPosition = i + 1;
|
---|
| 1597 | break;
|
---|
| 1598 | }
|
---|
| 1599 | }
|
---|
| 1600 | }
|
---|
| 1601 | }
|
---|
[77909] | 1602 |
|
---|
[77890] | 1603 | /* Return desired node position: */
|
---|
| 1604 | return iNewNodeDesiredPosition;
|
---|
| 1605 | }
|
---|
| 1606 |
|
---|
[84415] | 1607 | int UIChooserAbstractModel::getDefinedNodePosition(UIChooserNode *pParentNode, UIChooserNodeDataPrefixType enmDataType, const QString &strName)
|
---|
[77890] | 1608 | {
|
---|
| 1609 | /* Read group definitions: */
|
---|
[88585] | 1610 | const QStringList definitions = gEDataManager->machineGroupDefinitions(pParentNode->fullName());
|
---|
[77890] | 1611 | /* Return 'false' if no definitions found: */
|
---|
| 1612 | if (definitions.isEmpty())
|
---|
| 1613 | return -1;
|
---|
| 1614 |
|
---|
| 1615 | /* Prepare definition reg-exp: */
|
---|
| 1616 | QString strDefinitionTemplateShort;
|
---|
| 1617 | QString strDefinitionTemplateFull;
|
---|
[84415] | 1618 | const QString strNodePrefixLocal = prefixToString(UIChooserNodeDataPrefixType_Local);
|
---|
| 1619 | const QString strNodePrefixProvider = prefixToString(UIChooserNodeDataPrefixType_Provider);
|
---|
| 1620 | const QString strNodePrefixProfile = prefixToString(UIChooserNodeDataPrefixType_Profile);
|
---|
| 1621 | const QString strNodePrefixMachine = prefixToString(UIChooserNodeDataPrefixType_Machine);
|
---|
| 1622 | switch (enmDataType)
|
---|
[77890] | 1623 | {
|
---|
[84415] | 1624 | case UIChooserNodeDataPrefixType_Local:
|
---|
[84401] | 1625 | {
|
---|
| 1626 | strDefinitionTemplateShort = QString("^[%1%2%3](\\S)*=").arg(strNodePrefixLocal, strNodePrefixProvider, strNodePrefixProfile);
|
---|
[84415] | 1627 | strDefinitionTemplateFull = QString("^%1(\\S)*=%2$").arg(strNodePrefixLocal, strName);
|
---|
[77890] | 1628 | break;
|
---|
[84401] | 1629 | }
|
---|
[84415] | 1630 | case UIChooserNodeDataPrefixType_Provider:
|
---|
[84401] | 1631 | {
|
---|
[84415] | 1632 | strDefinitionTemplateShort = QString("^[%1%2%3](\\S)*=").arg(strNodePrefixLocal, strNodePrefixProvider, strNodePrefixProfile);
|
---|
| 1633 | strDefinitionTemplateFull = QString("^%1(\\S)*=%2$").arg(strNodePrefixProvider, strName);
|
---|
[77890] | 1634 | break;
|
---|
[84401] | 1635 | }
|
---|
[84415] | 1636 | case UIChooserNodeDataPrefixType_Profile:
|
---|
| 1637 | {
|
---|
| 1638 | strDefinitionTemplateShort = QString("^[%1%2%3](\\S)*=").arg(strNodePrefixLocal, strNodePrefixProvider, strNodePrefixProfile);
|
---|
| 1639 | strDefinitionTemplateFull = QString("^%1(\\S)*=%2$").arg(strNodePrefixProfile, strName);
|
---|
| 1640 | break;
|
---|
| 1641 | }
|
---|
| 1642 | case UIChooserNodeDataPrefixType_Machine:
|
---|
| 1643 | {
|
---|
| 1644 | strDefinitionTemplateShort = QString("^%1=").arg(strNodePrefixMachine);
|
---|
| 1645 | strDefinitionTemplateFull = QString("^%1=%2$").arg(strNodePrefixMachine, strName);
|
---|
| 1646 | break;
|
---|
| 1647 | }
|
---|
[84401] | 1648 | default:
|
---|
| 1649 | return -1;
|
---|
[77890] | 1650 | }
|
---|
[103362] | 1651 | const QRegularExpression definitionRegExpShort(strDefinitionTemplateShort);
|
---|
| 1652 | const QRegularExpression definitionRegExpFull(strDefinitionTemplateFull);
|
---|
[77890] | 1653 |
|
---|
| 1654 | /* For each the definition: */
|
---|
| 1655 | int iDefinitionIndex = -1;
|
---|
| 1656 | foreach (const QString &strDefinition, definitions)
|
---|
| 1657 | {
|
---|
| 1658 | /* Check if this definition is of required type: */
|
---|
[103362] | 1659 | const QRegularExpressionMatch mtShort = definitionRegExpShort.match(strDefinition);
|
---|
| 1660 | if (mtShort.capturedStart() == 0)
|
---|
[77890] | 1661 | {
|
---|
| 1662 | ++iDefinitionIndex;
|
---|
| 1663 | /* Check if this definition is exactly what we need: */
|
---|
[103362] | 1664 | const QRegularExpressionMatch mtFull = definitionRegExpFull.match(strDefinition);
|
---|
| 1665 | if (mtFull.capturedStart() == 0)
|
---|
[77890] | 1666 | return iDefinitionIndex;
|
---|
| 1667 | }
|
---|
| 1668 | }
|
---|
| 1669 |
|
---|
| 1670 | /* Return result: */
|
---|
| 1671 | return -1;
|
---|
| 1672 | }
|
---|
| 1673 |
|
---|
[83698] | 1674 | void UIChooserAbstractModel::createLocalMachineNode(UIChooserNode *pParentNode, const CMachine &comMachine)
|
---|
[77890] | 1675 | {
|
---|
| 1676 | new UIChooserNodeMachine(pParentNode,
|
---|
[83882] | 1677 | getDesiredNodePosition(pParentNode,
|
---|
[84415] | 1678 | UIChooserNodeDataPrefixType_Machine,
|
---|
[83882] | 1679 | toOldStyleUuid(comMachine.GetId())),
|
---|
[77890] | 1680 | comMachine);
|
---|
| 1681 | }
|
---|
| 1682 |
|
---|
[86664] | 1683 | void UIChooserAbstractModel::createCloudMachineNode(UIChooserNode *pParentNode, UIFakeCloudVirtualMachineItemState enmState)
|
---|
| 1684 | {
|
---|
| 1685 | new UIChooserNodeMachine(pParentNode,
|
---|
| 1686 | 0 /* position */,
|
---|
| 1687 | enmState);
|
---|
| 1688 | }
|
---|
| 1689 |
|
---|
[83705] | 1690 | void UIChooserAbstractModel::createCloudMachineNode(UIChooserNode *pParentNode, const CCloudMachine &comMachine)
|
---|
| 1691 | {
|
---|
| 1692 | UIChooserNodeMachine *pNode = new UIChooserNodeMachine(pParentNode,
|
---|
| 1693 | getDesiredNodePosition(pParentNode,
|
---|
[84415] | 1694 | UIChooserNodeDataPrefixType_Machine,
|
---|
[83705] | 1695 | toOldStyleUuid(comMachine.GetId())),
|
---|
| 1696 | comMachine);
|
---|
| 1697 | /* Request for async node update if necessary: */
|
---|
[102838] | 1698 | if ( m_fKeepCloudNodesUpdated
|
---|
| 1699 | || !comMachine.GetAccessible())
|
---|
[83926] | 1700 | {
|
---|
[84598] | 1701 | AssertReturnVoid(pNode && pNode->cacheType() == UIVirtualMachineItemType_CloudReal);
|
---|
[102836] | 1702 | UIVirtualMachineItemCloud *pCloudMachineItem = pNode->cache()->toCloud();
|
---|
[102838] | 1703 | pCloudMachineItem->setUpdateRequiredByGlobalReason(m_fKeepCloudNodesUpdated);
|
---|
[102836] | 1704 | pCloudMachineItem->updateInfoAsync(false /* delayed? */);
|
---|
[83926] | 1705 | }
|
---|
[83705] | 1706 | }
|
---|
| 1707 |
|
---|
[84545] | 1708 | QStringList UIChooserAbstractModel::gatherPossibleGroupNodeNames(UIChooserNode *pCurrentNode, QList<UIChooserNode*> exceptions) const
|
---|
| 1709 | {
|
---|
| 1710 | /* Prepare result: */
|
---|
| 1711 | QStringList result;
|
---|
| 1712 |
|
---|
| 1713 | /* Walk through all the children and make sure there are no exceptions: */
|
---|
| 1714 | bool fAddCurrent = true;
|
---|
| 1715 | foreach (UIChooserNode *pChild, pCurrentNode->nodes(UIChooserNodeType_Any))
|
---|
| 1716 | {
|
---|
| 1717 | AssertPtrReturn(pChild, result);
|
---|
| 1718 | if (exceptions.contains(pChild))
|
---|
| 1719 | fAddCurrent = false;
|
---|
| 1720 | else
|
---|
| 1721 | {
|
---|
| 1722 | if (pChild->type() == UIChooserNodeType_Group)
|
---|
| 1723 | {
|
---|
| 1724 | UIChooserNodeGroup *pChildGroup = pChild->toGroupNode();
|
---|
| 1725 | AssertPtrReturn(pChildGroup, result);
|
---|
| 1726 | if (pChildGroup->groupType() == UIChooserNodeGroupType_Local)
|
---|
| 1727 | result << gatherPossibleGroupNodeNames(pChild, exceptions);
|
---|
| 1728 | }
|
---|
| 1729 | }
|
---|
| 1730 | }
|
---|
| 1731 |
|
---|
| 1732 | /* Add current item if not overridden: */
|
---|
| 1733 | if (fAddCurrent)
|
---|
| 1734 | result.prepend(pCurrentNode->fullName());
|
---|
| 1735 |
|
---|
| 1736 | /* Return result: */
|
---|
| 1737 | return result;
|
---|
| 1738 | }
|
---|
| 1739 |
|
---|
[86678] | 1740 | bool UIChooserAbstractModel::checkIfNodeContainChildWithId(UIChooserNode *pParentNode, const QUuid &uId) const
|
---|
| 1741 | {
|
---|
| 1742 | /* Check parent-node type: */
|
---|
| 1743 | AssertPtrReturn(pParentNode, false);
|
---|
| 1744 | switch (pParentNode->type())
|
---|
| 1745 | {
|
---|
| 1746 | case UIChooserNodeType_Machine:
|
---|
| 1747 | {
|
---|
| 1748 | /* Check if pParentNode has the passed uId itself: */
|
---|
| 1749 | UIChooserNodeMachine *pMachineNode = pParentNode->toMachineNode();
|
---|
| 1750 | AssertPtrReturn(pMachineNode, false);
|
---|
| 1751 | if (pMachineNode->id() == uId)
|
---|
| 1752 | return true;
|
---|
| 1753 | break;
|
---|
| 1754 | }
|
---|
| 1755 | case UIChooserNodeType_Group:
|
---|
| 1756 | {
|
---|
| 1757 | /* Recursively iterate through children: */
|
---|
| 1758 | foreach (UIChooserNode *pChildNode, pParentNode->nodes())
|
---|
| 1759 | if (checkIfNodeContainChildWithId(pChildNode, uId))
|
---|
| 1760 | return true;
|
---|
| 1761 | break;
|
---|
| 1762 | }
|
---|
| 1763 | default:
|
---|
| 1764 | break;
|
---|
| 1765 | }
|
---|
| 1766 |
|
---|
| 1767 | /* False by default: */
|
---|
| 1768 | return false;
|
---|
| 1769 | }
|
---|
| 1770 |
|
---|
[84423] | 1771 | void UIChooserAbstractModel::saveGroupSettings()
|
---|
[77890] | 1772 | {
|
---|
[84423] | 1773 | /* Make sure there is no group settings saving activity: */
|
---|
| 1774 | if (UIThreadGroupSettingsSave::instance())
|
---|
[77890] | 1775 | return;
|
---|
| 1776 |
|
---|
| 1777 | /* Prepare full group map: */
|
---|
| 1778 | QMap<QString, QStringList> groups;
|
---|
[84423] | 1779 | gatherGroupSettings(groups, invisibleRoot());
|
---|
[77890] | 1780 |
|
---|
| 1781 | /* Save information in other thread: */
|
---|
[84423] | 1782 | UIThreadGroupSettingsSave::prepare();
|
---|
[77890] | 1783 | emit sigGroupSavingStateChanged();
|
---|
[84423] | 1784 | connect(UIThreadGroupSettingsSave::instance(), &UIThreadGroupSettingsSave::sigReload,
|
---|
[80760] | 1785 | this, &UIChooserAbstractModel::sltReloadMachine);
|
---|
[84423] | 1786 | UIThreadGroupSettingsSave::instance()->configure(this, m_groups, groups);
|
---|
| 1787 | UIThreadGroupSettingsSave::instance()->start();
|
---|
[77890] | 1788 | m_groups = groups;
|
---|
| 1789 | }
|
---|
| 1790 |
|
---|
[84424] | 1791 | void UIChooserAbstractModel::saveGroupDefinitions()
|
---|
[77890] | 1792 | {
|
---|
[84424] | 1793 | /* Make sure there is no group definitions save activity: */
|
---|
| 1794 | if (UIThreadGroupDefinitionsSave::instance())
|
---|
[77890] | 1795 | return;
|
---|
| 1796 |
|
---|
| 1797 | /* Prepare full group map: */
|
---|
| 1798 | QMap<QString, QStringList> groups;
|
---|
[84424] | 1799 | gatherGroupDefinitions(groups, invisibleRoot());
|
---|
[77890] | 1800 |
|
---|
| 1801 | /* Save information in other thread: */
|
---|
[84424] | 1802 | UIThreadGroupDefinitionsSave::prepare();
|
---|
[77890] | 1803 | emit sigGroupSavingStateChanged();
|
---|
[84424] | 1804 | UIThreadGroupDefinitionsSave::instance()->configure(this, groups);
|
---|
| 1805 | UIThreadGroupDefinitionsSave::instance()->start();
|
---|
[77890] | 1806 | }
|
---|
| 1807 |
|
---|
[84423] | 1808 | void UIChooserAbstractModel::gatherGroupSettings(QMap<QString, QStringList> &settings,
|
---|
| 1809 | UIChooserNode *pParentGroup)
|
---|
[77890] | 1810 | {
|
---|
| 1811 | /* Iterate over all the machine-nodes: */
|
---|
[83672] | 1812 | foreach (UIChooserNode *pNode, pParentGroup->nodes(UIChooserNodeType_Machine))
|
---|
[83946] | 1813 | {
|
---|
| 1814 | /* Make sure it's really machine node: */
|
---|
| 1815 | AssertPtrReturnVoid(pNode);
|
---|
| 1816 | UIChooserNodeMachine *pMachineNode = pNode->toMachineNode();
|
---|
| 1817 | AssertPtrReturnVoid(pMachineNode);
|
---|
| 1818 | /* Make sure it's local machine node exactly and it's accessible: */
|
---|
| 1819 | if ( pMachineNode->cacheType() == UIVirtualMachineItemType_Local
|
---|
| 1820 | && pMachineNode->accessible())
|
---|
[84423] | 1821 | settings[toOldStyleUuid(pMachineNode->id())] << pParentGroup->fullName();
|
---|
[83946] | 1822 | }
|
---|
[77890] | 1823 | /* Iterate over all the group-nodes: */
|
---|
[83672] | 1824 | foreach (UIChooserNode *pNode, pParentGroup->nodes(UIChooserNodeType_Group))
|
---|
[84423] | 1825 | gatherGroupSettings(settings, pNode);
|
---|
[77890] | 1826 | }
|
---|
| 1827 |
|
---|
[84424] | 1828 | void UIChooserAbstractModel::gatherGroupDefinitions(QMap<QString, QStringList> &definitions,
|
---|
| 1829 | UIChooserNode *pParentGroup)
|
---|
[77890] | 1830 | {
|
---|
| 1831 | /* Prepare extra-data key for current group: */
|
---|
[83041] | 1832 | const QString strExtraDataKey = pParentGroup->fullName();
|
---|
[77890] | 1833 | /* Iterate over all the global-nodes: */
|
---|
[83672] | 1834 | foreach (UIChooserNode *pNode, pParentGroup->nodes(UIChooserNodeType_Global))
|
---|
[77890] | 1835 | {
|
---|
[84373] | 1836 | /* Append node definition: */
|
---|
| 1837 | AssertPtrReturnVoid(pNode);
|
---|
[84424] | 1838 | definitions[strExtraDataKey] << pNode->definition(true /* full */);
|
---|
[77890] | 1839 | }
|
---|
| 1840 | /* Iterate over all the group-nodes: */
|
---|
[83672] | 1841 | foreach (UIChooserNode *pNode, pParentGroup->nodes(UIChooserNodeType_Group))
|
---|
[77890] | 1842 | {
|
---|
[84373] | 1843 | /* Append node definition: */
|
---|
| 1844 | AssertPtrReturnVoid(pNode);
|
---|
[84424] | 1845 | definitions[strExtraDataKey] << pNode->definition(true /* full */);
|
---|
[84373] | 1846 | /* Go recursively through children: */
|
---|
[84424] | 1847 | gatherGroupDefinitions(definitions, pNode);
|
---|
[77890] | 1848 | }
|
---|
| 1849 | /* Iterate over all the machine-nodes: */
|
---|
[83672] | 1850 | foreach (UIChooserNode *pNode, pParentGroup->nodes(UIChooserNodeType_Machine))
|
---|
[83946] | 1851 | {
|
---|
| 1852 | /* Make sure it's really machine node: */
|
---|
| 1853 | AssertPtrReturnVoid(pNode);
|
---|
| 1854 | UIChooserNodeMachine *pMachineNode = pNode->toMachineNode();
|
---|
| 1855 | AssertPtrReturnVoid(pMachineNode);
|
---|
[84373] | 1856 | /* Append node definition, make sure it's local or real cloud machine node only: */
|
---|
[83946] | 1857 | if ( pMachineNode->cacheType() == UIVirtualMachineItemType_Local
|
---|
| 1858 | || pMachineNode->cacheType() == UIVirtualMachineItemType_CloudReal)
|
---|
[84424] | 1859 | definitions[strExtraDataKey] << pNode->definition(true /* full */);
|
---|
[83946] | 1860 | }
|
---|
[77890] | 1861 | }
|
---|
| 1862 |
|
---|
[84423] | 1863 | void UIChooserAbstractModel::makeSureGroupSettingsSaveIsFinished()
|
---|
[77890] | 1864 | {
|
---|
| 1865 | /* Cleanup if necessary: */
|
---|
[84423] | 1866 | if (UIThreadGroupSettingsSave::instance())
|
---|
| 1867 | UIThreadGroupSettingsSave::cleanup();
|
---|
[77890] | 1868 | }
|
---|
| 1869 |
|
---|
[84424] | 1870 | void UIChooserAbstractModel::makeSureGroupDefinitionsSaveIsFinished()
|
---|
[77890] | 1871 | {
|
---|
| 1872 | /* Cleanup if necessary: */
|
---|
[84424] | 1873 | if (UIThreadGroupDefinitionsSave::instance())
|
---|
| 1874 | UIThreadGroupDefinitionsSave::cleanup();
|
---|
[77890] | 1875 | }
|
---|
| 1876 |
|
---|
[86745] | 1877 | UIChooserNode *UIChooserAbstractModel::searchProviderNode(const QUuid &uProviderId)
|
---|
| 1878 | {
|
---|
| 1879 | /* Search for a list of nodes matching passed name: */
|
---|
| 1880 | QList<UIChooserNode*> providerNodes;
|
---|
| 1881 | invisibleRoot()->searchForNodes(uProviderId.toString(),
|
---|
| 1882 | UIChooserItemSearchFlag_CloudProvider | UIChooserItemSearchFlag_ExactId,
|
---|
| 1883 | providerNodes);
|
---|
| 1884 |
|
---|
| 1885 | /* Return 1st node if any: */
|
---|
| 1886 | return providerNodes.value(0);
|
---|
| 1887 | }
|
---|
| 1888 |
|
---|
[86740] | 1889 | UIChooserNode *UIChooserAbstractModel::searchProviderNode(const QString &strProviderShortName)
|
---|
[86665] | 1890 | {
|
---|
[86740] | 1891 | /* Search for a list of nodes matching passed name: */
|
---|
| 1892 | QList<UIChooserNode*> providerNodes;
|
---|
| 1893 | invisibleRoot()->searchForNodes(strProviderShortName,
|
---|
| 1894 | UIChooserItemSearchFlag_CloudProvider | UIChooserItemSearchFlag_ExactName,
|
---|
| 1895 | providerNodes);
|
---|
[77890] | 1896 |
|
---|
[86740] | 1897 | /* Return 1st node if any: */
|
---|
| 1898 | return providerNodes.value(0);
|
---|
| 1899 | }
|
---|
| 1900 |
|
---|
| 1901 | UIChooserNode *UIChooserAbstractModel::searchProfileNode(UIChooserNode *pProviderNode, const QString &strProfileName)
|
---|
| 1902 | {
|
---|
| 1903 | AssertPtrReturn(pProviderNode, 0);
|
---|
| 1904 |
|
---|
| 1905 | /* Search for a list of nodes matching passed name: */
|
---|
[86665] | 1906 | QList<UIChooserNode*> profileNodes;
|
---|
[86740] | 1907 | pProviderNode->searchForNodes(strProfileName,
|
---|
| 1908 | UIChooserItemSearchFlag_CloudProfile | UIChooserItemSearchFlag_ExactName,
|
---|
| 1909 | profileNodes);
|
---|
[86665] | 1910 |
|
---|
| 1911 | /* Return 1st node if any: */
|
---|
| 1912 | return profileNodes.value(0);
|
---|
| 1913 | }
|
---|
| 1914 |
|
---|
[86740] | 1915 | UIChooserNode *UIChooserAbstractModel::searchProfileNode(const QString &strProviderShortName, const QString &strProfileName)
|
---|
[86665] | 1916 | {
|
---|
[86740] | 1917 | /* Wrap method above: */
|
---|
| 1918 | return searchProfileNode(searchProviderNode(strProviderShortName), strProfileName);
|
---|
| 1919 | }
|
---|
[86665] | 1920 |
|
---|
[86740] | 1921 | UIChooserNode *UIChooserAbstractModel::searchMachineNode(UIChooserNode *pProfileNode, const QUuid &uMachineId)
|
---|
| 1922 | {
|
---|
| 1923 | AssertPtrReturn(pProfileNode, 0);
|
---|
| 1924 |
|
---|
| 1925 | /* Search for a list of nodes matching passed ID: */
|
---|
| 1926 | QList<UIChooserNode*> machineNodes;
|
---|
| 1927 | pProfileNode->searchForNodes(uMachineId.toString(),
|
---|
| 1928 | UIChooserItemSearchFlag_Machine | UIChooserItemSearchFlag_ExactId,
|
---|
| 1929 | machineNodes);
|
---|
| 1930 |
|
---|
[86665] | 1931 | /* Return 1st node if any: */
|
---|
[86740] | 1932 | return machineNodes.value(0);
|
---|
[86665] | 1933 | }
|
---|
| 1934 |
|
---|
[86740] | 1935 | UIChooserNode *UIChooserAbstractModel::searchMachineNode(const QString &strProviderShortName, const QString &strProfileName, const QUuid &uMachineId)
|
---|
| 1936 | {
|
---|
| 1937 | /* Wrap method above: */
|
---|
| 1938 | return searchMachineNode(searchProfileNode(strProviderShortName, strProfileName), uMachineId);
|
---|
| 1939 | }
|
---|
[86665] | 1940 |
|
---|
[86740] | 1941 | UIChooserNode *UIChooserAbstractModel::searchFakeNode(UIChooserNode *pProfileNode)
|
---|
| 1942 | {
|
---|
| 1943 | /* Wrap method above: */
|
---|
| 1944 | return searchMachineNode(pProfileNode, QUuid());
|
---|
| 1945 | }
|
---|
| 1946 |
|
---|
| 1947 | UIChooserNode *UIChooserAbstractModel::searchFakeNode(const QString &strProviderShortName, const QString &strProfileName)
|
---|
| 1948 | {
|
---|
| 1949 | /* Wrap method above: */
|
---|
| 1950 | return searchMachineNode(strProviderShortName, strProfileName, QUuid());
|
---|
| 1951 | }
|
---|
| 1952 |
|
---|
[103021] | 1953 | QList<UIChooserNode*> UIChooserAbstractModel::enumerateCloudMachineNodes() const
|
---|
| 1954 | {
|
---|
| 1955 | /* Search for a list of provider nodes: */
|
---|
| 1956 | QList<UIChooserNode*> providerNodes;
|
---|
| 1957 | invisibleRoot()->searchForNodes(QString(),
|
---|
| 1958 | UIChooserItemSearchFlag_CloudProvider,
|
---|
| 1959 | providerNodes);
|
---|
| 1960 |
|
---|
| 1961 | /* Search for a list of profile nodes: */
|
---|
| 1962 | QList<UIChooserNode*> profileNodes;
|
---|
| 1963 | foreach (UIChooserNode *pProviderNode, providerNodes)
|
---|
| 1964 | pProviderNode->searchForNodes(QString(),
|
---|
| 1965 | UIChooserItemSearchFlag_CloudProfile,
|
---|
| 1966 | profileNodes);
|
---|
| 1967 |
|
---|
| 1968 | /* Search for a list of machine nodes: */
|
---|
| 1969 | QList<UIChooserNode*> machineNodes;
|
---|
| 1970 | foreach (UIChooserNode *pProfileNode, profileNodes)
|
---|
| 1971 | pProfileNode->searchForNodes(QString(),
|
---|
| 1972 | UIChooserItemSearchFlag_Machine,
|
---|
| 1973 | machineNodes);
|
---|
| 1974 |
|
---|
| 1975 | return machineNodes;
|
---|
| 1976 | }
|
---|
| 1977 |
|
---|
[90751] | 1978 | void UIChooserAbstractModel::stopCloudUpdates(bool fForced /* = false */)
|
---|
[90698] | 1979 | {
|
---|
| 1980 | /* Stop all cloud entity updates currently being performed: */
|
---|
| 1981 | foreach (const UICloudEntityKey &key, m_cloudEntityKeysBeingUpdated)
|
---|
| 1982 | {
|
---|
| 1983 | /* For profiles: */
|
---|
| 1984 | if (key.m_uMachineId.isNull())
|
---|
| 1985 | {
|
---|
| 1986 | /* Search task child by key: */
|
---|
| 1987 | UIProgressTaskReadCloudMachineList *pTask = findChild<UIProgressTaskReadCloudMachineList*>(key.toString());
|
---|
| 1988 | AssertPtrReturnVoid(pTask);
|
---|
[86740] | 1989 |
|
---|
[90698] | 1990 | /* Wait for cloud profile refresh task to complete,
|
---|
| 1991 | * then delete the task itself manually: */
|
---|
[90751] | 1992 | if (!fForced)
|
---|
| 1993 | pTask->cancel();
|
---|
[90698] | 1994 | delete pTask;
|
---|
| 1995 | }
|
---|
| 1996 | /* For machines: */
|
---|
| 1997 | else
|
---|
| 1998 | {
|
---|
| 1999 | /* Search machine node: */
|
---|
| 2000 | UIChooserNode *pNode = searchMachineNode(key.m_strProviderShortName, key.m_strProfileName, key.m_uMachineId);
|
---|
| 2001 | AssertPtrReturnVoid(pNode);
|
---|
| 2002 | /* Acquire cloud machine item: */
|
---|
| 2003 | UIVirtualMachineItemCloud *pCloudMachineItem = pNode->toMachineNode()->cache()->toCloud();
|
---|
| 2004 | AssertPtrReturnVoid(pCloudMachineItem);
|
---|
| 2005 |
|
---|
| 2006 | /* Wait for cloud machine refresh task to complete,
|
---|
| 2007 | * task itself will be deleted with the machine-node: */
|
---|
| 2008 | pCloudMachineItem->waitForAsyncInfoUpdateFinished();
|
---|
| 2009 | }
|
---|
| 2010 | }
|
---|
| 2011 |
|
---|
| 2012 | /* We haven't let tasks to unregister themselves
|
---|
| 2013 | * so we have to cleanup task set ourselves: */
|
---|
| 2014 | m_cloudEntityKeysBeingUpdated.clear();
|
---|
| 2015 | }
|
---|
| 2016 |
|
---|
| 2017 |
|
---|
[84436] | 2018 | #include "UIChooserAbstractModel.moc"
|
---|