[30022] | 1 | /* $Id: UIVirtualMachineItemLocal.cpp 104251 2024-04-09 12:36:47Z vboxsync $ */
|
---|
[382] | 2 | /** @file
|
---|
[73424] | 3 | * VBox Qt GUI - UIVirtualMachineItem class implementation.
|
---|
[382] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[382] | 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
|
---|
[382] | 26 | */
|
---|
| 27 |
|
---|
[41587] | 28 | /* Qt includes: */
|
---|
[76606] | 29 | #include <QFileInfo>
|
---|
| 30 | #include <QIcon>
|
---|
[382] | 31 |
|
---|
[41587] | 32 | /* GUI includes: */
|
---|
[79365] | 33 | #include "UICommon.h"
|
---|
[76606] | 34 | #include "UIConverter.h"
|
---|
[83254] | 35 | #include "UIErrorString.h"
|
---|
[76606] | 36 | #include "UIExtraDataManager.h"
|
---|
[91125] | 37 | #include "UIIconPool.h"
|
---|
[104251] | 38 | #include "UITranslationEventListener.h"
|
---|
[82960] | 39 | #include "UIVirtualMachineItemLocal.h"
|
---|
[76606] | 40 | #ifdef VBOX_WS_MAC
|
---|
| 41 | # include <ApplicationServices/ApplicationServices.h>
|
---|
| 42 | #endif /* VBOX_WS_MAC */
|
---|
[30691] | 43 |
|
---|
[41587] | 44 | /* COM includes: */
|
---|
[76606] | 45 | #include "CSnapshot.h"
|
---|
[83254] | 46 | #include "CVirtualBoxErrorInfo.h"
|
---|
[41587] | 47 |
|
---|
[382] | 48 |
|
---|
[82878] | 49 | /*********************************************************************************************************************************
|
---|
[82944] | 50 | * Class UIVirtualMachineItemLocal implementation. *
|
---|
[82878] | 51 | *********************************************************************************************************************************/
|
---|
| 52 |
|
---|
[82944] | 53 | UIVirtualMachineItemLocal::UIVirtualMachineItemLocal(const CMachine &comMachine)
|
---|
[83921] | 54 | : UIVirtualMachineItem(UIVirtualMachineItemType_Local)
|
---|
[82944] | 55 | , m_comMachine(comMachine)
|
---|
[82878] | 56 | , m_cSnaphot(0)
|
---|
[84189] | 57 | , m_enmMachineState(KMachineState_Null)
|
---|
[82878] | 58 | , m_enmSessionState(KSessionState_Null)
|
---|
[382] | 59 | {
|
---|
[8159] | 60 | recache();
|
---|
[382] | 61 | }
|
---|
| 62 |
|
---|
[82944] | 63 | UIVirtualMachineItemLocal::~UIVirtualMachineItemLocal()
|
---|
[382] | 64 | {
|
---|
| 65 | }
|
---|
| 66 |
|
---|
[82944] | 67 | void UIVirtualMachineItemLocal::recache()
|
---|
[41608] | 68 | {
|
---|
[82878] | 69 | /* Determine attributes which are always available: */
|
---|
[83290] | 70 | m_uId = m_comMachine.GetId();
|
---|
[82878] | 71 | m_strSettingsFile = m_comMachine.GetSettingsFilePath();
|
---|
[72215] | 72 |
|
---|
[82878] | 73 | /* Now determine whether VM is accessible: */
|
---|
| 74 | m_fAccessible = m_comMachine.GetAccessible();
|
---|
[30022] | 75 | if (m_fAccessible)
|
---|
[382] | 76 | {
|
---|
[82878] | 77 | /* Reset last access error information: */
|
---|
[83254] | 78 | m_strAccessError.clear();
|
---|
[14355] | 79 |
|
---|
[82878] | 80 | /* Determine own VM attributes: */
|
---|
| 81 | m_strName = m_comMachine.GetName();
|
---|
| 82 | m_strOSTypeId = m_comMachine.GetOSTypeId();
|
---|
| 83 | m_groups = m_comMachine.GetGroups().toList();
|
---|
[1068] | 84 |
|
---|
[82878] | 85 | /* Determine snapshot attributes: */
|
---|
| 86 | CSnapshot comSnapshot = m_comMachine.GetCurrentSnapshot();
|
---|
| 87 | m_strSnapshotName = comSnapshot.isNull() ? QString() : comSnapshot.GetName();
|
---|
[94006] | 88 | #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
|
---|
| 89 | m_lastStateChange.setSecsSinceEpoch(m_comMachine.GetLastStateChange() / 1000);
|
---|
| 90 | #else
|
---|
[82878] | 91 | m_lastStateChange.setTime_t(m_comMachine.GetLastStateChange() / 1000);
|
---|
[94006] | 92 | #endif
|
---|
[82878] | 93 | m_cSnaphot = m_comMachine.GetSnapshotCount();
|
---|
[1121] | 94 |
|
---|
[82878] | 95 | /* Determine VM states: */
|
---|
| 96 | m_enmMachineState = m_comMachine.GetState();
|
---|
[82931] | 97 | m_machineStateIcon = gpConverter->toIcon(m_enmMachineState);
|
---|
[82878] | 98 | m_enmSessionState = m_comMachine.GetSessionState();
|
---|
[72215] | 99 |
|
---|
[82878] | 100 | /* Determine configuration access level: */
|
---|
| 101 | m_enmConfigurationAccessLevel = ::configurationAccessLevel(m_enmSessionState, m_enmMachineState);
|
---|
| 102 | /* Also take restrictions into account: */
|
---|
| 103 | if ( m_enmConfigurationAccessLevel != ConfigurationAccessLevel_Null
|
---|
[83290] | 104 | && !gEDataManager->machineReconfigurationEnabled(m_uId))
|
---|
[82878] | 105 | m_enmConfigurationAccessLevel = ConfigurationAccessLevel_Null;
|
---|
| 106 |
|
---|
| 107 | /* Determine PID finally: */
|
---|
| 108 | if ( m_enmMachineState == KMachineState_PoweredOff
|
---|
| 109 | || m_enmMachineState == KMachineState_Saved
|
---|
| 110 | || m_enmMachineState == KMachineState_Teleported
|
---|
| 111 | || m_enmMachineState == KMachineState_Aborted
|
---|
[91363] | 112 | || m_enmMachineState == KMachineState_AbortedSaved
|
---|
[24301] | 113 | )
|
---|
[1121] | 114 | {
|
---|
[30022] | 115 | m_pid = (ULONG) ~0;
|
---|
[1121] | 116 | }
|
---|
| 117 | else
|
---|
| 118 | {
|
---|
[82878] | 119 | m_pid = m_comMachine.GetSessionPID();
|
---|
[1121] | 120 | }
|
---|
[45050] | 121 |
|
---|
[82878] | 122 | /* Determine whether we should show this VM details: */
|
---|
[83290] | 123 | m_fHasDetails = gEDataManager->showMachineInVirtualBoxManagerDetails(m_uId);
|
---|
[382] | 124 | }
|
---|
| 125 | else
|
---|
| 126 | {
|
---|
[82878] | 127 | /* Update last access error information: */
|
---|
[83254] | 128 | m_strAccessError = UIErrorString::formatErrorInfo(m_comMachine.GetAccessError());
|
---|
[1068] | 129 |
|
---|
[82878] | 130 | /* Determine machine name on the basis of settings file only: */
|
---|
[30022] | 131 | QFileInfo fi(m_strSettingsFile);
|
---|
[82878] | 132 | m_strName = UICommon::hasAllowedExtension(fi.completeSuffix(), VBoxFileExts)
|
---|
| 133 | ? fi.completeBaseName()
|
---|
| 134 | : fi.fileName();
|
---|
| 135 | /* Reset other VM attributes: */
|
---|
| 136 | m_strOSTypeId = QString();
|
---|
| 137 | m_groups.clear();
|
---|
| 138 |
|
---|
| 139 | /* Reset snapshot attributes: */
|
---|
| 140 | m_strSnapshotName = QString();
|
---|
[30022] | 141 | m_lastStateChange = QDateTime::currentDateTime();
|
---|
| 142 | m_cSnaphot = 0;
|
---|
[1121] | 143 |
|
---|
[82878] | 144 | /* Reset VM states: */
|
---|
| 145 | m_enmMachineState = KMachineState_Null;
|
---|
[82931] | 146 | m_machineStateIcon = gpConverter->toIcon(KMachineState_Aborted);
|
---|
[82878] | 147 | m_enmSessionState = KSessionState_Null;
|
---|
| 148 |
|
---|
| 149 | /* Reset configuration access level: */
|
---|
| 150 | m_enmConfigurationAccessLevel = ConfigurationAccessLevel_Null;
|
---|
| 151 |
|
---|
| 152 | /* Reset PID finally: */
|
---|
[30022] | 153 | m_pid = (ULONG) ~0;
|
---|
[45050] | 154 |
|
---|
[82878] | 155 | /* Reset whether we should show this VM details: */
|
---|
[45054] | 156 | m_fHasDetails = true;
|
---|
[382] | 157 | }
|
---|
| 158 |
|
---|
[72704] | 159 | /* Recache item pixmap: */
|
---|
| 160 | recachePixmap();
|
---|
[82931] | 161 |
|
---|
| 162 | /* Retranslate finally: */
|
---|
[104251] | 163 | sltRetranslateUI();
|
---|
| 164 | connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
|
---|
| 165 | this, &UIVirtualMachineItemLocal::sltRetranslateUI);
|
---|
[382] | 166 | }
|
---|
| 167 |
|
---|
[82944] | 168 | void UIVirtualMachineItemLocal::recachePixmap()
|
---|
[72704] | 169 | {
|
---|
| 170 | /* If machine is accessible: */
|
---|
| 171 | if (m_fAccessible)
|
---|
| 172 | {
|
---|
| 173 | /* First, we are trying to acquire personal machine guest OS type icon: */
|
---|
[91125] | 174 | m_pixmap = generalIconPool().userMachinePixmapDefault(m_comMachine, &m_logicalPixmapSize);
|
---|
[72704] | 175 | /* If there is nothing, we are using icon corresponding to cached guest OS type: */
|
---|
| 176 | if (m_pixmap.isNull())
|
---|
[91125] | 177 | m_pixmap = generalIconPool().guestOSTypePixmapDefault(m_strOSTypeId, &m_logicalPixmapSize);
|
---|
[72704] | 178 | }
|
---|
| 179 | /* Otherwise: */
|
---|
| 180 | else
|
---|
| 181 | {
|
---|
| 182 | /* We are using "Other" guest OS type icon: */
|
---|
[91125] | 183 | m_pixmap = generalIconPool().guestOSTypePixmapDefault("Other", &m_logicalPixmapSize);
|
---|
[72704] | 184 | }
|
---|
| 185 | }
|
---|
| 186 |
|
---|
[82944] | 187 | bool UIVirtualMachineItemLocal::isItemEditable() const
|
---|
[43460] | 188 | {
|
---|
[82942] | 189 | return accessible()
|
---|
| 190 | && sessionState() == KSessionState_Unlocked;
|
---|
[43460] | 191 | }
|
---|
| 192 |
|
---|
[84102] | 193 | bool UIVirtualMachineItemLocal::isItemRemovable() const
|
---|
| 194 | {
|
---|
| 195 | return !accessible()
|
---|
| 196 | || sessionState() == KSessionState_Unlocked;
|
---|
| 197 | }
|
---|
| 198 |
|
---|
[82944] | 199 | bool UIVirtualMachineItemLocal::isItemSaved() const
|
---|
[43460] | 200 | {
|
---|
[82942] | 201 | return accessible()
|
---|
[91363] | 202 | && ( machineState() == KMachineState_Saved
|
---|
| 203 | || machineState() == KMachineState_AbortedSaved);
|
---|
[43460] | 204 | }
|
---|
| 205 |
|
---|
[82944] | 206 | bool UIVirtualMachineItemLocal::isItemPoweredOff() const
|
---|
[43460] | 207 | {
|
---|
[82942] | 208 | return accessible()
|
---|
| 209 | && ( machineState() == KMachineState_PoweredOff
|
---|
| 210 | || machineState() == KMachineState_Saved
|
---|
| 211 | || machineState() == KMachineState_Teleported
|
---|
[91363] | 212 | || machineState() == KMachineState_Aborted
|
---|
| 213 | || machineState() == KMachineState_AbortedSaved);
|
---|
[43460] | 214 | }
|
---|
| 215 |
|
---|
[82944] | 216 | bool UIVirtualMachineItemLocal::isItemStarted() const
|
---|
[43460] | 217 | {
|
---|
[82942] | 218 | return isItemRunning()
|
---|
| 219 | || isItemPaused();
|
---|
[43460] | 220 | }
|
---|
| 221 |
|
---|
[82944] | 222 | bool UIVirtualMachineItemLocal::isItemRunning() const
|
---|
[43460] | 223 | {
|
---|
[82942] | 224 | return accessible()
|
---|
| 225 | && ( machineState() == KMachineState_Running
|
---|
| 226 | || machineState() == KMachineState_Teleporting
|
---|
| 227 | || machineState() == KMachineState_LiveSnapshotting);
|
---|
[43460] | 228 | }
|
---|
| 229 |
|
---|
[82944] | 230 | bool UIVirtualMachineItemLocal::isItemRunningHeadless() const
|
---|
[55552] | 231 | {
|
---|
[82942] | 232 | if (isItemRunning())
|
---|
[55552] | 233 | {
|
---|
| 234 | /* Open session to determine which frontend VM is started with: */
|
---|
[82942] | 235 | CSession comSession = uiCommon().openExistingSession(id());
|
---|
[82878] | 236 | if (!comSession.isNull())
|
---|
[55552] | 237 | {
|
---|
[55800] | 238 | /* Acquire the session name: */
|
---|
[82878] | 239 | const QString strSessionName = comSession.GetMachine().GetSessionName();
|
---|
[55552] | 240 | /* Close the session early: */
|
---|
[82878] | 241 | comSession.UnlockMachine();
|
---|
[55800] | 242 | /* Check whether we are in 'headless' session: */
|
---|
| 243 | return strSessionName == "headless";
|
---|
[55552] | 244 | }
|
---|
| 245 | }
|
---|
| 246 | return false;
|
---|
| 247 | }
|
---|
| 248 |
|
---|
[82944] | 249 | bool UIVirtualMachineItemLocal::isItemPaused() const
|
---|
[43460] | 250 | {
|
---|
[82942] | 251 | return accessible()
|
---|
| 252 | && ( machineState() == KMachineState_Paused
|
---|
| 253 | || machineState() == KMachineState_TeleportingPausedVM);
|
---|
[43460] | 254 | }
|
---|
| 255 |
|
---|
[82944] | 256 | bool UIVirtualMachineItemLocal::isItemStuck() const
|
---|
[43460] | 257 | {
|
---|
[82942] | 258 | return accessible()
|
---|
| 259 | && machineState() == KMachineState_Stuck;
|
---|
[43460] | 260 | }
|
---|
| 261 |
|
---|
[83755] | 262 | bool UIVirtualMachineItemLocal::isItemCanBeSwitchedTo() const
|
---|
| 263 | {
|
---|
| 264 | return const_cast<CMachine&>(m_comMachine).CanShowConsoleWindow()
|
---|
| 265 | || isItemRunningHeadless();
|
---|
| 266 | }
|
---|
| 267 |
|
---|
[104251] | 268 | void UIVirtualMachineItemLocal::sltRetranslateUI()
|
---|
[82931] | 269 | {
|
---|
| 270 | /* This is used in tool-tip generation: */
|
---|
[94009] | 271 | #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
|
---|
| 272 | const QString strDateTime = m_lastStateChange.date() == QDate::currentDate()
|
---|
| 273 | ? QLocale::system().toString(m_lastStateChange.time(), QLocale::ShortFormat)
|
---|
| 274 | : QLocale::system().toString(m_lastStateChange, QLocale::ShortFormat);
|
---|
| 275 | #else
|
---|
[82931] | 276 | const QString strDateTime = (m_lastStateChange.date() == QDate::currentDate())
|
---|
| 277 | ? m_lastStateChange.time().toString(Qt::LocalDate)
|
---|
| 278 | : m_lastStateChange.toString(Qt::LocalDate);
|
---|
[94009] | 279 | #endif
|
---|
[82878] | 280 |
|
---|
[82931] | 281 | /* If machine is accessible: */
|
---|
| 282 | if (m_fAccessible)
|
---|
| 283 | {
|
---|
[96487] | 284 | /* Just use the usual translation for valid states: */
|
---|
| 285 | m_strMachineStateName = gpConverter->toString(m_enmMachineState);
|
---|
| 286 | m_strSessionStateName = gpConverter->toString(m_enmSessionState);
|
---|
| 287 |
|
---|
[82931] | 288 | /* Update tool-tip: */
|
---|
| 289 | m_strToolTipText = QString("<b>%1</b>").arg(m_strName);
|
---|
| 290 | if (!m_strSnapshotName.isNull())
|
---|
| 291 | m_strToolTipText += QString(" (%1)").arg(m_strSnapshotName);
|
---|
| 292 | m_strToolTipText = tr("<nobr>%1<br></nobr>"
|
---|
| 293 | "<nobr>%2 since %3</nobr><br>"
|
---|
| 294 | "<nobr>Session %4</nobr>",
|
---|
| 295 | "VM tooltip (name, last state change, session state)")
|
---|
| 296 | .arg(m_strToolTipText)
|
---|
| 297 | .arg(gpConverter->toString(m_enmMachineState))
|
---|
| 298 | .arg(strDateTime)
|
---|
| 299 | .arg(gpConverter->toString(m_enmSessionState).toLower());
|
---|
| 300 | }
|
---|
| 301 | /* Otherwise: */
|
---|
| 302 | else
|
---|
| 303 | {
|
---|
[96487] | 304 | /* We have our own translation for Null states: */
|
---|
| 305 | m_strMachineStateName = tr("Inaccessible");
|
---|
| 306 | m_strSessionStateName = tr("Inaccessible");
|
---|
| 307 |
|
---|
[82931] | 308 | /* Update tool-tip: */
|
---|
| 309 | m_strToolTipText = tr("<nobr><b>%1</b><br></nobr>"
|
---|
| 310 | "<nobr>Inaccessible since %2</nobr>",
|
---|
| 311 | "Inaccessible VM tooltip (name, last state change)")
|
---|
| 312 | .arg(m_strSettingsFile)
|
---|
| 313 | .arg(strDateTime);
|
---|
| 314 | }
|
---|
| 315 | }
|
---|