VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/guestctrl/UIFileManagerGuestTable.cpp

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

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.7 KB
Line 
1/* $Id: UIFileManagerGuestTable.cpp 104393 2024-04-22 13:02:56Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIFileManagerGuestTable class implementation.
4 */
5
6/*
7 * Copyright (C) 2016-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 <QApplication>
30#include <QDateTime>
31#include <QFileInfo>
32#include <QHBoxLayout>
33#include <QPushButton>
34#include <QUuid>
35
36/* GUI includes: */
37#include "QILabel.h"
38#include "UIActionPool.h"
39#include "UIConverter.h"
40#include "UICommon.h"
41#include "UIErrorString.h"
42#include "UIFileSystemModel.h"
43#include "UIFileManager.h"
44#include "UIFileManagerHostTable.h"
45#include "UIFileManagerGuestTable.h"
46#include "UIFileTableNavigationWidget.h"
47#include "UIGlobalSession.h"
48#include "UIIconPool.h"
49#include "UIMessageCenter.h"
50#include "UIPathOperations.h"
51#include "UIUserNamePasswordEditor.h"
52#include "UIVirtualBoxEventHandler.h"
53#include "QILineEdit.h"
54#include "QIToolBar.h"
55#include "UITranslationEventListener.h"
56
57/* COM includes: */
58#include "CConsole.h"
59#include "CFsObjInfo.h"
60#include "CGuestFsObjInfo.h"
61#include "CGuestDirectory.h"
62#include "CProgress.h"
63#include "CGuestSessionStateChangedEvent.h"
64
65/* Other VBox includes: */
66#include <iprt/err.h>
67
68/*********************************************************************************************************************************
69* UIGuestSessionWidget definition. *
70*********************************************************************************************************************************/
71/** A QWidget extension containing text entry fields for password and username and buttons to
72 * start/stop a guest session. */
73class UIGuestSessionWidget : public QWidget
74{
75 Q_OBJECT;
76
77signals:
78
79 void sigOpenSession(QString strUserName, QString strPassword);
80 void sigCloseSession();
81
82public:
83
84 UIGuestSessionWidget(QWidget *pParent = 0);
85 /** Disables certain widget after a guest session has been opened. */
86 void switchSessionOpenMode();
87 /** Makes sure certain widgets are enabled so that a guest session can be opened. */
88 void switchSessionCloseMode();
89 void markForError(bool fMarkForError);
90 void setStatusLabelIconAndToolTip(const QIcon &icon, const QString &strToolTip);
91 void setLoginWidgetsEnabled(bool fEnabled);
92
93protected:
94
95 void keyPressEvent(QKeyEvent * pEvent) RT_OVERRIDE;
96 void showEvent(QShowEvent *pEvent) RT_OVERRIDE;
97
98private slots:
99
100 void sltRetranslateUI();
101 void sltButtonClick();
102 void sltHandleTextChanged(const QString &strText);
103
104private:
105
106 enum ButtonMode
107 {
108 ButtonMode_Open,
109 ButtonMode_Close
110 };
111
112 void prepareWidgets();
113 void updateButton();
114
115 ButtonMode m_enmButtonMode;
116 QILineEdit *m_pUserNameEdit;
117 UIPasswordLineEdit *m_pPasswordEdit;
118 QPushButton *m_pButton;
119 QHBoxLayout *m_pMainLayout;
120 QColor m_defaultBaseColor;
121 QColor m_errorBaseColor;
122 bool m_fMarkedForError;
123 QLabel *m_pStatusIconLabel;
124};
125
126
127/*********************************************************************************************************************************
128* UIGuestSessionWidget implementation. *
129*********************************************************************************************************************************/
130
131UIGuestSessionWidget::UIGuestSessionWidget(QWidget *pParent /* = 0 */)
132 : QWidget(pParent)
133 , m_enmButtonMode(ButtonMode_Open)
134 , m_pUserNameEdit(0)
135 , m_pPasswordEdit(0)
136 , m_pButton(0)
137 , m_pMainLayout(0)
138 , m_fMarkedForError(0)
139 , m_pStatusIconLabel(0)
140{
141 prepareWidgets();
142}
143
144void UIGuestSessionWidget::prepareWidgets()
145{
146 m_pMainLayout = new QHBoxLayout(this);
147 if (!m_pMainLayout)
148 return;
149
150 m_pMainLayout->setContentsMargins(0, 0, 0, 0);
151
152 m_pUserNameEdit = new QILineEdit;
153 if (m_pUserNameEdit)
154 {
155 m_pMainLayout->addWidget(m_pUserNameEdit, 2);
156 m_pUserNameEdit->setPlaceholderText(QApplication::translate("UIFileManager", "User Name"));
157 m_defaultBaseColor = m_pUserNameEdit->palette().color(QPalette::Base);
158 m_errorBaseColor = QColor(m_defaultBaseColor.red(),
159 0.5 * m_defaultBaseColor.green(),
160 0.5 * m_defaultBaseColor.blue());
161 connect(m_pUserNameEdit, &QILineEdit::textChanged,
162 this, &UIGuestSessionWidget::sltHandleTextChanged);
163 }
164
165 m_pPasswordEdit = new UIPasswordLineEdit;
166 if (m_pPasswordEdit)
167 {
168 m_pMainLayout->addWidget(m_pPasswordEdit, 2);
169 m_pPasswordEdit->setPlaceholderText(QApplication::translate("UIFileManager", "Password"));
170 m_pPasswordEdit->setEchoMode(QLineEdit::Password);
171 connect(m_pPasswordEdit, &UIPasswordLineEdit::textChanged,
172 this, &UIGuestSessionWidget::sltHandleTextChanged);
173 }
174
175 m_pButton = new QPushButton;
176 if (m_pButton)
177 {
178 m_pMainLayout->addWidget(m_pButton);
179 connect(m_pButton, &QPushButton::clicked, this, &UIGuestSessionWidget::sltButtonClick);
180 }
181 m_pStatusIconLabel = new QLabel(this);
182 if (m_pStatusIconLabel)
183 {
184 m_pMainLayout->addWidget(m_pStatusIconLabel);
185 m_pStatusIconLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
186 }
187
188 m_pMainLayout->insertStretch(-1, 1);
189 switchSessionOpenMode();
190 sltRetranslateUI();
191 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
192 this, &UIGuestSessionWidget::sltRetranslateUI);
193}
194
195void UIGuestSessionWidget::sltButtonClick()
196{
197 if (m_enmButtonMode == ButtonMode_Open && m_pUserNameEdit && m_pPasswordEdit)
198 emit sigOpenSession(m_pUserNameEdit->text(), m_pPasswordEdit->text());
199 else if (m_enmButtonMode == ButtonMode_Close)
200 emit sigCloseSession();
201}
202
203void UIGuestSessionWidget::sltHandleTextChanged(const QString &strText)
204{
205 Q_UNUSED(strText);
206 markForError(false);
207}
208
209void UIGuestSessionWidget::sltRetranslateUI()
210{
211 if (m_pUserNameEdit)
212 {
213 m_pUserNameEdit->setToolTip(QApplication::translate("UIFileManager", "User name to authenticate session creation"));
214 m_pUserNameEdit->setPlaceholderText(QApplication::translate("UIFileManager", "User Name"));
215
216 }
217 if (m_pPasswordEdit)
218 {
219 m_pPasswordEdit->setToolTip(QApplication::translate("UIFileManager", "Password to authenticate session creation"));
220 m_pPasswordEdit->setPlaceholderText(QApplication::translate("UIFileManager", "Password"));
221 }
222
223 if (m_pButton)
224 {
225 if (m_enmButtonMode == ButtonMode_Open)
226 {
227 m_pButton->setText(QApplication::translate("UIFileManager", "Open Session"));
228 m_pButton->setToolTip(QApplication::translate("UIFileManager", "Open Session"));
229 }
230 else
231 {
232 m_pButton->setText(QApplication::translate("UIFileManager", "Close Session"));
233 m_pButton->setToolTip(QApplication::translate("UIFileManager", "Close Session"));
234 }
235 }
236}
237
238void UIGuestSessionWidget::keyPressEvent(QKeyEvent * pEvent)
239{
240 /* Emit sigOpenSession upon enter press: */
241 if (pEvent->key() == Qt::Key_Enter || pEvent->key() == Qt::Key_Return)
242 {
243 if ((m_pUserNameEdit && m_pUserNameEdit->hasFocus()) ||
244 (m_pPasswordEdit && m_pPasswordEdit->hasFocus()))
245 sigOpenSession(m_pUserNameEdit->text(), m_pPasswordEdit->text());
246 }
247 QWidget::keyPressEvent(pEvent);
248}
249
250void UIGuestSessionWidget::showEvent(QShowEvent *pEvent)
251{
252 QWidget::showEvent(pEvent);
253 if (m_pUserNameEdit)
254 m_pUserNameEdit->setFocus();
255}
256
257void UIGuestSessionWidget::switchSessionOpenMode()
258{
259 if (m_pUserNameEdit)
260 m_pUserNameEdit->setEnabled(true);
261 if (m_pPasswordEdit)
262 m_pPasswordEdit->setEnabled(true);
263 m_enmButtonMode = ButtonMode_Open;
264 sltRetranslateUI();
265}
266
267void UIGuestSessionWidget::switchSessionCloseMode()
268{
269 if (m_pUserNameEdit)
270 m_pUserNameEdit->setEnabled(false);
271 if (m_pPasswordEdit)
272 m_pPasswordEdit->setEnabled(false);
273 m_enmButtonMode = ButtonMode_Close;
274 sltRetranslateUI();
275}
276
277void UIGuestSessionWidget::markForError(bool fMarkForError)
278{
279 if (m_fMarkedForError == fMarkForError)
280 return;
281 m_fMarkedForError = fMarkForError;
282
283 if (m_pUserNameEdit)
284 {
285 QPalette mPalette = m_pUserNameEdit->palette();
286 if (m_fMarkedForError)
287 mPalette.setColor(QPalette::Base, m_errorBaseColor);
288 else
289 mPalette.setColor(QPalette::Base, m_defaultBaseColor);
290 m_pUserNameEdit->setPalette(mPalette);
291 }
292 if (m_pPasswordEdit)
293 {
294 QPalette mPalette = m_pPasswordEdit->palette();
295 if (m_fMarkedForError)
296 mPalette.setColor(QPalette::Base, m_errorBaseColor);
297 else
298 mPalette.setColor(QPalette::Base, m_defaultBaseColor);
299 m_pPasswordEdit->setPalette(mPalette);
300 }
301}
302
303void UIGuestSessionWidget::setStatusLabelIconAndToolTip(const QIcon &icon, const QString &strToolTip)
304{
305 if (!m_pStatusIconLabel)
306 return;
307 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_ButtonIconSize);
308 m_pStatusIconLabel->setPixmap(icon.pixmap(QSize(iIconMetric, iIconMetric)));
309 m_pStatusIconLabel->setToolTip(strToolTip);
310}
311
312void UIGuestSessionWidget::setLoginWidgetsEnabled(bool fEnabled)
313{
314 if (m_pUserNameEdit)
315 m_pUserNameEdit->setEnabled(fEnabled);
316 if (m_pPasswordEdit)
317 m_pPasswordEdit->setEnabled(fEnabled);
318 if (m_pButton)
319 m_pButton->setEnabled(fEnabled);
320}
321
322
323/*********************************************************************************************************************************
324* UIGuestDirectoryDiskUsageComputer definition. *
325*********************************************************************************************************************************/
326
327/** Open directories recursively and sum the disk usage. Don't block the GUI thread while doing this */
328class UIGuestDirectoryDiskUsageComputer : public UIDirectoryDiskUsageComputer
329{
330 Q_OBJECT;
331
332public:
333
334 UIGuestDirectoryDiskUsageComputer(QObject *parent, QStringList strStartPath, const CGuestSession &session);
335
336protected:
337
338 virtual void run() RT_OVERRIDE;
339 virtual void directoryStatisticsRecursive(const QString &path, UIDirectoryStatistics &statistics) RT_OVERRIDE;
340
341private:
342
343 CGuestSession m_comGuestSession;
344};
345
346
347/*********************************************************************************************************************************
348* UIGuestDirectoryDiskUsageComputer implementation. *
349*********************************************************************************************************************************/
350
351UIGuestDirectoryDiskUsageComputer::UIGuestDirectoryDiskUsageComputer(QObject *parent, QStringList pathList, const CGuestSession &session)
352 :UIDirectoryDiskUsageComputer(parent, pathList)
353 , m_comGuestSession(session)
354{
355}
356
357void UIGuestDirectoryDiskUsageComputer::run()
358{
359 /* Initialize COM: */
360 COMBase::InitializeCOM(false);
361 UIDirectoryDiskUsageComputer::run();
362 /* Cleanup COM: */
363 COMBase::CleanupCOM();
364}
365
366void UIGuestDirectoryDiskUsageComputer::directoryStatisticsRecursive(const QString &path, UIDirectoryStatistics &statistics)
367{
368 if (m_comGuestSession.isNull())
369 return;
370 /* Prevent modification of the continue flag while reading: */
371 m_mutex.lock();
372 /* Check if m_fOkToContinue is set to false. if so just end recursion: */
373 if (!isOkToContinue())
374 {
375 m_mutex.unlock();
376 return;
377 }
378 m_mutex.unlock();
379
380 CGuestFsObjInfo fileInfo = m_comGuestSession.FsObjQueryInfo(path, true);
381
382 if (!m_comGuestSession.isOk())
383 return;
384 /* if the object is a file or a symlink then read the size and return: */
385 if (fileInfo.GetType() == KFsObjType_File)
386 {
387 statistics.m_totalSize += fileInfo.GetObjectSize();
388 ++statistics.m_uFileCount;
389 sigResultUpdated(statistics);
390 return;
391 }
392 else if (fileInfo.GetType() == KFsObjType_Symlink)
393 {
394 statistics.m_totalSize += fileInfo.GetObjectSize();
395 ++statistics.m_uSymlinkCount;
396 sigResultUpdated(statistics);
397 return;
398 }
399
400 if (fileInfo.GetType() != KFsObjType_Directory)
401 return;
402 /* Open the directory to start reading its content: */
403 QVector<KDirectoryOpenFlag> flag(1, KDirectoryOpenFlag_None);
404 CGuestDirectory directory = m_comGuestSession.DirectoryOpen(path, /*aFilter*/ "", flag);
405 if (!m_comGuestSession.isOk())
406 return;
407
408 if (directory.isOk())
409 {
410 CFsObjInfo fsInfo = directory.Read();
411 while (fsInfo.isOk())
412 {
413 if (fsInfo.GetType() == KFsObjType_File)
414 statistics.m_uFileCount++;
415 else if (fsInfo.GetType() == KFsObjType_Symlink)
416 statistics.m_uSymlinkCount++;
417 else if(fsInfo.GetType() == KFsObjType_Directory)
418 {
419 QString dirPath = UIPathOperations::mergePaths(path, fsInfo.GetName());
420 directoryStatisticsRecursive(dirPath, statistics);
421 }
422 }
423 }
424 sigResultUpdated(statistics);
425}
426
427UIFileManagerGuestTable::UIFileManagerGuestTable(UIActionPool *pActionPool, const CMachine &comMachine, QWidget *pParent /*= 0*/)
428 :UIFileManagerTable(pActionPool, pParent)
429 , m_comMachine(comMachine)
430 , m_pGuestSessionWidget(0)
431 , m_fIsCurrent(false)
432 , pszMinimumGuestAdditionVersion("6.1")
433{
434 setModelFileSystem(isWindowsFileSystem());
435 if (!m_comMachine.isNull())
436 m_strTableName = m_comMachine.GetName();
437 prepareToolbar();
438 prepareGuestSessionPanel();
439 prepareActionConnections();
440 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineStateChange,
441 this, &UIFileManagerGuestTable::sltMachineStateChange);
442 connect(&uiCommon(), &UICommon::sigAskToCommitData,
443 this, &UIFileManagerGuestTable::sltCommitDataSignalReceived);
444
445 if (m_pActionPool && m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession))
446 m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession)->setChecked(true);
447
448 if (!m_comMachine.isNull() && m_comMachine.GetState() == KMachineState_Running)
449 openMachineSession();
450 setStateAndEnableWidgets();
451
452 sltRetranslateUI();
453 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
454 this, &UIFileManagerGuestTable::sltRetranslateUI);
455}
456
457UIFileManagerGuestTable::~UIFileManagerGuestTable()
458{
459 cleanAll();
460}
461
462void UIFileManagerGuestTable::initFileTable()
463{
464 if (!m_comGuestSession.isOk() || m_comGuestSession.GetStatus() != KGuestSessionStatus_Started)
465 return;
466 /* To determine the path separator we need to have a valid guest session: */
467 determinePathSeparator();
468 initializeFileTree();
469}
470
471void UIFileManagerGuestTable::sltRetranslateUI()
472{
473 if (m_pLocationLabel)
474 m_pLocationLabel->setText(UIFileManager::tr("Guest File System:"));
475
476 if (m_pGuestSessionWidget)
477 {
478 QIcon icon;
479 QString strWarningText;
480 switch (m_enmState)
481 {
482 case State_InvalidMachineReference:
483 strWarningText = UIFileManager::tr("Machine reference is invalid.");
484 icon = UIIconPool::iconSet(":/status_error_16px.png");
485 break;
486 case State_MachineNotRunning:
487 strWarningText = UIFileManager::tr("File manager cannot work since the selected guest is not currently running.");
488 icon = UIIconPool::iconSet(":/status_error_16px.png");
489 break;
490 case State_MachinePaused:
491 strWarningText = UIFileManager::tr("File manager cannot work since the guest is paused.");
492 icon = UIIconPool::iconSet(":/session_info_16px.png");
493 break;
494 case State_NoGuestAdditions:
495 strWarningText = UIFileManager::tr("File manager cannot work since no guest additions were detected.");
496 icon = UIIconPool::iconSet(":/status_error_16px.png");
497 break;
498 case State_GuestAdditionsTooOld:
499 strWarningText = UIFileManager::tr("File manager cannot work. The guest additions need to be updated.");
500 icon = UIIconPool::iconSet(":/status_error_16px.png");
501 break;
502 case State_SessionPossible:
503 strWarningText = UIFileManager::tr("Enter a valid user name and password to initiate the file manager.");
504 icon = UIIconPool::iconSet(":/session_info_16px.png");
505 break;
506 case State_SessionRunning:
507 strWarningText = UIFileManager::tr("Guest control session is running.");
508 icon = UIIconPool::iconSet(":/status_check_16px.png");
509 break;
510 case State_SessionError:
511 strWarningText = UIFileManager::tr("Some error has occurred. Please check the log panel.");
512 icon = UIIconPool::iconSet(":/status_error_16px.png");
513 break;
514 default:
515 break;
516 }
517 m_pGuestSessionWidget->setStatusLabelIconAndToolTip(icon, strWarningText);
518 }
519
520 UIFileManagerTable::sltRetranslateUI();
521}
522
523bool UIFileManagerGuestTable::readDirectory(const QString& strPath,
524 UIFileSystemItem *parent, bool isStartDir /*= false*/)
525{
526 if (!parent)
527 return false;
528
529 CGuestDirectory directory;
530 QVector<KDirectoryOpenFlag> flag;
531 flag.push_back(KDirectoryOpenFlag_None);
532
533 directory = m_comGuestSession.DirectoryOpen(UIPathOperations::sanitize(strPath), /*aFilter*/ "", flag);
534 if (!m_comGuestSession.isOk())
535 {
536 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
537 return false;
538 }
539
540 parent->setIsOpened(true);
541 if (directory.isOk())
542 {
543 int const cMaxEntries = _4K; /* Maximum number of entries to read at once per List() call. */
544 bool fUseRead = false; /* Whether to use the Read() API or the newer (faster) List() call. */
545
546 QVector<CFsObjInfo> vecFsInfo = directory.List(cMaxEntries);
547 /* IGuestDirectory::List() will return VBOX_E_NOT_SUPPORTED if older Guest Additions are installed. */
548 if (directory.rc() == VBOX_E_NOT_SUPPORTED)
549 {
550 CFsObjInfo fsInfo = directory.Read();
551 if (directory.isOk())
552 {
553 vecFsInfo.push_back(fsInfo);
554 fUseRead = true;
555 }
556 }
557
558 QMap<QString, UIFileSystemItem*> fileObjects;
559
560 while (directory.isOk())
561 {
562 for (int i = 0; i < vecFsInfo.size(); i++)
563 {
564 CFsObjInfo const &fsInfo = vecFsInfo[i];
565
566 if (fsInfo.GetName() != "." && fsInfo.GetName() != "..")
567 {
568 QVector<QVariant> data;
569 QDateTime changeTime = QDateTime::fromMSecsSinceEpoch(fsInfo.GetChangeTime()/RT_NS_1MS);
570 KFsObjType fsObjectType = fileType(fsInfo);
571 UIFileSystemItem *item = new UIFileSystemItem(fsInfo.GetName(), parent, fsObjectType);
572 if (!item)
573 continue;
574 item->setData(static_cast<qulonglong>(fsInfo.GetObjectSize()), UIFileSystemModelData_Size);
575 item->setData(changeTime, UIFileSystemModelData_ChangeTime);
576 item->setData(fsInfo.GetUserName(), UIFileSystemModelData_Owner);
577 item->setData(permissionString(fsInfo), UIFileSystemModelData_Permissions);
578 item->setIsOpened(false);
579 item->setIsHidden(isFileObjectHidden(fsInfo));
580 fileObjects.insert(fsInfo.GetName(), item);
581 /* @todo. We will need to wait a fully implemented SymlinkRead function
582 * to be able to handle sym links properly: */
583 // QString path = UIPathOperations::mergePaths(strPath, fsInfo.GetName());
584 // QVector<KSymlinkReadFlag> aFlags;
585 // printf("%s %s %s\n", qPrintable(fsInfo.GetName()), qPrintable(path),
586 // qPrintable(m_comGuestSession.SymlinkRead(path, aFlags)));
587 }
588 }
589
590 if (fUseRead)
591 {
592 CFsObjInfo fsInfo = directory.Read();
593 if (directory.isOk())
594 {
595 vecFsInfo.clear();
596 vecFsInfo.push_back(fsInfo);
597 }
598 }
599 else
600 vecFsInfo = directory.List(cMaxEntries);
601 }
602
603 checkDotDot(fileObjects, parent, isStartDir);
604 }
605 else
606 {
607 directory.Close();
608 return false;
609 }
610 directory.Close();
611 return true;
612}
613
614void UIFileManagerGuestTable::deleteByItem(UIFileSystemItem *item)
615{
616 if (!item)
617 return;
618 if (item->isUpDirectory())
619 return;
620
621 if (item->isDirectory())
622 {
623 QVector<KDirectoryRemoveRecFlag> aFlags(1, KDirectoryRemoveRecFlag_ContentAndDir);
624 m_comGuestSession.DirectoryRemoveRecursive(UIPathOperations::removeTrailingDelimiters(item->path()), aFlags);
625 }
626 else
627 m_comGuestSession.FsObjRemove(UIPathOperations::removeTrailingDelimiters(item->path()));
628 if (!m_comGuestSession.isOk())
629 {
630 emit sigLogOutput(QString(item->path()).append(" could not be deleted"), m_strTableName, FileManagerLogType_Error);
631 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
632 }
633}
634
635void UIFileManagerGuestTable::goToHomeDirectory()
636{
637 if (m_comGuestSession.isNull())
638 return;
639 if (!rootItem() || rootItem()->childCount() <= 0)
640 return;
641 UIFileSystemItem *startDirItem = rootItem()->child(0);
642 if (!startDirItem)
643 return;
644
645 QString userHome = UIPathOperations::sanitize(m_comGuestSession.GetUserHome());
646 if (!m_comGuestSession.isOk())
647 {
648 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
649 return;
650 }
651#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
652 QStringList pathList = userHome.split(UIPathOperations::delimiter, Qt::SkipEmptyParts);
653#else
654 QStringList pathList = userHome.split(UIPathOperations::delimiter, QString::SkipEmptyParts);
655#endif
656 goIntoDirectory(UIPathOperations::pathTrail(userHome));
657}
658
659bool UIFileManagerGuestTable::renameItem(UIFileSystemItem *item, const QString &strOldPath)
660{
661 if (!item || item->isUpDirectory())
662 return false;
663 //QString newPath = UIPathOperations::removeTrailingDelimiters(UIPathOperations::constructNewItemPath(item->path(), newBaseName));
664 QVector<KFsObjRenameFlag> aFlags(1, KFsObjRenameFlag_Replace);
665
666 m_comGuestSession.FsObjRename(strOldPath, item->path(), aFlags);
667
668 if (!m_comGuestSession.isOk())
669 {
670 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
671 return false;
672 }
673
674 return true;
675}
676
677bool UIFileManagerGuestTable::createDirectory(const QString &path, const QString &directoryName)
678{
679 QString newDirectoryPath = UIPathOperations::mergePaths(path, directoryName);
680 QVector<KDirectoryCreateFlag> flags(1, KDirectoryCreateFlag_None);
681
682 m_comGuestSession.DirectoryCreate(newDirectoryPath, 0/*aMode*/, flags);
683
684 if (!m_comGuestSession.isOk())
685 {
686 emit sigLogOutput(newDirectoryPath.append(" could not be created"), m_strTableName, FileManagerLogType_Error);
687 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
688 return false;
689 }
690 emit sigLogOutput(newDirectoryPath.append(" has been created"), m_strTableName, FileManagerLogType_Info);
691 return true;
692}
693
694void UIFileManagerGuestTable::copyHostToGuest(const QStringList &hostSourcePathList,
695 const QString &strDestination /* = QString() */)
696{
697 if (!checkGuestSession())
698 return;
699 QVector<QString> sourcePaths = hostSourcePathList.toVector();
700 /* Remove empty source paths. Typically happens when up directory is selected: */
701 sourcePaths.removeAll(QString());
702
703 QVector<QString> aFilters;
704 QVector<QString> aFlags;
705 QString strDestinationPath = UIPathOperations::addTrailingDelimiters(strDestination);
706 if (strDestinationPath.isEmpty())
707 strDestinationPath = UIPathOperations::addTrailingDelimiters(currentDirectoryPath());
708
709 if (strDestinationPath.isEmpty())
710 {
711 emit sigLogOutput("No destination for copy operation", m_strTableName, FileManagerLogType_Error);
712 return;
713 }
714 if (sourcePaths.empty())
715 {
716 emit sigLogOutput("No source for copy operation", m_strTableName, FileManagerLogType_Error);
717 return;
718 }
719 QString strDirectoryFlags("CopyIntoExisting,Recursive,FollowLinks");
720 QString strFileFlags("FollowLinks");
721
722 for (int i = 0; i < sourcePaths.size(); ++i)
723 {
724 sourcePaths[i] = UIPathOperations::removeTrailingDelimiters(sourcePaths[i]);
725 KFsObjType enmFileType = UIFileManagerHostTable::fileType(sourcePaths[i]);
726 if (enmFileType == KFsObjType_Unknown)
727 emit sigLogOutput(QString("Querying information for host item %1 failed.").arg(sourcePaths[i]), m_strTableName, FileManagerLogType_Error);
728 /* If the source is an directory, make sure to add the appropriate flag to make copying work
729 * into existing directories on the guest. This otherwise would fail (default): */
730 else if (enmFileType == KFsObjType_Directory)
731 aFlags << strDirectoryFlags;
732 else
733 aFlags << strFileFlags;
734 }
735
736 CProgress progress = m_comGuestSession.CopyToGuest(sourcePaths, aFilters, aFlags, strDestinationPath);
737 if (!checkGuestSession())
738 return;
739 emit sigNewFileOperation(progress, m_strTableName);
740}
741
742QUuid UIFileManagerGuestTable::machineId()
743{
744 if (m_comMachine.isNull())
745 return QUuid();
746 return m_comMachine.GetId();
747}
748
749bool UIFileManagerGuestTable::isGuestSessionRunning() const
750{
751 return m_enmState == State_SessionRunning;
752}
753
754void UIFileManagerGuestTable::setIsCurrent(bool fIsCurrent)
755{
756 if (m_fIsCurrent == fIsCurrent)
757 return;
758 m_fIsCurrent = fIsCurrent;
759 prepareActionConnections();
760}
761
762void UIFileManagerGuestTable::copyGuestToHost(const QString& hostDestinationPath)
763{
764 if (!checkGuestSession())
765 return;
766 QVector<QString> sourcePaths = selectedItemPathList().toVector();
767 QVector<QString> aFilters;
768 QVector<QString> aFlags;
769
770 /* Remove empty source paths. Typically happens when up directory is selected: */
771 sourcePaths.removeAll(QString());
772
773 if (hostDestinationPath.isEmpty())
774 {
775 emit sigLogOutput("No destination for copy operation", m_strTableName, FileManagerLogType_Error);
776 return;
777 }
778 if (sourcePaths.empty())
779 {
780 emit sigLogOutput("No source for copy operation", m_strTableName, FileManagerLogType_Error);
781 return;
782 }
783
784 QString strDestinationPath = UIPathOperations::addTrailingDelimiters(hostDestinationPath);
785 QString strDirectoryFlags("CopyIntoExisting,Recursive,FollowLinks");
786 QString strFileFlags;
787 //foreach (const QString &strSource, sourcePaths)
788 for (int i = 0; i < sourcePaths.size(); ++i)
789 {
790 sourcePaths[i] = UIPathOperations::removeTrailingDelimiters(sourcePaths[i]);
791 /** @todo Cache this info and use the item directly, which has this info already? */
792
793 /* If the source is an directory, make sure to add the appropriate flag to make copying work
794 * into existing directories on the guest. This otherwise would fail (default). */
795 CGuestFsObjInfo fileInfo = m_comGuestSession.FsObjQueryInfo(sourcePaths[i], true);
796 if (!m_comGuestSession.isOk())
797 {
798 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
799 return;
800 }
801
802 if (fileType(fileInfo) == KFsObjType_Directory)
803 aFlags << strDirectoryFlags;
804 else
805 aFlags << strFileFlags;
806
807 }
808
809 CProgress progress = m_comGuestSession.CopyFromGuest(sourcePaths, aFilters, aFlags, strDestinationPath);
810 if (!checkGuestSession())
811 return;
812 emit sigNewFileOperation(progress, m_strTableName);
813}
814
815KFsObjType UIFileManagerGuestTable::fileType(const CFsObjInfo &fsInfo)
816{
817 if (fsInfo.isNull() || !fsInfo.isOk())
818 return KFsObjType_Unknown;
819 if (fsInfo.GetType() == KFsObjType_Directory)
820 return KFsObjType_Directory;
821 else if (fsInfo.GetType() == KFsObjType_File)
822 return KFsObjType_File;
823 else if (fsInfo.GetType() == KFsObjType_Symlink)
824 return KFsObjType_Symlink;
825
826 return KFsObjType_Unknown;
827}
828
829KFsObjType UIFileManagerGuestTable::fileType(const CGuestFsObjInfo &fsInfo)
830{
831 if (fsInfo.isNull() || !fsInfo.isOk())
832 return KFsObjType_Unknown;
833 if (fsInfo.GetType() == KFsObjType_Directory)
834 return KFsObjType_Directory;
835 else if (fsInfo.GetType() == KFsObjType_File)
836 return KFsObjType_File;
837 else if (fsInfo.GetType() == KFsObjType_Symlink)
838 return KFsObjType_Symlink;
839
840 return KFsObjType_Unknown;
841}
842
843
844QString UIFileManagerGuestTable::fsObjectPropertyString()
845{
846 QStringList selectedObjects = selectedItemPathList();
847 if (selectedObjects.isEmpty())
848 return QString();
849 if (selectedObjects.size() == 1)
850 {
851 if (selectedObjects.at(0).isNull())
852 return QString();
853
854 CGuestFsObjInfo fileInfo = m_comGuestSession.FsObjQueryInfo(selectedObjects.at(0), false /*aFollowSymlinks*/);
855 if (!m_comGuestSession.isOk())
856 {
857 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
858 return QString();
859 }
860
861 QStringList propertyStringList;
862
863 /* Name: */
864 propertyStringList << UIFileManager::tr("<b>Name:</b> %1<br/>").arg(UIPathOperations::getObjectName(fileInfo.GetName()));
865
866 /* Size: */
867 LONG64 size = fileInfo.GetObjectSize();
868 propertyStringList << UIFileManager::tr("<b>Size:</b> %1 bytes").arg(QString::number(size));
869 if (size >= UIFileManagerTable::m_iKiloByte)
870 propertyStringList << QString(" (%1)<br/>").arg(humanReadableSize(size));
871 else
872 propertyStringList << QString("<br/>");
873
874 /* Allocated size: */
875 size = fileInfo.GetAllocatedSize();
876 propertyStringList << UIFileManager::tr("<b>Allocated:</b> %1 bytes").arg(QString::number(size));
877 if (size >= UIFileManagerTable::m_iKiloByte)
878 propertyStringList << QString(" (%1)<br/>").arg(humanReadableSize(size));
879 else
880 propertyStringList << QString("<br/>");
881
882 /* Type: */
883 QString str;
884 KFsObjType const enmType = fileInfo.GetType();
885 switch (enmType)
886 {
887 case KFsObjType_Directory: str = UIFileManager::tr("directory"); break;
888 case KFsObjType_File: str = UIFileManager::tr("file"); break;
889 case KFsObjType_Symlink: str = UIFileManager::tr("symbolic link"); break;
890 case KFsObjType_DevChar: str = UIFileManager::tr("character device"); break;
891 case KFsObjType_DevBlock: str = UIFileManager::tr("block device"); break;
892 case KFsObjType_Fifo: str = UIFileManager::tr("fifo"); break;
893 case KFsObjType_Socket: str = UIFileManager::tr("socket"); break;
894 case KFsObjType_WhiteOut: str = UIFileManager::tr("whiteout"); break;
895 case KFsObjType_Unknown: str = UIFileManager::tr("unknown"); break;
896 default: str = UIFileManager::tr("illegal-value"); break;
897 }
898 propertyStringList << UIFileManager::tr("<b>Type:</b> %1<br/>").arg(str);
899
900 /* INode number, device, link count: */
901 propertyStringList << UIFileManager::tr("<b>INode:</b> %1<br/>").arg(fileInfo.GetNodeId());
902 propertyStringList << UIFileManager::tr("<b>Device:</b> %1<br/>").arg(fileInfo.GetNodeIdDevice()); /** @todo hex */
903 propertyStringList << UIFileManager::tr("<b>Hardlinks:</b> %1<br/>").arg(fileInfo.GetHardLinks());
904
905 /* Attributes: */
906 str = fileInfo.GetFileAttributes();
907 if (!str.isEmpty())
908 {
909 int offSpace = str.indexOf(' ');
910 if (offSpace < 0)
911 offSpace = str.length();
912 propertyStringList << UIFileManager::tr("<b>Mode:</b> %1<br/>").arg(str.left(offSpace));
913 propertyStringList << UIFileManager::tr("<b>Attributes:</b> %1<br/>").arg(str.mid(offSpace + 1).trimmed());
914 }
915
916 /* Character/block device ID: */
917 ULONG uDeviceNo = fileInfo.GetDeviceNumber();
918 if (uDeviceNo != 0 || enmType == KFsObjType_DevChar || enmType == KFsObjType_DevBlock)
919 propertyStringList << UIFileManager::tr("<b>Device ID:</b> %1<br/>").arg(uDeviceNo); /** @todo hex */
920
921 /* Owner: */
922 propertyStringList << UIFileManager::tr("<b>Owner:</b> %1 (%2)<br/>").
923 arg(fileInfo.GetUserName()).arg(fileInfo.GetUID());
924 propertyStringList << UIFileManager::tr("<b>Group:</b> %1 (%2)<br/>").
925 arg(fileInfo.GetGroupName()).arg(fileInfo.GetGID());
926
927 /* Timestamps: */
928 propertyStringList << UIFileManager::tr("<b>Birth:</b> %1<br/>").
929 arg(QDateTime::fromMSecsSinceEpoch(fileInfo.GetBirthTime() / RT_NS_1MS).toString());
930 propertyStringList << UIFileManager::tr("<b>Change:</b> %1<br/>").
931 arg(QDateTime::fromMSecsSinceEpoch(fileInfo.GetChangeTime() / RT_NS_1MS).toString());
932 propertyStringList << UIFileManager::tr("<b>Modified:</b> %1<br/>").
933 arg(QDateTime::fromMSecsSinceEpoch(fileInfo.GetModificationTime() / RT_NS_1MS).toString());
934 propertyStringList << UIFileManager::tr("<b>Access:</b> %1<br/>").
935 arg(QDateTime::fromMSecsSinceEpoch(fileInfo.GetAccessTime() / RT_NS_1MS).toString());
936
937 /* Join the list elements into a single string seperated by empty string: */
938 return propertyStringList.join(QString());
939 }
940
941 int fileCount = 0;
942 int directoryCount = 0;
943 ULONG64 totalSize = 0;
944
945 for(int i = 0; i < selectedObjects.size(); ++i)
946 {
947 CGuestFsObjInfo fileInfo = m_comGuestSession.FsObjQueryInfo(selectedObjects.at(0), true);
948 if (!m_comGuestSession.isOk())
949 {
950 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
951 continue;
952 }
953
954 KFsObjType type = fileType(fileInfo);
955
956 if (type == KFsObjType_File)
957 ++fileCount;
958 if (type == KFsObjType_Directory)
959 ++directoryCount;
960 totalSize += fileInfo.GetObjectSize();
961 }
962 QStringList propertyStringList;
963 propertyStringList << UIFileManager::tr("<b>Selected:</b> %1 files and %2 directories<br/>").
964 arg(QString::number(fileCount)).arg(QString::number(directoryCount));
965 propertyStringList << UIFileManager::tr("<b>Size (non-recursive):</b> %1 bytes").arg(QString::number(totalSize));
966 if (totalSize >= m_iKiloByte)
967 propertyStringList << QString(" (%1)").arg(humanReadableSize(totalSize));
968
969 return propertyStringList.join(QString());;
970}
971
972void UIFileManagerGuestTable::showProperties()
973{
974 if (m_comGuestSession.isNull())
975 return;
976 QString fsPropertyString = fsObjectPropertyString();
977 if (fsPropertyString.isEmpty())
978 return;
979
980 m_pPropertiesDialog = new UIPropertiesDialog(this);
981 if (!m_pPropertiesDialog)
982 return;
983
984 QStringList selectedObjects = selectedItemPathList();
985 if (selectedObjects.size() == 0)
986 return;
987
988 m_pPropertiesDialog->setWindowTitle(UIFileManager::tr("Properties"));
989 m_pPropertiesDialog->setPropertyText(fsPropertyString);
990 m_pPropertiesDialog->execute();
991
992 delete m_pPropertiesDialog;
993 m_pPropertiesDialog = 0;
994}
995
996void UIFileManagerGuestTable::determineDriveLetters()
997{
998 if (m_comGuestSession.isNull())
999 return;
1000
1001 KPathStyle pathStyle = m_comGuestSession.GetPathStyle();
1002 if (pathStyle != KPathStyle_DOS)
1003 return;
1004
1005 m_driveLetterList.clear();
1006
1007 QVector<QString> mountPoints = m_comGuestSession.GetMountPoints();
1008 if (m_comGuestSession.isOk())
1009 {
1010 foreach (const QString &strPoint, mountPoints)
1011 m_driveLetterList.push_back(UIPathOperations::replaceDosDelimeter(strPoint));
1012 }
1013 else
1014 {
1015 for (int i = 'A'; i <= 'Z'; ++i)
1016 {
1017 QString path((char)i);
1018 path += ":/";
1019 bool exists = m_comGuestSession.DirectoryExists(path, false /* aFollowSymlinks */);
1020 if (exists)
1021 m_driveLetterList.push_back(path);
1022 }
1023 }
1024}
1025
1026void UIFileManagerGuestTable::determinePathSeparator()
1027{
1028 if (m_comGuestSession.isNull())
1029 return;
1030 KPathStyle pathStyle = m_comGuestSession.GetPathStyle();
1031 if (pathStyle == KPathStyle_DOS)
1032 setPathSeparator(UIPathOperations::dosDelimiter);
1033}
1034
1035void UIFileManagerGuestTable::prepareToolbar()
1036{
1037 if (m_pToolBar && m_pActionPool)
1038 {
1039 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoBackward));
1040 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoForward));
1041 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoUp));
1042 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoHome));
1043 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Refresh));
1044 m_pToolBar->addSeparator();
1045 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Delete));
1046 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Rename));
1047 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_CreateNewDirectory));
1048
1049 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Copy));
1050 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Cut));
1051 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Paste));
1052 m_pToolBar->addSeparator();
1053 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_SelectAll));
1054 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_InvertSelection));
1055 m_pToolBar->addSeparator();
1056 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_ShowProperties));
1057 m_selectionDependentActions.insert(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Delete));
1058 m_selectionDependentActions.insert(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Rename));
1059 m_selectionDependentActions.insert(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Copy));
1060 m_selectionDependentActions.insert(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Cut));
1061 m_selectionDependentActions.insert(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_ShowProperties));
1062
1063 /* Hide these actions for now until we have a suitable guest-to-guest copy function: */
1064 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Copy)->setVisible(false);
1065 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Cut)->setVisible(false);
1066 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Paste)->setVisible(false);
1067
1068 m_pToolBar->addSeparator();
1069 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession));
1070 }
1071
1072 setSelectionDependentActionsEnabled(false);
1073 setPasteActionEnabled(false);
1074}
1075
1076void UIFileManagerGuestTable::createFileViewContextMenu(const QWidget *pWidget, const QPoint &point)
1077{
1078 if (!pWidget)
1079 return;
1080
1081 QMenu menu;
1082 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoBackward));
1083 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoForward));
1084 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoUp));
1085
1086 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoHome));
1087 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Refresh));
1088 menu.addSeparator();
1089 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Delete));
1090 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Rename));
1091 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_CreateNewDirectory));
1092 menu.addSeparator();
1093 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Copy));
1094 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Cut));
1095 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Paste));
1096 menu.addSeparator();
1097 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_SelectAll));
1098 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_InvertSelection));
1099 menu.addSeparator();
1100 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_ShowProperties));
1101 menu.exec(pWidget->mapToGlobal(point));
1102}
1103
1104void UIFileManagerGuestTable::setPasteActionEnabled(bool fEnabled)
1105{
1106 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Paste)->setEnabled(fEnabled);
1107}
1108
1109void UIFileManagerGuestTable::pasteCutCopiedObjects()
1110{
1111}
1112
1113void UIFileManagerGuestTable::manageConnection(bool fConnect, QAction *pAction, void (UIFileManagerGuestTable::*fptr)(void))
1114{
1115 if (!pAction || !fptr)
1116 return;
1117 if (fConnect)
1118 connect(pAction, &QAction::triggered, this, fptr);
1119 else
1120 disconnect(pAction, 0, this, 0);
1121}
1122
1123void UIFileManagerGuestTable::prepareActionConnections()
1124{
1125 if (m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession))
1126 {
1127 if (m_fIsCurrent)
1128 connect(m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession), &QAction::toggled,
1129 this, &UIFileManagerGuestTable::sltGuestSessionPanelToggled);
1130 else
1131 disconnect(m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession), 0, this, 0);
1132 }
1133
1134 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoUp), &UIFileManagerTable::sltGoUp);
1135 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoHome), &UIFileManagerTable::sltGoHome);
1136 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoBackward), &UIFileManagerTable::sltGoBackward);
1137 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoForward), &UIFileManagerTable::sltGoForward);
1138 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Refresh), &UIFileManagerTable::sltRefresh);
1139 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Delete), &UIFileManagerTable::sltDelete);
1140 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Rename), &UIFileManagerTable::sltRename);
1141 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Copy), &UIFileManagerTable::sltCopy);
1142 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Cut), &UIFileManagerTable::sltCut);
1143 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Paste), &UIFileManagerTable::sltPaste);
1144 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_SelectAll), &UIFileManagerTable::sltSelectAll);
1145 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_InvertSelection), &UIFileManagerTable::sltInvertSelection);
1146 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_ShowProperties), &UIFileManagerTable::sltShowProperties);
1147 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_CreateNewDirectory), &UIFileManagerTable::sltCreateNewDirectory);
1148
1149 /* Also disable/enable go forward/backward actions: */
1150 toggleForwardBackwardActions();
1151}
1152
1153void UIFileManagerGuestTable::prepareGuestSessionPanel()
1154{
1155 if (m_pMainLayout)
1156 {
1157 m_pGuestSessionWidget = new UIGuestSessionWidget;
1158 if (m_pGuestSessionWidget)
1159 {
1160 m_pMainLayout->addWidget(m_pGuestSessionWidget, m_pMainLayout->rowCount(), 0, 1, m_pMainLayout->columnCount());
1161 m_pGuestSessionWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
1162 connect(m_pGuestSessionWidget, &UIGuestSessionWidget::sigOpenSession,
1163 this, &UIFileManagerGuestTable::sltOpenGuestSession);
1164 connect(m_pGuestSessionWidget, &UIGuestSessionWidget::sigCloseSession,
1165 this, &UIFileManagerGuestTable::sltHandleCloseSessionRequest);
1166 }
1167 }
1168}
1169
1170bool UIFileManagerGuestTable::checkGuestSession()
1171{
1172 if (!m_comGuestSession.isOk())
1173 {
1174 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
1175 return false;
1176 }
1177 return true;
1178}
1179
1180QString UIFileManagerGuestTable::permissionString(const CFsObjInfo &fsInfo)
1181{
1182 /* Attributes: */
1183 QString strAttributes = fsInfo.GetFileAttributes();
1184
1185 if (strAttributes.isEmpty())
1186 return strAttributes;
1187
1188 int offSpace = strAttributes.indexOf(' ');
1189 if (offSpace < 0)
1190 offSpace = strAttributes.length();
1191 return strAttributes.left(offSpace);
1192}
1193
1194bool UIFileManagerGuestTable::isFileObjectHidden(const CFsObjInfo &fsInfo)
1195{
1196 QString strAttributes = fsInfo.GetFileAttributes();
1197
1198 if (strAttributes.isEmpty())
1199 return false;
1200
1201 int offSpace = strAttributes.indexOf(' ');
1202 if (offSpace < 0)
1203 offSpace = strAttributes.length();
1204 QString strRight(strAttributes.mid(offSpace + 1).trimmed());
1205
1206 if (strRight.indexOf('H', Qt::CaseSensitive) == -1)
1207 return false;
1208 return true;
1209}
1210
1211void UIFileManagerGuestTable::sltGuestSessionPanelToggled(bool fChecked)
1212{
1213 if (m_pGuestSessionWidget)
1214 m_pGuestSessionWidget->setVisible(fChecked);
1215}
1216
1217void UIFileManagerGuestTable::sltMachineStateChange(const QUuid &uMachineId, const KMachineState enmMachineState)
1218{
1219 if (uMachineId.isNull() || m_comMachine.isNull() || uMachineId != m_comMachine.GetId())
1220 return;
1221
1222 if (enmMachineState == KMachineState_Running)
1223 openMachineSession();
1224 else if (enmMachineState != KMachineState_Paused)
1225 cleanAll();
1226 setStateAndEnableWidgets();
1227}
1228
1229bool UIFileManagerGuestTable::closeMachineSession()
1230{
1231 if (!m_comGuest.isNull())
1232 m_comGuest.detach();
1233
1234 if (!m_comConsole.isNull())
1235 m_comConsole.detach();
1236
1237 if (!m_comSession.isNull())
1238 {
1239 m_comSession.UnlockMachine();
1240 m_comSession.detach();
1241 }
1242 return true;
1243}
1244
1245bool UIFileManagerGuestTable::openMachineSession()
1246{
1247 if (m_comMachine.isNull())
1248 {
1249 emit sigLogOutput("Invalid machine reference", m_strTableName, FileManagerLogType_Error);
1250 return false;
1251 }
1252 m_comSession = uiCommon().openSession(m_comMachine.GetId(), KLockType_Shared);
1253 if (m_comSession.isNull())
1254 {
1255 emit sigLogOutput("Could not open machine session", m_strTableName, FileManagerLogType_Error);
1256 return false;
1257 }
1258
1259 m_comConsole = m_comSession.GetConsole();
1260 if (m_comConsole.isNull())
1261 {
1262 emit sigLogOutput("Machine console is invalid", m_strTableName, FileManagerLogType_Error);
1263 return false;
1264 }
1265
1266 m_comGuest = m_comConsole.GetGuest();
1267 if (m_comGuest.isNull())
1268 {
1269 emit sigLogOutput("Guest reference is invalid", m_strTableName, FileManagerLogType_Error);
1270 return false;
1271 }
1272
1273 /* Prepare guest listener for guest session related events: */
1274 {
1275 QVector<KVBoxEventType> eventTypes;
1276 eventTypes << KVBoxEventType_OnGuestSessionRegistered;
1277 prepareListener(m_pQtGuestListener, m_comGuestListener, m_comGuest.GetEventSource(), eventTypes);
1278 connect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionUnregistered,
1279 this, &UIFileManagerGuestTable::sltGuestSessionUnregistered);
1280 connect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionRegistered,
1281 this, &UIFileManagerGuestTable::sltGuestSessionRegistered);
1282 }
1283
1284 /* Prepare console listener for guest additions state change events: */
1285 {
1286 QVector<KVBoxEventType> eventTypes;
1287 eventTypes << KVBoxEventType_OnAdditionsStateChanged;
1288 prepareListener(m_pQtConsoleListener, m_comConsoleListener, m_comConsole.GetEventSource(), eventTypes);
1289 connect(m_pQtConsoleListener->getWrapped(), &UIMainEventListener::sigAdditionsChange,
1290 this, &UIFileManagerGuestTable::sltAdditionsStateChange);
1291 }
1292 emit sigLogOutput("Shared machine session opened", m_strTableName, FileManagerLogType_Info);
1293 return true;
1294}
1295
1296int UIFileManagerGuestTable::isGuestAdditionsAvailable(const char* pszMinimumVersion)
1297{
1298 if (m_comGuest.isNull() || !pszMinimumVersion)
1299 return 0;
1300
1301 /* Guest control stuff is in userland: */
1302 if (!m_comGuest.GetAdditionsStatus(KAdditionsRunLevelType_Userland))
1303 return 0;
1304
1305 if (!m_comGuest.isOk())
1306 return 0;
1307
1308 /* Check the related GA facility: */
1309 LONG64 iLastUpdatedIgnored;
1310 if (m_comGuest.GetFacilityStatus(KAdditionsFacilityType_VBoxService, iLastUpdatedIgnored) != KAdditionsFacilityStatus_Active)
1311 return 0;
1312
1313 if (!m_comGuest.isOk())
1314 return 0;
1315
1316 /* Check if GA is new enough to have the goodies: */
1317 QString strGAVersion = m_comGuest.GetAdditionsVersion();
1318 int iCode = RTStrVersionCompare(strGAVersion.toUtf8().constData(), pszMinimumVersion);
1319 if (iCode >= 0)
1320 return 1;
1321 else
1322 return -1;
1323
1324 return 0;
1325}
1326
1327void UIFileManagerGuestTable::cleanupGuestListener()
1328{
1329 if (!m_pQtGuestListener.isNull())
1330 {
1331 m_pQtGuestListener->getWrapped()->disconnect();
1332 if (!m_comGuest.isNull())
1333 cleanupListener(m_pQtGuestListener, m_comGuestListener, m_comGuest.GetEventSource());
1334 }
1335}
1336
1337void UIFileManagerGuestTable::cleanupGuestSessionListener()
1338{
1339 if (!m_pQtSessionListener.isNull())
1340 {
1341 m_pQtSessionListener->getWrapped()->disconnect();
1342 if (!m_comGuestSession.isNull())
1343 cleanupListener(m_pQtSessionListener, m_comSessionListener, m_comGuestSession.GetEventSource());
1344 }
1345}
1346
1347void UIFileManagerGuestTable::cleanupConsoleListener()
1348{
1349 if (!m_pQtConsoleListener.isNull())
1350 {
1351 m_pQtConsoleListener->getWrapped()->disconnect();
1352 if (!m_comConsole.isNull())
1353 cleanupListener(m_pQtConsoleListener, m_comConsoleListener, m_comConsole.GetEventSource());
1354 }
1355}
1356
1357void UIFileManagerGuestTable::prepareListener(ComObjPtr<UIMainEventListenerImpl> &QtListener,
1358 CEventListener &comEventListener,
1359 CEventSource comEventSource, QVector<KVBoxEventType>& eventTypes)
1360{
1361 if (!comEventSource.isOk())
1362 return;
1363 /* Create event listener instance: */
1364 QtListener.createObject();
1365 QtListener->init(new UIMainEventListener, this);
1366 comEventListener = CEventListener(QtListener);
1367
1368 /* Register event listener for CProgress event source: */
1369 comEventSource.RegisterListener(comEventListener, eventTypes, FALSE /* active? */);
1370
1371 /* Register event sources in their listeners as well: */
1372 QtListener->getWrapped()->registerSource(comEventSource, comEventListener);
1373}
1374
1375void UIFileManagerGuestTable::cleanupListener(ComObjPtr<UIMainEventListenerImpl> &QtListener,
1376 CEventListener &comEventListener,
1377 CEventSource comEventSource)
1378{
1379 if (!comEventSource.isOk())
1380 return;
1381 /* Unregister everything: */
1382 QtListener->getWrapped()->unregisterSources();
1383 QtListener.setNull();
1384 /* Make sure VBoxSVC is available: */
1385 if (!gpGlobalSession->isVBoxSVCAvailable())
1386 return;
1387
1388 /* Unregister event listener for CProgress event source: */
1389 comEventSource.UnregisterListener(comEventListener);
1390}
1391
1392void UIFileManagerGuestTable::sltGuestSessionUnregistered(CGuestSession guestSession)
1393{
1394 if (guestSession.isNull())
1395 return;
1396 if (guestSession == m_comGuestSession && !m_comGuestSession.isNull())
1397 {
1398 m_comGuestSession.detach();
1399 emit sigLogOutput("Guest session unregistered", m_strTableName, FileManagerLogType_Info);
1400 }
1401}
1402
1403void UIFileManagerGuestTable::sltGuestSessionRegistered(CGuestSession guestSession)
1404{
1405 if (guestSession == m_comGuestSession && !m_comGuestSession.isNull())
1406 emit sigLogOutput("Guest session registered", m_strTableName, FileManagerLogType_Info);
1407}
1408
1409void UIFileManagerGuestTable::sltGuestSessionStateChanged(const CGuestSessionStateChangedEvent &cEvent)
1410{
1411 if (cEvent.isOk())
1412 {
1413 CVirtualBoxErrorInfo cErrorInfo = cEvent.GetError();
1414 if (cErrorInfo.GetResultDetail() < VINF_SUCCESS)
1415 emit sigLogOutput(cErrorInfo.GetText(), m_strTableName, FileManagerLogType_Error);
1416
1417 if (m_pGuestSessionWidget)
1418 m_pGuestSessionWidget->markForError(cErrorInfo.GetResultDetail() == VERR_AUTHENTICATION_FAILURE);
1419 }
1420
1421 setStateAndEnableWidgets();
1422
1423 if (m_comGuestSession.isNull())
1424 emit sigLogOutput("Guest session is invalid!", m_strTableName, FileManagerLogType_Error);
1425 else
1426 {
1427 if (m_comGuestSession.isOk())
1428 {
1429 emit sigLogOutput(QString("%1: %2").arg("Guest session status has changed").arg(gpConverter->toString(m_comGuestSession.GetStatus())),
1430 m_strTableName, FileManagerLogType_Info);
1431
1432 switch (m_comGuestSession.GetStatus())
1433 {
1434 case KGuestSessionStatus_Started:
1435 {
1436 initFileTable();
1437 break;
1438 }
1439 case KGuestSessionStatus_Terminating:
1440 case KGuestSessionStatus_Terminated:
1441 case KGuestSessionStatus_TimedOutKilled:
1442 case KGuestSessionStatus_TimedOutAbnormally:
1443 case KGuestSessionStatus_Down:
1444 case KGuestSessionStatus_Error:
1445 {
1446 cleanupGuestSessionListener();
1447 closeGuestSession();
1448 break;
1449 }
1450 case KGuestSessionStatus_Undefined:
1451 case KGuestSessionStatus_Starting:
1452 case KGuestSessionStatus_Max:
1453 default:
1454 break;
1455 }
1456 }
1457 else
1458 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
1459 }
1460}
1461
1462void UIFileManagerGuestTable::sltOpenGuestSession(QString strUserName, QString strPassword)
1463{
1464 if (strUserName.isEmpty())
1465 {
1466 emit sigLogOutput("No user name is given", m_strTableName, FileManagerLogType_Error);
1467 if (m_pGuestSessionWidget)
1468 m_pGuestSessionWidget->markForError(true);
1469 return;
1470 }
1471 openGuestSession(strUserName, strPassword);
1472}
1473
1474void UIFileManagerGuestTable::toggleForwardBackwardActions()
1475{
1476 if (!m_pNavigationWidget)
1477 return;
1478 if (m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoForward))
1479 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoForward)->setEnabled(m_pNavigationWidget->canGoForward());
1480 if (m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoBackward))
1481 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoBackward)->setEnabled(m_pNavigationWidget->canGoBackward());
1482}
1483
1484void UIFileManagerGuestTable::setState()
1485{
1486 if (m_comMachine.isNull())
1487 {
1488 m_enmState = State_InvalidMachineReference;
1489 return;
1490 }
1491 if (m_comMachine.GetState() == KMachineState_Paused)
1492 {
1493 m_enmState = State_MachinePaused;
1494 return;
1495 }
1496 if (m_comMachine.GetState() != KMachineState_Running)
1497 {
1498 m_enmState = State_MachineNotRunning;
1499 return;
1500 }
1501
1502 int iGADetectCode = isGuestAdditionsAvailable(pszMinimumGuestAdditionVersion);
1503 if (iGADetectCode == 0)
1504 {
1505 m_enmState = State_NoGuestAdditions;
1506 return;
1507 }
1508 else if (iGADetectCode == -1)
1509 {
1510 m_enmState = State_GuestAdditionsTooOld;
1511 return;
1512 }
1513
1514 if (!m_comGuestSession.isNull() && m_comGuestSession.GetStatus() == KGuestSessionStatus_Started)
1515 {
1516 m_enmState = State_SessionRunning;
1517 return;
1518 }
1519 if (!m_comGuestSession.isNull() && m_comGuestSession.GetStatus() == KGuestSessionStatus_Error)
1520 {
1521 m_enmState = State_SessionError;
1522 return;
1523 }
1524 m_enmState = State_SessionPossible;
1525}
1526
1527void UIFileManagerGuestTable::setStateAndEnableWidgets()
1528{
1529 setState();
1530 setSessionDependentWidgetsEnabled();
1531 sltRetranslateUI();
1532}
1533
1534void UIFileManagerGuestTable::sltHandleCloseSessionRequest()
1535{
1536 cleanupGuestSessionListener();
1537 closeGuestSession();
1538 setStateAndEnableWidgets();
1539}
1540
1541void UIFileManagerGuestTable::sltCommitDataSignalReceived()
1542{
1543 cleanAll();
1544 if (!m_comMachine.isNull())
1545 m_comMachine.detach();
1546}
1547
1548void UIFileManagerGuestTable::sltAdditionsStateChange()
1549{
1550 setStateAndEnableWidgets();
1551}
1552
1553void UIFileManagerGuestTable::setSessionDependentWidgetsEnabled()
1554{
1555 /* Disable menu actions if guest session is not running: */
1556 UIMenu *pGuestSubmenu = m_pActionPool->action(UIActionIndex_M_FileManager_M_GuestSubmenu)->menu();
1557 if (pGuestSubmenu)
1558 pGuestSubmenu->setEnabled(m_enmState == State_SessionRunning);
1559 UIMenu *pHostSubmenu = m_pActionPool->action(UIActionIndex_M_FileManager_M_HostSubmenu)->menu();
1560 if (pHostSubmenu)
1561 pHostSubmenu->setEnabled(m_enmState == State_SessionRunning);
1562
1563 /*Manage the guest session (login) widget: */
1564 if (m_pGuestSessionWidget)
1565 {
1566 m_pGuestSessionWidget->setLoginWidgetsEnabled(m_enmState == State_SessionPossible ||
1567 m_enmState == State_SessionRunning ||
1568 m_enmState == State_SessionError);
1569 if (m_enmState == State_SessionPossible)
1570 m_pGuestSessionWidget->switchSessionOpenMode();
1571 else if (m_enmState == State_SessionRunning)
1572 m_pGuestSessionWidget->switchSessionCloseMode();
1573 }
1574 /* Call to parent: */
1575 setSessionWidgetsEnabled(m_enmState == State_SessionRunning);
1576
1577 emit sigStateChanged(m_enmState == State_SessionRunning);
1578}
1579
1580bool UIFileManagerGuestTable::isWindowsFileSystem() const
1581{
1582 if (!m_comMachine.isOk())
1583 return false;
1584 return m_comMachine.GetOSTypeId().contains("windows", Qt::CaseInsensitive);
1585}
1586
1587bool UIFileManagerGuestTable::openGuestSession(const QString &strUserName, const QString &strPassword)
1588{
1589 if (m_comGuest.isNull())
1590 {
1591 emit sigLogOutput("Guest reference is invalid", m_strTableName, FileManagerLogType_Error);
1592 return false;
1593 }
1594
1595 int iGADetectCode = isGuestAdditionsAvailable(pszMinimumGuestAdditionVersion);
1596 if (iGADetectCode == 0)
1597 {
1598 emit sigLogOutput("Could not find Guest Additions",
1599 m_strTableName, FileManagerLogType_Error);
1600 if (m_pGuestSessionWidget)
1601 m_pGuestSessionWidget->markForError(true);
1602 return false;
1603 }
1604 else if (iGADetectCode == -1)
1605 {
1606 emit sigLogOutput(QString("%1 %2").arg("The Guest Additions are older than ").arg(pszMinimumGuestAdditionVersion),
1607 m_strTableName, FileManagerLogType_Error);
1608 if (m_pGuestSessionWidget)
1609 m_pGuestSessionWidget->markForError(true);
1610 return false;
1611 }
1612
1613 m_comGuestSession = m_comGuest.CreateSession(strUserName, strPassword,
1614 QString() /* Domain */, "File Manager Session");
1615 if (m_comGuestSession.isNull())
1616 {
1617 emit sigLogOutput("Could not create guest session", m_strTableName, FileManagerLogType_Error);
1618 return false;
1619 }
1620
1621 if (!m_comGuestSession.isOk())
1622 {
1623 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
1624 return false;
1625 }
1626
1627 QVector<KVBoxEventType> eventTypes(QVector<KVBoxEventType>() << KVBoxEventType_OnGuestSessionStateChanged);
1628 prepareListener(m_pQtSessionListener, m_comSessionListener, m_comGuestSession.GetEventSource(), eventTypes);
1629 qRegisterMetaType<CGuestSessionStateChangedEvent>();
1630 connect(m_pQtSessionListener->getWrapped(), &UIMainEventListener::sigGuestSessionStatedChanged,
1631 this, &UIFileManagerGuestTable::sltGuestSessionStateChanged);
1632
1633 return true;
1634}
1635
1636void UIFileManagerGuestTable::closeGuestSession()
1637{
1638 if (!m_comGuestSession.isNull())
1639 {
1640 m_comGuestSession.Close();
1641 m_comGuestSession.detach();
1642 emit sigLogOutput("Guest session is closed", m_strTableName, FileManagerLogType_Info);
1643 }
1644 reset();
1645}
1646
1647void UIFileManagerGuestTable::cleanAll()
1648{
1649 cleanupConsoleListener();
1650 cleanupGuestListener();
1651 cleanupGuestSessionListener();
1652
1653 closeGuestSession();
1654 closeMachineSession();
1655}
1656
1657#include "UIFileManagerGuestTable.moc"
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use