VirtualBox

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

Last change on this file since 104251 was 104251, checked in by vboxsync, 8 weeks ago

FE/Qt. bugref:10622. Using new UITranslationEventListener in the manager UI classes.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use