VirtualBox

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

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

FE/Qt. bugref:10622. Using new UITranslationEventListener in the UIActionPool class.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use