VirtualBox

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

Last change on this file was 105773, checked in by vboxsync, 4 weeks ago

FE/Qt: VBox Manager / Chooser pane: Adjust NLS for Cloud VM Cloning dialog.

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