VirtualBox

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

Last change on this file since 102493 was 102485, checked in by vboxsync, 9 months ago

FE/Qt: bugref:10561. Some refactoring.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette