VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.cpp@ 104158

Last change on this file since 104158 was 101230, checked in by vboxsync, 17 months ago

FE/Qt: bugref:10513: Update UIEditor with API to register sub-editors; This will be useful to use outside of the editor code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.1 KB
Line 
1/* $Id: UIMachineSettingsStorage.cpp 101230 2023-09-21 20:17:24Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMachineSettingsStorage class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QVBoxLayout>
30
31/* GUI includes: */
32#include "UICommon.h"
33#include "UIConverter.h"
34#include "UIErrorString.h"
35#include "UIMachineSettingsStorage.h"
36#include "UIMedium.h"
37#include "UIStorageSettingsEditor.h"
38
39/* COM includes: */
40#include "CMediumAttachment.h"
41#include "CStorageController.h"
42
43
44/** Machine settings: Storage Attachment data structure. */
45struct UIDataSettingsMachineStorageAttachment
46{
47 /** Constructs data. */
48 UIDataSettingsMachineStorageAttachment() {}
49
50 /** Returns whether @a another passed data is equal to this one. */
51 bool equal(const UIDataSettingsMachineStorageAttachment &another) const
52 {
53 return true
54 && (m_guiValue == another.m_guiValue)
55 ;
56 }
57
58 /** Returns whether @a another passed data is equal to this one. */
59 bool operator==(const UIDataSettingsMachineStorageAttachment &another) const { return equal(another); }
60 /** Returns whether @a another passed data is different from this one. */
61 bool operator!=(const UIDataSettingsMachineStorageAttachment &another) const { return !equal(another); }
62
63 /** Holds the storage attachment data. */
64 UIDataStorageAttachment m_guiValue;
65};
66
67
68/** Machine settings: Storage Controller data structure. */
69struct UIDataSettingsMachineStorageController
70{
71 /** Constructs data. */
72 UIDataSettingsMachineStorageController() {}
73
74 /** Returns whether @a another passed data is equal to this one. */
75 bool equal(const UIDataSettingsMachineStorageController &another) const
76 {
77 return true
78 && (m_guiValue == another.m_guiValue)
79 ;
80 }
81
82 /** Returns whether @a another passed data is equal to this one. */
83 bool operator==(const UIDataSettingsMachineStorageController &another) const { return equal(another); }
84 /** Returns whether @a another passed data is different from this one. */
85 bool operator!=(const UIDataSettingsMachineStorageController &another) const { return !equal(another); }
86
87 /** Holds the storage controller data. */
88 UIDataStorageController m_guiValue;
89};
90
91
92/** Machine settings: Storage page data structure. */
93struct UIDataSettingsMachineStorage
94{
95 /** Constructs data. */
96 UIDataSettingsMachineStorage() {}
97
98 /** Returns whether @a another passed data is equal to this one. */
99 bool operator==(const UIDataSettingsMachineStorage & /* another */) const { return true; }
100 /** Returns whether @a another passed data is different from this one. */
101 bool operator!=(const UIDataSettingsMachineStorage & /* another */) const { return false; }
102};
103
104
105/*********************************************************************************************************************************
106* Class UIMachineSettingsStorage implementation. *
107*********************************************************************************************************************************/
108
109UIMachineSettingsStorage::UIMachineSettingsStorage(UIActionPool *pActionPool)
110 : m_pActionPool(pActionPool)
111 , m_pCache(0)
112 , m_pEditorStorageSettings(0)
113{
114 prepare();
115}
116
117UIMachineSettingsStorage::~UIMachineSettingsStorage()
118{
119 cleanup();
120}
121
122void UIMachineSettingsStorage::setChipsetType(KChipsetType enmType)
123{
124 if (m_pEditorStorageSettings)
125 m_pEditorStorageSettings->setChipsetType(enmType);
126}
127
128bool UIMachineSettingsStorage::changed() const
129{
130 return m_pCache ? m_pCache->wasChanged() : false;
131}
132
133void UIMachineSettingsStorage::loadToCacheFrom(QVariant &data)
134{
135 /* Sanity check: */
136 if (!m_pCache)
137 return;
138
139 /* Fetch data to machine: */
140 UISettingsPageMachine::fetchData(data);
141
142 /* Clear cache initially: */
143 m_pCache->clear();
144
145 /* Prepare old data: */
146 UIDataSettingsMachineStorage oldStorageData;
147
148 /* Gather old data: */
149 m_uMachineId = m_machine.GetId();
150 m_strMachineName = m_machine.GetName();
151 m_strMachineSettingsFilePath = m_machine.GetSettingsFilePath();
152 m_strMachineGuestOSTypeId = m_machine.GetOSTypeId();
153
154 /* For each controller: */
155 const CStorageControllerVector &controllers = m_machine.GetStorageControllers();
156 for (int iControllerIndex = 0; iControllerIndex < controllers.size(); ++iControllerIndex)
157 {
158 /* Prepare old data & cache key: */
159 UIDataSettingsMachineStorageController oldControllerData;
160 QString strControllerKey = QString::number(iControllerIndex);
161
162 /* Check whether controller is valid: */
163 const CStorageController &comController = controllers.at(iControllerIndex);
164 if (!comController.isNull())
165 {
166 /* Gather old data: */
167 oldControllerData.m_guiValue.m_strName = comController.GetName();
168 oldControllerData.m_guiValue.m_enmBus = comController.GetBus();
169 oldControllerData.m_guiValue.m_enmType = comController.GetControllerType();
170 oldControllerData.m_guiValue.m_uPortCount = comController.GetPortCount();
171 oldControllerData.m_guiValue.m_fUseHostIOCache = comController.GetUseHostIOCache();
172 oldControllerData.m_guiValue.m_strKey = oldControllerData.m_guiValue.m_strName;
173 /* Override controller cache key: */
174 strControllerKey = oldControllerData.m_guiValue.m_strKey;
175
176 /* Sort attachments before caching/fetching: */
177 const CMediumAttachmentVector &attachmentVector =
178 m_machine.GetMediumAttachmentsOfController(oldControllerData.m_guiValue.m_strName);
179 QMap<StorageSlot, CMediumAttachment> attachmentMap;
180 foreach (const CMediumAttachment &comAttachment, attachmentVector)
181 {
182 const StorageSlot storageSlot(oldControllerData.m_guiValue.m_enmBus,
183 comAttachment.GetPort(), comAttachment.GetDevice());
184 attachmentMap.insert(storageSlot, comAttachment);
185 }
186 const QList<CMediumAttachment> &attachments = attachmentMap.values();
187
188 /* For each attachment: */
189 for (int iAttachmentIndex = 0; iAttachmentIndex < attachments.size(); ++iAttachmentIndex)
190 {
191 /* Prepare old data & cache key: */
192 UIDataSettingsMachineStorageAttachment oldAttachmentData;
193 QString strAttachmentKey = QString::number(iAttachmentIndex);
194
195 /* Check whether attachment is valid: */
196 const CMediumAttachment &comAttachment = attachments.at(iAttachmentIndex);
197 if (!comAttachment.isNull())
198 {
199 /* Gather old data: */
200 oldAttachmentData.m_guiValue.m_enmDeviceType = comAttachment.GetType();
201 oldAttachmentData.m_guiValue.m_iPort = comAttachment.GetPort();
202 oldAttachmentData.m_guiValue.m_iDevice = comAttachment.GetDevice();
203 oldAttachmentData.m_guiValue.m_fPassthrough = comAttachment.GetPassthrough();
204 oldAttachmentData.m_guiValue.m_fTempEject = comAttachment.GetTemporaryEject();
205 oldAttachmentData.m_guiValue.m_fNonRotational = comAttachment.GetNonRotational();
206 oldAttachmentData.m_guiValue.m_fHotPluggable = comAttachment.GetHotPluggable();
207 const CMedium comMedium = comAttachment.GetMedium();
208 oldAttachmentData.m_guiValue.m_uMediumId = comMedium.isNull() ? UIMedium::nullID() : comMedium.GetId();
209 oldAttachmentData.m_guiValue.m_strKey = QString("%1:%2").arg(oldAttachmentData.m_guiValue.m_iPort)
210 .arg(oldAttachmentData.m_guiValue.m_iDevice);
211 /* Override attachment cache key: */
212 strAttachmentKey = oldAttachmentData.m_guiValue.m_strKey;
213 }
214
215 /* Cache old data: */
216 m_pCache->child(strControllerKey).child(strAttachmentKey).cacheInitialData(oldAttachmentData);
217 }
218 }
219
220 /* Cache old data: */
221 m_pCache->child(strControllerKey).cacheInitialData(oldControllerData);
222 }
223
224 /* Cache old data: */
225 m_pCache->cacheInitialData(oldStorageData);
226
227 /* Upload machine to data: */
228 UISettingsPageMachine::uploadData(data);
229}
230
231void UIMachineSettingsStorage::getFromCache()
232{
233 /* Sanity check: */
234 if ( !m_pCache
235 || !m_pEditorStorageSettings)
236 return;
237
238 /* Load old data from cache: */
239 m_pEditorStorageSettings->setMachineId(m_uMachineId);
240 m_pEditorStorageSettings->setMachineName(m_strMachineName);
241 m_pEditorStorageSettings->setMachineSettingsFilePath(m_strMachineSettingsFilePath);
242 m_pEditorStorageSettings->setMachineGuestOSTypeId(m_strMachineGuestOSTypeId);
243
244 /* Load old data from cache: */
245 QList<UIDataStorageController> controllers;
246 QList<QList<UIDataStorageAttachment> > attachments;
247
248 /* For each controller: */
249 for (int iControllerIndex = 0; iControllerIndex < m_pCache->childCount(); ++iControllerIndex)
250 {
251 /* Get controller cache: */
252 const UISettingsCacheMachineStorageController &controllerCache = m_pCache->child(iControllerIndex);
253 /* Get old data from cache: */
254 const UIDataSettingsMachineStorageController &oldControllerData = controllerCache.base();
255
256 /* For each attachment: */
257 QList<UIDataStorageAttachment> controllerAttachments;
258 for (int iAttachmentIndex = 0; iAttachmentIndex < controllerCache.childCount(); ++iAttachmentIndex)
259 {
260 /* Get attachment cache: */
261 const UISettingsCacheMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
262 /* Get old data from cache: */
263 const UIDataSettingsMachineStorageAttachment &oldAttachmentData = attachmentCache.base();
264
265 /* Append controller's attachment: */
266 controllerAttachments << oldAttachmentData.m_guiValue;
267 }
268
269 /* Append controller & controller's attachments: */
270 controllers << oldControllerData.m_guiValue;
271 attachments << controllerAttachments;
272 }
273
274 /* Set to editor: */
275 m_pEditorStorageSettings->setValue(controllers, attachments);
276
277 /* Polish page finally: */
278 polishPage();
279
280 /* Revalidate: */
281 revalidate();
282}
283
284void UIMachineSettingsStorage::putToCache()
285{
286 /* Sanity check: */
287 if ( !m_pCache
288 || !m_pEditorStorageSettings)
289 return;
290
291 /* Prepare new data: */
292 UIDataSettingsMachineStorage newStorageData;
293
294 /* Save new data to cache: */
295 QList<UIDataStorageController> controllers;
296 QList<QList<UIDataStorageAttachment> > attachments;
297
298 /* Get from editor: */
299 m_pEditorStorageSettings->getValue(controllers, attachments);
300
301 /* For each controller: */
302 for (int iControllerIndex = 0; iControllerIndex < controllers.size(); ++iControllerIndex)
303 {
304 /* Acquire controller: */
305 const UIDataStorageController &controller = controllers.at(iControllerIndex);
306
307 /* Gather new data & cache key from model: */
308 UIDataSettingsMachineStorageController newControllerData;
309 newControllerData.m_guiValue = controller;
310 const QString strControllerKey = newControllerData.m_guiValue.m_strKey;
311
312 /* For each attachment: */
313 const QList<UIDataStorageAttachment> &controllerAttachments = attachments.at(iControllerIndex);
314 for (int iAttachmentIndex = 0; iAttachmentIndex < controllerAttachments.size(); ++iAttachmentIndex)
315 {
316 /* Acquire attachment: */
317 const UIDataStorageAttachment &attachment = controllerAttachments.at(iAttachmentIndex);
318
319 /* Gather new data & cache key from model: */
320 UIDataSettingsMachineStorageAttachment newAttachmentData;
321 newAttachmentData.m_guiValue = attachment;
322 const QString strAttachmentKey = newAttachmentData.m_guiValue.m_strKey;
323
324 /* Cache new data: */
325 m_pCache->child(strControllerKey).child(strAttachmentKey).cacheCurrentData(newAttachmentData);
326 }
327
328 /* Cache new data: */
329 m_pCache->child(strControllerKey).cacheCurrentData(newControllerData);
330 }
331
332 /* Cache new data: */
333 m_pCache->cacheCurrentData(newStorageData);
334}
335
336void UIMachineSettingsStorage::saveFromCacheTo(QVariant &data)
337{
338 /* Fetch data to machine: */
339 UISettingsPageMachine::fetchData(data);
340
341 /* Update data and failing state: */
342 setFailed(!saveData());
343
344 /* Upload machine to data: */
345 UISettingsPageMachine::uploadData(data);
346}
347
348bool UIMachineSettingsStorage::validate(QList<UIValidationMessage> &messages)
349{
350 /* Pass by default: */
351 bool fPass = true;
352
353 /* Prepare message: */
354 UIValidationMessage message;
355
356 /* Save new data to cache: */
357 QList<UIDataStorageController> controllers;
358 QList<QList<UIDataStorageAttachment> > attachments;
359
360 /* Get from editor: */
361 m_pEditorStorageSettings->getValue(controllers, attachments);
362
363 /* Check controllers for name emptiness & coincidence.
364 * Check attachments for the hd presence / uniqueness. */
365 QMap<QString, QString> config;
366 QMap<int, QString> names;
367 /* For each controller: */
368 for (int iControllerIndex = 0; iControllerIndex < controllers.size(); ++iControllerIndex)
369 {
370 const UIDataStorageController &controller = controllers.at(iControllerIndex);
371 const QString strControllerName = controller.m_strName;
372
373 /* Check for name emptiness: */
374 if (strControllerName.isEmpty())
375 {
376 message.second << tr("No name is currently specified for the controller at position <b>%1</b>.")
377 .arg(iControllerIndex + 1);
378 fPass = false;
379 }
380 /* Check for name coincidence: */
381 if (names.values().contains(strControllerName))
382 {
383 message.second << tr("The controller at position <b>%1</b> has the same name as the controller at position <b>%2</b>.")
384 .arg(iControllerIndex + 1).arg(names.key(strControllerName) + 1);
385 fPass = false;
386 }
387 else
388 names.insert(iControllerIndex, strControllerName);
389
390 /* For each attachment: */
391 const QList<UIDataStorageAttachment> &controllerAttachments = attachments.at(iControllerIndex);
392 for (int iAttachmentIndex = 0; iAttachmentIndex < controllerAttachments.size(); ++iAttachmentIndex)
393 {
394 const UIDataStorageAttachment &attachment = controllerAttachments.at(iAttachmentIndex);
395 const StorageSlot guiAttachmentSlot = StorageSlot(controller.m_enmBus, attachment.m_iPort, attachment.m_iDevice);
396 const KDeviceType enmDeviceType = attachment.m_enmDeviceType;
397 const QString strKey = attachment.m_uMediumId.toString();
398 const QString strValue = QString("%1 (%2)").arg(strControllerName, gpConverter->toString(guiAttachmentSlot));
399 /* Check for emptiness: */
400 if (uiCommon().medium(QUuid(strKey)).isNull() && enmDeviceType == KDeviceType_HardDisk)
401 {
402 message.second << tr("No hard disk is selected for <i>%1</i>.")
403 .arg(strValue);
404 fPass = false;
405 }
406 /* Check for coincidence: */
407 if (!uiCommon().medium(QUuid(strKey)).isNull() && config.contains(strKey) && enmDeviceType != KDeviceType_DVD)
408 {
409 message.second << tr("<i>%1</i> is using a disk that is already attached to <i>%2</i>.")
410 .arg(strValue).arg(config[strKey]);
411 fPass = false;
412 }
413 else
414 config.insert(strKey, strValue);
415 }
416 }
417
418 /* Check for excessive controllers on Storage page controllers list: */
419 QStringList excessiveList;
420 const QMap<KStorageBus, int> currentType = m_pEditorStorageSettings->currentControllerTypes();
421 const QMap<KStorageBus, int> maximumType = m_pEditorStorageSettings->maximumControllerTypes();
422 for (int iStorageBusType = KStorageBus_IDE; iStorageBusType < KStorageBus_Max; ++iStorageBusType)
423 {
424 if (currentType[(KStorageBus)iStorageBusType] > maximumType[(KStorageBus)iStorageBusType])
425 {
426 QString strExcessiveRecord = QString("%1 (%2)");
427 strExcessiveRecord = strExcessiveRecord.arg(QString("<b>%1</b>").arg(gpConverter->toString((KStorageBus)iStorageBusType)));
428 strExcessiveRecord = strExcessiveRecord.arg(maximumType[(KStorageBus)iStorageBusType] == 1 ?
429 tr("at most one supported", "controller") :
430 tr("up to %1 supported", "controllers").arg(maximumType[(KStorageBus)iStorageBusType]));
431 excessiveList << strExcessiveRecord;
432 }
433 }
434 if (!excessiveList.isEmpty())
435 {
436 message.second << tr("The machine currently has more storage controllers assigned than a %1 chipset supports. "
437 "Please change the chipset type on the System settings page or reduce the number "
438 "of the following storage controllers on the Storage settings page: %2")
439 .arg(gpConverter->toString(m_pEditorStorageSettings->chipsetType()))
440 .arg(excessiveList.join(", "));
441 fPass = false;
442 }
443
444 /* Serialize message: */
445 if (!message.second.isEmpty())
446 messages << message;
447
448 /* Return result: */
449 return fPass;
450}
451
452void UIMachineSettingsStorage::setConfigurationAccessLevel(ConfigurationAccessLevel enmLevel)
453{
454 /* Update model 'configuration access level': */
455 m_pEditorStorageSettings->setConfigurationAccessLevel(enmLevel);
456 /* Update 'configuration access level' of base class: */
457 UISettingsPageMachine::setConfigurationAccessLevel(enmLevel);
458}
459
460void UIMachineSettingsStorage::retranslateUi()
461{
462}
463
464void UIMachineSettingsStorage::polishPage()
465{
466 m_pEditorStorageSettings->setConfigurationAccessLevel(configurationAccessLevel());
467}
468
469void UIMachineSettingsStorage::prepare()
470{
471 /* Prepare cache: */
472 m_pCache = new UISettingsCacheMachineStorage;
473 AssertPtrReturnVoid(m_pCache);
474
475 /* Start full medium-enumeration (if necessary): */
476 if (!uiCommon().isFullMediumEnumerationRequested())
477 uiCommon().enumerateMedia();
478
479 /* Prepare everything: */
480 prepareWidgets();
481 prepareConnections();
482
483 /* Apply language settings: */
484 retranslateUi();
485}
486
487void UIMachineSettingsStorage::prepareWidgets()
488{
489 /* Create main layout: */
490 QVBoxLayout *pLayout = new QVBoxLayout(this);
491 if (pLayout)
492 {
493 /* Create storage settings editor: */
494 m_pEditorStorageSettings = new UIStorageSettingsEditor(this);
495 if (m_pEditorStorageSettings)
496 {
497 addEditor(m_pEditorStorageSettings);
498 m_pEditorStorageSettings->setActionPool(m_pActionPool);
499 pLayout->addWidget(m_pEditorStorageSettings);
500 }
501 }
502}
503
504void UIMachineSettingsStorage::prepareConnections()
505{
506 connect(m_pEditorStorageSettings, &UIStorageSettingsEditor::sigValueChanged,
507 this, &UIMachineSettingsStorage::revalidate);
508}
509
510void UIMachineSettingsStorage::cleanup()
511{
512 /* Cleanup cache: */
513 delete m_pCache;
514 m_pCache = 0;
515}
516
517bool UIMachineSettingsStorage::saveData()
518{
519 /* Sanity check: */
520 if (!m_pCache)
521 return false;
522
523 /* Prepare result: */
524 bool fSuccess = true;
525 /* Save storage settings from cache: */
526 if (fSuccess && isMachineInValidMode() && m_pCache->wasChanged())
527 {
528 /* For each controller ('removing' step): */
529 // We need to separately remove controllers first because
530 // there could be limited amount of controllers available.
531 for (int iControllerIndex = 0; fSuccess && iControllerIndex < m_pCache->childCount(); ++iControllerIndex)
532 {
533 /* Get controller cache: */
534 const UISettingsCacheMachineStorageController &controllerCache = m_pCache->child(iControllerIndex);
535
536 /* Remove controller marked for 'remove' or 'update' (if it can't be updated): */
537 if (controllerCache.wasRemoved() || (controllerCache.wasUpdated() && !isControllerCouldBeUpdated(controllerCache)))
538 fSuccess = removeStorageController(controllerCache);
539 }
540
541 /* For each controller ('updating' step): */
542 // We need to separately update controllers first because
543 // attachments should be removed/updated/created same separate way.
544 for (int iControllerIndex = 0; fSuccess && iControllerIndex < m_pCache->childCount(); ++iControllerIndex)
545 {
546 /* Get controller cache: */
547 const UISettingsCacheMachineStorageController &controllerCache = m_pCache->child(iControllerIndex);
548
549 /* Update controller marked for 'update' (if it can be updated): */
550 if (controllerCache.wasUpdated() && isControllerCouldBeUpdated(controllerCache))
551 fSuccess = updateStorageController(controllerCache, true);
552 }
553 for (int iControllerIndex = 0; fSuccess && iControllerIndex < m_pCache->childCount(); ++iControllerIndex)
554 {
555 /* Get controller cache: */
556 const UISettingsCacheMachineStorageController &controllerCache = m_pCache->child(iControllerIndex);
557
558 /* Update controller marked for 'update' (if it can be updated): */
559 if (controllerCache.wasUpdated() && isControllerCouldBeUpdated(controllerCache))
560 fSuccess = updateStorageController(controllerCache, false);
561 }
562
563 /* For each controller ('creating' step): */
564 // Finally we are creating new controllers,
565 // with attachments which were released for sure.
566 for (int iControllerIndex = 0; fSuccess && iControllerIndex < m_pCache->childCount(); ++iControllerIndex)
567 {
568 /* Get controller cache: */
569 const UISettingsCacheMachineStorageController &controllerCache = m_pCache->child(iControllerIndex);
570
571 /* Create controller marked for 'create' or 'update' (if it can't be updated): */
572 if (controllerCache.wasCreated() || (controllerCache.wasUpdated() && !isControllerCouldBeUpdated(controllerCache)))
573 fSuccess = createStorageController(controllerCache);
574 }
575 }
576 /* Return result: */
577 return fSuccess;
578}
579
580bool UIMachineSettingsStorage::removeStorageController(const UISettingsCacheMachineStorageController &controllerCache)
581{
582 /* Prepare result: */
583 bool fSuccess = true;
584 /* Remove controller: */
585 if (fSuccess && isMachineOffline())
586 {
587 /* Get old data from cache: */
588 const UIDataSettingsMachineStorageController &oldControllerData = controllerCache.base();
589
590 /* Search for a controller with the same name: */
591 const CStorageController &comController = m_machine.GetStorageControllerByName(oldControllerData.m_guiValue.m_strName);
592 fSuccess = m_machine.isOk() && comController.isNotNull();
593
594 /* Make sure controller really exists: */
595 if (fSuccess)
596 {
597 /* Remove controller with all the attachments at one shot: */
598 m_machine.RemoveStorageController(oldControllerData.m_guiValue.m_strName);
599 fSuccess = m_machine.isOk();
600 }
601
602 /* Show error message if necessary: */
603 if (!fSuccess)
604 notifyOperationProgressError(UIErrorString::formatErrorInfo(m_machine));
605 }
606 /* Return result: */
607 return fSuccess;
608}
609
610bool UIMachineSettingsStorage::createStorageController(const UISettingsCacheMachineStorageController &controllerCache)
611{
612 /* Prepare result: */
613 bool fSuccess = true;
614 /* Create controller: */
615 if (fSuccess && isMachineOffline())
616 {
617 /* Get new data from cache: */
618 const UIDataSettingsMachineStorageController &newControllerData = controllerCache.data();
619
620 /* Search for a controller with the same name: */
621 const CMachine comMachine(m_machine);
622 CStorageController comController = comMachine.GetStorageControllerByName(newControllerData.m_guiValue.m_strName);
623 fSuccess = !comMachine.isOk() && comController.isNull();
624 AssertReturn(fSuccess, false);
625
626 /* Make sure controller doesn't exist: */
627 if (fSuccess)
628 {
629 /* Create controller: */
630 comController = m_machine.AddStorageController(newControllerData.m_guiValue.m_strName,
631 newControllerData.m_guiValue.m_enmBus);
632 fSuccess = m_machine.isOk() && comController.isNotNull();
633 }
634
635 /* Show error message if necessary: */
636 if (!fSuccess)
637 notifyOperationProgressError(UIErrorString::formatErrorInfo(m_machine));
638 else
639 {
640 /* Save controller type: */
641 if (fSuccess)
642 {
643 comController.SetControllerType(newControllerData.m_guiValue.m_enmType);
644 fSuccess = comController.isOk();
645 }
646 /* Save whether controller uses host IO cache: */
647 if (fSuccess)
648 {
649 comController.SetUseHostIOCache(newControllerData.m_guiValue.m_fUseHostIOCache);
650 fSuccess = comController.isOk();
651 }
652 /* Save controller port number: */
653 if ( fSuccess
654 && ( newControllerData.m_guiValue.m_enmBus == KStorageBus_SATA
655 || newControllerData.m_guiValue.m_enmBus == KStorageBus_SAS
656 || newControllerData.m_guiValue.m_enmBus == KStorageBus_PCIe
657 || newControllerData.m_guiValue.m_enmBus == KStorageBus_VirtioSCSI))
658 {
659 ULONG uNewPortCount = newControllerData.m_guiValue.m_uPortCount;
660 if (fSuccess)
661 {
662 uNewPortCount = qMax(uNewPortCount, comController.GetMinPortCount());
663 fSuccess = comController.isOk();
664 }
665 if (fSuccess)
666 {
667 uNewPortCount = qMin(uNewPortCount, comController.GetMaxPortCount());
668 fSuccess = comController.isOk();
669 }
670 if (fSuccess)
671 {
672 comController.SetPortCount(uNewPortCount);
673 fSuccess = comController.isOk();
674 }
675 }
676
677 /* Show error message if necessary: */
678 if (!fSuccess)
679 notifyOperationProgressError(UIErrorString::formatErrorInfo(comController));
680
681 /* For each attachment: */
682 for (int iAttachmentIndex = 0; fSuccess && iAttachmentIndex < controllerCache.childCount(); ++iAttachmentIndex)
683 {
684 /* Get attachment cache: */
685 const UISettingsCacheMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
686
687 /* Create attachment if it was not 'removed': */
688 if (!attachmentCache.wasRemoved())
689 fSuccess = createStorageAttachment(controllerCache, attachmentCache);
690 }
691 }
692 }
693 /* Return result: */
694 return fSuccess;
695}
696
697bool UIMachineSettingsStorage::updateStorageController(const UISettingsCacheMachineStorageController &controllerCache,
698 bool fRemovingStep)
699{
700 /* Prepare result: */
701 bool fSuccess = true;
702 /* Update controller: */
703 if (fSuccess)
704 {
705 /* Get old data from cache: */
706 const UIDataSettingsMachineStorageController &oldControllerData = controllerCache.base();
707 /* Get new data from cache: */
708 const UIDataSettingsMachineStorageController &newControllerData = controllerCache.data();
709
710 /* Search for a controller with the same name: */
711 CStorageController comController = m_machine.GetStorageControllerByName(oldControllerData.m_guiValue.m_strName);
712 fSuccess = m_machine.isOk() && comController.isNotNull();
713
714 /* Show error message if necessary: */
715 if (!fSuccess)
716 notifyOperationProgressError(UIErrorString::formatErrorInfo(m_machine));
717 else
718 {
719 /* Save controller type: */
720 if (fSuccess && newControllerData.m_guiValue.m_enmType != oldControllerData.m_guiValue.m_enmType)
721 {
722 comController.SetControllerType(newControllerData.m_guiValue.m_enmType);
723 fSuccess = comController.isOk();
724 }
725 /* Save whether controller uses IO cache: */
726 if (fSuccess && newControllerData.m_guiValue.m_fUseHostIOCache != oldControllerData.m_guiValue.m_fUseHostIOCache)
727 {
728 comController.SetUseHostIOCache(newControllerData.m_guiValue.m_fUseHostIOCache);
729 fSuccess = comController.isOk();
730 }
731 /* Save controller port number: */
732 if ( fSuccess
733 && newControllerData.m_guiValue.m_uPortCount != oldControllerData.m_guiValue.m_uPortCount
734 && ( newControllerData.m_guiValue.m_enmBus == KStorageBus_SATA
735 || newControllerData.m_guiValue.m_enmBus == KStorageBus_SAS
736 || newControllerData.m_guiValue.m_enmBus == KStorageBus_PCIe
737 || newControllerData.m_guiValue.m_enmBus == KStorageBus_VirtioSCSI))
738 {
739 ULONG uNewPortCount = newControllerData.m_guiValue.m_uPortCount;
740 if (fSuccess)
741 {
742 uNewPortCount = qMax(uNewPortCount, comController.GetMinPortCount());
743 fSuccess = comController.isOk();
744 }
745 if (fSuccess)
746 {
747 uNewPortCount = qMin(uNewPortCount, comController.GetMaxPortCount());
748 fSuccess = comController.isOk();
749 }
750 if (fSuccess)
751 {
752 comController.SetPortCount(uNewPortCount);
753 fSuccess = comController.isOk();
754 }
755 }
756
757 /* Show error message if necessary: */
758 if (!fSuccess)
759 notifyOperationProgressError(UIErrorString::formatErrorInfo(comController));
760
761 // We need to separately remove attachments first because
762 // there could be limited amount of attachments or media available.
763 if (fRemovingStep)
764 {
765 /* For each attachment ('removing' step): */
766 for (int iAttachmentIndex = 0; fSuccess && iAttachmentIndex < controllerCache.childCount(); ++iAttachmentIndex)
767 {
768 /* Get attachment cache: */
769 const UISettingsCacheMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
770
771 /* Remove attachment marked for 'remove' or 'update' (if it can't be updated): */
772 if ( attachmentCache.wasRemoved()
773 || (attachmentCache.wasUpdated() && !isAttachmentCouldBeUpdated(attachmentCache)))
774 fSuccess = removeStorageAttachment(controllerCache, attachmentCache);
775 }
776 }
777 else
778 {
779 /* For each attachment ('creating' step): */
780 for (int iAttachmentIndex = 0; fSuccess && iAttachmentIndex < controllerCache.childCount(); ++iAttachmentIndex)
781 {
782 /* Get attachment cache: */
783 const UISettingsCacheMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
784
785 /* Create attachment marked for 'create' or 'update' (if it can't be updated): */
786 if ( attachmentCache.wasCreated()
787 || (attachmentCache.wasUpdated() && !isAttachmentCouldBeUpdated(attachmentCache)))
788 fSuccess = createStorageAttachment(controllerCache, attachmentCache);
789
790 else
791
792 /* Update attachment marked for 'update' (if it can be updated): */
793 if (attachmentCache.wasUpdated() && isAttachmentCouldBeUpdated(attachmentCache))
794 fSuccess = updateStorageAttachment(controllerCache, attachmentCache);
795 }
796 }
797 }
798 }
799 /* Return result: */
800 return fSuccess;
801}
802
803bool UIMachineSettingsStorage::removeStorageAttachment(const UISettingsCacheMachineStorageController &controllerCache,
804 const UISettingsCacheMachineStorageAttachment &attachmentCache)
805{
806 /* Prepare result: */
807 bool fSuccess = true;
808 /* Remove attachment: */
809 if (fSuccess)
810 {
811 /* Get old data from cache: */
812 const UIDataSettingsMachineStorageController &oldControllerData = controllerCache.base();
813 /* Get old data from cache: */
814 const UIDataSettingsMachineStorageAttachment &oldAttachmentData = attachmentCache.base();
815
816 /* Search for an attachment with the same parameters: */
817 const CMediumAttachment &comAttachment = m_machine.GetMediumAttachment(oldControllerData.m_guiValue.m_strName,
818 oldAttachmentData.m_guiValue.m_iPort,
819 oldAttachmentData.m_guiValue.m_iDevice);
820 fSuccess = m_machine.isOk() && comAttachment.isNotNull();
821
822 /* Make sure attachment really exists: */
823 if (fSuccess)
824 {
825 /* Remove attachment: */
826 m_machine.DetachDevice(oldControllerData.m_guiValue.m_strName,
827 oldAttachmentData.m_guiValue.m_iPort,
828 oldAttachmentData.m_guiValue.m_iDevice);
829 fSuccess = m_machine.isOk();
830 }
831
832 /* Show error message if necessary: */
833 if (!fSuccess)
834 notifyOperationProgressError(UIErrorString::formatErrorInfo(m_machine));
835 }
836 /* Return result: */
837 return fSuccess;
838}
839
840bool UIMachineSettingsStorage::createStorageAttachment(const UISettingsCacheMachineStorageController &controllerCache,
841 const UISettingsCacheMachineStorageAttachment &attachmentCache)
842{
843 /* Prepare result: */
844 bool fSuccess = true;
845 /* Create attachment: */
846 if (fSuccess)
847 {
848 /* Get new data from cache: */
849 const UIDataSettingsMachineStorageController &newControllerData = controllerCache.data();
850 /* Get new data from cache: */
851 const UIDataSettingsMachineStorageAttachment &newAttachmentData = attachmentCache.data();
852
853 /* Search for an attachment with the same parameters: */
854 const CMachine comMachine(m_machine);
855 const CMediumAttachment &comAttachment = comMachine.GetMediumAttachment(newControllerData.m_guiValue.m_strName,
856 newAttachmentData.m_guiValue.m_iPort,
857 newAttachmentData.m_guiValue.m_iDevice);
858 fSuccess = !comMachine.isOk() && comAttachment.isNull();
859 AssertReturn(fSuccess, false);
860
861 /* Make sure attachment doesn't exist: */
862 if (fSuccess)
863 {
864 /* Create attachment: */
865 const UIMedium vboxMedium = uiCommon().medium(newAttachmentData.m_guiValue.m_uMediumId);
866 const CMedium comMedium = vboxMedium.medium();
867 m_machine.AttachDevice(newControllerData.m_guiValue.m_strName,
868 newAttachmentData.m_guiValue.m_iPort,
869 newAttachmentData.m_guiValue.m_iDevice,
870 newAttachmentData.m_guiValue.m_enmDeviceType,
871 comMedium);
872 fSuccess = m_machine.isOk();
873 }
874
875 if (newAttachmentData.m_guiValue.m_enmDeviceType == KDeviceType_DVD)
876 {
877 /* Save whether this is a passthrough device: */
878 if (fSuccess && isMachineOffline())
879 {
880 m_machine.PassthroughDevice(newControllerData.m_guiValue.m_strName,
881 newAttachmentData.m_guiValue.m_iPort,
882 newAttachmentData.m_guiValue.m_iDevice,
883 newAttachmentData.m_guiValue.m_fPassthrough);
884 fSuccess = m_machine.isOk();
885 }
886 /* Save whether this is a live cd device: */
887 if (fSuccess)
888 {
889 m_machine.TemporaryEjectDevice(newControllerData.m_guiValue.m_strName,
890 newAttachmentData.m_guiValue.m_iPort,
891 newAttachmentData.m_guiValue.m_iDevice,
892 newAttachmentData.m_guiValue.m_fTempEject);
893 fSuccess = m_machine.isOk();
894 }
895 }
896 else if (newAttachmentData.m_guiValue.m_enmDeviceType == KDeviceType_HardDisk)
897 {
898 /* Save whether this is a ssd device: */
899 if (fSuccess && isMachineOffline())
900 {
901 m_machine.NonRotationalDevice(newControllerData.m_guiValue.m_strName,
902 newAttachmentData.m_guiValue.m_iPort,
903 newAttachmentData.m_guiValue.m_iDevice,
904 newAttachmentData.m_guiValue.m_fNonRotational);
905 fSuccess = m_machine.isOk();
906 }
907 }
908
909 if (newControllerData.m_guiValue.m_enmBus == KStorageBus_SATA)
910 {
911 /* Save whether this device is hot-pluggable: */
912 if (fSuccess && isMachineOffline())
913 {
914 m_machine.SetHotPluggableForDevice(newControllerData.m_guiValue.m_strName,
915 newAttachmentData.m_guiValue.m_iPort,
916 newAttachmentData.m_guiValue.m_iDevice,
917 newAttachmentData.m_guiValue.m_fHotPluggable);
918 fSuccess = m_machine.isOk();
919 }
920 }
921
922 /* Show error message if necessary: */
923 if (!fSuccess)
924 notifyOperationProgressError(UIErrorString::formatErrorInfo(m_machine));
925 }
926 /* Return result: */
927 return fSuccess;
928}
929
930bool UIMachineSettingsStorage::updateStorageAttachment(const UISettingsCacheMachineStorageController &controllerCache,
931 const UISettingsCacheMachineStorageAttachment &attachmentCache)
932{
933 /* Prepare result: */
934 bool fSuccess = true;
935 /* Update attachment: */
936 if (fSuccess)
937 {
938 /* Get new data from cache: */
939 const UIDataSettingsMachineStorageController &newControllerData = controllerCache.data();
940 /* Get new data from cache: */
941 const UIDataSettingsMachineStorageAttachment &newAttachmentData = attachmentCache.data();
942
943 /* Search for an attachment with the same parameters: */
944 const CMediumAttachment &comAttachment = m_machine.GetMediumAttachment(newControllerData.m_guiValue.m_strName,
945 newAttachmentData.m_guiValue.m_iPort,
946 newAttachmentData.m_guiValue.m_iDevice);
947 fSuccess = m_machine.isOk() && comAttachment.isNotNull();
948
949 /* Make sure attachment doesn't exist: */
950 if (fSuccess)
951 {
952 /* Remount attachment: */
953 const UIMedium vboxMedium = uiCommon().medium(newAttachmentData.m_guiValue.m_uMediumId);
954 const CMedium comMedium = vboxMedium.medium();
955 m_machine.MountMedium(newControllerData.m_guiValue.m_strName,
956 newAttachmentData.m_guiValue.m_iPort,
957 newAttachmentData.m_guiValue.m_iDevice,
958 comMedium,
959 true /* force? */);
960 fSuccess = m_machine.isOk();
961 }
962
963 if (newAttachmentData.m_guiValue.m_enmDeviceType == KDeviceType_DVD)
964 {
965 /* Save whether this is a passthrough device: */
966 if (fSuccess && isMachineOffline())
967 {
968 m_machine.PassthroughDevice(newControllerData.m_guiValue.m_strName,
969 newAttachmentData.m_guiValue.m_iPort,
970 newAttachmentData.m_guiValue.m_iDevice,
971 newAttachmentData.m_guiValue.m_fPassthrough);
972 fSuccess = m_machine.isOk();
973 }
974 /* Save whether this is a live cd device: */
975 if (fSuccess)
976 {
977 m_machine.TemporaryEjectDevice(newControllerData.m_guiValue.m_strName,
978 newAttachmentData.m_guiValue.m_iPort,
979 newAttachmentData.m_guiValue.m_iDevice,
980 newAttachmentData.m_guiValue.m_fTempEject);
981 fSuccess = m_machine.isOk();
982 }
983 }
984 else if (newAttachmentData.m_guiValue.m_enmDeviceType == KDeviceType_HardDisk)
985 {
986 /* Save whether this is a ssd device: */
987 if (fSuccess && isMachineOffline())
988 {
989 m_machine.NonRotationalDevice(newControllerData.m_guiValue.m_strName,
990 newAttachmentData.m_guiValue.m_iPort,
991 newAttachmentData.m_guiValue.m_iDevice,
992 newAttachmentData.m_guiValue.m_fNonRotational);
993 fSuccess = m_machine.isOk();
994 }
995 }
996
997 if (newControllerData.m_guiValue.m_enmBus == KStorageBus_SATA)
998 {
999 /* Save whether this device is hot-pluggable: */
1000 if (fSuccess && isMachineOffline())
1001 {
1002 m_machine.SetHotPluggableForDevice(newControllerData.m_guiValue.m_strName,
1003 newAttachmentData.m_guiValue.m_iPort,
1004 newAttachmentData.m_guiValue.m_iDevice,
1005 newAttachmentData.m_guiValue.m_fHotPluggable);
1006 fSuccess = m_machine.isOk();
1007 }
1008 }
1009
1010 /* Show error message if necessary: */
1011 if (!fSuccess)
1012 notifyOperationProgressError(UIErrorString::formatErrorInfo(m_machine));
1013 }
1014 /* Return result: */
1015 return fSuccess;
1016}
1017
1018bool UIMachineSettingsStorage::isControllerCouldBeUpdated(const UISettingsCacheMachineStorageController &controllerCache) const
1019{
1020 /* IController interface doesn't allow to change 'bus' attribute but allows
1021 * to change 'name' attribute which can conflict with another one controller.
1022 * Both those attributes could be changed in GUI directly or indirectly.
1023 * For such cases we have to recreate IController instance,
1024 * for other cases we will update controller attributes only. */
1025 const UIDataSettingsMachineStorageController &oldControllerData = controllerCache.base();
1026 const UIDataSettingsMachineStorageController &newControllerData = controllerCache.data();
1027 return true
1028 && (newControllerData.m_guiValue.m_strName == oldControllerData.m_guiValue.m_strName)
1029 && (newControllerData.m_guiValue.m_enmBus == oldControllerData.m_guiValue.m_enmBus)
1030 ;
1031}
1032
1033bool UIMachineSettingsStorage::isAttachmentCouldBeUpdated(const UISettingsCacheMachineStorageAttachment &attachmentCache) const
1034{
1035 /* IMediumAttachment could be indirectly updated through IMachine
1036 * only if attachment type, device and port were NOT changed and is one of the next types:
1037 * KDeviceType_Floppy or KDeviceType_DVD.
1038 * For other cases we will recreate attachment fully: */
1039 const UIDataSettingsMachineStorageAttachment &oldAttachmentData = attachmentCache.base();
1040 const UIDataSettingsMachineStorageAttachment &newAttachmentData = attachmentCache.data();
1041 return true
1042 && (newAttachmentData.m_guiValue.m_enmDeviceType == oldAttachmentData.m_guiValue.m_enmDeviceType)
1043 && (newAttachmentData.m_guiValue.m_iPort == oldAttachmentData.m_guiValue.m_iPort)
1044 && (newAttachmentData.m_guiValue.m_iDevice == oldAttachmentData.m_guiValue.m_iDevice)
1045 && ( newAttachmentData.m_guiValue.m_enmDeviceType == KDeviceType_Floppy
1046 || newAttachmentData.m_guiValue.m_enmDeviceType == KDeviceType_DVD)
1047 ;
1048}
Note: See TracBrowser for help on using the repository browser.

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