VirtualBox

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

Last change on this file since 103977 was 103793, checked in by vboxsync, 9 months ago

FE/Qt: UICommon: Move versioning related functionality to UIVersion / UIVersionInfo; Rework user cases accordingly.

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