VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/manager/UIVirtualBoxManager.cpp

Last change on this file was 106349, checked in by vboxsync, 7 weeks ago

FE/Qt: bugref:10407. Default to Wayland QPA even if XWayland is around.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 166.6 KB
Line 
1/* $Id: UIVirtualBoxManager.cpp 106349 2024-10-16 10:03:28Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIVirtualBoxManager class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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 <QActionGroup>
30#include <QApplication>
31#include <QClipboard>
32#include <QFile>
33#include <QFontDatabase>
34#include <QGuiApplication>
35#include <QMenuBar>
36#include <QProcess>
37#include <QPushButton>
38#include <QStandardPaths>
39#include <QStatusBar>
40#include <QStyle>
41#include <QTextEdit>
42#include <QVBoxLayout>
43#include <QWindow>
44#ifndef VBOX_WS_WIN
45# include <QRegularExpression>
46#endif
47
48/* GUI includes: */
49#include "QIDialogButtonBox.h"
50#include "QIFileDialog.h"
51#include "QILineEdit.h"
52#include "QIRichTextLabel.h"
53#include "UIActionPoolManager.h"
54#include "UIAdvancedSettingsDialogSpecific.h"
55#include "UICloudConsoleManager.h"
56#include "UICloudMachineManager.h"
57#include "UICloudNetworkingStuff.h"
58#include "UICloudProfileManager.h"
59#include "UICommon.h"
60#include "UIDesktopServices.h"
61#include "UIDesktopWidgetWatchdog.h"
62#include "UIErrorString.h"
63#include "UIExtension.h"
64#include "UIExtensionPackManager.h"
65#include "UIExtraDataManager.h"
66#include "UIGlobalSession.h"
67#include "UIHelpBrowserDialog.h"
68#include "UIIconPool.h"
69#include "UILocalMachineStuff.h"
70#include "UILoggingDefs.h"
71#include "UIMedium.h"
72#include "UIMediumEnumerator.h"
73#include "UIMediumTools.h"
74#include "UIMediumManager.h"
75#include "UIMessageCenter.h"
76#include "UIModalWindowManager.h"
77#include "UINetworkManager.h"
78#include "UINotificationCenter.h"
79#include "UIQObjectStuff.h"
80#include "UITranslationEventListener.h"
81#include "UIVirtualBoxManager.h"
82#include "UIVirtualBoxManagerWidget.h"
83#include "UIVirtualMachineItemCloud.h"
84#include "UIVirtualMachineItemLocal.h"
85#include "UIVirtualBoxEventHandler.h"
86#include "UIVMLogViewerDialog.h"
87#include "UIWizardAddCloudVM.h"
88#include "UIWizardCloneVM.h"
89#include "UIWizardExportApp.h"
90#include "UIWizardImportApp.h"
91#include "UIWizardNewCloudVM.h"
92#include "UIWizardNewVD.h"
93#include "UIWizardNewVM.h"
94#ifdef VBOX_GUI_WITH_NETWORK_MANAGER
95# include "UIUpdateManager.h"
96#endif
97#ifdef VBOX_WS_MAC
98# include "UIImageTools.h"
99# include "UIWindowMenuManager.h"
100# include "UIVersion.h"
101# include "VBoxUtils.h"
102#else
103# include "UIMenuBar.h"
104#endif
105#ifdef VBOX_WS_NIX
106# include "UIDesktopWidgetWatchdog.h"
107#endif
108
109/* COM includes: */
110#include "CHostUSBDevice.h"
111#include "CGuestOSType.h"
112#include "CSystemProperties.h"
113#include "CUnattended.h"
114#include "CVirtualBoxErrorInfo.h"
115#ifdef VBOX_WS_MAC
116# include "CVirtualBox.h"
117#endif
118
119/* Other VBox stuff: */
120#include <iprt/buildconfig.h>
121#include <VBox/version.h>
122
123/** QDialog extension used to ask for a public key for console connection needs. */
124class UIAcquirePublicKeyDialog : public QDialog
125{
126 Q_OBJECT;
127
128public:
129
130 /** Constructs dialog passing @a pParent to the base-class. */
131 UIAcquirePublicKeyDialog(QWidget *pParent = 0);
132
133 /** Return public key. */
134 QString publicKey() const;
135
136private slots:
137
138 /** Handles help-viewer @a link click. */
139 void sltHandleHelpViewerLinkClick(const QUrl &link);
140
141 /** Handles abstract @a pButton click. */
142 void sltHandleButtonClicked(QAbstractButton *pButton);
143 /** Handles Open button click. */
144 void sltHandleOpenButtonClick();
145
146 /** Performs revalidation. */
147 void sltRevalidate();
148
149 /** Handles translation event. */
150 void sltRetranslateUI();
151
152private:
153
154 /** Prepares all. */
155 void prepare();
156 /** Prepares widgets. */
157 void prepareWidgets();
158 /** Prepare editor contents. */
159 void prepareEditorContents();
160
161 /** Returns a list of default key folders. */
162 QStringList defaultKeyFolders() const;
163 /** Returns a list of key generation tools. */
164 QStringList keyGenerationTools() const;
165
166 /** Loads file contents.
167 * @returns Whether file was really loaded. */
168 bool loadFileContents(const QString &strPath, bool fIgnoreErrors = false);
169
170 /** Holds the help-viewer instance. */
171 QIRichTextLabel *m_pHelpViewer;
172 /** Holds the text-editor instance. */
173 QTextEdit *m_pTextEditor;
174 /** Holds the button-box instance. */
175 QIDialogButtonBox *m_pButtonBox;
176};
177
178/** QDialog extension used to ask for a cloud machine clone name. */
179class UIAcquireCloudMachineCloneNameDialog : public QDialog
180{
181 Q_OBJECT;
182
183public:
184
185 /** Constructs dialog passing @a pParent to the base-class.
186 * @param strName Brings the clone name by default. */
187 UIAcquireCloudMachineCloneNameDialog(QWidget *pParent, const QString &strName);
188
189 /** Returns value. */
190 QString value() const;
191
192private slots:
193
194 /** Handles translation event. */
195 void sltRetranslateUI();
196
197 /** Performs revalidation. */
198 void sltRevalidate();
199
200private:
201
202 /** Prepares all. */
203 void prepare();
204 /** Prepares widgets. */
205 void prepareWidgets();
206
207 /** Holds the clone name by default. */
208 QString m_strName;
209
210 /** Holds the text-editor instance. */
211 QILineEdit *m_pEditor;
212 /** Holds the button-box instance. */
213 QIDialogButtonBox *m_pButtonBox;
214};
215
216
217/*********************************************************************************************************************************
218* Class UIAcquirePublicKeyDialog implementation. *
219*********************************************************************************************************************************/
220
221UIAcquirePublicKeyDialog::UIAcquirePublicKeyDialog(QWidget *pParent /* = 0 */)
222 : QDialog(pParent)
223 , m_pHelpViewer(0)
224 , m_pTextEditor(0)
225 , m_pButtonBox(0)
226{
227 prepare();
228 sltRevalidate();
229}
230
231QString UIAcquirePublicKeyDialog::publicKey() const
232{
233 return m_pTextEditor->toPlainText();
234}
235
236void UIAcquirePublicKeyDialog::sltHandleHelpViewerLinkClick(const QUrl &link)
237{
238 /* Parse the link meta and use it to get tool path to copy to clipboard: */
239 bool fOk = false;
240 const uint uToolNumber = link.toString().section('#', 1, 1).toUInt(&fOk);
241 if (fOk)
242 QApplication::clipboard()->setText(keyGenerationTools().value(uToolNumber), QClipboard::Clipboard);
243}
244
245void UIAcquirePublicKeyDialog::sltHandleButtonClicked(QAbstractButton *pButton)
246{
247 const QDialogButtonBox::StandardButton enmStandardButton = m_pButtonBox->standardButton(pButton);
248 switch (enmStandardButton)
249 {
250 case QDialogButtonBox::Ok: return accept();
251 case QDialogButtonBox::Cancel: return reject();
252 case QDialogButtonBox::Open: return sltHandleOpenButtonClick();
253 default: break;
254 }
255}
256
257void UIAcquirePublicKeyDialog::sltHandleOpenButtonClick()
258{
259 CVirtualBox comVBox = gpGlobalSession->virtualBox();
260 const QString strFileName = QIFileDialog::getOpenFileName(comVBox.GetHomeFolder(), QString(),
261 this, tr("Choose a public key file"));
262 if (!strFileName.isEmpty())
263 {
264 gEDataManager->setCloudConsolePublicKeyPath(strFileName);
265 loadFileContents(strFileName);
266 }
267}
268
269void UIAcquirePublicKeyDialog::sltRevalidate()
270{
271 m_pButtonBox->button(QDialogButtonBox::Ok)->setEnabled(!m_pTextEditor->toPlainText().isEmpty());
272}
273
274void UIAcquirePublicKeyDialog::sltRetranslateUI()
275{
276 setWindowTitle(tr("Public key"));
277
278 /* Generating help-viewer text: */
279 QStringList folders;
280 foreach (const QString &strFolder, defaultKeyFolders())
281 folders << QString("&nbsp;%1").arg(strFolder);
282 const QStringList initialTools = keyGenerationTools();
283 QStringList tools;
284 foreach (const QString &strTool, initialTools)
285 tools << QString("&nbsp;<a href=#%1><img src='manager://copy'/></a>&nbsp;&nbsp;%2")
286 .arg(initialTools.indexOf(strTool))
287 .arg(strTool);
288#ifdef VBOX_WS_WIN
289 m_pHelpViewer->setText(tr("We haven't found public key id_rsa[.pub] in suitable locations. "
290 "If you have one, please put it under one of those folders OR copy "
291 "content to the edit box below:<br><br>"
292 "%1<br><br>"
293 "If you don't have one, please consider using one of the following "
294 "tools to generate it:<br><br>"
295 "%2")
296 .arg(folders.join("<br>"))
297 .arg(tools.join("<br>")));
298#else
299 m_pHelpViewer->setText(tr("We haven't found public key id_rsa[.pub] in suitable location. "
300 "If you have one, please put it under specified folder OR copy "
301 "content to the edit box below:<br><br>"
302 "%1<br><br>"
303 "If you don't have one, please consider using the following "
304 "tool to generate it:<br><br>"
305 "%2")
306 .arg(folders.join("<br>"))
307 .arg(tools.join("<br>")));
308#endif
309
310 m_pTextEditor->setPlaceholderText(tr("Paste public key"));
311 m_pButtonBox->button(QDialogButtonBox::Open)->setText(tr("Browse"));
312}
313
314void UIAcquirePublicKeyDialog::prepare()
315{
316 /* Prepare widgets: */
317 prepareWidgets();
318 /* Prepare editor contents: */
319 prepareEditorContents();
320 /* Apply language settings: */
321 sltRetranslateUI();
322 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
323 this, &UIAcquirePublicKeyDialog::sltRetranslateUI);
324
325 /* Resize to suitable size: */
326 const int iMinimumHeightHint = minimumSizeHint().height();
327 resize(iMinimumHeightHint * 1.618, iMinimumHeightHint);
328}
329
330void UIAcquirePublicKeyDialog::prepareWidgets()
331{
332 /* Prepare layout: */
333 QVBoxLayout *pLayout = new QVBoxLayout(this);
334 if (pLayout)
335 {
336 /* Create help-viewer: */
337 m_pHelpViewer = new QIRichTextLabel(this);
338 if (m_pHelpViewer)
339 {
340 /* Prepare icon and size as well: */
341 const QIcon icon = UIIconPool::iconSet(":/file_manager_copy_16px.png");
342 const int iMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) * 2 / 3;
343
344 /* Configure help-viewer: */
345 m_pHelpViewer->setHidden(true);
346 m_pHelpViewer->setMinimumTextWidth(gpDesktop->screenGeometry(window()).width() / 5);
347 const qreal fDevicePixelRatio = windowHandle() ? windowHandle()->devicePixelRatio() : 1;
348 m_pHelpViewer->registerPixmap(icon.pixmap(QSize(iMetric, iMetric), fDevicePixelRatio), "manager://copy");
349 connect(m_pHelpViewer, &QIRichTextLabel::sigLinkClicked, this, &UIAcquirePublicKeyDialog::sltHandleHelpViewerLinkClick);
350 pLayout->addWidget(m_pHelpViewer, 2);
351 }
352
353 /* Prepare text-editor: */
354 m_pTextEditor = new QTextEdit(this);
355 if (m_pTextEditor)
356 {
357 connect(m_pTextEditor, &QTextEdit::textChanged, this, &UIAcquirePublicKeyDialog::sltRevalidate);
358 pLayout->addWidget(m_pTextEditor, 1);
359 }
360
361 /* Prepare button-box: */
362 m_pButtonBox = new QIDialogButtonBox(this);
363 if (m_pButtonBox)
364 {
365 m_pButtonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Open);
366 connect(m_pButtonBox, &QIDialogButtonBox::clicked, this, &UIAcquirePublicKeyDialog::sltHandleButtonClicked);
367 pLayout->addWidget(m_pButtonBox);
368 }
369 }
370}
371
372void UIAcquirePublicKeyDialog::prepareEditorContents()
373{
374 /* Check whether we were able to load key file: */
375 bool fFileLoaded = false;
376
377 /* Try to load last remembered file contents: */
378 fFileLoaded = loadFileContents(gEDataManager->cloudConsolePublicKeyPath(), true /* ignore errors */);
379 if (!fFileLoaded)
380 {
381 /* We have failed to load file mentioned in extra-data, now we have
382 * to check whether file present in one of default paths: */
383 QString strAbsoluteFilePathWeNeed;
384 foreach (const QString &strPath, defaultKeyFolders())
385 {
386 /* Gather possible file names, there can be few of them: */
387 const QStringList fileNames = QStringList() << "id_rsa.pub" << "id_rsa";
388 /* For each file name we have to: */
389 foreach (const QString &strFileName, fileNames)
390 {
391 /* Compose absolute file path: */
392 const QString strAbsoluteFilePath = QDir(strPath).absoluteFilePath(strFileName);
393 /* If that file exists, we are referring it: */
394 if (QFile::exists(strAbsoluteFilePath))
395 {
396 strAbsoluteFilePathWeNeed = strAbsoluteFilePath;
397 break;
398 }
399 }
400 /* Break early if we have found something: */
401 if (!strAbsoluteFilePathWeNeed.isEmpty())
402 break;
403 }
404
405 /* Try to open file if it was really found: */
406 if (!strAbsoluteFilePathWeNeed.isEmpty())
407 fFileLoaded = loadFileContents(strAbsoluteFilePathWeNeed, true /* ignore errors */);
408 }
409
410 /* Show/hide help-viewer depending on
411 * whether we were able to load the file: */
412 m_pHelpViewer->setHidden(fFileLoaded);
413}
414
415QStringList UIAcquirePublicKeyDialog::defaultKeyFolders() const
416{
417 QStringList folders;
418#ifdef VBOX_WS_WIN
419 // WORKAROUND:
420 // There is additional default folder on Windows:
421 folders << QDir::toNativeSeparators(QDir(QDir::homePath()).absoluteFilePath("oci"));
422#endif
423 folders << QDir::toNativeSeparators(QDir(QDir::homePath()).absoluteFilePath(".ssh"));
424 return folders;
425}
426
427QStringList UIAcquirePublicKeyDialog::keyGenerationTools() const
428{
429 QStringList tools;
430#ifdef VBOX_WS_WIN
431 // WORKAROUND:
432 // There is additional key generation tool on Windows:
433 tools << "puttygen.exe";
434 tools << "ssh-keygen.exe -m PEM -t rsa -b 4096";
435#else
436 tools << "ssh-keygen -m PEM -t rsa -b 4096";
437#endif
438 return tools;
439}
440
441bool UIAcquirePublicKeyDialog::loadFileContents(const QString &strPath, bool fIgnoreErrors /* = false */)
442{
443 /* Make sure file path isn't empty: */
444 if (strPath.isEmpty())
445 {
446 if (!fIgnoreErrors)
447 UINotificationMessage::warnAboutPublicKeyFilePathIsEmpty();
448 return false;
449 }
450
451 /* Make sure file exists and is of suitable size: */
452 QFileInfo fi(strPath);
453 if (!fi.exists())
454 {
455 if (!fIgnoreErrors)
456 UINotificationMessage::warnAboutPublicKeyFileDoesntExist(strPath);
457 return false;
458 }
459 if (fi.size() > 10 * _1K)
460 {
461 if (!fIgnoreErrors)
462 UINotificationMessage::warnAboutPublicKeyFileIsOfTooLargeSize(strPath);
463 return false;
464 }
465
466 /* Make sure file can be opened: */
467 QFile file(strPath);
468 if (!file.open(QIODevice::ReadOnly))
469 {
470 if (!fIgnoreErrors)
471 UINotificationMessage::warnAboutPublicKeyFileIsntReadable(strPath);
472 return false;
473 }
474
475 /* File opened and read, filling editor: */
476 m_pTextEditor->setPlainText(file.readAll());
477 return true;
478}
479
480
481/*********************************************************************************************************************************
482* Class UIAcquireCloudMachineCloneNameDialog implementation. *
483*********************************************************************************************************************************/
484
485UIAcquireCloudMachineCloneNameDialog::UIAcquireCloudMachineCloneNameDialog(QWidget *pParent, const QString &strName)
486 : QDialog(pParent)
487 , m_strName(strName)
488 , m_pEditor(0)
489 , m_pButtonBox(0)
490{
491 prepare();
492 sltRevalidate();
493}
494
495QString UIAcquireCloudMachineCloneNameDialog::value() const
496{
497 return m_pEditor ? m_pEditor->text() : QString();
498}
499
500void UIAcquireCloudMachineCloneNameDialog::prepare()
501{
502 /* Prepare widgets: */
503 prepareWidgets();
504 /* Apply language settings: */
505 sltRetranslateUI();
506 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
507 this, &UIAcquireCloudMachineCloneNameDialog::sltRetranslateUI);
508
509 /* Resize to suitable size: */
510 const int iMinimumHeightHint = minimumSizeHint().height();
511 resize(iMinimumHeightHint * 1.618, iMinimumHeightHint);
512}
513
514void UIAcquireCloudMachineCloneNameDialog::prepareWidgets()
515{
516 /* Prepare layout: */
517 QVBoxLayout *pLayout = new QVBoxLayout(this);
518 if (pLayout)
519 {
520 /* Prepare editor: */
521 m_pEditor = new QILineEdit(this);
522 if (m_pEditor)
523 {
524 m_pEditor->setText(m_strName);
525 m_pEditor->setMinimumWidthByText(QString().fill('0', 20));
526 connect(m_pEditor, &QILineEdit::textChanged, this, &UIAcquireCloudMachineCloneNameDialog::sltRevalidate);
527 pLayout->addWidget(m_pEditor);
528 }
529
530 /* Intermediate stretch: */
531 pLayout->addStretch();
532
533 /* Prepare button-box: */
534 m_pButtonBox = new QIDialogButtonBox(this);
535 if (m_pButtonBox)
536 {
537 m_pButtonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
538 connect(m_pButtonBox, &QIDialogButtonBox::accepted, this, &UIAcquireCloudMachineCloneNameDialog::accept);
539 connect(m_pButtonBox, &QIDialogButtonBox::rejected, this, &UIAcquireCloudMachineCloneNameDialog::reject);
540 pLayout->addWidget(m_pButtonBox);
541 }
542 }
543}
544
545void UIAcquireCloudMachineCloneNameDialog::sltRetranslateUI()
546{
547 setWindowTitle(tr("Clone Virtual Machine"));
548 m_pEditor->setPlaceholderText(tr("Enter machine name..."));
549}
550
551void UIAcquireCloudMachineCloneNameDialog::sltRevalidate()
552{
553 m_pButtonBox->button(QDialogButtonBox::Ok)->setEnabled(!m_pEditor->text().isEmpty());
554}
555
556
557/*********************************************************************************************************************************
558* Class UIVirtualBoxManager implementation. *
559*********************************************************************************************************************************/
560
561/* static */
562UIVirtualBoxManager *UIVirtualBoxManager::s_pInstance = 0;
563
564/* static */
565void UIVirtualBoxManager::create()
566{
567 /* Make sure VirtualBox Manager isn't created: */
568 AssertReturnVoid(s_pInstance == 0);
569
570 /* Create VirtualBox Manager: */
571 new UIVirtualBoxManager;
572 /* Prepare VirtualBox Manager: */
573 s_pInstance->prepare();
574 /* Show VirtualBox Manager: */
575 s_pInstance->show();
576 /* Register in the modal window manager: */
577 windowManager().setMainWindowShown(s_pInstance);
578}
579
580/* static */
581void UIVirtualBoxManager::destroy()
582{
583 /* Make sure VirtualBox Manager is created: */
584 if (!s_pInstance)
585 return;
586
587 /* Unregister in the modal window manager: */
588 windowManager().setMainWindowShown(0);
589 /* Cleanup VirtualBox Manager: */
590 s_pInstance->cleanup();
591 /* Destroy machine UI: */
592 delete s_pInstance;
593}
594
595UIVirtualBoxManager::UIVirtualBoxManager()
596 : m_fPolished(false)
597 , m_fFirstMediumEnumerationHandled(false)
598 , m_pActionPool(0)
599 , m_pWidget(0)
600 , m_iGeometrySaveTimerId(-1)
601 , m_fSnapshotCloneByDefault(false)
602 , m_fImportFromOCI(false)
603 , m_fExportToOCI(false)
604{
605 s_pInstance = this;
606 setAcceptDrops(true);
607}
608
609UIVirtualBoxManager::~UIVirtualBoxManager()
610{
611 s_pInstance = 0;
612}
613
614bool UIVirtualBoxManager::shouldBeMaximized() const
615{
616 return gEDataManager->selectorWindowShouldBeMaximized();
617}
618
619#ifdef VBOX_WS_MAC
620bool UIVirtualBoxManager::eventFilter(QObject *pObject, QEvent *pEvent)
621{
622 /* Ignore for non-active window except for FileOpen event which should be always processed: */
623 if (!isActiveWindow() && pEvent->type() != QEvent::FileOpen)
624 return QMainWindowWithRestorableGeometry::eventFilter(pObject, pEvent);
625
626 /* Ignore for other objects: */
627 if (qobject_cast<QWidget*>(pObject) &&
628 qobject_cast<QWidget*>(pObject)->window() != this)
629 return QMainWindowWithRestorableGeometry::eventFilter(pObject, pEvent);
630
631 /* Which event do we have? */
632 switch (pEvent->type())
633 {
634 case QEvent::FileOpen:
635 {
636 sltHandleOpenUrlCall(QList<QUrl>() << static_cast<QFileOpenEvent*>(pEvent)->url());
637 pEvent->accept();
638 return true;
639 break;
640 }
641 default:
642 break;
643 }
644
645 /* Call to base-class: */
646 return QMainWindowWithRestorableGeometry::eventFilter(pObject, pEvent);
647}
648#endif /* VBOX_WS_MAC */
649
650void UIVirtualBoxManager::sltRetranslateUI()
651{
652 /* Set window title: */
653 QString strTitle(VBOX_PRODUCT);
654 strTitle += " " + tr("Manager", "Note: main window title which is prepended by the product name.");
655#ifdef VBOX_BLEEDING_EDGE
656 strTitle += QString(" EXPERIMENTAL build ")
657 + QString(RTBldCfgVersion())
658 + QString(" r")
659 + QString(RTBldCfgRevisionStr())
660 + QString(" - " VBOX_BLEEDING_EDGE);
661#endif /* VBOX_BLEEDING_EDGE */
662 setWindowTitle(strTitle);
663}
664
665bool UIVirtualBoxManager::event(QEvent *pEvent)
666{
667 /* Which event do we have? */
668 switch (pEvent->type())
669 {
670 /* Handle every ScreenChangeInternal event to notify listeners: */
671 case QEvent::ScreenChangeInternal:
672 {
673 emit sigWindowRemapped();
674 break;
675 }
676 /* Handle move/resize geometry changes: */
677 case QEvent::Move:
678 case QEvent::Resize:
679 {
680 if (m_iGeometrySaveTimerId != -1)
681 killTimer(m_iGeometrySaveTimerId);
682 m_iGeometrySaveTimerId = startTimer(300);
683 break;
684 }
685 /* Handle timer event started above: */
686 case QEvent::Timer:
687 {
688 QTimerEvent *pTimerEvent = static_cast<QTimerEvent*>(pEvent);
689 if (pTimerEvent->timerId() == m_iGeometrySaveTimerId)
690 {
691 killTimer(m_iGeometrySaveTimerId);
692 m_iGeometrySaveTimerId = -1;
693 const QRect geo = currentGeometry();
694 LogRel2(("GUI: UIVirtualBoxManager: Saving geometry as: Origin=%dx%d, Size=%dx%d\n",
695 geo.x(), geo.y(), geo.width(), geo.height()));
696 gEDataManager->setSelectorWindowGeometry(geo, isCurrentlyMaximized());
697 }
698 break;
699 }
700 default:
701 break;
702 }
703 /* Call to base-class: */
704 return QMainWindowWithRestorableGeometry::event(pEvent);
705}
706
707void UIVirtualBoxManager::showEvent(QShowEvent *pEvent)
708{
709 /* Call to base-class: */
710 QMainWindowWithRestorableGeometry::showEvent(pEvent);
711
712 /* Is polishing required? */
713 if (!m_fPolished)
714 {
715 /* Pass the show-event to polish-event: */
716 polishEvent(pEvent);
717 /* Mark as polished: */
718 m_fPolished = true;
719 }
720}
721
722void UIVirtualBoxManager::polishEvent(QShowEvent *)
723{
724 /* Make sure user warned about inaccessible media: */
725 QMetaObject::invokeMethod(this, "sltHandleMediumEnumerationFinish", Qt::QueuedConnection);
726}
727
728void UIVirtualBoxManager::closeEvent(QCloseEvent *pEvent)
729{
730 /* Call to base-class: */
731 QMainWindowWithRestorableGeometry::closeEvent(pEvent);
732
733 /* Quit application: */
734 QApplication::quit();
735}
736
737void UIVirtualBoxManager::dragEnterEvent(QDragEnterEvent *pEvent)
738{
739 if (pEvent->mimeData()->hasUrls())
740 pEvent->acceptProposedAction();
741}
742
743void UIVirtualBoxManager::dropEvent(QDropEvent *pEvent)
744{
745 if (!pEvent->mimeData()->hasUrls())
746 return;
747 sltHandleOpenUrlCall(pEvent->mimeData()->urls());
748 pEvent->acceptProposedAction();
749}
750
751#ifdef VBOX_WS_NIX
752void UIVirtualBoxManager::sltHandleHostScreenAvailableAreaChange()
753{
754 /* Prevent handling if fake screen detected: */
755 if (UIDesktopWidgetWatchdog::isFakeScreenDetected())
756 return;
757
758 /* Restore the geometry cached by the window: */
759 const QRect geo = currentGeometry();
760 resize(geo.size());
761 move(geo.topLeft());
762}
763#endif /* VBOX_WS_NIX */
764
765void UIVirtualBoxManager::sltHandleCommitData()
766{
767 /* Close the sub-dialogs first: */
768 sltCloseManagerWindow(UIToolType_Extensions);
769 sltCloseManagerWindow(UIToolType_Media);
770 sltCloseManagerWindow(UIToolType_Network);
771 sltCloseManagerWindow(UIToolType_Cloud);
772 sltCloseManagerWindow(UIToolType_CloudConsole);
773 sltCloseSettingsDialog();
774 sltClosePreferencesDialog();
775
776 // WORKAROUND:
777 // This will be fixed proper way during session management cleanup for Qt6.
778 // But for now we will just cleanup connections which is Ok anyway.
779 cleanupConnections();
780}
781
782void UIVirtualBoxManager::sltHandleMediumEnumerationFinish()
783{
784#if 0 // ohh, come on!
785 /* To avoid annoying the user, we check for inaccessible media just once, after
786 * the first media emumeration [started from main() at startup] is complete. */
787 if (m_fFirstMediumEnumerationHandled)
788 return;
789 m_fFirstMediumEnumerationHandled = true;
790
791 /* Make sure MM window/tool is not opened,
792 * otherwise user sees everything himself: */
793 if ( m_pManagerVirtualMedia
794 || m_pWidget->isGlobalToolOpened(UIToolType_Media))
795 return;
796
797 /* Look for at least one inaccessible medium: */
798 bool fIsThereAnyInaccessibleMedium = false;
799 foreach (const QUuid &uMediumID, gpMediumEnumerator->mediumIDs())
800 {
801 if (gpMediumEnumerator->medium(uMediumID).state() == KMediumState_Inaccessible)
802 {
803 fIsThereAnyInaccessibleMedium = true;
804 break;
805 }
806 }
807 /* Warn the user about inaccessible medium, propose to open MM window/tool: */
808 if (fIsThereAnyInaccessibleMedium && msgCenter().warnAboutInaccessibleMedia())
809 {
810 /* Open the MM window: */
811 sltOpenVirtualMediumManagerWindow();
812 }
813#endif
814}
815
816void UIVirtualBoxManager::sltHandleOpenUrlCall(QList<QUrl> list /* = QList<QUrl>() */)
817{
818 /* If passed list is empty, we take the one from UICommon: */
819 if (list.isEmpty())
820 list = uiCommon().takeArgumentUrls();
821
822 /* Check if we are can handle the dropped urls: */
823 for (int i = 0; i < list.size(); ++i)
824 {
825#ifdef VBOX_WS_MAC
826 const QString strFile = ::darwinResolveAlias(list.at(i).toLocalFile());
827#else
828 const QString strFile = list.at(i).toLocalFile();
829#endif
830 const QStringList isoExtensionList = QStringList() << "iso";
831 /* If there is such file exists: */
832 if (!strFile.isEmpty() && QFile::exists(strFile))
833 {
834 /* And has allowed VBox config file extension: */
835 if (UICommon::hasAllowedExtension(strFile, VBoxFileExts))
836 {
837 /* Handle VBox config file: */
838 CVirtualBox comVBox = gpGlobalSession->virtualBox();
839 CMachine comMachine = comVBox.FindMachine(strFile);
840 if (comVBox.isOk() && comMachine.isNotNull())
841 launchMachine(comMachine);
842 else
843 openAddMachineDialog(strFile);
844 }
845 /* And has allowed VBox OVF file extension: */
846 else if (UICommon::hasAllowedExtension(strFile, OVFFileExts))
847 {
848 /* Allow only one file at the time: */
849 openImportApplianceWizard(strFile);
850 break;
851 }
852 /* And has allowed VBox extension pack file extension: */
853 else if (UICommon::hasAllowedExtension(strFile, VBoxExtPackFileExts))
854 {
855#ifdef VBOX_GUI_WITH_NETWORK_MANAGER
856 /* Prevent update manager from proposing us to update EP: */
857 gUpdateManager->setEPInstallationRequested(true);
858#endif
859 /* Propose the user to install EP described by the arguments @a list. */
860 UIExtension::install(strFile, QString(), this, NULL);
861#ifdef VBOX_GUI_WITH_NETWORK_MANAGER
862 /* Allow update manager to propose us to update EP: */
863 gUpdateManager->setEPInstallationRequested(false);
864#endif
865 }
866 else if (UICommon::hasAllowedExtension(strFile, isoExtensionList))
867 {
868 openNewMachineWizard(strFile);
869 }
870 }
871 }
872}
873
874void UIVirtualBoxManager::sltCheckUSBAccesibility()
875{
876 CHost comHost = gpGlobalSession->host();
877 if (!comHost.isOk())
878 return;
879 if (comHost.GetUSBDevices().isEmpty() && comHost.isWarning())
880 UINotificationMessage::cannotEnumerateHostUSBDevices(comHost);
881}
882
883void UIVirtualBoxManager::sltHandleChooserPaneIndexChange()
884{
885 // WORKAROUND:
886 // These menus are dynamical since local and cloud VMs have different menu contents.
887 // Yet .. we have to prepare Machine/Group menus beforehand, they contains shortcuts.
888 updateMenuGroup(actionPool()->action(UIActionIndexMN_M_Group)->menu());
889 updateMenuMachine(actionPool()->action(UIActionIndexMN_M_Machine)->menu());
890
891 updateActionsVisibility();
892 updateActionsAppearance();
893
894 /* Special handling for opened settings dialog: */
895 if ( m_pWidget->isLocalMachineItemSelected()
896 && m_settings.contains(UIAdvancedSettingsDialog::Type_Machine))
897 {
898 /* Cast dialog to required type: */
899 UIAdvancedSettingsDialogMachine *pDialog =
900 qobject_cast<UIAdvancedSettingsDialogMachine*>(m_settings.value(UIAdvancedSettingsDialog::Type_Machine));
901 AssertPtrReturnVoid(pDialog);
902
903 /* Get current item: */
904 UIVirtualMachineItem *pItem = currentItem();
905 AssertPtrReturnVoid(pItem);
906
907 /* Update machine stuff: */
908 pDialog->setNewMachineId(pItem->id());
909 }
910 else if ( m_pWidget->isCloudMachineItemSelected()
911 && m_pCloudSettings)
912 {
913 /* Get current item: */
914 UIVirtualMachineItem *pItem = currentItem();
915 AssertPtrReturnVoid(pItem);
916 UIVirtualMachineItemCloud *pItemCloud = pItem->toCloud();
917 AssertPtrReturnVoid(pItemCloud);
918
919 /* Update machine stuff: */
920 m_pCloudSettings->setCloudMachine(pItemCloud->machine());
921 }
922}
923
924void UIVirtualBoxManager::sltHandleGroupSavingProgressChange()
925{
926 updateActionsAppearance();
927}
928
929void UIVirtualBoxManager::sltHandleCloudUpdateProgressChange()
930{
931 updateActionsAppearance();
932}
933
934void UIVirtualBoxManager::sltHandleGlobalToolTypeChange()
935{
936 /* Update actions stuff: */
937 updateActionsVisibility();
938 updateActionsAppearance();
939
940 /* Make sure separate dialog closed when corresponding tool opened: */
941 sltCloseManagerWindow(m_pWidget->toolsTypeGlobal());
942}
943
944void UIVirtualBoxManager::sltHandleMachineToolTypeChange()
945{
946 /* Update actions stuff: */
947 updateActionsVisibility();
948 updateActionsAppearance();
949
950 /* Make sure separate dialog closed when corresponding tool opened: */
951 sltCloseManagerWindow(m_pWidget->toolsTypeMachine());
952}
953
954void UIVirtualBoxManager::sltCreateMedium()
955{
956 /* Open Create VD Wizard: */
957 sltOpenWizard(WizardType_NewVD);
958}
959
960void UIVirtualBoxManager::sltCopyMedium(const QUuid &uMediumId)
961{
962 /* Configure wizard variables: */
963 m_uMediumId = uMediumId;
964
965 /* Open Clone VD Wizard: */
966 sltOpenWizard(WizardType_CloneVD);
967}
968
969void UIVirtualBoxManager::sltCurrentSnapshotItemChange()
970{
971 updateActionsAppearance();
972}
973
974void UIVirtualBoxManager::sltDetachToolPane(UIToolType enmToolType)
975{
976 AssertReturnVoid(enmToolType != UIToolType_Invalid);
977 /* Add tool to detached: */
978 QList<UIToolType> tools = gEDataManager->detachedTools();
979 if (!tools.contains(enmToolType))
980 {
981 tools << enmToolType;
982 gEDataManager->setDetachedTools(tools);
983 }
984
985 /* Detach Log Viewer: */
986 sltOpenManagerWindow(enmToolType);
987}
988
989void UIVirtualBoxManager::sltHandleCloudMachineStateChange(const QUuid & /* uId */)
990{
991 updateActionsAppearance();
992}
993
994void UIVirtualBoxManager::sltHandleStateChange(const QUuid &)
995{
996 updateActionsAppearance();
997}
998
999void UIVirtualBoxManager::sltHandleMenuPrepare(int iIndex, QMenu *pMenu)
1000{
1001 /* Update if there is update-handler: */
1002 if (m_menuUpdateHandlers.contains(iIndex))
1003 (this->*(m_menuUpdateHandlers.value(iIndex)))(pMenu);
1004}
1005
1006void UIVirtualBoxManager::sltOpenManagerWindow(UIToolType enmType /* = UIToolType_Invalid */)
1007{
1008 /* Determine actual tool type on the basis of sender action if possible: */
1009 if (enmType == UIToolType_Invalid)
1010 {
1011 if ( sender()
1012 && sender()->inherits("UIAction"))
1013 {
1014 UIAction *pAction = qobject_cast<UIAction*>(sender());
1015 AssertPtrReturnVoid(pAction);
1016 enmType = pAction->property("UIToolType").value<UIToolType>();
1017 }
1018 }
1019 /* Make sure type is valid: */
1020 AssertReturnVoid(enmType != UIToolType_Invalid);
1021
1022 /* First check if instance of widget opened the embedded way: */
1023 if (m_pWidget->isGlobalToolOpened(enmType))
1024 {
1025 m_pWidget->setToolsTypeGlobal(UIToolType_Welcome);
1026 m_pWidget->closeGlobalTool(enmType);
1027 }
1028 if (m_pWidget->isMachineToolOpened(enmType))
1029 {
1030 m_pWidget->setToolsTypeMachine(UIToolType_Details);
1031 m_pWidget->closeMachineTool(enmType);
1032 }
1033
1034 /* Create instance if not yet created: */
1035 if (!m_managers.contains(enmType))
1036 {
1037 switch (enmType)
1038 {
1039 case UIToolType_Extensions: UIExtensionPackManagerFactory(m_pActionPool).prepare(m_managers[enmType], this); break;
1040 case UIToolType_Media: UIMediumManagerFactory(m_pActionPool).prepare(m_managers[enmType], this); break;
1041 case UIToolType_Network: UINetworkManagerFactory(m_pActionPool).prepare(m_managers[enmType], this); break;
1042 case UIToolType_Cloud: UICloudProfileManagerFactory(m_pActionPool).prepare(m_managers[enmType], this); break;
1043 case UIToolType_CloudConsole: UICloudConsoleManagerFactory(m_pActionPool).prepare(m_managers[enmType], this); break;
1044 case UIToolType_Logs:
1045 {
1046 /* Compose a list of selected machine IDs: */
1047 QList<QUuid> machineIDs;
1048 /* For each selected item: */
1049 foreach (UIVirtualMachineItem *pItem, currentItems())
1050 {
1051 /* Make sure current item is local one: */
1052 UIVirtualMachineItemLocal *pItemLocal = pItem->toLocal();
1053 if (!pItemLocal)
1054 continue;
1055 /* Append machine ID: */
1056 machineIDs << pItemLocal->id();
1057 }
1058 UIVMLogViewerDialogFactory(m_pActionPool, machineIDs).prepare(m_managers[enmType], this);
1059 break;
1060 }
1061 default: break;
1062 }
1063
1064 connect(m_managers[enmType], &QIManagerDialog::sigEmbed,
1065 this, &UIVirtualBoxManager::sltEmbedManagerWindowDefault);
1066 connect(m_managers[enmType], &QIManagerDialog::sigClose,
1067 this, &UIVirtualBoxManager::sltCloseManagerWindowDefault);
1068 }
1069
1070 /* Expose instance: */
1071 UIDesktopWidgetWatchdog::restoreWidget(m_managers.value(enmType));
1072}
1073
1074void UIVirtualBoxManager::sltEmbedManagerWindow(UIToolType enmType /* = UIToolType_Invalid */)
1075{
1076 /* Determine actual tool type if possible: */
1077 if (enmType == UIToolType_Invalid)
1078 {
1079 if ( sender()
1080 && sender()->inherits("QIManagerDialog"))
1081 {
1082 QIManagerDialog *pManager = qobject_cast<QIManagerDialog*>(sender());
1083 AssertPtrReturnVoid(pManager);
1084 enmType = m_managers.key(pManager);
1085 }
1086 }
1087
1088 /* Make sure type is valid: */
1089 AssertReturnVoid(enmType != UIToolType_Invalid);
1090
1091 /* Remove tool from detached: */
1092 QList<UIToolType> tools = gEDataManager->detachedTools();
1093 if (tools.contains(UIToolType_Logs))
1094 {
1095 tools.removeAll(UIToolType_Logs);
1096 gEDataManager->setDetachedTools(tools);
1097 }
1098
1099 /* Open known tool finally: */
1100 switch (enmType)
1101 {
1102 case UIToolType_Logs: m_pWidget->setToolsTypeMachine(enmType); break;
1103 default: break;
1104 }
1105}
1106
1107void UIVirtualBoxManager::sltCloseManagerWindow(UIToolType enmType /* = UIToolType_Invalid */)
1108{
1109 /* Determine actual tool type if possible: */
1110 if (enmType == UIToolType_Invalid)
1111 {
1112 if ( sender()
1113 && sender()->inherits("QIManagerDialog"))
1114 {
1115 QIManagerDialog *pManager = qobject_cast<QIManagerDialog*>(sender());
1116 AssertPtrReturnVoid(pManager);
1117 enmType = m_managers.key(pManager);
1118 }
1119 }
1120
1121 /* Make sure type is valid: */
1122 AssertReturnVoid(enmType != UIToolType_Invalid);
1123
1124 /* Destroy instance if still exists: */
1125 if (m_managers.contains(enmType))
1126 {
1127 switch (enmType)
1128 {
1129 case UIToolType_Extensions: UIExtensionPackManagerFactory().cleanup(m_managers[enmType]); break;
1130 case UIToolType_Media: UIMediumManagerFactory().cleanup(m_managers[enmType]); break;
1131 case UIToolType_Network: UINetworkManagerFactory().cleanup(m_managers[enmType]); break;
1132 case UIToolType_Cloud: UICloudProfileManagerFactory().cleanup(m_managers[enmType]); break;
1133 case UIToolType_CloudConsole: UICloudConsoleManagerFactory().cleanup(m_managers[enmType]); break;
1134 case UIToolType_Logs: UIVMLogViewerDialogFactory().cleanup(m_managers[enmType]); break;
1135 default: break;
1136 }
1137
1138 m_managers.remove(enmType);
1139 }
1140}
1141
1142void UIVirtualBoxManager::sltOpenExportApplianceWizard()
1143{
1144 /* Check what was the action invoked us: */
1145 UIAction *pAction = qobject_cast<UIAction*>(sender());
1146
1147 /* Export to OCI action invokes wizard directly in OCI mode: */
1148 m_fExportToOCI = pAction
1149 && pAction == actionPool()->action(UIActionIndexMN_M_Machine_S_ExportToOCI);
1150 /* Populate the list of VM names: */
1151 m_names.clear();
1152 foreach (UIVirtualMachineItem *pItem, currentItems())
1153 m_names << pItem->name();
1154
1155 /* Open Export Appliance Wizard: */
1156 sltOpenWizard(WizardType_ExportAppliance);
1157}
1158
1159#ifdef VBOX_GUI_WITH_EXTRADATA_MANAGER_UI
1160void UIVirtualBoxManager::sltOpenExtraDataManagerWindow()
1161{
1162 gEDataManager->openWindow(this);
1163}
1164#endif /* VBOX_GUI_WITH_EXTRADATA_MANAGER_UI */
1165
1166void UIVirtualBoxManager::sltOpenPreferencesDialog()
1167{
1168 /* Don't show the inaccessible warning
1169 * if the user tries to open global settings: */
1170 m_fFirstMediumEnumerationHandled = true;
1171
1172 /* Create instance if not yet created: */
1173 if (!m_settings.contains(UIAdvancedSettingsDialog::Type_Global))
1174 {
1175 m_settings[UIAdvancedSettingsDialog::Type_Global] = new UIAdvancedSettingsDialogGlobal(this);
1176 connect(m_settings[UIAdvancedSettingsDialog::Type_Global], &UIAdvancedSettingsDialogGlobal::sigClose,
1177 this, &UIVirtualBoxManager::sltClosePreferencesDialog);
1178 const bool fSuccess = m_settings.value(UIAdvancedSettingsDialog::Type_Global)->load();
1179 if (!fSuccess)
1180 {
1181 delete m_settings.take(UIAdvancedSettingsDialog::Type_Global);
1182 return;
1183 }
1184 }
1185
1186 /* Expose instance: */
1187 UIDesktopWidgetWatchdog::restoreWidget(m_settings.value(UIAdvancedSettingsDialog::Type_Global));
1188}
1189
1190void UIVirtualBoxManager::sltClosePreferencesDialog()
1191{
1192 /* Remove instance if exist: */
1193 delete m_settings.take(UIAdvancedSettingsDialog::Type_Global);
1194}
1195
1196void UIVirtualBoxManager::sltPerformSwitchToGlobalTool(QAction *pAction)
1197{
1198 /* Sanity checks: */
1199 AssertPtrReturnVoid(pAction);
1200 AssertPtrReturnVoid(m_pWidget);
1201
1202 /* Acquire tool type: */
1203 const UIToolType enmType = pAction->property("UIToolType").value<UIToolType>();
1204 AssertReturnVoid(enmType != UIToolType_Invalid);
1205
1206 /* Make sure global item is selected: */
1207 m_pWidget->switchToGlobalItem();
1208
1209 /* Open the tool finally: */
1210 m_pWidget->setToolsTypeGlobal(enmType);
1211}
1212
1213void UIVirtualBoxManager::sltPerformExit()
1214{
1215 close();
1216}
1217
1218void UIVirtualBoxManager::sltOpenWizard(WizardType enmType)
1219{
1220 /* Create instance if not yet created: */
1221 if (!m_wizards.contains(enmType))
1222 {
1223 switch (enmType)
1224 {
1225 case WizardType_NewVM:
1226 m_wizards[enmType] = new UIWizardNewVM(this, actionPool(), m_pWidget->fullGroupName(), m_strISOFilePath);
1227 break;
1228 case WizardType_CloneVM:
1229 {
1230 UIVirtualMachineItem *pItem = currentItem();
1231 UIVirtualMachineItemLocal *pItemLocal = pItem ? pItem->toLocal() : 0;
1232 CMachine comMachine = pItemLocal ? pItemLocal->machine() : CMachine();
1233 CSnapshot comSnapshot;
1234 if (m_fSnapshotCloneByDefault)
1235 {
1236 const QUuid uId = m_pWidget->currentSnapshotId();
1237 if (!uId.isNull() && comMachine.isNotNull())
1238 {
1239 comSnapshot = comMachine.FindSnapshot(uId.toString());
1240 if (comSnapshot.isNotNull())
1241 {
1242 const CMachine comSnapshotMachine = comSnapshot.GetMachine();
1243 if (comSnapshotMachine.isNotNull())
1244 comMachine = comSnapshotMachine;
1245 }
1246 }
1247 }
1248 m_wizards[enmType] = new UIWizardCloneVM(this,
1249 comMachine,
1250 pItemLocal->groups().value(0),
1251 comSnapshot);
1252 break;
1253 }
1254 case WizardType_ExportAppliance:
1255 m_wizards[enmType] = new UIWizardExportApp(this, m_names, m_fExportToOCI);
1256 break;
1257 case WizardType_ImportAppliance:
1258 m_wizards[enmType] = new UIWizardImportApp(this, m_fImportFromOCI, m_strFileName);
1259 break;
1260 case WizardType_NewCloudVM:
1261 m_wizards[enmType] = new UIWizardNewCloudVM(this, m_pWidget->fullGroupName());
1262 break;
1263 case WizardType_AddCloudVM:
1264 m_wizards[enmType] = new UIWizardAddCloudVM(this, m_pWidget->fullGroupName());
1265 break;
1266 case WizardType_NewVD:
1267 {
1268 const QString strFolder = UIMediumTools::defaultFolderPathForType(UIMediumDeviceType_HardDisk);
1269 const QString strDiskName = uiCommon().findUniqueFileName(strFolder, "NewVirtualDisk");
1270 const CGuestOSType comGuestOSType = gpGlobalSession->virtualBox().GetGuestOSType("Other");
1271 const qulonglong uDiskSize = comGuestOSType.GetRecommendedHDD();
1272 m_wizards[enmType] = new UIWizardNewVD(this,
1273 strDiskName,
1274 strFolder,
1275 uDiskSize);
1276 break;
1277 }
1278 case WizardType_CloneVD:
1279 m_wizards[enmType] = new UIWizardNewVD(this, m_uMediumId);
1280 break;
1281 default:
1282 break;
1283 }
1284
1285 connect(m_wizards.value(enmType), &UINativeWizard::sigClose,
1286 this, &UIVirtualBoxManager::sltCloseWizard);
1287 }
1288
1289 /* Expose instance: */
1290 m_wizards.value(enmType)->show();
1291 m_wizards.value(enmType)->setWindowState(m_wizards.value(enmType)->windowState() & ~Qt::WindowMinimized);
1292 m_wizards.value(enmType)->activateWindow();
1293 m_wizards.value(enmType)->raise();
1294}
1295
1296void UIVirtualBoxManager::sltCloseWizard(WizardType enmType)
1297{
1298 /* Postprocess wizard if still exists: */
1299 if (m_wizards.contains(enmType))
1300 {
1301 switch (enmType)
1302 {
1303 case WizardType_NewVM:
1304 {
1305 UIWizardNewVM *pWizard = qobject_cast<UIWizardNewVM*>(m_wizards.value(enmType));
1306 if (pWizard->isUnattendedEnabled())
1307 startUnattendedInstall(pWizard->installer(),
1308 pWizard->startHeadless(),
1309 pWizard->createdMachineId().toString());
1310 break;
1311 }
1312 default:
1313 break;
1314 }
1315 }
1316
1317 /* Cleanup instance: */
1318 delete m_wizards.take(enmType);
1319}
1320
1321void UIVirtualBoxManager::sltOpenNewMachineWizard()
1322{
1323 /* Get first selected item: */
1324 UIVirtualMachineItem *pItem = currentItem();
1325
1326 /* For global item or local machine: */
1327 if ( !pItem
1328 || pItem->itemType() == UIVirtualMachineItemType_Local)
1329 openNewMachineWizard();
1330 /* For cloud machine: */
1331 else
1332 sltOpenWizard(WizardType_NewCloudVM);
1333}
1334
1335void UIVirtualBoxManager::sltOpenAddMachineDialog()
1336{
1337 /* Get first selected item: */
1338 UIVirtualMachineItem *pItem = currentItem();
1339
1340 /* For global item or local machine: */
1341 if ( !pItem
1342 || pItem->itemType() == UIVirtualMachineItemType_Local)
1343 openAddMachineDialog();
1344 /* For cloud machine: */
1345 else
1346 sltOpenWizard(WizardType_AddCloudVM);
1347}
1348
1349void UIVirtualBoxManager::sltOpenGroupNameEditor()
1350{
1351 m_pWidget->openGroupNameEditor();
1352}
1353
1354void UIVirtualBoxManager::sltDisbandGroup()
1355{
1356 m_pWidget->disbandGroup();
1357}
1358
1359void UIVirtualBoxManager::sltOpenSettingsDialog(QString strCategory /* = QString() */,
1360 QString strControl /* = QString() */,
1361 const QUuid &uID /* = QString() */)
1362{
1363 /* Get current item: */
1364 UIVirtualMachineItem *pItem = currentItem();
1365 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
1366
1367 /* For local machine: */
1368 if (pItem->itemType() == UIVirtualMachineItemType_Local)
1369 {
1370 /* Process href from VM details / description: */
1371 if (!strCategory.isEmpty() && strCategory[0] != '#')
1372 {
1373 uiCommon().openURL(strCategory);
1374 }
1375 else
1376 {
1377 /* Check if control is coded into the URL by %%: */
1378 if (strControl.isEmpty())
1379 {
1380 QStringList parts = strCategory.split("%%");
1381 if (parts.size() == 2)
1382 {
1383 strCategory = parts.at(0);
1384 strControl = parts.at(1);
1385 }
1386 }
1387
1388 /* Don't show the inaccessible warning
1389 * if the user tries to open VM settings: */
1390 m_fFirstMediumEnumerationHandled = true;
1391
1392 /* Create instance if not yet created: */
1393 if (!m_settings.contains(UIAdvancedSettingsDialog::Type_Machine))
1394 {
1395 m_settings[UIAdvancedSettingsDialog::Type_Machine] = new UIAdvancedSettingsDialogMachine(this,
1396 uID.isNull() ? pItem->id() : uID,
1397 actionPool(),
1398 strCategory,
1399 strControl);
1400 connect(m_settings[UIAdvancedSettingsDialog::Type_Machine], &UIAdvancedSettingsDialogMachine::sigClose,
1401 this, &UIVirtualBoxManager::sltCloseSettingsDialog);
1402 const bool fSuccess = m_settings.value(UIAdvancedSettingsDialog::Type_Machine)->load();
1403 if (!fSuccess)
1404 {
1405 delete m_settings.take(UIAdvancedSettingsDialog::Type_Machine);
1406 return;
1407 }
1408 }
1409
1410 /* Expose instance: */
1411 UIDesktopWidgetWatchdog::restoreWidget(m_settings.value(UIAdvancedSettingsDialog::Type_Machine));
1412 }
1413 }
1414 /* For cloud machine: */
1415 else
1416 {
1417 /* Create instance if not yet created: */
1418 if (m_pCloudSettings.isNull())
1419 {
1420 m_pCloudSettings = new UICloudMachineSettingsDialog(this,
1421 pItem->toCloud()->machine());
1422 connect(m_pCloudSettings, &UICloudMachineSettingsDialog::sigClose,
1423 this, &UIVirtualBoxManager::sltCloseSettingsDialog);
1424 }
1425
1426 /* Expose instance: */
1427 UIDesktopWidgetWatchdog::restoreWidget(m_pCloudSettings);
1428 }
1429}
1430
1431void UIVirtualBoxManager::sltCloseSettingsDialog()
1432{
1433 /* What type of dialog should we delete? */
1434 enum DelType { None, Local, Cloud, All } enmType = None;
1435 if (qobject_cast<UIAdvancedSettingsDialog*>(sender()))
1436 enmType = (DelType)(enmType | Local);
1437 else if (qobject_cast<UICloudMachineSettingsDialog*>(sender()))
1438 enmType = (DelType)(enmType | Cloud);
1439
1440 /* It's all if nothing: */
1441 if (enmType == None)
1442 enmType = All;
1443
1444 /* Remove requested instances: */
1445 if (enmType & Local)
1446 delete m_settings.take(UIAdvancedSettingsDialog::Type_Machine);
1447 if (enmType & Cloud)
1448 delete m_pCloudSettings;
1449}
1450
1451void UIVirtualBoxManager::sltOpenCloneMachineWizard()
1452{
1453 /* Get current items: */
1454 QList<UIVirtualMachineItem*> items = currentItems();
1455
1456 /* We are opening Clone VM wizard for local VMs only: */
1457 if (isItemsLocal(items))
1458 {
1459 /* Configure wizard variables: */
1460 m_fSnapshotCloneByDefault = false;
1461 QAction *pAction = qobject_cast<QAction*>(sender());
1462 if ( pAction
1463 && pAction == actionPool()->action(UIActionIndexMN_M_Snapshot_S_Clone))
1464 m_fSnapshotCloneByDefault = true;
1465
1466 /* Open Clone VM Wizard: */
1467 sltOpenWizard(WizardType_CloneVM);
1468 }
1469 /* For cloud VMs we have no such wizard for now: */
1470 else if (isItemsCloud(items))
1471 {
1472 /* Acquire item, propose clone name: */
1473 UIVirtualMachineItem *pItem = items.first();
1474 const QString strName = QString("%1_clone").arg(pItem->name());
1475
1476 /* Create Acquire Clone VM name dialog: */
1477 QPointer<UIAcquireCloudMachineCloneNameDialog> pDialog = new UIAcquireCloudMachineCloneNameDialog(this, strName);
1478 if (pDialog->exec() == QDialog::Accepted)
1479 {
1480 /* Parse current full group name: */
1481 const QString strFullGroupName = m_pWidget->fullGroupName();
1482 const QString strProviderShortName = strFullGroupName.section('/', 1, 1);
1483 const QString strProfileName = strFullGroupName.section('/', 2, 2);
1484
1485 /* Acquire cloud machine: */
1486 const CCloudMachine comMachine = pItem->toCloud()->machine();
1487
1488 /* Clone VM: */
1489 createCloudMachineClone(strProviderShortName, strProfileName,
1490 comMachine, pDialog->value(),
1491 gpNotificationCenter);
1492 }
1493 delete pDialog;
1494 }
1495}
1496
1497void UIVirtualBoxManager::sltPerformMachineMove()
1498{
1499 /* Get current item: */
1500 UIVirtualMachineItem *pItem = currentItem();
1501 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
1502
1503 /* Open a file dialog for the user to select a destination folder. Start with the default machine folder: */
1504 const QString strBaseFolder = gpGlobalSession->virtualBox().GetSystemProperties().GetDefaultMachineFolder();
1505 const QString strTitle = tr("Select a destination folder to move the selected virtual machine");
1506 const QString strDestinationFolder = QIFileDialog::getExistingDirectory(strBaseFolder, this, strTitle);
1507 if (!strDestinationFolder.isEmpty())
1508 {
1509 /* Move machine: */
1510 UINotificationProgressMachineMove *pNotification = new UINotificationProgressMachineMove(pItem->id(),
1511 strDestinationFolder,
1512 "basic");
1513 gpNotificationCenter->append(pNotification);
1514 }
1515}
1516
1517void UIVirtualBoxManager::sltPerformMachineRemove()
1518{
1519 m_pWidget->removeMachine();
1520}
1521
1522void UIVirtualBoxManager::sltPerformMachineMoveToNewGroup()
1523{
1524 m_pWidget->moveMachineToGroup();
1525}
1526
1527void UIVirtualBoxManager::sltPerformMachineMoveToSpecificGroup()
1528{
1529 AssertPtrReturnVoid(sender());
1530 QAction *pAction = qobject_cast<QAction*>(sender());
1531 AssertPtrReturnVoid(pAction);
1532 m_pWidget->moveMachineToGroup(pAction->property("actual_group_name").toString());
1533}
1534
1535void UIVirtualBoxManager::sltPerformStartOrShowMachine()
1536{
1537 /* Start selected VMs in corresponding mode: */
1538 QList<UIVirtualMachineItem*> items = currentItems();
1539 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
1540 performStartOrShowVirtualMachines(items, UILaunchMode_Invalid);
1541}
1542
1543void UIVirtualBoxManager::sltPerformStartMachineNormal()
1544{
1545 /* Start selected VMs in corresponding mode: */
1546 QList<UIVirtualMachineItem*> items = currentItems();
1547 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
1548 performStartOrShowVirtualMachines(items, UILaunchMode_Default);
1549}
1550
1551void UIVirtualBoxManager::sltPerformStartMachineHeadless()
1552{
1553 /* Start selected VMs in corresponding mode: */
1554 QList<UIVirtualMachineItem*> items = currentItems();
1555 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
1556 performStartOrShowVirtualMachines(items, UILaunchMode_Headless);
1557}
1558
1559void UIVirtualBoxManager::sltPerformStartMachineDetachable()
1560{
1561 /* Start selected VMs in corresponding mode: */
1562 QList<UIVirtualMachineItem*> items = currentItems();
1563 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
1564 performStartOrShowVirtualMachines(items, UILaunchMode_Separate);
1565}
1566
1567void UIVirtualBoxManager::sltPerformCreateConsoleConnectionForGroup()
1568{
1569 /* Get selected items: */
1570 QList<UIVirtualMachineItem*> items = currentItems();
1571 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
1572
1573 /* Create input dialog to pass public key to newly created console connection: */
1574 QPointer<UIAcquirePublicKeyDialog> pDialog = new UIAcquirePublicKeyDialog(this);
1575 if (pDialog)
1576 {
1577 if (pDialog->exec() == QDialog::Accepted)
1578 {
1579 foreach (UIVirtualMachineItem *pItem, items)
1580 {
1581 /* Make sure the item exists: */
1582 AssertPtr(pItem);
1583 if (pItem)
1584 {
1585 /* Make sure the item is of cloud type: */
1586 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
1587 if (pCloudItem)
1588 {
1589 /* Acquire current machine: */
1590 CCloudMachine comMachine = pCloudItem->machine();
1591
1592 /* Acquire machine console connection fingerprint: */
1593 QString strConsoleConnectionFingerprint;
1594 if (cloudMachineConsoleConnectionFingerprint(comMachine, strConsoleConnectionFingerprint))
1595 {
1596 /* Only if no fingerprint exist: */
1597 if (strConsoleConnectionFingerprint.isEmpty())
1598 {
1599 /* Create cloud console connection: */
1600 UINotificationProgressCloudConsoleConnectionCreate *pNotification =
1601 new UINotificationProgressCloudConsoleConnectionCreate(comMachine,
1602 pDialog->publicKey());
1603 gpNotificationCenter->append(pNotification);
1604 }
1605 }
1606 }
1607 }
1608 }
1609 }
1610 delete pDialog;
1611 }
1612}
1613
1614void UIVirtualBoxManager::sltPerformCreateConsoleConnectionForMachine()
1615{
1616 /* Get current item: */
1617 UIVirtualMachineItem *pItem = currentItem();
1618 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
1619
1620 /* Create input dialog to pass public key to newly created console connection: */
1621 QPointer<UIAcquirePublicKeyDialog> pDialog = new UIAcquirePublicKeyDialog(this);
1622 if (pDialog)
1623 {
1624 if (pDialog->exec() == QDialog::Accepted)
1625 {
1626 /* Make sure the item is of cloud type: */
1627 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
1628 AssertPtr(pCloudItem);
1629 if (pCloudItem)
1630 {
1631 /* Acquire current machine: */
1632 CCloudMachine comMachine = pCloudItem->machine();
1633
1634 /* Acquire machine console connection fingerprint: */
1635 QString strConsoleConnectionFingerprint;
1636 if (cloudMachineConsoleConnectionFingerprint(comMachine, strConsoleConnectionFingerprint))
1637 {
1638 /* Only if no fingerprint exist: */
1639 if (strConsoleConnectionFingerprint.isEmpty())
1640 {
1641 /* Create cloud console connection: */
1642 UINotificationProgressCloudConsoleConnectionCreate *pNotification =
1643 new UINotificationProgressCloudConsoleConnectionCreate(comMachine,
1644 pDialog->publicKey());
1645 gpNotificationCenter->append(pNotification);
1646 }
1647 }
1648 }
1649 }
1650 delete pDialog;
1651 }
1652}
1653
1654void UIVirtualBoxManager::sltPerformDeleteConsoleConnectionForGroup()
1655{
1656 /* Get selected items: */
1657 QList<UIVirtualMachineItem*> items = currentItems();
1658 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
1659
1660 foreach (UIVirtualMachineItem *pItem, items)
1661 {
1662 /* Make sure the item exists: */
1663 AssertPtr(pItem);
1664 if (pItem)
1665 {
1666 /* Make sure the item is of cloud type: */
1667 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
1668 if (pCloudItem)
1669 {
1670 /* Acquire current machine: */
1671 CCloudMachine comMachine = pCloudItem->machine();
1672
1673 /* Acquire machine console connection fingerprint: */
1674 QString strConsoleConnectionFingerprint;
1675 if (cloudMachineConsoleConnectionFingerprint(comMachine, strConsoleConnectionFingerprint))
1676 {
1677 /* Only if fingerprint exists: */
1678 if (!strConsoleConnectionFingerprint.isEmpty())
1679 {
1680 /* Delete cloud console connection: */
1681 UINotificationProgressCloudConsoleConnectionDelete *pNotification =
1682 new UINotificationProgressCloudConsoleConnectionDelete(comMachine);
1683 gpNotificationCenter->append(pNotification);
1684 }
1685 }
1686 }
1687 }
1688 }
1689}
1690
1691void UIVirtualBoxManager::sltPerformDeleteConsoleConnectionForMachine()
1692{
1693 /* Get current item: */
1694 UIVirtualMachineItem *pItem = currentItem();
1695 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
1696
1697 /* Make sure the item is of cloud type: */
1698 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
1699 AssertPtr(pCloudItem);
1700 if (pCloudItem)
1701 {
1702 /* Acquire current machine: */
1703 CCloudMachine comMachine = pCloudItem->machine();
1704
1705 /* Acquire machine console connection fingerprint: */
1706 QString strConsoleConnectionFingerprint;
1707 if (cloudMachineConsoleConnectionFingerprint(comMachine, strConsoleConnectionFingerprint))
1708 {
1709 /* Only if fingerprint exists: */
1710 if (!strConsoleConnectionFingerprint.isEmpty())
1711 {
1712 /* Delete cloud console connection: */
1713 UINotificationProgressCloudConsoleConnectionDelete *pNotification =
1714 new UINotificationProgressCloudConsoleConnectionDelete(comMachine);
1715 gpNotificationCenter->append(pNotification);
1716 }
1717 }
1718 }
1719}
1720
1721void UIVirtualBoxManager::sltCopyConsoleConnectionFingerprint()
1722{
1723 QAction *pAction = qobject_cast<QAction*>(sender());
1724 AssertPtrReturnVoid(pAction);
1725 QClipboard *pClipboard = QGuiApplication::clipboard();
1726 AssertPtrReturnVoid(pClipboard);
1727 pClipboard->setText(pAction->property("fingerprint").toString());
1728}
1729
1730void UIVirtualBoxManager::sltExecuteExternalApplication()
1731{
1732 /* Acquire passed path and argument strings: */
1733 QAction *pAction = qobject_cast<QAction*>(sender());
1734 AssertMsgReturnVoid(pAction, ("This slot should be called by action only!\n"));
1735 const QString strPath = pAction->property("path").toString();
1736 const QString strArguments = pAction->property("arguments").toString();
1737
1738 /* Get current-item: */
1739 UIVirtualMachineItem *pItem = currentItem();
1740 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
1741 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
1742 AssertPtrReturnVoid(pCloudItem);
1743
1744 /* Get cloud machine to acquire serial command: */
1745 const CCloudMachine comMachine = pCloudItem->machine();
1746
1747#if defined(VBOX_WS_MAC)
1748 /* Gather arguments: */
1749 QStringList arguments;
1750 arguments << parseShellArguments(strArguments);
1751
1752 /* Make sure that isn't a request to start Open command: */
1753 if (strPath != "open" && strPath != "/usr/bin/open")
1754 {
1755 /* In that case just add the command we have as simple argument: */
1756 arguments << comMachine.GetSerialConsoleCommand();
1757 }
1758 else
1759 {
1760 /* Otherwise upload command to external file which can be opened with Open command: */
1761 QDir uiHomeFolder(gpGlobalSession->virtualBox().GetHomeFolder());
1762 const QString strAbsoluteCommandName = uiHomeFolder.absoluteFilePath("last.command");
1763 QFile file(strAbsoluteCommandName);
1764 file.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner);
1765 if (!file.open(QIODevice::WriteOnly))
1766 AssertFailedReturnVoid();
1767 file.write(comMachine.GetSerialConsoleCommand().toUtf8());
1768 file.close();
1769 arguments << strAbsoluteCommandName;
1770 }
1771
1772 /* Execute console application finally: */
1773 QProcess::startDetached(strPath, arguments);
1774#elif defined(VBOX_WS_WIN)
1775 /* Gather arguments: */
1776 QStringList arguments;
1777 arguments << strArguments;
1778 arguments << comMachine.GetSerialConsoleCommandWindows();
1779
1780 /* Execute console application finally: */
1781 QProcess::startDetached(QString("%1 %2").arg(strPath, arguments.join(' ')));
1782#elif defined(VBOX_WS_NIX)
1783 /* Gather arguments: */
1784 QStringList arguments;
1785 arguments << parseShellArguments(strArguments);
1786 arguments << comMachine.GetSerialConsoleCommand();
1787
1788 /* Execute console application finally: */
1789 QProcess::startDetached(strPath, arguments);
1790#endif /* VBOX_WS_NIX */
1791}
1792
1793void UIVirtualBoxManager::sltPerformCopyCommandSerialUnix()
1794{
1795 /* Get current item: */
1796 UIVirtualMachineItem *pItem = currentItem();
1797 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
1798 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
1799 AssertPtrReturnVoid(pCloudItem);
1800
1801 /* Acquire cloud machine: */
1802 CCloudMachine comMachine = pCloudItem->machine();
1803
1804 /* Put copied serial command to clipboard: */
1805 QClipboard *pClipboard = QGuiApplication::clipboard();
1806 AssertPtrReturnVoid(pClipboard);
1807 pClipboard->setText(comMachine.GetSerialConsoleCommand());
1808}
1809
1810void UIVirtualBoxManager::sltPerformCopyCommandSerialWindows()
1811{
1812 /* Get current item: */
1813 UIVirtualMachineItem *pItem = currentItem();
1814 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
1815 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
1816 AssertPtrReturnVoid(pCloudItem);
1817
1818 /* Acquire cloud machine: */
1819 CCloudMachine comMachine = pCloudItem->machine();
1820
1821 /* Put copied serial command to clipboard: */
1822 QClipboard *pClipboard = QGuiApplication::clipboard();
1823 AssertPtrReturnVoid(pClipboard);
1824 pClipboard->setText(comMachine.GetSerialConsoleCommandWindows());
1825}
1826
1827void UIVirtualBoxManager::sltPerformCopyCommandVNCUnix()
1828{
1829 /* Get current item: */
1830 UIVirtualMachineItem *pItem = currentItem();
1831 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
1832 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
1833 AssertPtrReturnVoid(pCloudItem);
1834
1835 /* Acquire cloud machine: */
1836 CCloudMachine comMachine = pCloudItem->machine();
1837
1838 /* Put copied VNC command to clipboard: */
1839 QClipboard *pClipboard = QGuiApplication::clipboard();
1840 AssertPtrReturnVoid(pClipboard);
1841 pClipboard->setText(comMachine.GetVNCConsoleCommand());
1842}
1843
1844void UIVirtualBoxManager::sltPerformCopyCommandVNCWindows()
1845{
1846 /* Get current item: */
1847 UIVirtualMachineItem *pItem = currentItem();
1848 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
1849 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
1850 AssertPtrReturnVoid(pCloudItem);
1851
1852 /* Acquire cloud machine: */
1853 CCloudMachine comMachine = pCloudItem->machine();
1854
1855 /* Put copied VNC command to clipboard: */
1856 QClipboard *pClipboard = QGuiApplication::clipboard();
1857 AssertPtrReturnVoid(pClipboard);
1858 pClipboard->setText(comMachine.GetVNCConsoleCommandWindows());
1859}
1860
1861void UIVirtualBoxManager::sltPerformShowLog()
1862{
1863 /* Get current item: */
1864 UIVirtualMachineItem *pItem = currentItem();
1865 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
1866 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
1867 AssertPtrReturnVoid(pCloudItem);
1868
1869 /* Acquire cloud machine: */
1870 CCloudMachine comMachine = pCloudItem->machine();
1871
1872 /* Requesting cloud console log: */
1873 UINotificationProgressCloudConsoleLogAcquire *pNotification = new UINotificationProgressCloudConsoleLogAcquire(comMachine);
1874 connect(pNotification, &UINotificationProgressCloudConsoleLogAcquire::sigLogRead,
1875 this, &UIVirtualBoxManager::sltHandleConsoleLogRead);
1876 gpNotificationCenter->append(pNotification);
1877}
1878
1879void UIVirtualBoxManager::sltHandleConsoleLogRead(const QString &strName, const QString &strLog)
1880{
1881 /* Prepare dialog: */
1882 QWidget *pWindow = new QWidget(this, Qt::Window);
1883 if (pWindow)
1884 {
1885 pWindow->setAttribute(Qt::WA_DeleteOnClose);
1886 pWindow->setWindowTitle(QString("%1 - Console Log").arg(strName));
1887
1888 QVBoxLayout *pLayout = new QVBoxLayout(pWindow);
1889 if (pLayout)
1890 {
1891 QTextEdit *pTextEdit = new QTextEdit(pWindow);
1892 if (pTextEdit)
1893 {
1894 pTextEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
1895 pTextEdit->setReadOnly(true);
1896 pTextEdit->setText(strLog);
1897 pLayout->addWidget(pTextEdit);
1898 }
1899 }
1900 }
1901
1902 /* Show dialog: */
1903 pWindow->show();
1904}
1905
1906void UIVirtualBoxManager::sltPerformDiscardMachineState()
1907{
1908 /* Get selected items: */
1909 QList<UIVirtualMachineItem*> items = currentItems();
1910 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
1911
1912 /* Prepare the list of the machines to be discarded/terminated: */
1913 QStringList machinesToDiscard;
1914 QList<UIVirtualMachineItem*> itemsToDiscard;
1915 foreach (UIVirtualMachineItem *pItem, items)
1916 {
1917 if (isActionEnabled(UIActionIndexMN_M_Group_S_Discard, QList<UIVirtualMachineItem*>() << pItem))
1918 {
1919 machinesToDiscard << pItem->name();
1920 itemsToDiscard << pItem;
1921 }
1922 }
1923 AssertMsg(!machinesToDiscard.isEmpty(), ("This action should not be allowed!"));
1924
1925 /* Confirm discarding: */
1926 if ( machinesToDiscard.isEmpty()
1927 || !msgCenter().confirmDiscardSavedState(machinesToDiscard.join(", ")))
1928 return;
1929
1930 /* For every confirmed item to discard: */
1931 foreach (UIVirtualMachineItem *pItem, itemsToDiscard)
1932 {
1933 /* Open a session to modify VM: */
1934 AssertPtrReturnVoid(pItem);
1935 CSession comSession = openSession(pItem->id());
1936 if (comSession.isNull())
1937 return;
1938
1939 /* Get session machine: */
1940 CMachine comMachine = comSession.GetMachine();
1941 comMachine.DiscardSavedState(true);
1942 if (!comMachine.isOk())
1943 UINotificationMessage::cannotDiscardSavedState(comMachine);
1944
1945 /* Unlock machine finally: */
1946 comSession.UnlockMachine();
1947 }
1948}
1949
1950void UIVirtualBoxManager::sltPerformPauseOrResumeMachine(bool fPause)
1951{
1952 /* Get selected items: */
1953 QList<UIVirtualMachineItem*> items = currentItems();
1954 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
1955
1956 /* For every selected item: */
1957 foreach (UIVirtualMachineItem *pItem, items)
1958 {
1959 /* But for local machine items only: */
1960 AssertPtrReturnVoid(pItem);
1961 if (pItem->itemType() != UIVirtualMachineItemType_Local)
1962 continue;
1963
1964 /* Get local machine item state: */
1965 UIVirtualMachineItemLocal *pLocalItem = pItem->toLocal();
1966 AssertPtrReturnVoid(pLocalItem);
1967 const KMachineState enmState = pLocalItem->machineState();
1968
1969 /* Check if current item could be paused/resumed: */
1970 if (!isActionEnabled(UIActionIndexMN_M_Group_T_Pause, QList<UIVirtualMachineItem*>() << pItem))
1971 continue;
1972
1973 /* Check if current item already paused: */
1974 if (fPause &&
1975 (enmState == KMachineState_Paused ||
1976 enmState == KMachineState_TeleportingPausedVM))
1977 continue;
1978
1979 /* Check if current item already resumed: */
1980 if (!fPause &&
1981 (enmState == KMachineState_Running ||
1982 enmState == KMachineState_Teleporting ||
1983 enmState == KMachineState_LiveSnapshotting))
1984 continue;
1985
1986 /* Open a session to modify VM state: */
1987 CSession comSession = openExistingSession(pItem->id());
1988 if (comSession.isNull())
1989 return;
1990
1991 /* Get session console: */
1992 CConsole comConsole = comSession.GetConsole();
1993 /* Pause/resume VM: */
1994 if (fPause)
1995 comConsole.Pause();
1996 else
1997 comConsole.Resume();
1998 if (!comConsole.isOk())
1999 {
2000 if (fPause)
2001 UINotificationMessage::cannotPauseMachine(comConsole);
2002 else
2003 UINotificationMessage::cannotResumeMachine(comConsole);
2004 }
2005
2006 /* Unlock machine finally: */
2007 comSession.UnlockMachine();
2008 }
2009}
2010
2011void UIVirtualBoxManager::sltPerformResetMachine()
2012{
2013 /* Get selected items: */
2014 QList<UIVirtualMachineItem*> items = currentItems();
2015 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
2016
2017 /* Prepare the list of the machines to be reseted: */
2018 QStringList machineNames;
2019 QList<UIVirtualMachineItem*> itemsToReset;
2020 foreach (UIVirtualMachineItem *pItem, items)
2021 {
2022 if (isActionEnabled(UIActionIndexMN_M_Group_S_Reset, QList<UIVirtualMachineItem*>() << pItem))
2023 {
2024 machineNames << pItem->name();
2025 itemsToReset << pItem;
2026 }
2027 }
2028 AssertMsg(!machineNames.isEmpty(), ("This action should not be allowed!"));
2029
2030 /* Confirm reseting VM: */
2031 if (!msgCenter().confirmResetMachine(machineNames.join(", ")))
2032 return;
2033
2034 /* For each selected item: */
2035 foreach (UIVirtualMachineItem *pItem, itemsToReset)
2036 {
2037 switch (pItem->itemType())
2038 {
2039 case UIVirtualMachineItemType_Local:
2040 {
2041 /* Open a session to modify VM state: */
2042 CSession comSession = openExistingSession(pItem->id());
2043 if (comSession.isNull())
2044 return;
2045
2046 /* Get session console: */
2047 CConsole comConsole = comSession.GetConsole();
2048 /* Reset VM: */
2049 comConsole.Reset();
2050
2051 /* Unlock machine finally: */
2052 comSession.UnlockMachine();
2053 break;
2054 }
2055 case UIVirtualMachineItemType_CloudReal:
2056 {
2057 /* Reset VM: */
2058 UINotificationProgressCloudMachineReset *pNotification =
2059 new UINotificationProgressCloudMachineReset(pItem->toCloud()->machine());
2060 gpNotificationCenter->append(pNotification);
2061 break;
2062 }
2063 default:
2064 break;
2065 }
2066 }
2067}
2068
2069void UIVirtualBoxManager::sltPerformDetachMachineUI()
2070{
2071 /* Get selected items: */
2072 QList<UIVirtualMachineItem*> items = currentItems();
2073 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
2074
2075 /* For each selected item: */
2076 foreach (UIVirtualMachineItem *pItem, items)
2077 {
2078 /* Check if current item could be detached: */
2079 if (!isActionEnabled(UIActionIndexMN_M_Machine_S_Detach, QList<UIVirtualMachineItem*>() << pItem))
2080 continue;
2081
2082 /// @todo Detach separate UI process..
2083 AssertFailed();
2084 }
2085}
2086
2087void UIVirtualBoxManager::sltPerformSaveMachineState()
2088{
2089 /* Get selected items: */
2090 QList<UIVirtualMachineItem*> items = currentItems();
2091 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
2092
2093 /* For each selected item: */
2094 foreach (UIVirtualMachineItem *pItem, items)
2095 {
2096 /* Sanity check: */
2097 AssertPtrReturnVoid(pItem);
2098 AssertPtrReturnVoid(pItem->toLocal());
2099
2100 /* Check if current item could be saved: */
2101 if (!isActionEnabled(UIActionIndexMN_M_Machine_M_Stop_S_SaveState, QList<UIVirtualMachineItem*>() << pItem))
2102 continue;
2103
2104 /* Saving VM state: */
2105 UINotificationProgressMachineSaveState *pNotification = new UINotificationProgressMachineSaveState(pItem->toLocal()->machine());
2106 gpNotificationCenter->append(pNotification);
2107 }
2108}
2109
2110void UIVirtualBoxManager::sltPerformTerminateMachine()
2111{
2112 /* Get selected items: */
2113 QList<UIVirtualMachineItem*> items = currentItems();
2114 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
2115
2116 /* Prepare the list of the machines to be terminated: */
2117 QStringList machinesToTerminate;
2118 QList<UIVirtualMachineItem*> itemsToTerminate;
2119 foreach (UIVirtualMachineItem *pItem, items)
2120 {
2121 if (isActionEnabled(UIActionIndexMN_M_Group_M_Stop_S_Terminate, QList<UIVirtualMachineItem*>() << pItem))
2122 {
2123 machinesToTerminate << pItem->name();
2124 itemsToTerminate << pItem;
2125 }
2126 }
2127 AssertMsg(!machinesToTerminate.isEmpty(), ("This action should not be allowed!"));
2128
2129 /* Confirm terminating: */
2130 if ( machinesToTerminate.isEmpty()
2131 || !msgCenter().confirmTerminateCloudInstance(machinesToTerminate.join(", ")))
2132 return;
2133
2134 /* For every confirmed item to terminate: */
2135 foreach (UIVirtualMachineItem *pItem, itemsToTerminate)
2136 {
2137 /* Sanity check: */
2138 AssertPtrReturnVoid(pItem);
2139
2140 /* Terminating cloud VM: */
2141 UINotificationProgressCloudMachineTerminate *pNotification =
2142 new UINotificationProgressCloudMachineTerminate(pItem->toCloud()->machine());
2143 gpNotificationCenter->append(pNotification);
2144 }
2145}
2146
2147void UIVirtualBoxManager::sltPerformShutdownMachine()
2148{
2149 /* Get selected items: */
2150 QList<UIVirtualMachineItem*> items = currentItems();
2151 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
2152
2153 /* Prepare the list of the machines to be shutdowned: */
2154 QStringList machineNames;
2155 QList<UIVirtualMachineItem*> itemsToShutdown;
2156 foreach (UIVirtualMachineItem *pItem, items)
2157 {
2158 if (isActionEnabled(UIActionIndexMN_M_Machine_M_Stop_S_Shutdown, QList<UIVirtualMachineItem*>() << pItem))
2159 {
2160 machineNames << pItem->name();
2161 itemsToShutdown << pItem;
2162 }
2163 }
2164 AssertMsg(!machineNames.isEmpty(), ("This action should not be allowed!"));
2165
2166 /* Confirm ACPI shutdown current VM: */
2167 if (!msgCenter().confirmACPIShutdownMachine(machineNames.join(", ")))
2168 return;
2169
2170 /* For each selected item: */
2171 foreach (UIVirtualMachineItem *pItem, itemsToShutdown)
2172 {
2173 /* Sanity check: */
2174 AssertPtrReturnVoid(pItem);
2175
2176 /* For local machine: */
2177 if (pItem->itemType() == UIVirtualMachineItemType_Local)
2178 {
2179 /* Open a session to modify VM state: */
2180 CSession comSession = openExistingSession(pItem->id());
2181 if (comSession.isNull())
2182 return;
2183
2184 /* Get session console: */
2185 CConsole comConsole = comSession.GetConsole();
2186 /* ACPI Shutdown: */
2187 comConsole.PowerButton();
2188 if (!comConsole.isOk())
2189 UINotificationMessage::cannotACPIShutdownMachine(comConsole);
2190
2191 /* Unlock machine finally: */
2192 comSession.UnlockMachine();
2193 }
2194 /* For real cloud machine: */
2195 else if (pItem->itemType() == UIVirtualMachineItemType_CloudReal)
2196 {
2197 /* Shutting cloud VM down: */
2198 UINotificationProgressCloudMachineShutdown *pNotification =
2199 new UINotificationProgressCloudMachineShutdown(pItem->toCloud()->machine());
2200 gpNotificationCenter->append(pNotification);
2201 }
2202 }
2203}
2204
2205void UIVirtualBoxManager::sltPerformPowerOffMachine()
2206{
2207 /* Get selected items: */
2208 QList<UIVirtualMachineItem*> items = currentItems();
2209 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
2210
2211 /* Prepare the list of the machines to be powered off: */
2212 QStringList machineNames;
2213 QList<UIVirtualMachineItem*> itemsToPowerOff;
2214 foreach (UIVirtualMachineItem *pItem, items)
2215 {
2216 if (isActionEnabled(UIActionIndexMN_M_Machine_M_Stop_S_PowerOff, QList<UIVirtualMachineItem*>() << pItem))
2217 {
2218 machineNames << pItem->name();
2219 itemsToPowerOff << pItem;
2220 }
2221 }
2222 AssertMsg(!machineNames.isEmpty(), ("This action should not be allowed!"));
2223
2224 /* Confirm Power Off current VM: */
2225 if (!msgCenter().confirmPowerOffMachine(machineNames.join(", ")))
2226 return;
2227
2228 /* For each selected item: */
2229 foreach (UIVirtualMachineItem *pItem, itemsToPowerOff)
2230 {
2231 /* Sanity check: */
2232 AssertPtrReturnVoid(pItem);
2233
2234 /* For local machine: */
2235 if (pItem->itemType() == UIVirtualMachineItemType_Local)
2236 {
2237 /* Powering VM off: */
2238 UINotificationProgressMachinePowerOff *pNotification =
2239 new UINotificationProgressMachinePowerOff(pItem->toLocal()->machine(),
2240 CConsole() /* dummy */,
2241 gEDataManager->discardStateOnPowerOff(pItem->id()));
2242 pNotification->setProperty("machine_id", pItem->id());
2243 connect(pNotification, &UINotificationProgressMachinePowerOff::sigMachinePoweredOff,
2244 this, &UIVirtualBoxManager::sltHandlePoweredOffMachine);
2245 gpNotificationCenter->append(pNotification);
2246 }
2247 /* For real cloud machine: */
2248 else if (pItem->itemType() == UIVirtualMachineItemType_CloudReal)
2249 {
2250 /* Powering cloud VM off: */
2251 UINotificationProgressCloudMachinePowerOff *pNotification =
2252 new UINotificationProgressCloudMachinePowerOff(pItem->toCloud()->machine());
2253 gpNotificationCenter->append(pNotification);
2254 }
2255 }
2256}
2257
2258void UIVirtualBoxManager::sltHandlePoweredOffMachine(bool fSuccess, bool fIncludingDiscard)
2259{
2260 /* Was previous step successful? */
2261 if (fSuccess)
2262 {
2263 /* Do we have other tasks? */
2264 if (fIncludingDiscard)
2265 {
2266 /* Discard state if requested: */
2267 AssertPtrReturnVoid(sender());
2268 UINotificationProgressSnapshotRestore *pNotification =
2269 new UINotificationProgressSnapshotRestore(sender()->property("machine_id").toUuid());
2270 gpNotificationCenter->append(pNotification);
2271 }
2272 }
2273}
2274
2275void UIVirtualBoxManager::sltPerformSwitchToMachineTool(QAction *pAction)
2276{
2277 /* Sanity checks: */
2278 AssertPtrReturnVoid(pAction);
2279 AssertPtrReturnVoid(m_pWidget);
2280
2281 /* Acquire tool type: */
2282 const UIToolType enmType = pAction->property("UIToolType").value<UIToolType>();
2283 AssertReturnVoid(enmType != UIToolType_Invalid);
2284
2285 /* Check if this tool should be opened detached way: */
2286 if (gEDataManager->detachedTools().contains(enmType))
2287 return sltOpenManagerWindow(enmType);
2288
2289 /* Open the tool finally: */
2290 m_pWidget->setToolsTypeMachine(enmType);
2291}
2292
2293void UIVirtualBoxManager::sltPerformRefreshMachine()
2294{
2295 m_pWidget->refreshMachine();
2296}
2297
2298void UIVirtualBoxManager::sltShowMachineInFileManager()
2299{
2300 /* Get selected items: */
2301 QList<UIVirtualMachineItem*> items = currentItems();
2302 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
2303
2304 /* For each selected item: */
2305 foreach (UIVirtualMachineItem *pItem, items)
2306 {
2307 /* Make sure current item is local one: */
2308 UIVirtualMachineItemLocal *pItemLocal = pItem->toLocal();
2309 if (!pItemLocal)
2310 continue;
2311
2312 /* Check if that item could be shown in file-browser: */
2313 if (!isActionEnabled(UIActionIndexMN_M_Group_S_ShowInFileManager, QList<UIVirtualMachineItem*>() << pItem))
2314 continue;
2315
2316 /* Show VM in filebrowser: */
2317 UIDesktopServices::openInFileManager(pItemLocal->machine().GetSettingsFilePath());
2318 }
2319}
2320
2321void UIVirtualBoxManager::sltPerformCreateMachineShortcut()
2322{
2323 /* Get selected items: */
2324 QList<UIVirtualMachineItem*> items = currentItems();
2325 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
2326
2327 /* For each selected item: */
2328 foreach (UIVirtualMachineItem *pItem, items)
2329 {
2330 /* Make sure current item is local one: */
2331 UIVirtualMachineItemLocal *pItemLocal = pItem->toLocal();
2332 if (!pItemLocal)
2333 continue;
2334
2335 /* Check if shortcuts could be created for this item: */
2336 if (!isActionEnabled(UIActionIndexMN_M_Group_S_CreateShortcut, QList<UIVirtualMachineItem*>() << pItem))
2337 continue;
2338
2339 /* Create shortcut for this VM: */
2340 const CMachine &comMachine = pItemLocal->machine();
2341 UIDesktopServices::createMachineShortcut(comMachine.GetSettingsFilePath(),
2342 QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),
2343 comMachine.GetName(), comMachine.GetId());
2344 }
2345}
2346
2347void UIVirtualBoxManager::sltPerformGroupSorting()
2348{
2349 m_pWidget->sortGroup();
2350}
2351
2352void UIVirtualBoxManager::sltPerformMachineSearchWidgetVisibilityToggling(bool fVisible)
2353{
2354 m_pWidget->setMachineSearchWidgetVisibility(fVisible);
2355}
2356
2357void UIVirtualBoxManager::sltPerformShowHelpBrowser()
2358{
2359 QString strHelpKeyword;
2360 if (m_pWidget)
2361 strHelpKeyword = m_pWidget->currentHelpKeyword();
2362 if (!strHelpKeyword.isEmpty())
2363 UIHelpBrowserDialog::findManualFileAndShow(strHelpKeyword);
2364}
2365
2366void UIVirtualBoxManager::sltExtensionPackInstalledUninstalled(const QString &strName)
2367{
2368 Q_UNUSED(strName);
2369 updateActionsAppearance();
2370}
2371
2372void UIVirtualBoxManager::prepare()
2373{
2374#ifdef VBOX_WS_NIX
2375 NativeWindowSubsystem::setWMClass(this, "VirtualBox Manager", "VirtualBox Manager");
2376#endif
2377
2378#ifdef VBOX_WS_MAC
2379 /* We have to make sure that we are getting the front most process: */
2380 ::darwinSetFrontMostProcess();
2381 /* Install global event-filter, since vmstarter.app can send us FileOpen events,
2382 * see UIVirtualBoxManager::eventFilter for handler implementation. */
2383 qApp->installEventFilter(this);
2384#endif
2385
2386 /* Cache media data early if necessary: */
2387 if (uiCommon().agressiveCaching())
2388 gpMediumEnumerator->enumerateMedia();
2389
2390 /* Prepare: */
2391 prepareCloudMachineManager();
2392 prepareIcon();
2393 prepareMenuBar();
2394 prepareStatusBar();
2395 prepareWidgets();
2396 prepareConnections();
2397
2398 /* Update actions initially: */
2399 sltHandleChooserPaneIndexChange();
2400
2401 /* Load settings: */
2402 loadSettings();
2403
2404 /* Translate UI: */
2405 sltRetranslateUI();
2406 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
2407 this, &UIVirtualBoxManager::sltRetranslateUI);
2408
2409#ifdef VBOX_WS_MAC
2410 /* Beta label? */
2411 if (UIVersionInfo::showBetaLabel())
2412 {
2413 QPixmap betaLabel = ::betaLabel(QSize(74, darwinWindowTitleHeight(this) - 1));
2414 ::darwinLabelWindow(this, &betaLabel);
2415 }
2416#endif /* VBOX_WS_MAC */
2417
2418 /* If there are unhandled URLs we should handle them after manager is shown: */
2419 if (uiCommon().argumentUrlsPresent())
2420 QMetaObject::invokeMethod(this, "sltHandleOpenUrlCall", Qt::QueuedConnection);
2421 QMetaObject::invokeMethod(this, "sltCheckUSBAccesibility", Qt::QueuedConnection);
2422}
2423
2424void UIVirtualBoxManager::prepareCloudMachineManager()
2425{
2426 UICloudMachineManager::create();
2427}
2428
2429void UIVirtualBoxManager::prepareIcon()
2430{
2431 /* Prepare application icon.
2432 * On Win host it's built-in to the executable.
2433 * On Mac OS X the icon referenced in info.plist is used.
2434 * On X11 we will provide as much icons as we can. */
2435#if !defined(VBOX_WS_WIN) && !defined(VBOX_WS_MAC)
2436 QIcon icon(":/VirtualBox.svg");
2437 icon.addFile(":/VirtualBox_48px.png");
2438 icon.addFile(":/VirtualBox_64px.png");
2439 setWindowIcon(icon);
2440#endif /* !VBOX_WS_WIN && !VBOX_WS_MAC */
2441}
2442
2443void UIVirtualBoxManager::prepareMenuBar()
2444{
2445#ifndef VBOX_WS_MAC
2446 /* Create menu-bar: */
2447 setMenuBar(new UIMenuBar);
2448 if (menuBar())
2449 {
2450 /* Make sure menu-bar fills own solid background: */
2451 menuBar()->setAutoFillBackground(true);
2452# ifdef VBOX_WS_WIN
2453 // WORKAROUND:
2454 // On Windows we have to override Windows Vista style with style-sheet:
2455 menuBar()->setStyleSheet(QString("QMenuBar { background-color: %1; }")
2456 .arg(QApplication::palette().color(QPalette::Active, QPalette::Window).name(QColor::HexRgb)));
2457# endif
2458 }
2459#endif
2460
2461 /* Create action-pool: */
2462 m_pActionPool = UIActionPool::create(UIType_ManagerUI);
2463
2464 /* Prepare menu update-handlers: */
2465 m_menuUpdateHandlers[UIActionIndexMN_M_Group] = &UIVirtualBoxManager::updateMenuGroup;
2466 m_menuUpdateHandlers[UIActionIndexMN_M_Machine] = &UIVirtualBoxManager::updateMenuMachine;
2467 m_menuUpdateHandlers[UIActionIndexMN_M_Group_M_MoveToGroup] = &UIVirtualBoxManager::updateMenuGroupMoveToGroup;
2468 m_menuUpdateHandlers[UIActionIndexMN_M_Group_M_Console] = &UIVirtualBoxManager::updateMenuGroupConsole;
2469 m_menuUpdateHandlers[UIActionIndexMN_M_Group_M_Stop] = &UIVirtualBoxManager::updateMenuGroupClose;
2470 m_menuUpdateHandlers[UIActionIndexMN_M_Machine_M_MoveToGroup] = &UIVirtualBoxManager::updateMenuMachineMoveToGroup;
2471 m_menuUpdateHandlers[UIActionIndexMN_M_Machine_M_Console] = &UIVirtualBoxManager::updateMenuMachineConsole;
2472 m_menuUpdateHandlers[UIActionIndexMN_M_Machine_M_Stop] = &UIVirtualBoxManager::updateMenuMachineClose;
2473
2474 /* Build menu-bar: */
2475 foreach (QMenu *pMenu, actionPool()->menus())
2476 {
2477#ifdef VBOX_WS_MAC
2478 /* Before 'Help' menu we should: */
2479 if (pMenu == actionPool()->action(UIActionIndex_Menu_Help)->menu())
2480 {
2481 /* Insert 'Window' menu: */
2482 UIWindowMenuManager::create();
2483 menuBar()->addMenu(gpWindowMenuManager->createMenu(this));
2484 gpWindowMenuManager->addWindow(this);
2485 }
2486#endif
2487 menuBar()->addMenu(pMenu);
2488 }
2489
2490 /* Setup menu-bar policy: */
2491 menuBar()->setContextMenuPolicy(Qt::CustomContextMenu);
2492}
2493
2494void UIVirtualBoxManager::prepareStatusBar()
2495{
2496 /* We are not using status-bar anymore: */
2497 statusBar()->setHidden(true);
2498}
2499
2500void UIVirtualBoxManager::prepareWidgets()
2501{
2502 /* Prepare central-widget: */
2503 m_pWidget = new UIVirtualBoxManagerWidget(this);
2504 if (m_pWidget)
2505 setCentralWidget(m_pWidget);
2506}
2507
2508void UIVirtualBoxManager::prepareConnections()
2509{
2510#ifdef VBOX_WS_NIX
2511 /* Desktop event handlers: */
2512 connect(gpDesktop, &UIDesktopWidgetWatchdog::sigHostScreenWorkAreaResized,
2513 this, &UIVirtualBoxManager::sltHandleHostScreenAvailableAreaChange);
2514#endif
2515
2516 /* UICommon connections: */
2517 connect(&uiCommon(), &UICommon::sigAskToCommitData,
2518 this, &UIVirtualBoxManager::sltHandleCommitData);
2519 connect(gpMediumEnumerator, &UIMediumEnumerator::sigMediumEnumerationFinished,
2520 this, &UIVirtualBoxManager::sltHandleMediumEnumerationFinish);
2521
2522 /* Widget connections: */
2523 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigChooserPaneIndexChange,
2524 this, &UIVirtualBoxManager::sltHandleChooserPaneIndexChange);
2525 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigGroupSavingStateChanged,
2526 this, &UIVirtualBoxManager::sltHandleGroupSavingProgressChange);
2527 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigCloudUpdateStateChanged,
2528 this, &UIVirtualBoxManager::sltHandleCloudUpdateProgressChange);
2529 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigStartOrShowRequest,
2530 this, &UIVirtualBoxManager::sltPerformStartOrShowMachine);
2531 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigCloudMachineStateChange,
2532 this, &UIVirtualBoxManager::sltHandleCloudMachineStateChange);
2533 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigToolTypeChangeGlobal,
2534 this, &UIVirtualBoxManager::sltHandleGlobalToolTypeChange);
2535 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigToolTypeChangeMachine,
2536 this, &UIVirtualBoxManager::sltHandleMachineToolTypeChange);
2537 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigCreateMedium,
2538 this, &UIVirtualBoxManager::sltCreateMedium);
2539 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigCopyMedium,
2540 this, &UIVirtualBoxManager::sltCopyMedium);
2541 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigMachineSettingsLinkClicked,
2542 this, &UIVirtualBoxManager::sltOpenSettingsDialog);
2543 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigCurrentSnapshotItemChange,
2544 this, &UIVirtualBoxManager::sltCurrentSnapshotItemChange);
2545 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigDetachToolPane,
2546 this, &UIVirtualBoxManager::sltDetachToolPane);
2547
2548 connect(menuBar(), &QMenuBar::customContextMenuRequested,
2549 m_pWidget, &UIVirtualBoxManagerWidget::sltHandleToolBarContextMenuRequest);
2550
2551 /* Global VBox event handlers: */
2552 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigExtensionPackInstalled,
2553 this, &UIVirtualBoxManager::sltExtensionPackInstalledUninstalled);
2554 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigExtensionPackUninstalled,
2555 this, &UIVirtualBoxManager::sltExtensionPackInstalledUninstalled);
2556 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineStateChange,
2557 this, &UIVirtualBoxManager::sltHandleStateChange);
2558 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigSessionStateChange,
2559 this, &UIVirtualBoxManager::sltHandleStateChange);
2560
2561 /* General action-pool connections: */
2562 connect(actionPool(), &UIActionPool::sigNotifyAboutMenuPrepare, this, &UIVirtualBoxManager::sltHandleMenuPrepare);
2563
2564 /* 'File' menu connections: */
2565 connect(actionPool()->action(UIActionIndexMN_M_File_S_ImportAppliance), &UIAction::triggered,
2566 this, &UIVirtualBoxManager::sltOpenImportApplianceWizard);
2567 connect(actionPool()->action(UIActionIndexMN_M_File_S_ExportAppliance), &UIAction::triggered,
2568 this, &UIVirtualBoxManager::sltOpenExportApplianceWizard);
2569#ifdef VBOX_GUI_WITH_EXTRADATA_MANAGER_UI
2570 connect(actionPool()->action(UIActionIndexMN_M_File_S_ShowExtraDataManager), &UIAction::triggered,
2571 this, &UIVirtualBoxManager::sltOpenExtraDataManagerWindow);
2572#endif /* VBOX_GUI_WITH_EXTRADATA_MANAGER_UI */
2573 connect(actionPool()->action(UIActionIndex_M_Application_S_Preferences), &UIAction::triggered,
2574 this, &UIVirtualBoxManager::sltOpenPreferencesDialog);
2575 connect(actionPool()->action(UIActionIndexMN_M_File_S_Close), &UIAction::triggered,
2576 this, &UIVirtualBoxManager::sltPerformExit);
2577
2578 /* 'File/Tools' menu connections: */
2579 connect(actionPool()->actionGroup(UIActionIndexMN_M_File_M_Tools), &QActionGroup::triggered,
2580 this, &UIVirtualBoxManager::sltPerformSwitchToGlobalTool);
2581
2582 /* 'Welcome' menu connections: */
2583 connect(actionPool()->action(UIActionIndexMN_M_Welcome_S_New), &UIAction::triggered,
2584 this, &UIVirtualBoxManager::sltOpenNewMachineWizard);
2585 connect(actionPool()->action(UIActionIndexMN_M_Welcome_S_Add), &UIAction::triggered,
2586 this, &UIVirtualBoxManager::sltOpenAddMachineDialog);
2587
2588 /* 'Group' menu connections: */
2589 connect(actionPool()->action(UIActionIndexMN_M_Group_S_New), &UIAction::triggered,
2590 this, &UIVirtualBoxManager::sltOpenNewMachineWizard);
2591 connect(actionPool()->action(UIActionIndexMN_M_Group_S_Add), &UIAction::triggered,
2592 this, &UIVirtualBoxManager::sltOpenAddMachineDialog);
2593 connect(actionPool()->action(UIActionIndexMN_M_Group_S_Rename), &UIAction::triggered,
2594 this, &UIVirtualBoxManager::sltOpenGroupNameEditor);
2595 connect(actionPool()->action(UIActionIndexMN_M_Group_S_Remove), &UIAction::triggered,
2596 this, &UIVirtualBoxManager::sltDisbandGroup);
2597 connect(actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow), &UIAction::triggered,
2598 this, &UIVirtualBoxManager::sltPerformStartOrShowMachine);
2599 connect(actionPool()->action(UIActionIndexMN_M_Group_T_Pause), &UIAction::toggled,
2600 this, &UIVirtualBoxManager::sltPerformPauseOrResumeMachine);
2601 connect(actionPool()->action(UIActionIndexMN_M_Group_S_Reset), &UIAction::triggered,
2602 this, &UIVirtualBoxManager::sltPerformResetMachine);
2603 connect(actionPool()->action(UIActionIndexMN_M_Group_S_Detach), &UIAction::triggered,
2604 this, &UIVirtualBoxManager::sltPerformDetachMachineUI);
2605 connect(actionPool()->action(UIActionIndexMN_M_Group_S_Discard), &UIAction::triggered,
2606 this, &UIVirtualBoxManager::sltPerformDiscardMachineState);
2607 connect(actionPool()->action(UIActionIndexMN_M_Group_S_Refresh), &UIAction::triggered,
2608 this, &UIVirtualBoxManager::sltPerformRefreshMachine);
2609 connect(actionPool()->action(UIActionIndexMN_M_Group_S_ShowInFileManager), &UIAction::triggered,
2610 this, &UIVirtualBoxManager::sltShowMachineInFileManager);
2611 connect(actionPool()->action(UIActionIndexMN_M_Group_S_CreateShortcut), &UIAction::triggered,
2612 this, &UIVirtualBoxManager::sltPerformCreateMachineShortcut);
2613 connect(actionPool()->action(UIActionIndexMN_M_Group_S_Sort), &UIAction::triggered,
2614 this, &UIVirtualBoxManager::sltPerformGroupSorting);
2615 connect(actionPool()->action(UIActionIndexMN_M_Group_T_Search), &UIAction::toggled,
2616 this, &UIVirtualBoxManager::sltPerformMachineSearchWidgetVisibilityToggling);
2617 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigMachineSearchWidgetVisibilityChanged,
2618 actionPool()->action(UIActionIndexMN_M_Group_T_Search), &QAction::setChecked);
2619
2620 /* 'Machine' menu connections: */
2621 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_New), &UIAction::triggered,
2622 this, &UIVirtualBoxManager::sltOpenNewMachineWizard);
2623 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_Add), &UIAction::triggered,
2624 this, &UIVirtualBoxManager::sltOpenAddMachineDialog);
2625 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_Settings), &UIAction::triggered,
2626 this, &UIVirtualBoxManager::sltOpenSettingsDialogDefault);
2627 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_Clone), &UIAction::triggered,
2628 this, &UIVirtualBoxManager::sltOpenCloneMachineWizard);
2629 connect(actionPool()->action(UIActionIndexMN_M_Snapshot_S_Clone), &UIAction::triggered,
2630 this, &UIVirtualBoxManager::sltOpenCloneMachineWizard);
2631 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_Move), &UIAction::triggered,
2632 this, &UIVirtualBoxManager::sltPerformMachineMove);
2633 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_ExportToOCI), &UIAction::triggered,
2634 this, &UIVirtualBoxManager::sltOpenExportApplianceWizard);
2635 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_Remove), &UIAction::triggered,
2636 this, &UIVirtualBoxManager::sltPerformMachineRemove);
2637 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_MoveToGroup_S_New), &UIAction::triggered,
2638 this, &UIVirtualBoxManager::sltPerformMachineMoveToNewGroup);
2639 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow), &UIAction::triggered,
2640 this, &UIVirtualBoxManager::sltPerformStartOrShowMachine);
2641 connect(actionPool()->action(UIActionIndexMN_M_Machine_T_Pause), &UIAction::toggled,
2642 this, &UIVirtualBoxManager::sltPerformPauseOrResumeMachine);
2643 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_Reset), &UIAction::triggered,
2644 this, &UIVirtualBoxManager::sltPerformResetMachine);
2645 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_Detach), &UIAction::triggered,
2646 this, &UIVirtualBoxManager::sltPerformDetachMachineUI);
2647 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_Discard), &UIAction::triggered,
2648 this, &UIVirtualBoxManager::sltPerformDiscardMachineState);
2649 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_Refresh), &UIAction::triggered,
2650 this, &UIVirtualBoxManager::sltPerformRefreshMachine);
2651 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_ShowInFileManager), &UIAction::triggered,
2652 this, &UIVirtualBoxManager::sltShowMachineInFileManager);
2653 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_CreateShortcut), &UIAction::triggered,
2654 this, &UIVirtualBoxManager::sltPerformCreateMachineShortcut);
2655 connect(actionPool()->action(UIActionIndexMN_M_Machine_S_SortParent), &UIAction::triggered,
2656 this, &UIVirtualBoxManager::sltPerformGroupSorting);
2657 connect(actionPool()->action(UIActionIndexMN_M_Machine_T_Search), &UIAction::toggled,
2658 this, &UIVirtualBoxManager::sltPerformMachineSearchWidgetVisibilityToggling);
2659 connect(m_pWidget, &UIVirtualBoxManagerWidget::sigMachineSearchWidgetVisibilityChanged,
2660 actionPool()->action(UIActionIndexMN_M_Machine_T_Search), &QAction::setChecked);
2661
2662 /* 'Group/Start or Show' menu connections: */
2663 connect(actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow_S_StartNormal), &UIAction::triggered,
2664 this, &UIVirtualBoxManager::sltPerformStartMachineNormal);
2665 connect(actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow_S_StartHeadless), &UIAction::triggered,
2666 this, &UIVirtualBoxManager::sltPerformStartMachineHeadless);
2667 connect(actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow_S_StartDetachable), &UIAction::triggered,
2668 this, &UIVirtualBoxManager::sltPerformStartMachineDetachable);
2669
2670 /* 'Machine/Start or Show' menu connections: */
2671 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow_S_StartNormal), &UIAction::triggered,
2672 this, &UIVirtualBoxManager::sltPerformStartMachineNormal);
2673 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow_S_StartHeadless), &UIAction::triggered,
2674 this, &UIVirtualBoxManager::sltPerformStartMachineHeadless);
2675 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow_S_StartDetachable), &UIAction::triggered,
2676 this, &UIVirtualBoxManager::sltPerformStartMachineDetachable);
2677
2678 /* 'Group/Console' menu connections: */
2679 connect(actionPool()->action(UIActionIndexMN_M_Group_M_Console_S_CreateConnection), &UIAction::triggered,
2680 this, &UIVirtualBoxManager::sltPerformCreateConsoleConnectionForGroup);
2681 connect(actionPool()->action(UIActionIndexMN_M_Group_M_Console_S_DeleteConnection), &UIAction::triggered,
2682 this, &UIVirtualBoxManager::sltPerformDeleteConsoleConnectionForGroup);
2683 connect(actionPool()->action(UIActionIndexMN_M_Group_M_Console_S_ConfigureApplications), &UIAction::triggered,
2684 this, &UIVirtualBoxManager::sltOpenManagerWindowDefault);
2685
2686 /* 'Machine/Console' menu connections: */
2687 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CreateConnection), &UIAction::triggered,
2688 this, &UIVirtualBoxManager::sltPerformCreateConsoleConnectionForMachine);
2689 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_DeleteConnection), &UIAction::triggered,
2690 this, &UIVirtualBoxManager::sltPerformDeleteConsoleConnectionForMachine);
2691 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandSerialUnix), &UIAction::triggered,
2692 this, &UIVirtualBoxManager::sltPerformCopyCommandSerialUnix);
2693 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandSerialWindows), &UIAction::triggered,
2694 this, &UIVirtualBoxManager::sltPerformCopyCommandSerialWindows);
2695 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandVNCUnix), &UIAction::triggered,
2696 this, &UIVirtualBoxManager::sltPerformCopyCommandVNCUnix);
2697 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandVNCWindows), &UIAction::triggered,
2698 this, &UIVirtualBoxManager::sltPerformCopyCommandVNCWindows);
2699 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_ConfigureApplications), &UIAction::triggered,
2700 this, &UIVirtualBoxManager::sltOpenManagerWindowDefault);
2701 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_ShowLog), &UIAction::triggered,
2702 this, &UIVirtualBoxManager::sltPerformShowLog);
2703
2704 /* 'Group/Stop' menu connections: */
2705 connect(actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_SaveState), &UIAction::triggered,
2706 this, &UIVirtualBoxManager::sltPerformSaveMachineState);
2707 connect(actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_Terminate), &UIAction::triggered,
2708 this, &UIVirtualBoxManager::sltPerformTerminateMachine);
2709 connect(actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_Shutdown), &UIAction::triggered,
2710 this, &UIVirtualBoxManager::sltPerformShutdownMachine);
2711 connect(actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_PowerOff), &UIAction::triggered,
2712 this, &UIVirtualBoxManager::sltPerformPowerOffMachine);
2713
2714 /* 'Machine/Stop' menu connections: */
2715 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_SaveState), &UIAction::triggered,
2716 this, &UIVirtualBoxManager::sltPerformSaveMachineState);
2717 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_Terminate), &UIAction::triggered,
2718 this, &UIVirtualBoxManager::sltPerformTerminateMachine);
2719 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_Shutdown), &UIAction::triggered,
2720 this, &UIVirtualBoxManager::sltPerformShutdownMachine);
2721 connect(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_PowerOff), &UIAction::triggered,
2722 this, &UIVirtualBoxManager::sltPerformPowerOffMachine);
2723
2724 /* 'Group/Tools' menu connections: */
2725 connect(actionPool()->actionGroup(UIActionIndexMN_M_Group_M_Tools), &QActionGroup::triggered,
2726 this, &UIVirtualBoxManager::sltPerformSwitchToMachineTool);
2727
2728 /* 'Machine/Tools' menu connections: */
2729 connect(actionPool()->actionGroup(UIActionIndexMN_M_Machine_M_Tools), &QActionGroup::triggered,
2730 this, &UIVirtualBoxManager::sltPerformSwitchToMachineTool);
2731
2732 /* 'Help' menu contents action connection. It is done here since we need different behaviour in
2733 * the manager and runtime UIs: */
2734 connect(actionPool()->action(UIActionIndex_Simple_Contents), &UIAction::triggered,
2735 this, &UIVirtualBoxManager::sltPerformShowHelpBrowser);
2736}
2737
2738void UIVirtualBoxManager::loadSettings()
2739{
2740 /* Load window geometry: */
2741 {
2742 const QRect geo = gEDataManager->selectorWindowGeometry(this);
2743 LogRel2(("GUI: UIVirtualBoxManager: Restoring geometry to: Origin=%dx%d, Size=%dx%d\n",
2744 geo.x(), geo.y(), geo.width(), geo.height()));
2745 restoreGeometry(geo);
2746 }
2747}
2748
2749void UIVirtualBoxManager::cleanupConnections()
2750{
2751 /* Honestly we should disconnect everything here,
2752 * but for now it's enough to disconnect the most critical. */
2753 m_pWidget->disconnect(this);
2754}
2755
2756void UIVirtualBoxManager::cleanupWidgets()
2757{
2758 /* Deconfigure central-widget: */
2759 setCentralWidget(0);
2760 /* Destroy central-widget: */
2761 delete m_pWidget;
2762 m_pWidget = 0;
2763}
2764
2765void UIVirtualBoxManager::cleanupMenuBar()
2766{
2767#ifdef VBOX_WS_MAC
2768 /* Cleanup 'Window' menu: */
2769 UIWindowMenuManager::destroy();
2770#endif
2771
2772 /* Destroy action-pool: */
2773 UIActionPool::destroy(m_pActionPool);
2774 m_pActionPool = 0;
2775}
2776
2777void UIVirtualBoxManager::cleanupCloudMachineManager()
2778{
2779 UICloudMachineManager::destroy();
2780}
2781
2782void UIVirtualBoxManager::cleanup()
2783{
2784 /* Ask sub-dialogs to commit data: */
2785 sltHandleCommitData();
2786
2787 /* Cleanup: */
2788 cleanupWidgets();
2789 cleanupMenuBar();
2790 cleanupCloudMachineManager();
2791}
2792
2793UIVirtualMachineItem *UIVirtualBoxManager::currentItem() const
2794{
2795 return m_pWidget->currentItem();
2796}
2797
2798QList<UIVirtualMachineItem*> UIVirtualBoxManager::currentItems() const
2799{
2800 return m_pWidget->currentItems();
2801}
2802
2803bool UIVirtualBoxManager::isGroupSavingInProgress() const
2804{
2805 return m_pWidget->isGroupSavingInProgress();
2806}
2807
2808bool UIVirtualBoxManager::isAllItemsOfOneGroupSelected() const
2809{
2810 return m_pWidget->isAllItemsOfOneGroupSelected();
2811}
2812
2813bool UIVirtualBoxManager::isSingleGroupSelected() const
2814{
2815 return m_pWidget->isSingleGroupSelected();
2816}
2817
2818bool UIVirtualBoxManager::isSingleLocalGroupSelected() const
2819{
2820 return m_pWidget->isSingleLocalGroupSelected();
2821}
2822
2823bool UIVirtualBoxManager::isSingleCloudProviderGroupSelected() const
2824{
2825 return m_pWidget->isSingleCloudProviderGroupSelected();
2826}
2827
2828bool UIVirtualBoxManager::isSingleCloudProfileGroupSelected() const
2829{
2830 return m_pWidget->isSingleCloudProfileGroupSelected();
2831}
2832
2833bool UIVirtualBoxManager::isCloudProfileUpdateInProgress() const
2834{
2835 return m_pWidget->isCloudProfileUpdateInProgress();
2836}
2837
2838bool UIVirtualBoxManager::checkUnattendedInstallError(const CUnattended &comUnattended) const
2839{
2840 if (!comUnattended.isOk())
2841 {
2842 UINotificationMessage::cannotRunUnattendedGuestInstall(comUnattended);
2843 return false;
2844 }
2845 return true;
2846}
2847
2848void UIVirtualBoxManager::openAddMachineDialog(const QString &strFileName /* = QString() */)
2849{
2850 /* Lock the actions preventing cascade calls: */
2851 UIQObjectPropertySetter guardBlock(QList<QObject*>() << actionPool()->action(UIActionIndexMN_M_Welcome_S_Add)
2852 << actionPool()->action(UIActionIndexMN_M_Machine_S_Add)
2853 << actionPool()->action(UIActionIndexMN_M_Group_S_Add),
2854 "opened", true);
2855 connect(&guardBlock, &UIQObjectPropertySetter::sigAboutToBeDestroyed,
2856 this, &UIVirtualBoxManager::sltHandleUpdateActionAppearanceRequest);
2857 updateActionsAppearance();
2858
2859 /* Initialize variables: */
2860#ifdef VBOX_WS_MAC
2861 QString strTmpFile = ::darwinResolveAlias(strFileName);
2862#else
2863 QString strTmpFile = strFileName;
2864#endif
2865 CVirtualBox comVBox = gpGlobalSession->virtualBox();
2866
2867 /* No file specified: */
2868 if (strTmpFile.isEmpty())
2869 {
2870 QString strBaseFolder;
2871 if (currentItem() && currentItem()->toLocal())
2872 {
2873 QDir folder = QFileInfo(currentItem()->toLocal()->settingsFile()).absoluteDir();
2874 folder.cdUp();
2875 strBaseFolder = folder.absolutePath();
2876 }
2877 if (strBaseFolder.isEmpty())
2878 strBaseFolder = comVBox.GetSystemProperties().GetDefaultMachineFolder();
2879 QString strTitle = tr("Select a virtual machine file");
2880 QStringList extensions;
2881 for (int i = 0; i < VBoxFileExts.size(); ++i)
2882 extensions << QString("*.%1").arg(VBoxFileExts[i]);
2883 QString strFilter = tr("Virtual machine files (%1)").arg(extensions.join(" "));
2884 /* Create open file dialog: */
2885 QStringList fileNames = QIFileDialog::getOpenFileNames(strBaseFolder, strFilter, this, strTitle, 0, true, true);
2886 if (!fileNames.isEmpty())
2887 strTmpFile = fileNames.at(0);
2888 }
2889
2890 /* Nothing was chosen? */
2891 if (strTmpFile.isEmpty())
2892 return;
2893
2894 /* Make sure this machine can be opened: */
2895 CMachine comMachineNew = comVBox.OpenMachine(strTmpFile, QString());
2896 if (!comVBox.isOk())
2897 {
2898 UINotificationMessage::cannotOpenMachine(comVBox, strTmpFile);
2899 return;
2900 }
2901
2902 /* Make sure this machine was NOT registered already: */
2903 CMachine comMachineOld = comVBox.FindMachine(comMachineNew.GetId().toString());
2904 if (!comMachineOld.isNull())
2905 {
2906 UINotificationMessage::cannotReregisterExistingMachine(comMachineOld.GetName(), strTmpFile);
2907 return;
2908 }
2909
2910 /* Register that machine: */
2911 comVBox.RegisterMachine(comMachineNew);
2912}
2913
2914void UIVirtualBoxManager::openNewMachineWizard(const QString &strISOFilePath /* = QString() */)
2915{
2916 /* Configure wizard variables: */
2917 m_strISOFilePath = strISOFilePath;
2918
2919 /* Open New VM Wizard: */
2920 sltOpenWizard(WizardType_NewVM);
2921}
2922
2923void UIVirtualBoxManager::openImportApplianceWizard(const QString &strFileName /* = QString() */)
2924{
2925 /* Configure wizard variables: */
2926 m_fImportFromOCI = false;
2927#ifdef VBOX_WS_MAC
2928 m_strFileName = ::darwinResolveAlias(strFileName);
2929#else
2930 m_strFileName = strFileName;
2931#endif
2932
2933 /* If there is no file-name passed,
2934 * check if cloud stuff focused currently: */
2935 if ( m_strFileName.isEmpty()
2936 && ( m_pWidget->isSingleCloudProviderGroupSelected()
2937 || m_pWidget->isSingleCloudProfileGroupSelected()
2938 || m_pWidget->isCloudMachineItemSelected()))
2939 {
2940 m_fImportFromOCI = true;
2941 /* We can generate cloud hints as well: */
2942 m_strFileName = m_pWidget->fullGroupName();
2943 }
2944
2945 /* Open Import Appliance Wizard: */
2946 sltOpenWizard(WizardType_ImportAppliance);
2947}
2948
2949/* static */
2950void UIVirtualBoxManager::launchMachine(CMachine &comMachine,
2951 UILaunchMode enmLaunchMode /* = UILaunchMode_Default */)
2952{
2953 /* Switch to machine window(s) if possible: */
2954 if ( comMachine.GetSessionState() == KSessionState_Locked // precondition for CanShowConsoleWindow()
2955 && comMachine.CanShowConsoleWindow())
2956 {
2957 switchToMachine(comMachine);
2958 return;
2959 }
2960
2961 /* Not for separate UI (which can connect to machine in any state): */
2962 if (enmLaunchMode != UILaunchMode_Separate)
2963 {
2964 /* Make sure machine-state is one of required: */
2965 const KMachineState enmState = comMachine.GetState(); Q_UNUSED(enmState);
2966 AssertMsg( enmState == KMachineState_PoweredOff
2967 || enmState == KMachineState_Saved
2968 || enmState == KMachineState_Teleported
2969 || enmState == KMachineState_Aborted
2970 || enmState == KMachineState_AbortedSaved
2971 , ("Machine must be PoweredOff/Saved/Teleported/Aborted (%d)", enmState));
2972 }
2973
2974 /* Powering VM up: */
2975 UINotificationProgressMachinePowerUp *pNotification =
2976 new UINotificationProgressMachinePowerUp(comMachine, enmLaunchMode);
2977 gpNotificationCenter->append(pNotification);
2978}
2979
2980/* static */
2981void UIVirtualBoxManager::launchMachine(CCloudMachine &comMachine)
2982{
2983 /* Powering cloud VM up: */
2984 UINotificationProgressCloudMachinePowerUp *pNotification =
2985 new UINotificationProgressCloudMachinePowerUp(comMachine);
2986 gpNotificationCenter->append(pNotification);
2987}
2988
2989void UIVirtualBoxManager::startUnattendedInstall(const CUnattended &comUnattendedRef,
2990 bool fStartHeadless, const QString &strMachineId)
2991{
2992 CVirtualBox comVBox = gpGlobalSession->virtualBox();
2993 CMachine comMachine = comVBox.FindMachine(strMachineId);
2994 if (comMachine.isNull())
2995 return;
2996
2997 CUnattended comUnattended = comUnattendedRef;
2998 comUnattended.Prepare();
2999 AssertReturnVoid(checkUnattendedInstallError(comUnattended));
3000 comUnattended.ConstructMedia();
3001 AssertReturnVoid(checkUnattendedInstallError(comUnattended));
3002 comUnattended.ReconfigureVM();
3003 AssertReturnVoid(checkUnattendedInstallError(comUnattended));
3004
3005 launchMachine(comMachine, fStartHeadless ? UILaunchMode_Headless : UILaunchMode_Default);
3006}
3007
3008void UIVirtualBoxManager::performStartOrShowVirtualMachines(const QList<UIVirtualMachineItem*> &items, UILaunchMode enmLaunchMode)
3009{
3010 /* Do nothing while group saving is in progress: */
3011 if (isGroupSavingInProgress())
3012 return;
3013
3014 /* Compose the list of startable items: */
3015 QStringList startableMachineNames;
3016 QList<UIVirtualMachineItem*> startableItems;
3017 foreach (UIVirtualMachineItem *pItem, items)
3018 {
3019 if (isAtLeastOneItemCanBeStarted(QList<UIVirtualMachineItem*>() << pItem))
3020 {
3021 startableItems << pItem;
3022 startableMachineNames << pItem->name();
3023 }
3024 }
3025
3026 /* Initially we have start auto-confirmed: */
3027 bool fStartConfirmed = true;
3028 /* But if we have more than one item to start =>
3029 * We should still ask user for a confirmation: */
3030 if (startableItems.size() > 1)
3031 fStartConfirmed = msgCenter().confirmStartMultipleMachines(startableMachineNames.join(", "));
3032
3033 /* For every item => check if it could be launched: */
3034 foreach (UIVirtualMachineItem *pItem, items)
3035 {
3036 if ( isAtLeastOneItemCanBeShown(QList<UIVirtualMachineItem*>() << pItem)
3037 || ( isAtLeastOneItemCanBeStarted(QList<UIVirtualMachineItem*>() << pItem)
3038 && fStartConfirmed))
3039 {
3040 /* For local machine: */
3041 if (pItem->itemType() == UIVirtualMachineItemType_Local)
3042 {
3043 /* Fetch item launch mode: */
3044 UILaunchMode enmItemLaunchMode = enmLaunchMode;
3045 if (enmItemLaunchMode == UILaunchMode_Invalid)
3046 enmItemLaunchMode = pItem->isItemRunningHeadless()
3047 ? UILaunchMode_Separate
3048 : qApp->keyboardModifiers() == Qt::ShiftModifier
3049 ? UILaunchMode_Headless
3050 : UILaunchMode_Default;
3051 /* Acquire local machine: */
3052 CMachine machine = pItem->toLocal()->machine();
3053 /* Launch current VM: */
3054 launchMachine(machine, enmItemLaunchMode);
3055 }
3056 /* For real cloud machine: */
3057 else if (pItem->itemType() == UIVirtualMachineItemType_CloudReal)
3058 {
3059 /* Acquire cloud machine: */
3060 CCloudMachine comCloudMachine = pItem->toCloud()->machine();
3061 /* Launch current VM: */
3062 launchMachine(comCloudMachine);
3063 }
3064 }
3065 }
3066}
3067
3068#ifndef VBOX_WS_WIN
3069QStringList UIVirtualBoxManager::parseShellArguments(const QString &strArguments)
3070{
3071 //printf("start processing arguments\n");
3072
3073 /* Parse argument string: */
3074 QStringList arguments;
3075 const QRegularExpression re("(\"[^\"]+\")|('[^']+')|([^\\s\"']+)");
3076 int iPosition = 0;
3077 QRegularExpressionMatch mt = re.match(strArguments, iPosition);
3078 int iIndex = mt.capturedStart();
3079 while (iIndex != -1)
3080 {
3081 /* Get what's the sequence we have: */
3082 const QString strCap0 = mt.captured(0);
3083 /* Get what's the double-quoted sequence we have: */
3084 const QString strCap1 = mt.captured(1);
3085 /* Get what's the single-quoted sequence we have: */
3086 const QString strCap2 = mt.captured(2);
3087 /* Get what's the unquoted sequence we have: */
3088 const QString strCap3 = mt.captured(3);
3089
3090 /* If new sequence starts where previous ended
3091 * we are appending new value to previous one, otherwise
3092 * we are appending new value to argument list itself.. */
3093
3094 /* Do we have double-quoted sequence? */
3095 if (!strCap1.isEmpty())
3096 {
3097 //printf(" [D] double-quoted sequence starting at: %d\n", iIndex);
3098 /* Unquote the value and add it to the list: */
3099 const QString strValue = strCap1.mid(1, strCap1.size() - 2);
3100 if (!arguments.isEmpty() && iIndex == iPosition)
3101 arguments.last() += strValue;
3102 else
3103 arguments << strValue;
3104 }
3105 /* Do we have single-quoted sequence? */
3106 else if (!strCap2.isEmpty())
3107 {
3108 //printf(" [S] single-quoted sequence starting at: %d\n", iIndex);
3109 /* Unquote the value and add it to the list: */
3110 const QString strValue = strCap2.mid(1, strCap2.size() - 2);
3111 if (!arguments.isEmpty() && iIndex == iPosition)
3112 arguments.last() += strValue;
3113 else
3114 arguments << strValue;
3115 }
3116 /* Do we have unquoted sequence? */
3117 else if (!strCap3.isEmpty())
3118 {
3119 //printf(" [U] unquoted sequence starting at: %d\n", iIndex);
3120 /* Value wasn't unquoted, add it to the list: */
3121 if (!arguments.isEmpty() && iIndex == iPosition)
3122 arguments.last() += strCap3;
3123 else
3124 arguments << strCap3;
3125 }
3126
3127 /* Advance position: */
3128 iPosition = iIndex + strCap0.size();
3129 /* Search for a next sequence: */
3130 mt = re.match(strArguments, iPosition);
3131 iIndex = mt.capturedStart();
3132 }
3133
3134 //printf("arguments processed:\n");
3135 //foreach (const QString &strArgument, arguments)
3136 // printf(" %s\n", strArgument.toUtf8().constData());
3137
3138 /* Return parsed arguments: */
3139 return arguments;
3140}
3141#endif /* !VBOX_WS_WIN */
3142
3143void UIVirtualBoxManager::updateMenuGroup(QMenu *pMenu)
3144{
3145 /* For single cloud provider/profile: */
3146 if ( isSingleCloudProviderGroupSelected()
3147 || isSingleCloudProfileGroupSelected())
3148 {
3149 /* Populate Group-menu: */
3150 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_New));
3151 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Add));
3152 pMenu->addSeparator();
3153 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow));
3154 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Reset));
3155 pMenu->addMenu(actionPool()->action(UIActionIndexMN_M_Group_M_Console)->menu());
3156 pMenu->addMenu(actionPool()->action(UIActionIndexMN_M_Group_M_Stop)->menu());
3157 pMenu->addSeparator();
3158 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Refresh));
3159 pMenu->addSeparator();
3160 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Sort));
3161 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_T_Search));
3162 }
3163 /* For other cases, like local group or no group at all: */
3164 else
3165 {
3166 /* Populate Group-menu: */
3167 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_New));
3168 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Add));
3169 pMenu->addSeparator();
3170 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Rename));
3171 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Remove));
3172 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_MoveToGroup));
3173 pMenu->addSeparator();
3174 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow));
3175 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_T_Pause));
3176 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Reset));
3177 // pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Detach));
3178 pMenu->addMenu(actionPool()->action(UIActionIndexMN_M_Group_M_Stop)->menu());
3179 pMenu->addSeparator();
3180 pMenu->addMenu(actionPool()->action(UIActionIndexMN_M_Group_M_Tools)->menu());
3181 pMenu->addSeparator();
3182 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Discard));
3183 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Refresh));
3184 pMenu->addSeparator();
3185 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_ShowInFileManager));
3186 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_CreateShortcut));
3187 pMenu->addSeparator();
3188 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_S_Sort));
3189 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_T_Search));
3190 }
3191}
3192
3193void UIVirtualBoxManager::updateMenuMachine(QMenu *pMenu)
3194{
3195 /* Get first selected item: */
3196 UIVirtualMachineItem *pItem = currentItem();
3197
3198 /* For cloud machine(s): */
3199 if ( pItem
3200 && ( pItem->itemType() == UIVirtualMachineItemType_CloudFake
3201 || pItem->itemType() == UIVirtualMachineItemType_CloudReal))
3202 {
3203 /* Populate Machine-menu: */
3204 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_New));
3205 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Add));
3206 pMenu->addSeparator();
3207 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Settings));
3208 if (gEDataManager->isSettingsInExpertMode())
3209 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Clone));
3210 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Remove));
3211 pMenu->addSeparator();
3212 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow));
3213 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Reset));
3214 pMenu->addMenu(actionPool()->action(UIActionIndexMN_M_Machine_M_Console)->menu());
3215 pMenu->addMenu(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop)->menu());
3216 pMenu->addSeparator();
3217 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Refresh));
3218 pMenu->addSeparator();
3219 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_SortParent));
3220 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_T_Search));
3221 }
3222 /* For other cases, like local machine(s) or no machine at all: */
3223 else
3224 {
3225 /* Populate Machine-menu: */
3226 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_New));
3227 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Add));
3228 pMenu->addSeparator();
3229 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Settings));
3230 if (gEDataManager->isSettingsInExpertMode())
3231 {
3232 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Clone));
3233 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Move));
3234 }
3235 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_ExportToOCI));
3236 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Remove));
3237 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_MoveToGroup));
3238 pMenu->addSeparator();
3239 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow));
3240 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_T_Pause));
3241 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Reset));
3242 // pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Detach));
3243 pMenu->addMenu(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop)->menu());
3244 pMenu->addSeparator();
3245 pMenu->addMenu(actionPool()->action(UIActionIndexMN_M_Machine_M_Tools)->menu());
3246 pMenu->addSeparator();
3247 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Discard));
3248 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_Refresh));
3249 pMenu->addSeparator();
3250 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_ShowInFileManager));
3251 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_CreateShortcut));
3252 pMenu->addSeparator();
3253 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_S_SortParent));
3254 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_T_Search));
3255 }
3256}
3257
3258void UIVirtualBoxManager::updateMenuGroupMoveToGroup(QMenu *pMenu)
3259{
3260 const QStringList groups = m_pWidget->possibleGroupsForGroupToMove(m_pWidget->fullGroupName());
3261 if (!groups.isEmpty())
3262 pMenu->addSeparator();
3263 foreach (const QString &strGroupName, groups)
3264 {
3265 QString strVisibleGroupName = strGroupName;
3266 if (strVisibleGroupName.startsWith('/'))
3267 strVisibleGroupName.remove(0, 1);
3268 if (strVisibleGroupName.isEmpty())
3269 strVisibleGroupName = QApplication::translate("UIActionPool", "[Root]", "group");
3270 QAction *pAction = pMenu->addAction(strVisibleGroupName, this, &UIVirtualBoxManager::sltPerformMachineMoveToSpecificGroup);
3271 pAction->setProperty("actual_group_name", strGroupName);
3272 }
3273}
3274
3275void UIVirtualBoxManager::updateMenuGroupConsole(QMenu *pMenu)
3276{
3277 /* Populate 'Group' / 'Console' menu: */
3278 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_Console_S_CreateConnection));
3279 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_Console_S_DeleteConnection));
3280 pMenu->addSeparator();
3281 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_Console_S_ConfigureApplications));
3282}
3283
3284void UIVirtualBoxManager::updateMenuGroupClose(QMenu *pMenu)
3285{
3286 /* Get first selected item: */
3287 UIVirtualMachineItem *pItem = currentItem();
3288 AssertPtrReturnVoid(pItem);
3289 /* Get selected items: */
3290 QList<UIVirtualMachineItem*> items = currentItems();
3291 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
3292
3293 /* For local machine: */
3294 if (pItem->itemType() == UIVirtualMachineItemType_Local)
3295 {
3296 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_SaveState));
3297 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_Shutdown));
3298 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_PowerOff));
3299 }
3300 else
3301 {
3302 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_Terminate));
3303 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_Shutdown));
3304 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_PowerOff));
3305 }
3306
3307 /* Configure 'Group' / 'Stop' menu: */
3308 actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_Shutdown)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_Stop_S_Shutdown, items));
3309}
3310
3311void UIVirtualBoxManager::updateMenuMachineMoveToGroup(QMenu *pMenu)
3312{
3313 /* Get current item: */
3314 UIVirtualMachineItem *pItem = currentItem();
3315 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
3316
3317 const QStringList groups = m_pWidget->possibleGroupsForMachineToMove(pItem->id());
3318 if (!groups.isEmpty())
3319 pMenu->addSeparator();
3320 foreach (const QString &strGroupName, groups)
3321 {
3322 QString strVisibleGroupName = strGroupName;
3323 if (strVisibleGroupName.startsWith('/'))
3324 strVisibleGroupName.remove(0, 1);
3325 if (strVisibleGroupName.isEmpty())
3326 strVisibleGroupName = QApplication::translate("UIActionPool", "[Root]", "group");
3327 QAction *pAction = pMenu->addAction(strVisibleGroupName, this, &UIVirtualBoxManager::sltPerformMachineMoveToSpecificGroup);
3328 pAction->setProperty("actual_group_name", strGroupName);
3329 }
3330}
3331
3332void UIVirtualBoxManager::updateMenuMachineConsole(QMenu *pMenu)
3333{
3334 /* Get current item: */
3335 UIVirtualMachineItem *pItem = currentItem();
3336 AssertMsgReturnVoid(pItem, ("Current item should be selected!\n"));
3337 UIVirtualMachineItemCloud *pCloudItem = pItem->toCloud();
3338 AssertPtrReturnVoid(pCloudItem);
3339
3340 /* Acquire current cloud machine: */
3341 CCloudMachine comMachine = pCloudItem->machine();
3342 const QString strFingerprint = comMachine.GetConsoleConnectionFingerprint();
3343
3344 /* Populate 'Group' / 'Console' menu: */
3345 if (strFingerprint.isEmpty())
3346 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CreateConnection));
3347 else
3348 {
3349 /* Copy fingerprint to clipboard action: */
3350 const QString strFingerprintCompressed = strFingerprint.size() <= 12
3351 ? strFingerprint
3352 : QString("%1...%2").arg(strFingerprint.left(6), strFingerprint.right(6));
3353 QAction *pAction = pMenu->addAction(UIIconPool::iconSet(":/cloud_machine_console_copy_connection_fingerprint_16px.png",
3354 ":/cloud_machine_console_copy_connection_fingerprint_disabled_16px.png"),
3355 QApplication::translate("UIActionPool", "Copy Key Fingerprint (%1)").arg(strFingerprintCompressed),
3356 this, &UIVirtualBoxManager::sltCopyConsoleConnectionFingerprint);
3357 pAction->setProperty("fingerprint", strFingerprint);
3358
3359 /* Copy command to clipboard actions: */
3360 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandSerialUnix));
3361 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandSerialWindows));
3362// pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandVNCUnix));
3363// pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandVNCWindows));
3364 pMenu->addSeparator();
3365
3366 /* Default Connect action: */
3367 QAction *pDefaultAction = pMenu->addAction(QApplication::translate("UIActionPool", "Connect", "to cloud VM"),
3368 this, &UIVirtualBoxManager::sltExecuteExternalApplication);
3369#if defined(VBOX_WS_MAC)
3370 pDefaultAction->setProperty("path", "open");
3371#elif defined(VBOX_WS_WIN)
3372 pDefaultAction->setProperty("path", "powershell");
3373#elif defined(VBOX_WS_NIX)
3374 const QPair<QString, QString> terminalData = defaultTerminalData();
3375 pDefaultAction->setProperty("path", terminalData.first);
3376 pDefaultAction->setProperty("arguments", QString("%1 sh -c").arg(terminalData.second));
3377#endif
3378
3379 /* Terminal application/profile action list: */
3380 const QStringList restrictions = gEDataManager->cloudConsoleManagerRestrictions();
3381 foreach (const QString strApplicationId, gEDataManager->cloudConsoleManagerApplications())
3382 {
3383 const QString strApplicationDefinition = QString("/%1").arg(strApplicationId);
3384 if (restrictions.contains(strApplicationDefinition))
3385 continue;
3386 const QString strApplicationOptions = gEDataManager->cloudConsoleManagerApplication(strApplicationId);
3387 const QStringList applicationValues = strApplicationOptions.split(',');
3388 bool fAtLeastOneProfileListed = false;
3389 foreach (const QString strProfileId, gEDataManager->cloudConsoleManagerProfiles(strApplicationId))
3390 {
3391 const QString strProfileDefinition = QString("/%1/%2").arg(strApplicationId, strProfileId);
3392 if (restrictions.contains(strProfileDefinition))
3393 continue;
3394 const QString strProfileOptions = gEDataManager->cloudConsoleManagerProfile(strApplicationId, strProfileId);
3395 const QStringList profileValues = strProfileOptions.split(',');
3396 QAction *pAction = pMenu->addAction(QApplication::translate("UIActionPool",
3397 "Connect with %1 (%2)",
3398 "with terminal application (profile)")
3399 .arg(applicationValues.value(0), profileValues.value(0)),
3400 this, &UIVirtualBoxManager::sltExecuteExternalApplication);
3401 pAction->setProperty("path", applicationValues.value(1));
3402 pAction->setProperty("arguments", profileValues.value(1));
3403 fAtLeastOneProfileListed = true;
3404 }
3405 if (!fAtLeastOneProfileListed)
3406 {
3407 QAction *pAction = pMenu->addAction(QApplication::translate("UIActionPool",
3408 "Connect with %1",
3409 "with terminal application")
3410 .arg(applicationValues.value(0)),
3411 this, &UIVirtualBoxManager::sltExecuteExternalApplication);
3412 pAction->setProperty("path", applicationValues.value(1));
3413 pAction->setProperty("arguments", applicationValues.value(2));
3414 }
3415 }
3416 /* Terminal application configuration tool: */
3417 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_ConfigureApplications));
3418 pMenu->addSeparator();
3419
3420 /* Delete connection action finally: */
3421 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_DeleteConnection));
3422 }
3423
3424 /* Show console log action: */
3425 pMenu->addSeparator();
3426 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_ShowLog));
3427}
3428
3429void UIVirtualBoxManager::updateMenuMachineClose(QMenu *pMenu)
3430{
3431 /* Get first selected item: */
3432 UIVirtualMachineItem *pItem = currentItem();
3433 AssertPtrReturnVoid(pItem);
3434 /* Get selected items: */
3435 QList<UIVirtualMachineItem*> items = currentItems();
3436 AssertMsgReturnVoid(!items.isEmpty(), ("At least one item should be selected!\n"));
3437
3438 /* For local machine: */
3439 if (pItem->itemType() == UIVirtualMachineItemType_Local)
3440 {
3441 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_SaveState));
3442 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_Shutdown));
3443 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_PowerOff));
3444 }
3445 else
3446 {
3447 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_Terminate));
3448 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_Shutdown));
3449 pMenu->addAction(actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_PowerOff));
3450 }
3451
3452 /* Configure 'Machine' / 'Stop' menu: */
3453 actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_Shutdown)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Stop_S_Shutdown, items));
3454}
3455
3456void UIVirtualBoxManager::updateActionsVisibility()
3457{
3458 /* Determine whether Machine or Group menu should be shown at all: */
3459 const bool fGlobalMenuShown = m_pWidget->isGlobalItemSelected();
3460 const bool fGroupMenuShown = m_pWidget->isGroupItemSelected() && isSingleGroupSelected();
3461 const bool fMachineMenuShown = m_pWidget->isMachineItemSelected() && !isSingleGroupSelected();
3462 actionPool()->action(UIActionIndexMN_M_Welcome)->setVisible(fGlobalMenuShown);
3463 actionPool()->action(UIActionIndexMN_M_Group)->setVisible(fGroupMenuShown);
3464 actionPool()->action(UIActionIndexMN_M_Machine)->setVisible(fMachineMenuShown);
3465
3466 /* Determine whether Extensions menu should be visible: */
3467 const bool fExtensionsMenuShown = fGlobalMenuShown && m_pWidget->currentGlobalTool() == UIToolType_Extensions;
3468 actionPool()->action(UIActionIndexMN_M_Extension)->setVisible(fExtensionsMenuShown);
3469 /* Determine whether Media menu should be visible: */
3470 const bool fMediumMenuShown = fGlobalMenuShown && m_pWidget->currentGlobalTool() == UIToolType_Media;
3471 actionPool()->action(UIActionIndexMN_M_Medium)->setVisible(fMediumMenuShown);
3472 /* Determine whether Network menu should be visible: */
3473 const bool fNetworkMenuShown = fGlobalMenuShown && m_pWidget->currentGlobalTool() == UIToolType_Network;
3474 actionPool()->action(UIActionIndexMN_M_Network)->setVisible(fNetworkMenuShown);
3475 /* Determine whether Cloud menu should be visible: */
3476 const bool fCloudMenuShown = fGlobalMenuShown && m_pWidget->currentGlobalTool() == UIToolType_Cloud;
3477 actionPool()->action(UIActionIndexMN_M_Cloud)->setVisible(fCloudMenuShown);
3478 /* Determine whether Resources menu should be visible: */
3479 const bool fResourcesMenuShown = fGlobalMenuShown && m_pWidget->currentGlobalTool() == UIToolType_VMActivityOverview;
3480 actionPool()->action(UIActionIndexMN_M_VMActivityOverview)->setVisible(fResourcesMenuShown);
3481
3482 /* Determine whether Snapshots menu should be visible: */
3483 const bool fSnapshotMenuShown = (fMachineMenuShown || fGroupMenuShown) &&
3484 m_pWidget->currentMachineTool() == UIToolType_Snapshots;
3485 actionPool()->action(UIActionIndexMN_M_Snapshot)->setVisible(fSnapshotMenuShown);
3486 /* Determine whether Logs menu should be visible: */
3487 const bool fLogViewerMenuShown = (fMachineMenuShown || fGroupMenuShown) &&
3488 m_pWidget->currentMachineTool() == UIToolType_Logs;
3489 actionPool()->action(UIActionIndex_M_Log)->setVisible(fLogViewerMenuShown);
3490 /* Determine whether Performance menu should be visible: */
3491 const bool fPerformanceMenuShown = (fMachineMenuShown || fGroupMenuShown) &&
3492 m_pWidget->currentMachineTool() == UIToolType_VMActivity;
3493 actionPool()->action(UIActionIndex_M_Activity)->setVisible(fPerformanceMenuShown);
3494 /* Determine whether File Manager menu item should be visible: */
3495 const bool fFileManagerMenuShown = (fMachineMenuShown || fGroupMenuShown) &&
3496 m_pWidget->currentMachineTool() == UIToolType_FileManager;
3497 actionPool()->action(UIActionIndex_M_FileManager)->setVisible(fFileManagerMenuShown);
3498
3499 /* Hide action shortcuts: */
3500 if (!fGlobalMenuShown)
3501 actionPool()->setShortcutsVisible(UIActionIndexMN_M_Welcome, false);
3502 if (!fGroupMenuShown)
3503 actionPool()->setShortcutsVisible(UIActionIndexMN_M_Group, false);
3504 if (!fMachineMenuShown)
3505 actionPool()->setShortcutsVisible(UIActionIndexMN_M_Machine, false);
3506
3507 /* Show action shortcuts: */
3508 if (fGlobalMenuShown)
3509 actionPool()->setShortcutsVisible(UIActionIndexMN_M_Welcome, true);
3510 if (fGroupMenuShown)
3511 actionPool()->setShortcutsVisible(UIActionIndexMN_M_Group, true);
3512 if (fMachineMenuShown)
3513 actionPool()->setShortcutsVisible(UIActionIndexMN_M_Machine, true);
3514}
3515
3516void UIVirtualBoxManager::updateActionsAppearance()
3517{
3518 /* Get current items: */
3519 QList<UIVirtualMachineItem*> items = currentItems();
3520
3521 /* Enable/disable File/Application actions: */
3522 actionPool()->action(UIActionIndex_M_Application_S_Preferences)->setEnabled(isActionEnabled(UIActionIndex_M_Application_S_Preferences, items));
3523 actionPool()->action(UIActionIndexMN_M_File_S_ExportAppliance)->setEnabled(isActionEnabled(UIActionIndexMN_M_File_S_ExportAppliance, items));
3524 actionPool()->action(UIActionIndexMN_M_File_S_ImportAppliance)->setEnabled(isActionEnabled(UIActionIndexMN_M_File_S_ImportAppliance, items));
3525
3526 /* Enable/disable welcome actions: */
3527 actionPool()->action(UIActionIndexMN_M_Welcome_S_New)->setEnabled(isActionEnabled(UIActionIndexMN_M_Welcome_S_New, items));
3528 actionPool()->action(UIActionIndexMN_M_Welcome_S_Add)->setEnabled(isActionEnabled(UIActionIndexMN_M_Welcome_S_Add, items));
3529
3530 /* Enable/disable group actions: */
3531 actionPool()->action(UIActionIndexMN_M_Group_S_New)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_New, items));
3532 actionPool()->action(UIActionIndexMN_M_Group_S_Add)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_Add, items));
3533 actionPool()->action(UIActionIndexMN_M_Group_S_Rename)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_Rename, items));
3534 actionPool()->action(UIActionIndexMN_M_Group_S_Remove)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_Remove, items));
3535 actionPool()->action(UIActionIndexMN_M_Group_M_MoveToGroup)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_MoveToGroup, items));
3536 actionPool()->action(UIActionIndexMN_M_Group_T_Pause)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_T_Pause, items));
3537 actionPool()->action(UIActionIndexMN_M_Group_S_Reset)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_Reset, items));
3538 actionPool()->action(UIActionIndexMN_M_Group_S_Detach)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_Detach, items));
3539 actionPool()->action(UIActionIndexMN_M_Group_S_Discard)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_Discard, items));
3540 actionPool()->action(UIActionIndexMN_M_Group_S_Refresh)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_Refresh, items));
3541 actionPool()->action(UIActionIndexMN_M_Group_S_ShowInFileManager)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_ShowInFileManager, items));
3542 actionPool()->action(UIActionIndexMN_M_Group_S_CreateShortcut)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_CreateShortcut, items));
3543 actionPool()->action(UIActionIndexMN_M_Group_S_Sort)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_S_Sort, items));
3544
3545 /* Enable/disable machine actions: */
3546 actionPool()->action(UIActionIndexMN_M_Machine_S_New)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_New, items));
3547 actionPool()->action(UIActionIndexMN_M_Machine_S_Add)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_Add, items));
3548 actionPool()->action(UIActionIndexMN_M_Machine_S_Settings)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_Settings, items));
3549 actionPool()->action(UIActionIndexMN_M_Machine_S_Clone)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_Clone, items));
3550 actionPool()->action(UIActionIndexMN_M_Machine_S_Move)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_Move, items));
3551 actionPool()->action(UIActionIndexMN_M_Machine_S_ExportToOCI)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_ExportToOCI, items));
3552 actionPool()->action(UIActionIndexMN_M_Machine_S_Remove)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_Remove, items));
3553 actionPool()->action(UIActionIndexMN_M_Machine_M_MoveToGroup)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_MoveToGroup, items));
3554 actionPool()->action(UIActionIndexMN_M_Machine_M_MoveToGroup_S_New)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_MoveToGroup_S_New, items));
3555 actionPool()->action(UIActionIndexMN_M_Machine_T_Pause)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_T_Pause, items));
3556 actionPool()->action(UIActionIndexMN_M_Machine_S_Reset)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_Reset, items));
3557 actionPool()->action(UIActionIndexMN_M_Machine_S_Detach)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_Detach, items));
3558 actionPool()->action(UIActionIndexMN_M_Machine_S_Discard)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_Discard, items));
3559 actionPool()->action(UIActionIndexMN_M_Machine_S_Refresh)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_Refresh, items));
3560 actionPool()->action(UIActionIndexMN_M_Machine_S_ShowInFileManager)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_ShowInFileManager, items));
3561 actionPool()->action(UIActionIndexMN_M_Machine_S_CreateShortcut)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_CreateShortcut, items));
3562 actionPool()->action(UIActionIndexMN_M_Machine_S_SortParent)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_S_SortParent, items));
3563
3564 /* Enable/disable group-start-or-show actions: */
3565 actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_StartOrShow, items));
3566 actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow_S_StartNormal)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_StartOrShow_S_StartNormal, items));
3567 actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow_S_StartHeadless)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_StartOrShow_S_StartHeadless, items));
3568 actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow_S_StartDetachable)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_StartOrShow_S_StartDetachable, items));
3569
3570 /* Enable/disable machine-start-or-show actions: */
3571 actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_StartOrShow, items));
3572 actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow_S_StartNormal)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_StartOrShow_S_StartNormal, items));
3573 actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow_S_StartHeadless)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_StartOrShow_S_StartHeadless, items));
3574 actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow_S_StartDetachable)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_StartOrShow_S_StartDetachable, items));
3575
3576 /* Enable/disable group-console actions: */
3577 actionPool()->action(UIActionIndexMN_M_Group_M_Console)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_Console, items));
3578 actionPool()->action(UIActionIndexMN_M_Group_M_Console_S_CreateConnection)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_Console_S_CreateConnection, items));
3579 actionPool()->action(UIActionIndexMN_M_Group_M_Console_S_DeleteConnection)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_Console_S_DeleteConnection, items));
3580 actionPool()->action(UIActionIndexMN_M_Group_M_Console_S_ConfigureApplications)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_Console_S_ConfigureApplications, items));
3581
3582 /* Enable/disable machine-console actions: */
3583 actionPool()->action(UIActionIndexMN_M_Machine_M_Console)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Console, items));
3584 actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CreateConnection)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Console_S_CreateConnection, items));
3585 actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_DeleteConnection)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Console_S_DeleteConnection, items));
3586 actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandSerialUnix)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandSerialUnix, items));
3587 actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandSerialWindows)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandSerialWindows, items));
3588 actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandVNCUnix)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandVNCUnix, items));
3589 actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandVNCWindows)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Console_S_CopyCommandVNCWindows, items));
3590 actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_ConfigureApplications)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Console_S_ConfigureApplications, items));
3591 actionPool()->action(UIActionIndexMN_M_Machine_M_Console_S_ShowLog)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Console_S_ShowLog, items));
3592
3593 /* Enable/disable group-stop actions: */
3594 actionPool()->action(UIActionIndexMN_M_Group_M_Stop)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_Stop, items));
3595 actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_SaveState)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_Stop_S_SaveState, items));
3596 actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_Terminate)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_Stop_S_Terminate, items));
3597 actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_Shutdown)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_Stop_S_Shutdown, items));
3598 actionPool()->action(UIActionIndexMN_M_Group_M_Stop_S_PowerOff)->setEnabled(isActionEnabled(UIActionIndexMN_M_Group_M_Stop_S_PowerOff, items));
3599
3600 /* Enable/disable machine-stop actions: */
3601 actionPool()->action(UIActionIndexMN_M_Machine_M_Stop)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Stop, items));
3602 actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_SaveState)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Stop_S_SaveState, items));
3603 actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_Terminate)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Stop_S_Terminate, items));
3604 actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_Shutdown)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Stop_S_Shutdown, items));
3605 actionPool()->action(UIActionIndexMN_M_Machine_M_Stop_S_PowerOff)->setEnabled(isActionEnabled(UIActionIndexMN_M_Machine_M_Stop_S_PowerOff, items));
3606
3607 /* Get current item: */
3608 UIVirtualMachineItem *pItem = currentItem();
3609
3610 /* Start/Show action is deremined by 1st item: */
3611 if (pItem && pItem->accessible())
3612 {
3613 actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow)->setState(pItem->isItemPoweredOff() ? 0 : 1);
3614 actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow)->setState(pItem->isItemPoweredOff() ? 0 : 1);
3615 m_pWidget->updateToolBarMenuButtons(pItem->isItemPoweredOff());
3616 }
3617 else
3618 {
3619 actionPool()->action(UIActionIndexMN_M_Group_M_StartOrShow)->setState(0);
3620 actionPool()->action(UIActionIndexMN_M_Machine_M_StartOrShow)->setState(0);
3621 m_pWidget->updateToolBarMenuButtons(true /* separate menu section? */);
3622 }
3623
3624 /* Pause/Resume action is deremined by 1st started item: */
3625 UIVirtualMachineItem *pFirstStartedAction = 0;
3626 foreach (UIVirtualMachineItem *pSelectedItem, items)
3627 {
3628 if (pSelectedItem->isItemStarted())
3629 {
3630 pFirstStartedAction = pSelectedItem;
3631 break;
3632 }
3633 }
3634 /* Update the group Pause/Resume action appearance: */
3635 actionPool()->action(UIActionIndexMN_M_Group_T_Pause)->blockSignals(true);
3636 actionPool()->action(UIActionIndexMN_M_Group_T_Pause)->setChecked(pFirstStartedAction && pFirstStartedAction->isItemPaused());
3637 actionPool()->action(UIActionIndexMN_M_Group_T_Pause)->retranslateUi();
3638 actionPool()->action(UIActionIndexMN_M_Group_T_Pause)->blockSignals(false);
3639 /* Update the machine Pause/Resume action appearance: */
3640 actionPool()->action(UIActionIndexMN_M_Machine_T_Pause)->blockSignals(true);
3641 actionPool()->action(UIActionIndexMN_M_Machine_T_Pause)->setChecked(pFirstStartedAction && pFirstStartedAction->isItemPaused());
3642 actionPool()->action(UIActionIndexMN_M_Machine_T_Pause)->retranslateUi();
3643 actionPool()->action(UIActionIndexMN_M_Machine_T_Pause)->blockSignals(false);
3644
3645 /* Update action toggle states: */
3646 if (m_pWidget)
3647 {
3648 switch (m_pWidget->currentMachineTool())
3649 {
3650 case UIToolType_Details:
3651 {
3652 actionPool()->action(UIActionIndexMN_M_Group_M_Tools_T_Details)->setChecked(true);
3653 actionPool()->action(UIActionIndexMN_M_Machine_M_Tools_T_Details)->setChecked(true);
3654 break;
3655 }
3656 case UIToolType_Snapshots:
3657 {
3658 actionPool()->action(UIActionIndexMN_M_Group_M_Tools_T_Snapshots)->setChecked(true);
3659 actionPool()->action(UIActionIndexMN_M_Machine_M_Tools_T_Snapshots)->setChecked(true);
3660 break;
3661 }
3662 case UIToolType_Logs:
3663 {
3664 actionPool()->action(UIActionIndexMN_M_Group_M_Tools_T_Logs)->setChecked(true);
3665 actionPool()->action(UIActionIndexMN_M_Machine_M_Tools_T_Logs)->setChecked(true);
3666 break;
3667 }
3668 case UIToolType_VMActivity:
3669 {
3670 actionPool()->action(UIActionIndexMN_M_Group_M_Tools_T_Activity)->setChecked(true);
3671 actionPool()->action(UIActionIndexMN_M_Machine_M_Tools_T_Activity)->setChecked(true);
3672 break;
3673 }
3674 case UIToolType_FileManager:
3675 {
3676 actionPool()->action(UIActionIndexMN_M_Group_M_Tools_T_FileManager)->setChecked(true);
3677 actionPool()->action(UIActionIndexMN_M_Machine_M_Tools_T_FileManager)->setChecked(true);
3678 break;
3679 }
3680 default:
3681 break;
3682 }
3683 }
3684}
3685
3686bool UIVirtualBoxManager::isActionEnabled(int iActionIndex, const QList<UIVirtualMachineItem*> &items)
3687{
3688 /* Make sure action pool exists: */
3689 AssertPtrReturn(actionPool(), false);
3690
3691 /* Any "opened" action is by definition disabled: */
3692 if ( actionPool()->action(iActionIndex)
3693 && actionPool()->action(iActionIndex)->property("opened").toBool())
3694 return false;
3695
3696 /* For known *global* action types: */
3697 switch (iActionIndex)
3698 {
3699 case UIActionIndex_M_Application_S_Preferences:
3700 case UIActionIndexMN_M_File_S_ExportAppliance:
3701 case UIActionIndexMN_M_File_S_ImportAppliance:
3702 case UIActionIndexMN_M_Welcome_S_New:
3703 case UIActionIndexMN_M_Welcome_S_Add:
3704 return true;
3705 default:
3706 break;
3707 }
3708
3709 /* No *machine* actions enabled for empty item list: */
3710 if (items.isEmpty())
3711 return false;
3712
3713 /* Get first item: */
3714 UIVirtualMachineItem *pItem = items.first();
3715
3716 /* For known *machine* action types: */
3717 switch (iActionIndex)
3718 {
3719 case UIActionIndexMN_M_Group_S_New:
3720 case UIActionIndexMN_M_Group_S_Add:
3721 {
3722 return !isGroupSavingInProgress();
3723 }
3724 case UIActionIndexMN_M_Group_S_Sort:
3725 {
3726 return !isGroupSavingInProgress() &&
3727 isSingleGroupSelected() &&
3728 isItemsLocal(items);
3729 }
3730 case UIActionIndexMN_M_Group_S_Rename:
3731 case UIActionIndexMN_M_Group_S_Remove:
3732 {
3733 return !isGroupSavingInProgress() &&
3734 isSingleGroupSelected() &&
3735 isItemsLocal(items) &&
3736 isItemsPoweredOff(items);
3737 }
3738 case UIActionIndexMN_M_Machine_S_New:
3739 case UIActionIndexMN_M_Machine_S_Add:
3740 {
3741 return !isGroupSavingInProgress();
3742 }
3743 case UIActionIndexMN_M_Machine_S_Settings:
3744 {
3745 return !isGroupSavingInProgress() &&
3746 items.size() == 1 &&
3747 pItem->configurationAccessLevel() != ConfigurationAccessLevel_Null &&
3748 (m_pWidget->currentMachineTool() != UIToolType_Snapshots ||
3749 m_pWidget->isCurrentStateItemSelected());
3750 }
3751 case UIActionIndexMN_M_Machine_S_Clone:
3752 case UIActionIndexMN_M_Machine_S_Move:
3753 {
3754 return !isGroupSavingInProgress() &&
3755 items.size() == 1 &&
3756 pItem->isItemEditable();
3757 }
3758 case UIActionIndexMN_M_Machine_S_ExportToOCI:
3759 {
3760 return items.size() == 1 &&
3761 UIExtension::isExtentionPackInstalled() &&
3762 pItem->toLocal();
3763 }
3764 case UIActionIndexMN_M_Machine_S_Remove:
3765 {
3766 return !isGroupSavingInProgress() &&
3767 (isItemsLocal(items) || !isCloudProfileUpdateInProgress()) &&
3768 isAtLeastOneItemRemovable(items);
3769 }
3770 case UIActionIndexMN_M_Group_M_MoveToGroup:
3771 case UIActionIndexMN_M_Machine_M_MoveToGroup:
3772 case UIActionIndexMN_M_Machine_M_MoveToGroup_S_New:
3773 {
3774 return !isGroupSavingInProgress() &&
3775 isItemsLocal(items) &&
3776 isItemsPoweredOff(items);
3777 }
3778 case UIActionIndexMN_M_Group_M_StartOrShow:
3779 case UIActionIndexMN_M_Group_M_StartOrShow_S_StartNormal:
3780 case UIActionIndexMN_M_Machine_M_StartOrShow:
3781 case UIActionIndexMN_M_Machine_M_StartOrShow_S_StartNormal:
3782 {
3783 return !isGroupSavingInProgress() &&
3784 isAtLeastOneItemCanBeStartedOrShown(items) &&
3785 (m_pWidget->currentMachineTool() != UIToolType_Snapshots ||
3786 m_pWidget->isCurrentStateItemSelected());
3787 }
3788 case UIActionIndexMN_M_Group_M_StartOrShow_S_StartHeadless:
3789 case UIActionIndexMN_M_Group_M_StartOrShow_S_StartDetachable:
3790 case UIActionIndexMN_M_Machine_M_StartOrShow_S_StartHeadless:
3791 case UIActionIndexMN_M_Machine_M_StartOrShow_S_StartDetachable:
3792 {
3793 return !isGroupSavingInProgress() &&
3794 isItemsLocal(items) &&
3795 isAtLeastOneItemCanBeStartedOrShown(items) &&
3796 (m_pWidget->currentMachineTool() != UIToolType_Snapshots ||
3797 m_pWidget->isCurrentStateItemSelected());
3798 }
3799 case UIActionIndexMN_M_Group_S_Discard:
3800 case UIActionIndexMN_M_Machine_S_Discard:
3801 {
3802 return !isGroupSavingInProgress() &&
3803 isItemsLocal(items) &&
3804 isAtLeastOneItemDiscardable(items) &&
3805 (m_pWidget->currentMachineTool() != UIToolType_Snapshots ||
3806 m_pWidget->isCurrentStateItemSelected());
3807 }
3808 case UIActionIndexMN_M_Group_T_Pause:
3809 case UIActionIndexMN_M_Machine_T_Pause:
3810 {
3811 return isItemsLocal(items) &&
3812 isAtLeastOneItemStarted(items);
3813 }
3814 case UIActionIndexMN_M_Group_S_Reset:
3815 case UIActionIndexMN_M_Machine_S_Reset:
3816 {
3817 return isAtLeastOneItemRunning(items);
3818 }
3819 case UIActionIndexMN_M_Group_S_Detach:
3820 case UIActionIndexMN_M_Machine_S_Detach:
3821 {
3822 return isItemsLocal(items) &&
3823 isAtLeastOneItemRunning(items) &&
3824 isAtLeastOneItemDetachable(items);
3825 }
3826 case UIActionIndexMN_M_Group_S_Refresh:
3827 case UIActionIndexMN_M_Machine_S_Refresh:
3828 {
3829 return isAtLeastOneItemInaccessible(items);
3830 }
3831 case UIActionIndexMN_M_Group_S_ShowInFileManager:
3832 case UIActionIndexMN_M_Machine_S_ShowInFileManager:
3833 {
3834 return isItemsLocal(items) &&
3835 isAtLeastOneItemAccessible(items);
3836 }
3837 case UIActionIndexMN_M_Machine_S_SortParent:
3838 {
3839 return !isGroupSavingInProgress() &&
3840 isItemsLocal(items);
3841 }
3842 case UIActionIndexMN_M_Group_S_CreateShortcut:
3843 case UIActionIndexMN_M_Machine_S_CreateShortcut:
3844 {
3845 return isAtLeastOneItemSupportsShortcuts(items);
3846 }
3847 case UIActionIndexMN_M_Group_M_Console:
3848 case UIActionIndexMN_M_Group_M_Console_S_CreateConnection:
3849 case UIActionIndexMN_M_Group_M_Console_S_DeleteConnection:
3850 case UIActionIndexMN_M_Group_M_Console_S_ConfigureApplications:
3851 case UIActionIndexMN_M_Machine_M_Console:
3852 case UIActionIndexMN_M_Machine_M_Console_S_CreateConnection:
3853 case UIActionIndexMN_M_Machine_M_Console_S_DeleteConnection:
3854 case UIActionIndexMN_M_Machine_M_Console_S_CopyCommandSerialUnix:
3855 case UIActionIndexMN_M_Machine_M_Console_S_CopyCommandSerialWindows:
3856 case UIActionIndexMN_M_Machine_M_Console_S_CopyCommandVNCUnix:
3857 case UIActionIndexMN_M_Machine_M_Console_S_CopyCommandVNCWindows:
3858 case UIActionIndexMN_M_Machine_M_Console_S_ConfigureApplications:
3859 case UIActionIndexMN_M_Machine_M_Console_S_ShowLog:
3860 {
3861 return isAtLeastOneItemStarted(items);
3862 }
3863 case UIActionIndexMN_M_Group_M_Stop:
3864 case UIActionIndexMN_M_Machine_M_Stop:
3865 {
3866 return (isItemsLocal(items) && isAtLeastOneItemStarted(items))
3867 || (isItemsCloud(items) && isAtLeastOneItemDiscardable(items));
3868 }
3869 case UIActionIndexMN_M_Group_M_Stop_S_SaveState:
3870 case UIActionIndexMN_M_Machine_M_Stop_S_SaveState:
3871 {
3872 return isActionEnabled(UIActionIndexMN_M_Machine_M_Stop, items)
3873 && isItemsLocal(items);
3874 }
3875 case UIActionIndexMN_M_Group_M_Stop_S_Terminate:
3876 case UIActionIndexMN_M_Machine_M_Stop_S_Terminate:
3877 {
3878 return isActionEnabled(UIActionIndexMN_M_Machine_M_Stop, items)
3879 && isAtLeastOneItemDiscardable(items);
3880 }
3881 case UIActionIndexMN_M_Group_M_Stop_S_Shutdown:
3882 case UIActionIndexMN_M_Machine_M_Stop_S_Shutdown:
3883 {
3884 return isActionEnabled(UIActionIndexMN_M_Machine_M_Stop, items)
3885 && isAtLeastOneItemAbleToShutdown(items);
3886 }
3887 case UIActionIndexMN_M_Group_M_Stop_S_PowerOff:
3888 case UIActionIndexMN_M_Machine_M_Stop_S_PowerOff:
3889 {
3890 return isActionEnabled(UIActionIndexMN_M_Machine_M_Stop, items)
3891 && isAtLeastOneItemStarted(items);
3892 }
3893 default:
3894 break;
3895 }
3896
3897 /* Unknown actions are disabled: */
3898 return false;
3899}
3900
3901/* static */
3902bool UIVirtualBoxManager::isItemsLocal(const QList<UIVirtualMachineItem*> &items)
3903{
3904 foreach (UIVirtualMachineItem *pItem, items)
3905 if (!pItem->toLocal())
3906 return false;
3907 return true;
3908}
3909
3910/* static */
3911bool UIVirtualBoxManager::isItemsCloud(const QList<UIVirtualMachineItem*> &items)
3912{
3913 foreach (UIVirtualMachineItem *pItem, items)
3914 if (!pItem->toCloud())
3915 return false;
3916 return true;
3917}
3918
3919/* static */
3920bool UIVirtualBoxManager::isItemsPoweredOff(const QList<UIVirtualMachineItem*> &items)
3921{
3922 foreach (UIVirtualMachineItem *pItem, items)
3923 if (!pItem->isItemPoweredOff())
3924 return false;
3925 return true;
3926}
3927
3928/* static */
3929bool UIVirtualBoxManager::isAtLeastOneItemAbleToShutdown(const QList<UIVirtualMachineItem*> &items)
3930{
3931 /* Enumerate all the passed items: */
3932 foreach (UIVirtualMachineItem *pItem, items)
3933 {
3934 /* Skip non-running machines: */
3935 if (!pItem->isItemRunning())
3936 continue;
3937
3938 /* For local machine: */
3939 if (pItem->itemType() == UIVirtualMachineItemType_Local)
3940 {
3941 /* Skip session failures: */
3942 CSession session = openExistingSession(pItem->id());
3943 if (session.isNull())
3944 continue;
3945 /* Skip console failures: */
3946 CConsole console = session.GetConsole();
3947 if (console.isNull())
3948 {
3949 /* Do not forget to release machine: */
3950 session.UnlockMachine();
3951 continue;
3952 }
3953 /* Is the guest entered ACPI mode? */
3954 bool fGuestEnteredACPIMode = console.GetGuestEnteredACPIMode();
3955 /* Do not forget to release machine: */
3956 session.UnlockMachine();
3957 /* True if the guest entered ACPI mode: */
3958 if (fGuestEnteredACPIMode)
3959 return true;
3960 }
3961 /* For real cloud machine: */
3962 else if (pItem->itemType() == UIVirtualMachineItemType_CloudReal)
3963 {
3964 /* Running cloud VM has it by definition: */
3965 return true;
3966 }
3967 }
3968 /* False by default: */
3969 return false;
3970}
3971
3972/* static */
3973bool UIVirtualBoxManager::isAtLeastOneItemSupportsShortcuts(const QList<UIVirtualMachineItem*> &items)
3974{
3975 foreach (UIVirtualMachineItem *pItem, items)
3976 {
3977 if ( pItem->accessible()
3978 && pItem->toLocal()
3979#ifdef VBOX_WS_MAC
3980 /* On Mac OS X this are real alias files, which don't work with the old legacy xml files. */
3981 && pItem->toLocal()->settingsFile().endsWith(".vbox", Qt::CaseInsensitive)
3982#endif
3983 )
3984 return true;
3985 }
3986 return false;
3987}
3988
3989/* static */
3990bool UIVirtualBoxManager::isAtLeastOneItemAccessible(const QList<UIVirtualMachineItem*> &items)
3991{
3992 foreach (UIVirtualMachineItem *pItem, items)
3993 if (pItem->accessible())
3994 return true;
3995 return false;
3996}
3997
3998/* static */
3999bool UIVirtualBoxManager::isAtLeastOneItemInaccessible(const QList<UIVirtualMachineItem*> &items)
4000{
4001 foreach (UIVirtualMachineItem *pItem, items)
4002 if (!pItem->accessible())
4003 return true;
4004 return false;
4005}
4006
4007/* static */
4008bool UIVirtualBoxManager::isAtLeastOneItemRemovable(const QList<UIVirtualMachineItem*> &items)
4009{
4010 foreach (UIVirtualMachineItem *pItem, items)
4011 if (pItem->isItemRemovable())
4012 return true;
4013 return false;
4014}
4015
4016/* static */
4017bool UIVirtualBoxManager::isAtLeastOneItemCanBeStarted(const QList<UIVirtualMachineItem*> &items)
4018{
4019 foreach (UIVirtualMachineItem *pItem, items)
4020 {
4021 if (pItem->isItemPoweredOff() && pItem->isItemEditable())
4022 return true;
4023 }
4024 return false;
4025}
4026
4027/* static */
4028bool UIVirtualBoxManager::isAtLeastOneItemCanBeShown(const QList<UIVirtualMachineItem*> &items)
4029{
4030 foreach (UIVirtualMachineItem *pItem, items)
4031 {
4032 if ( pItem->isItemStarted()
4033 && pItem->isItemCanBeSwitchedTo())
4034 return true;
4035 }
4036 return false;
4037}
4038
4039/* static */
4040bool UIVirtualBoxManager::isAtLeastOneItemCanBeStartedOrShown(const QList<UIVirtualMachineItem*> &items)
4041{
4042 foreach (UIVirtualMachineItem *pItem, items)
4043 {
4044 if ( ( pItem->isItemPoweredOff()
4045 && pItem->isItemEditable())
4046 || ( pItem->isItemStarted()
4047 && pItem->isItemCanBeSwitchedTo()))
4048 return true;
4049 }
4050 return false;
4051}
4052
4053/* static */
4054bool UIVirtualBoxManager::isAtLeastOneItemDiscardable(const QList<UIVirtualMachineItem*> &items)
4055{
4056 foreach (UIVirtualMachineItem *pItem, items)
4057 if ( pItem->isItemSaved()
4058 && pItem->isItemEditable())
4059 return true;
4060 return false;
4061}
4062
4063/* static */
4064bool UIVirtualBoxManager::isAtLeastOneItemStarted(const QList<UIVirtualMachineItem*> &items)
4065{
4066 foreach (UIVirtualMachineItem *pItem, items)
4067 if (pItem->isItemStarted())
4068 return true;
4069 return false;
4070}
4071
4072/* static */
4073bool UIVirtualBoxManager::isAtLeastOneItemRunning(const QList<UIVirtualMachineItem*> &items)
4074{
4075 foreach (UIVirtualMachineItem *pItem, items)
4076 if (pItem->isItemRunning())
4077 return true;
4078 return false;
4079}
4080
4081/* static */
4082bool UIVirtualBoxManager::isAtLeastOneItemDetachable(const QList<UIVirtualMachineItem*> &items)
4083{
4084 foreach (UIVirtualMachineItem *pItem, items)
4085 if (pItem->isItemRunningHeadless())
4086 return true;
4087 return false;
4088}
4089
4090#ifdef VBOX_WS_NIX
4091/* static */
4092QPair<QString, QString> UIVirtualBoxManager::defaultTerminalData()
4093{
4094 /* List known terminals: */
4095 QStringList knownTerminalNames;
4096 knownTerminalNames << "gnome-terminal"
4097 << "terminator"
4098 << "konsole"
4099 << "xfce4-terminal"
4100 << "mate-terminal"
4101 << "lxterminal"
4102 << "tilda"
4103 << "xterm"
4104 << "aterm"
4105 << "rxvt-unicode"
4106 << "rxvt";
4107
4108 /* Fill map of known terminal --execute argument exceptions,
4109 * keep in mind, terminals doesn't mentioned here will be
4110 * used with default `-e` argument: */
4111 QMap<QString, QString> knownTerminalArguments;
4112 knownTerminalArguments["gnome-terminal"] = "--";
4113 knownTerminalArguments["terminator"] = "-x";
4114 knownTerminalArguments["xfce4-terminal"] = "-x";
4115 knownTerminalArguments["mate-terminal"] = "-x";
4116 knownTerminalArguments["tilda"] = "-c";
4117
4118 /* Search for a first one suitable through shell command -v test: */
4119 foreach (const QString &strTerminalName, knownTerminalNames)
4120 {
4121 const QString strPath = "sh";
4122 const QStringList arguments = QStringList() << "-c" << QString("command -v '%1'").arg(strTerminalName);
4123 QProcess process;
4124 process.start(strPath, arguments, QIODevice::ReadOnly);
4125 process.waitForFinished(3000);
4126 if (process.exitCode() == 0)
4127 {
4128 const QString strResult = process.readAllStandardOutput();
4129 if (strResult.startsWith('/'))
4130 return qMakePair(strResult.trimmed(), knownTerminalArguments.value(strTerminalName, "-e"));
4131 }
4132 }
4133 return QPair<QString, QString>();
4134}
4135#endif
4136
4137
4138#include "UIVirtualBoxManager.moc"
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