VirtualBox

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

Last change on this file since 100347 was 100324, checked in by vboxsync, 19 months ago

FE/Qt: bugref:6699, bugref:9080. A bit better API for forward/backward action toggle.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.4 KB
Line 
1/* $Id: UIFileManagerGuestTable.cpp 100324 2023-06-28 12:35:20Z 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 "UICustomFileSystemModel.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 if (!m_comMachine.isNull())
430 m_strTableName = m_comMachine.GetName();
431 prepareToolbar();
432 prepareGuestSessionPanel();
433 prepareActionConnections();
434
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
516void UIFileManagerGuestTable::readDirectory(const QString& strPath,
517 UICustomFileSystemItem *parent, bool isStartDir /*= false*/)
518{
519 if (!parent)
520 return;
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;
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, UICustomFileSystemItem*> 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 UICustomFileSystemItem *item = new UICustomFileSystemItem(fsInfo.GetName(), parent, fsObjectType);
565 if (!item)
566 continue;
567 item->setData(static_cast<qulonglong>(fsInfo.GetObjectSize()), UICustomFileSystemModelData_Size);
568 item->setData(changeTime, UICustomFileSystemModelData_ChangeTime);
569 item->setData(fsInfo.GetUserName(), UICustomFileSystemModelData_Owner);
570 item->setData(permissionString(fsInfo), UICustomFileSystemModelData_Permissions);
571 item->setPath(UIPathOperations::removeTrailingDelimiters(UIPathOperations::mergePaths(strPath, fsInfo.GetName())));
572 item->setIsOpened(false);
573 item->setIsHidden(isFileObjectHidden(fsInfo));
574 fileObjects.insert(fsInfo.GetName(), item);
575 /* @todo. We will need to wait a fully implemented SymlinkRead function
576 * to be able to handle sym links properly: */
577 // QString path = UIPathOperations::mergePaths(strPath, fsInfo.GetName());
578 // QVector<KSymlinkReadFlag> aFlags;
579 // printf("%s %s %s\n", qPrintable(fsInfo.GetName()), qPrintable(path),
580 // qPrintable(m_comGuestSession.SymlinkRead(path, aFlags)));
581 }
582 }
583
584 if (fUseRead)
585 {
586 CFsObjInfo fsInfo = directory.Read();
587 if (directory.isOk())
588 {
589 vecFsInfo.clear();
590 vecFsInfo.push_back(fsInfo);
591 }
592 }
593 else
594 vecFsInfo = directory.List(cMaxEntries);
595 }
596
597 checkDotDot(fileObjects, parent, isStartDir);
598 }
599
600 directory.Close();
601}
602
603void UIFileManagerGuestTable::deleteByItem(UICustomFileSystemItem *item)
604{
605 if (!item)
606 return;
607 if (item->isUpDirectory())
608 return;
609
610 if (item->isDirectory())
611 {
612 QVector<KDirectoryRemoveRecFlag> aFlags(1, KDirectoryRemoveRecFlag_ContentAndDir);
613 m_comGuestSession.DirectoryRemoveRecursive(item->path(), aFlags);
614 }
615 else
616 m_comGuestSession.FsObjRemove(item->path());
617 if (!m_comGuestSession.isOk())
618 {
619 emit sigLogOutput(QString(item->path()).append(" could not be deleted"), m_strTableName, FileManagerLogType_Error);
620 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
621 }
622}
623
624void UIFileManagerGuestTable::deleteByPath(const QStringList &pathList)
625{
626 foreach (const QString &strPath, pathList)
627 {
628 CGuestFsObjInfo fileInfo = m_comGuestSession.FsObjQueryInfo(strPath, true);
629 KFsObjType eType = fileType(fileInfo);
630 if (eType == KFsObjType_File || eType == KFsObjType_Symlink)
631 {
632 m_comGuestSession.FsObjRemove(strPath);
633 }
634 else if (eType == KFsObjType_Directory)
635 {
636 QVector<KDirectoryRemoveRecFlag> aFlags(1, KDirectoryRemoveRecFlag_ContentAndDir);
637 m_comGuestSession.DirectoryRemoveRecursive(strPath, aFlags);
638 }
639 }
640}
641
642void UIFileManagerGuestTable::goToHomeDirectory()
643{
644 if (m_comGuestSession.isNull())
645 return;
646 if (!rootItem() || rootItem()->childCount() <= 0)
647 return;
648 UICustomFileSystemItem *startDirItem = rootItem()->child(0);
649 if (!startDirItem)
650 return;
651
652 QString userHome = UIPathOperations::sanitize(m_comGuestSession.GetUserHome());
653 if (!m_comGuestSession.isOk())
654 {
655 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
656 return;
657 }
658#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
659 QStringList pathList = userHome.split(UIPathOperations::delimiter, Qt::SkipEmptyParts);
660#else
661 QStringList pathList = userHome.split(UIPathOperations::delimiter, QString::SkipEmptyParts);
662#endif
663 goIntoDirectory(UIPathOperations::pathTrail(userHome));
664}
665
666bool UIFileManagerGuestTable::renameItem(UICustomFileSystemItem *item, QString newBaseName)
667{
668
669 if (!item || item->isUpDirectory() || newBaseName.isEmpty())
670 return false;
671 QString newPath = UIPathOperations::removeTrailingDelimiters(UIPathOperations::constructNewItemPath(item->path(), newBaseName));
672 QVector<KFsObjRenameFlag> aFlags(1, KFsObjRenameFlag_Replace);
673
674 m_comGuestSession.FsObjRename(item->path(), newPath, aFlags);
675
676 if (!m_comGuestSession.isOk())
677 {
678 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
679 return false;
680 }
681 item->setPath(newPath);
682 return true;
683}
684
685bool UIFileManagerGuestTable::createDirectory(const QString &path, const QString &directoryName)
686{
687 QString newDirectoryPath = UIPathOperations::mergePaths(path, directoryName);
688 QVector<KDirectoryCreateFlag> flags(1, KDirectoryCreateFlag_None);
689
690 m_comGuestSession.DirectoryCreate(newDirectoryPath, 0/*aMode*/, flags);
691
692 if (!m_comGuestSession.isOk())
693 {
694 emit sigLogOutput(newDirectoryPath.append(" could not be created"), m_strTableName, FileManagerLogType_Error);
695 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
696 return false;
697 }
698 emit sigLogOutput(newDirectoryPath.append(" has been created"), m_strTableName, FileManagerLogType_Info);
699 return true;
700}
701
702void UIFileManagerGuestTable::copyHostToGuest(const QStringList &hostSourcePathList,
703 const QString &strDestination /* = QString() */)
704{
705 if (!checkGuestSession())
706 return;
707 QVector<QString> sourcePaths = hostSourcePathList.toVector();
708 QVector<QString> aFilters;
709 QVector<QString> aFlags;
710 QString strDestinationPath = strDestination;
711
712 /* Remove empty source paths. Typically happens when up directory is selected: */
713 sourcePaths.removeAll(QString());
714
715 if (strDestinationPath.isEmpty())
716 strDestinationPath = currentDirectoryPath();
717
718 if (strDestinationPath.isEmpty())
719 {
720 emit sigLogOutput("No destination for copy operation", m_strTableName, FileManagerLogType_Error);
721 return;
722 }
723 if (sourcePaths.empty())
724 {
725 emit sigLogOutput("No source for copy operation", m_strTableName, FileManagerLogType_Error);
726 return;
727 }
728 QString strDirectoryFlags("CopyIntoExisting,Recursive,FollowLinks");
729 QString strFileFlags("FollowLinks");
730 foreach (const QString &strSource, sourcePaths)
731 {
732 KFsObjType enmFileType = UIFileManagerHostTable::fileType(strSource);
733 if (enmFileType == KFsObjType_Unknown)
734 emit sigLogOutput(QString("Querying information for host item %1 failed.").arg(strSource), m_strTableName, FileManagerLogType_Error);
735 /* If the source is an directory, make sure to add the appropriate flag to make copying work
736 * into existing directories on the guest. This otherwise would fail (default): */
737 else if (enmFileType == KFsObjType_Directory)
738 {
739 /* Make sure that if the source is a directory, that we append a trailing delimiter to it,
740 * so that it gets copied *into* the destination directory as a whole, and not just it's contents. */
741 strDestinationPath = UIPathOperations::addTrailingDelimiters(strDestinationPath);
742 aFlags << strDirectoryFlags;
743 }
744 else
745 {
746 /* Ditto goes for source files, as the destination always is a directory path. */
747 strDestinationPath = UIPathOperations::addTrailingDelimiters(strDestinationPath);
748 aFlags << strFileFlags;
749 }
750 }
751
752 CProgress progress = m_comGuestSession.CopyToGuest(sourcePaths, aFilters, aFlags, strDestinationPath);
753 if (!checkGuestSession())
754 return;
755 emit sigNewFileOperation(progress, m_strTableName);
756}
757
758QUuid UIFileManagerGuestTable::machineId()
759{
760 if (m_comMachine.isNull())
761 return QUuid();
762 return m_comMachine.GetId();
763}
764
765bool UIFileManagerGuestTable::isGuestSessionRunning() const
766{
767 return m_enmState == State_SessionRunning;
768}
769
770void UIFileManagerGuestTable::setIsCurrent(bool fIsCurrent)
771{
772 if (m_fIsCurrent == fIsCurrent)
773 return;
774 m_fIsCurrent = fIsCurrent;
775 prepareActionConnections();
776}
777
778void UIFileManagerGuestTable::copyGuestToHost(const QString& hostDestinationPath)
779{
780 if (!checkGuestSession())
781 return;
782 QVector<QString> sourcePaths = selectedItemPathList().toVector();
783 QVector<QString> aFilters;
784 QVector<QString> aFlags;
785
786 /* Remove empty source paths. Typically happens when up directory is selected: */
787 sourcePaths.removeAll(QString());
788
789 if (hostDestinationPath.isEmpty())
790 {
791 emit sigLogOutput("No destination for copy operation", m_strTableName, FileManagerLogType_Error);
792 return;
793 }
794 if (sourcePaths.empty())
795 {
796 emit sigLogOutput("No source for copy operation", m_strTableName, FileManagerLogType_Error);
797 return;
798 }
799
800 QString strDestinationPath = hostDestinationPath;
801 QString strDirectoryFlags("CopyIntoExisting,Recursive,FollowLinks");
802 QString strFileFlags;
803 foreach (const QString &strSource, sourcePaths)
804 {
805 /** @todo Cache this info and use the item directly, which has this info already? */
806
807 /* If the source is an directory, make sure to add the appropriate flag to make copying work
808 * into existing directories on the guest. This otherwise would fail (default). */
809 CGuestFsObjInfo fileInfo = m_comGuestSession.FsObjQueryInfo(strSource, true);
810 if (!m_comGuestSession.isOk())
811 {
812 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
813 return;
814 }
815
816 if (fileType(fileInfo) == KFsObjType_Directory)
817 {
818 /* Make sure that if the source is a directory, that we append a trailing delimiter to the destination,
819 * so that the source directory gets copied *into* the destination directory as a whole, and not
820 * just it's contents. */
821 strDestinationPath = UIPathOperations::addTrailingDelimiters(strDestinationPath);
822 aFlags << strDirectoryFlags;
823 }
824 else
825 {
826 /* Ditto goes for source files, as the destination always is a directory path. */
827 strDestinationPath = UIPathOperations::addTrailingDelimiters(strDestinationPath);
828 aFlags << strFileFlags;
829 }
830 }
831
832 CProgress progress = m_comGuestSession.CopyFromGuest(sourcePaths, aFilters, aFlags, strDestinationPath);
833 if (!checkGuestSession())
834 return;
835 emit sigNewFileOperation(progress, m_strTableName);
836}
837
838KFsObjType UIFileManagerGuestTable::fileType(const CFsObjInfo &fsInfo)
839{
840 if (fsInfo.isNull() || !fsInfo.isOk())
841 return KFsObjType_Unknown;
842 if (fsInfo.GetType() == KFsObjType_Directory)
843 return KFsObjType_Directory;
844 else if (fsInfo.GetType() == KFsObjType_File)
845 return KFsObjType_File;
846 else if (fsInfo.GetType() == KFsObjType_Symlink)
847 return KFsObjType_Symlink;
848
849 return KFsObjType_Unknown;
850}
851
852KFsObjType UIFileManagerGuestTable::fileType(const CGuestFsObjInfo &fsInfo)
853{
854 if (fsInfo.isNull() || !fsInfo.isOk())
855 return KFsObjType_Unknown;
856 if (fsInfo.GetType() == KFsObjType_Directory)
857 return KFsObjType_Directory;
858 else if (fsInfo.GetType() == KFsObjType_File)
859 return KFsObjType_File;
860 else if (fsInfo.GetType() == KFsObjType_Symlink)
861 return KFsObjType_Symlink;
862
863 return KFsObjType_Unknown;
864}
865
866
867QString UIFileManagerGuestTable::fsObjectPropertyString()
868{
869 QStringList selectedObjects = selectedItemPathList();
870 if (selectedObjects.isEmpty())
871 return QString();
872 if (selectedObjects.size() == 1)
873 {
874 if (selectedObjects.at(0).isNull())
875 return QString();
876
877 CGuestFsObjInfo fileInfo = m_comGuestSession.FsObjQueryInfo(selectedObjects.at(0), false /*aFollowSymlinks*/);
878 if (!m_comGuestSession.isOk())
879 {
880 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
881 return QString();
882 }
883
884 QStringList propertyStringList;
885
886 /* Name: */
887 propertyStringList << UIFileManager::tr("<b>Name:</b> %1<br/>").arg(UIPathOperations::getObjectName(fileInfo.GetName()));
888
889 /* Size: */
890 LONG64 size = fileInfo.GetObjectSize();
891 propertyStringList << UIFileManager::tr("<b>Size:</b> %1 bytes").arg(QString::number(size));
892 if (size >= UIFileManagerTable::m_iKiloByte)
893 propertyStringList << QString(" (%1)<br/>").arg(humanReadableSize(size));
894 else
895 propertyStringList << QString("<br/>");
896
897 /* Allocated size: */
898 size = fileInfo.GetAllocatedSize();
899 propertyStringList << UIFileManager::tr("<b>Allocated:</b> %1 bytes").arg(QString::number(size));
900 if (size >= UIFileManagerTable::m_iKiloByte)
901 propertyStringList << QString(" (%1)<br/>").arg(humanReadableSize(size));
902 else
903 propertyStringList << QString("<br/>");
904
905 /* Type: */
906 QString str;
907 KFsObjType const enmType = fileInfo.GetType();
908 switch (enmType)
909 {
910 case KFsObjType_Directory: str = UIFileManager::tr("directory"); break;
911 case KFsObjType_File: str = UIFileManager::tr("file"); break;
912 case KFsObjType_Symlink: str = UIFileManager::tr("symbolic link"); break;
913 case KFsObjType_DevChar: str = UIFileManager::tr("character device"); break;
914 case KFsObjType_DevBlock: str = UIFileManager::tr("block device"); break;
915 case KFsObjType_Fifo: str = UIFileManager::tr("fifo"); break;
916 case KFsObjType_Socket: str = UIFileManager::tr("socket"); break;
917 case KFsObjType_WhiteOut: str = UIFileManager::tr("whiteout"); break;
918 case KFsObjType_Unknown: str = UIFileManager::tr("unknown"); break;
919 default: str = UIFileManager::tr("illegal-value"); break;
920 }
921 propertyStringList << UIFileManager::tr("<b>Type:</b> %1<br/>").arg(str);
922
923 /* INode number, device, link count: */
924 propertyStringList << UIFileManager::tr("<b>INode:</b> %1<br/>").arg(fileInfo.GetNodeId());
925 propertyStringList << UIFileManager::tr("<b>Device:</b> %1<br/>").arg(fileInfo.GetNodeIdDevice()); /** @todo hex */
926 propertyStringList << UIFileManager::tr("<b>Hardlinks:</b> %1<br/>").arg(fileInfo.GetHardLinks());
927
928 /* Attributes: */
929 str = fileInfo.GetFileAttributes();
930 if (!str.isEmpty())
931 {
932 int offSpace = str.indexOf(' ');
933 if (offSpace < 0)
934 offSpace = str.length();
935 propertyStringList << UIFileManager::tr("<b>Mode:</b> %1<br/>").arg(str.left(offSpace));
936 propertyStringList << UIFileManager::tr("<b>Attributes:</b> %1<br/>").arg(str.mid(offSpace + 1).trimmed());
937 }
938
939 /* Character/block device ID: */
940 ULONG uDeviceNo = fileInfo.GetDeviceNumber();
941 if (uDeviceNo != 0 || enmType == KFsObjType_DevChar || enmType == KFsObjType_DevBlock)
942 propertyStringList << UIFileManager::tr("<b>Device ID:</b> %1<br/>").arg(uDeviceNo); /** @todo hex */
943
944 /* Owner: */
945 propertyStringList << UIFileManager::tr("<b>Owner:</b> %1 (%2)<br/>").
946 arg(fileInfo.GetUserName()).arg(fileInfo.GetUID());
947 propertyStringList << UIFileManager::tr("<b>Group:</b> %1 (%2)<br/>").
948 arg(fileInfo.GetGroupName()).arg(fileInfo.GetGID());
949
950 /* Timestamps: */
951 propertyStringList << UIFileManager::tr("<b>Birth:</b> %1<br/>").
952 arg(QDateTime::fromMSecsSinceEpoch(fileInfo.GetBirthTime() / RT_NS_1MS).toString());
953 propertyStringList << UIFileManager::tr("<b>Change:</b> %1<br/>").
954 arg(QDateTime::fromMSecsSinceEpoch(fileInfo.GetChangeTime() / RT_NS_1MS).toString());
955 propertyStringList << UIFileManager::tr("<b>Modified:</b> %1<br/>").
956 arg(QDateTime::fromMSecsSinceEpoch(fileInfo.GetModificationTime() / RT_NS_1MS).toString());
957 propertyStringList << UIFileManager::tr("<b>Access:</b> %1<br/>").
958 arg(QDateTime::fromMSecsSinceEpoch(fileInfo.GetAccessTime() / RT_NS_1MS).toString());
959
960 /* Join the list elements into a single string seperated by empty string: */
961 return propertyStringList.join(QString());
962 }
963
964 int fileCount = 0;
965 int directoryCount = 0;
966 ULONG64 totalSize = 0;
967
968 for(int i = 0; i < selectedObjects.size(); ++i)
969 {
970 CGuestFsObjInfo fileInfo = m_comGuestSession.FsObjQueryInfo(selectedObjects.at(0), true);
971 if (!m_comGuestSession.isOk())
972 {
973 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
974 continue;
975 }
976
977 KFsObjType type = fileType(fileInfo);
978
979 if (type == KFsObjType_File)
980 ++fileCount;
981 if (type == KFsObjType_Directory)
982 ++directoryCount;
983 totalSize += fileInfo.GetObjectSize();
984 }
985 QStringList propertyStringList;
986 propertyStringList << UIFileManager::tr("<b>Selected:</b> %1 files and %2 directories<br/>").
987 arg(QString::number(fileCount)).arg(QString::number(directoryCount));
988 propertyStringList << UIFileManager::tr("<b>Size (non-recursive):</b> %1 bytes").arg(QString::number(totalSize));
989 if (totalSize >= m_iKiloByte)
990 propertyStringList << QString(" (%1)").arg(humanReadableSize(totalSize));
991
992 return propertyStringList.join(QString());;
993}
994
995void UIFileManagerGuestTable::showProperties()
996{
997 if (m_comGuestSession.isNull())
998 return;
999 QString fsPropertyString = fsObjectPropertyString();
1000 if (fsPropertyString.isEmpty())
1001 return;
1002
1003 m_pPropertiesDialog = new UIPropertiesDialog(this);
1004 if (!m_pPropertiesDialog)
1005 return;
1006
1007 QStringList selectedObjects = selectedItemPathList();
1008 if (selectedObjects.size() == 0)
1009 return;
1010
1011 m_pPropertiesDialog->setWindowTitle(UIFileManager::tr("Properties"));
1012 m_pPropertiesDialog->setPropertyText(fsPropertyString);
1013 m_pPropertiesDialog->execute();
1014
1015 delete m_pPropertiesDialog;
1016 m_pPropertiesDialog = 0;
1017}
1018
1019void UIFileManagerGuestTable::determineDriveLetters()
1020{
1021 if (m_comGuestSession.isNull())
1022 return;
1023 KPathStyle pathStyle = m_comGuestSession.GetPathStyle();
1024 if (pathStyle != KPathStyle_DOS)
1025 return;
1026
1027 /** @todo Currently API lacks a way to query windows drive letters.
1028 * so we enumarate them by using CGuestSession::DirectoryExists() */
1029 m_driveLetterList.clear();
1030 for (int i = 'A'; i <= 'Z'; ++i)
1031 {
1032 QString path((char)i);
1033 path += ":/";
1034 bool exists = m_comGuestSession.DirectoryExists(path, false /* aFollowSymlinks */);
1035 if (exists)
1036 m_driveLetterList.push_back(path);
1037 }
1038}
1039
1040void UIFileManagerGuestTable::determinePathSeparator()
1041{
1042 if (m_comGuestSession.isNull())
1043 return;
1044 KPathStyle pathStyle = m_comGuestSession.GetPathStyle();
1045 if (pathStyle == KPathStyle_DOS)
1046 setPathSeparator(UIPathOperations::dosDelimiter);
1047}
1048
1049void UIFileManagerGuestTable::prepareToolbar()
1050{
1051 if (m_pToolBar && m_pActionPool)
1052 {
1053 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoBackward));
1054 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoForward));
1055 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoUp));
1056 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoHome));
1057 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Refresh));
1058 m_pToolBar->addSeparator();
1059 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Delete));
1060 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Rename));
1061 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_CreateNewDirectory));
1062
1063 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Copy));
1064 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Cut));
1065 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Paste));
1066 m_pToolBar->addSeparator();
1067 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_SelectAll));
1068 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_InvertSelection));
1069 m_pToolBar->addSeparator();
1070 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_ShowProperties));
1071 m_selectionDependentActions.insert(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Delete));
1072 m_selectionDependentActions.insert(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Rename));
1073 m_selectionDependentActions.insert(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Copy));
1074 m_selectionDependentActions.insert(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Cut));
1075 m_selectionDependentActions.insert(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_ShowProperties));
1076
1077 /* Hide these actions for now until we have a suitable guest-to-guest copy function: */
1078 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Copy)->setVisible(false);
1079 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Cut)->setVisible(false);
1080 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Paste)->setVisible(false);
1081
1082 m_pToolBar->addSeparator();
1083 m_pToolBar->addAction(m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession));
1084 }
1085
1086 setSelectionDependentActionsEnabled(false);
1087 setPasteActionEnabled(false);
1088}
1089
1090void UIFileManagerGuestTable::createFileViewContextMenu(const QWidget *pWidget, const QPoint &point)
1091{
1092 if (!pWidget)
1093 return;
1094
1095 QMenu menu;
1096 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoBackward));
1097 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoForward));
1098 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoUp));
1099
1100 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoHome));
1101 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Refresh));
1102 menu.addSeparator();
1103 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Delete));
1104 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Rename));
1105 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_CreateNewDirectory));
1106 menu.addSeparator();
1107 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Copy));
1108 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Cut));
1109 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Paste));
1110 menu.addSeparator();
1111 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_SelectAll));
1112 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_InvertSelection));
1113 menu.addSeparator();
1114 menu.addAction(m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_ShowProperties));
1115 menu.exec(pWidget->mapToGlobal(point));
1116}
1117
1118void UIFileManagerGuestTable::setPasteActionEnabled(bool fEnabled)
1119{
1120 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Paste)->setEnabled(fEnabled);
1121}
1122
1123void UIFileManagerGuestTable::pasteCutCopiedObjects()
1124{
1125}
1126
1127void UIFileManagerGuestTable::manageConnection(bool fConnect, QAction *pAction, void (UIFileManagerGuestTable::*fptr)(void))
1128{
1129 if (!pAction || !fptr)
1130 return;
1131 if (fConnect)
1132 connect(pAction, &QAction::triggered, this, fptr);
1133 else
1134 disconnect(pAction, 0, this, 0);
1135}
1136
1137void UIFileManagerGuestTable::prepareActionConnections()
1138{
1139 if (m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession))
1140 {
1141 if (m_fIsCurrent)
1142 connect(m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession), &QAction::toggled,
1143 this, &UIFileManagerGuestTable::sltGuestSessionPanelToggled);
1144 else
1145 disconnect(m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession), 0, this, 0);
1146 }
1147
1148 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoUp), &UIFileManagerTable::sltGoUp);
1149 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoHome), &UIFileManagerTable::sltGoHome);
1150 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoBackward), &UIFileManagerTable::sltGoBackward);
1151 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoForward), &UIFileManagerTable::sltGoForward);
1152 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Refresh), &UIFileManagerTable::sltRefresh);
1153 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Delete), &UIFileManagerTable::sltDelete);
1154 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Rename), &UIFileManagerTable::sltRename);
1155 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Copy), &UIFileManagerTable::sltCopy);
1156 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Cut), &UIFileManagerTable::sltCut);
1157 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_Paste), &UIFileManagerTable::sltPaste);
1158 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_SelectAll), &UIFileManagerTable::sltSelectAll);
1159 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_InvertSelection), &UIFileManagerTable::sltInvertSelection);
1160 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_ShowProperties), &UIFileManagerTable::sltShowProperties);
1161 manageConnection(m_fIsCurrent, m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_CreateNewDirectory), &UIFileManagerTable::sltCreateNewDirectory);
1162
1163 /* Also disable/enable go forward/backward actions: */
1164 toggleForwardBackwardActions();
1165}
1166
1167void UIFileManagerGuestTable::prepareGuestSessionPanel()
1168{
1169 if (m_pMainLayout)
1170 {
1171 m_pGuestSessionWidget = new UIGuestSessionWidget;
1172 if (m_pGuestSessionWidget)
1173 {
1174 m_pMainLayout->addWidget(m_pGuestSessionWidget, m_pMainLayout->rowCount(), 0, 1, m_pMainLayout->columnCount());
1175 m_pGuestSessionWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
1176 connect(m_pGuestSessionWidget, &UIGuestSessionWidget::sigOpenSession,
1177 this, &UIFileManagerGuestTable::sltOpenGuestSession);
1178 connect(m_pGuestSessionWidget, &UIGuestSessionWidget::sigCloseSession,
1179 this, &UIFileManagerGuestTable::sltHandleCloseSessionRequest);
1180 }
1181 }
1182}
1183
1184bool UIFileManagerGuestTable::checkGuestSession()
1185{
1186 if (!m_comGuestSession.isOk())
1187 {
1188 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
1189 return false;
1190 }
1191 return true;
1192}
1193
1194QString UIFileManagerGuestTable::permissionString(const CFsObjInfo &fsInfo)
1195{
1196 /* Attributes: */
1197 QString strAttributes = fsInfo.GetFileAttributes();
1198
1199 if (strAttributes.isEmpty())
1200 return strAttributes;
1201
1202 int offSpace = strAttributes.indexOf(' ');
1203 if (offSpace < 0)
1204 offSpace = strAttributes.length();
1205 return strAttributes.left(offSpace);
1206}
1207
1208bool UIFileManagerGuestTable::isFileObjectHidden(const CFsObjInfo &fsInfo)
1209{
1210 QString strAttributes = fsInfo.GetFileAttributes();
1211
1212 if (strAttributes.isEmpty())
1213 return false;
1214
1215 int offSpace = strAttributes.indexOf(' ');
1216 if (offSpace < 0)
1217 offSpace = strAttributes.length();
1218 QString strRight(strAttributes.mid(offSpace + 1).trimmed());
1219
1220 if (strRight.indexOf('H', Qt::CaseSensitive) == -1)
1221 return false;
1222 return true;
1223}
1224
1225void UIFileManagerGuestTable::sltGuestSessionPanelToggled(bool fChecked)
1226{
1227 if (m_pGuestSessionWidget)
1228 m_pGuestSessionWidget->setVisible(fChecked);
1229}
1230
1231void UIFileManagerGuestTable::sltMachineStateChange(const QUuid &uMachineId, const KMachineState enmMachineState)
1232{
1233 if (uMachineId.isNull() || m_comMachine.isNull() || uMachineId != m_comMachine.GetId())
1234 return;
1235
1236 if (enmMachineState == KMachineState_Running)
1237 openMachineSession();
1238 else if (enmMachineState != KMachineState_Paused)
1239 cleanAll();
1240 setStateAndEnableWidgets();
1241}
1242
1243bool UIFileManagerGuestTable::closeMachineSession()
1244{
1245 if (!m_comGuest.isNull())
1246 m_comGuest.detach();
1247
1248 if (!m_comConsole.isNull())
1249 m_comConsole.detach();
1250
1251 if (!m_comSession.isNull())
1252 {
1253 m_comSession.UnlockMachine();
1254 m_comSession.detach();
1255 }
1256 return true;
1257}
1258
1259bool UIFileManagerGuestTable::openMachineSession()
1260{
1261 if (m_comMachine.isNull())
1262 {
1263 emit sigLogOutput("Invalid machine reference", m_strTableName, FileManagerLogType_Error);
1264 return false;
1265 }
1266 m_comSession = uiCommon().openSession(m_comMachine.GetId(), KLockType_Shared);
1267 if (m_comSession.isNull())
1268 {
1269 emit sigLogOutput("Could not open machine session", m_strTableName, FileManagerLogType_Error);
1270 return false;
1271 }
1272
1273 m_comConsole = m_comSession.GetConsole();
1274 if (m_comConsole.isNull())
1275 {
1276 emit sigLogOutput("Machine console is invalid", m_strTableName, FileManagerLogType_Error);
1277 return false;
1278 }
1279
1280 m_comGuest = m_comConsole.GetGuest();
1281 if (m_comGuest.isNull())
1282 {
1283 emit sigLogOutput("Guest reference is invalid", m_strTableName, FileManagerLogType_Error);
1284 return false;
1285 }
1286
1287 /* Prepare guest listener for guest session related events: */
1288 {
1289 QVector<KVBoxEventType> eventTypes;
1290 eventTypes << KVBoxEventType_OnGuestSessionRegistered;
1291 prepareListener(m_pQtGuestListener, m_comGuestListener, m_comGuest.GetEventSource(), eventTypes);
1292 connect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionUnregistered,
1293 this, &UIFileManagerGuestTable::sltGuestSessionUnregistered);
1294 connect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionRegistered,
1295 this, &UIFileManagerGuestTable::sltGuestSessionRegistered);
1296 }
1297
1298 /* Prepare console listener for guest additions state change events: */
1299 {
1300 QVector<KVBoxEventType> eventTypes;
1301 eventTypes << KVBoxEventType_OnAdditionsStateChanged;
1302 prepareListener(m_pQtConsoleListener, m_comConsoleListener, m_comConsole.GetEventSource(), eventTypes);
1303 connect(m_pQtConsoleListener->getWrapped(), &UIMainEventListener::sigAdditionsChange,
1304 this, &UIFileManagerGuestTable::sltAdditionsStateChange);
1305 }
1306 emit sigLogOutput("Shared machine session opened", m_strTableName, FileManagerLogType_Info);
1307 return true;
1308}
1309
1310int UIFileManagerGuestTable::isGuestAdditionsAvailable(const char* pszMinimumVersion)
1311{
1312 if (m_comGuest.isNull() || !pszMinimumVersion)
1313 return 0;
1314
1315 /* Guest control stuff is in userland: */
1316 if (!m_comGuest.GetAdditionsStatus(KAdditionsRunLevelType_Userland))
1317 return 0;
1318
1319 if (!m_comGuest.isOk())
1320 return 0;
1321
1322 /* Check the related GA facility: */
1323 LONG64 iLastUpdatedIgnored;
1324 if (m_comGuest.GetFacilityStatus(KAdditionsFacilityType_VBoxService, iLastUpdatedIgnored) != KAdditionsFacilityStatus_Active)
1325 return 0;
1326
1327 if (!m_comGuest.isOk())
1328 return 0;
1329
1330 /* Check if GA is new enough to have the goodies: */
1331 QString strGAVersion = m_comGuest.GetAdditionsVersion();
1332 int iCode = RTStrVersionCompare(strGAVersion.toUtf8().constData(), pszMinimumVersion);
1333 if (iCode >= 0)
1334 return 1;
1335 else
1336 return -1;
1337
1338 return 0;
1339}
1340
1341void UIFileManagerGuestTable::cleanupGuestListener()
1342{
1343 if (!m_pQtGuestListener.isNull())
1344 {
1345 m_pQtGuestListener->getWrapped()->disconnect();
1346 if (!m_comGuest.isNull())
1347 cleanupListener(m_pQtGuestListener, m_comGuestListener, m_comGuest.GetEventSource());
1348 }
1349}
1350
1351void UIFileManagerGuestTable::cleanupGuestSessionListener()
1352{
1353 if (!m_pQtSessionListener.isNull())
1354 {
1355 m_pQtSessionListener->getWrapped()->disconnect();
1356 if (!m_comGuestSession.isNull())
1357 cleanupListener(m_pQtSessionListener, m_comSessionListener, m_comGuestSession.GetEventSource());
1358 }
1359}
1360
1361void UIFileManagerGuestTable::cleanupConsoleListener()
1362{
1363 if (!m_pQtConsoleListener.isNull())
1364 {
1365 m_pQtConsoleListener->getWrapped()->disconnect();
1366 if (!m_comConsole.isNull())
1367 cleanupListener(m_pQtConsoleListener, m_comConsoleListener, m_comConsole.GetEventSource());
1368 }
1369}
1370
1371void UIFileManagerGuestTable::prepareListener(ComObjPtr<UIMainEventListenerImpl> &QtListener,
1372 CEventListener &comEventListener,
1373 CEventSource comEventSource, QVector<KVBoxEventType>& eventTypes)
1374{
1375 if (!comEventSource.isOk())
1376 return;
1377 /* Create event listener instance: */
1378 QtListener.createObject();
1379 QtListener->init(new UIMainEventListener, this);
1380 comEventListener = CEventListener(QtListener);
1381
1382 /* Register event listener for CProgress event source: */
1383 comEventSource.RegisterListener(comEventListener, eventTypes, FALSE /* active? */);
1384
1385 /* Register event sources in their listeners as well: */
1386 QtListener->getWrapped()->registerSource(comEventSource, comEventListener);
1387}
1388
1389void UIFileManagerGuestTable::cleanupListener(ComObjPtr<UIMainEventListenerImpl> &QtListener,
1390 CEventListener &comEventListener,
1391 CEventSource comEventSource)
1392{
1393 if (!comEventSource.isOk())
1394 return;
1395 /* Unregister everything: */
1396 QtListener->getWrapped()->unregisterSources();
1397 QtListener.setNull();
1398 /* Make sure VBoxSVC is available: */
1399 if (!uiCommon().isVBoxSVCAvailable())
1400 return;
1401
1402 /* Unregister event listener for CProgress event source: */
1403 comEventSource.UnregisterListener(comEventListener);
1404}
1405
1406void UIFileManagerGuestTable::sltGuestSessionUnregistered(CGuestSession guestSession)
1407{
1408 if (guestSession.isNull())
1409 return;
1410 if (guestSession == m_comGuestSession && !m_comGuestSession.isNull())
1411 {
1412 m_comGuestSession.detach();
1413 emit sigLogOutput("Guest session unregistered", m_strTableName, FileManagerLogType_Info);
1414 }
1415}
1416
1417void UIFileManagerGuestTable::sltGuestSessionRegistered(CGuestSession guestSession)
1418{
1419 if (guestSession == m_comGuestSession && !m_comGuestSession.isNull())
1420 emit sigLogOutput("Guest session registered", m_strTableName, FileManagerLogType_Info);
1421}
1422
1423void UIFileManagerGuestTable::sltGuestSessionStateChanged(const CGuestSessionStateChangedEvent &cEvent)
1424{
1425 if (cEvent.isOk())
1426 {
1427 CVirtualBoxErrorInfo cErrorInfo = cEvent.GetError();
1428 if (cErrorInfo.GetResultDetail() < VINF_SUCCESS)
1429 emit sigLogOutput(cErrorInfo.GetText(), m_strTableName, FileManagerLogType_Error);
1430
1431 if (m_pGuestSessionWidget)
1432 m_pGuestSessionWidget->markForError(cErrorInfo.GetResultDetail() == VERR_AUTHENTICATION_FAILURE);
1433 }
1434
1435 setStateAndEnableWidgets();
1436
1437 if (m_comGuestSession.isNull())
1438 emit sigLogOutput("Guest session is invalid!", m_strTableName, FileManagerLogType_Error);
1439 else
1440 {
1441 if (m_comGuestSession.isOk())
1442 {
1443 emit sigLogOutput(QString("%1: %2").arg("Guest session status has changed").arg(gpConverter->toString(m_comGuestSession.GetStatus())),
1444 m_strTableName, FileManagerLogType_Info);
1445
1446 switch (m_comGuestSession.GetStatus())
1447 {
1448 case KGuestSessionStatus_Started:
1449 {
1450 initFileTable();
1451 break;
1452 }
1453 case KGuestSessionStatus_Terminating:
1454 case KGuestSessionStatus_Terminated:
1455 case KGuestSessionStatus_TimedOutKilled:
1456 case KGuestSessionStatus_TimedOutAbnormally:
1457 case KGuestSessionStatus_Down:
1458 case KGuestSessionStatus_Error:
1459 {
1460 cleanupGuestSessionListener();
1461 closeGuestSession();
1462 break;
1463 }
1464 case KGuestSessionStatus_Undefined:
1465 case KGuestSessionStatus_Starting:
1466 case KGuestSessionStatus_Max:
1467 default:
1468 break;
1469 }
1470 }
1471 else
1472 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
1473 }
1474}
1475
1476void UIFileManagerGuestTable::sltOpenGuestSession(QString strUserName, QString strPassword)
1477{
1478 if (strUserName.isEmpty())
1479 {
1480 emit sigLogOutput("No user name is given", m_strTableName, FileManagerLogType_Error);
1481 if (m_pGuestSessionWidget)
1482 m_pGuestSessionWidget->markForError(true);
1483 return;
1484 }
1485 openGuestSession(strUserName, strPassword);
1486}
1487
1488void UIFileManagerGuestTable::toggleForwardBackwardActions()
1489{
1490 if (!m_pNavigationWidget)
1491 return;
1492 if (m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoForward))
1493 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoForward)->setEnabled(m_pNavigationWidget->canGoForward());
1494 if (m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoBackward))
1495 m_pActionPool->action(UIActionIndex_M_FileManager_S_Guest_GoBackward)->setEnabled(m_pNavigationWidget->canGoBackward());
1496}
1497
1498void UIFileManagerGuestTable::setState()
1499{
1500 if (m_comMachine.isNull())
1501 {
1502 m_enmState = State_InvalidMachineReference;
1503 return;
1504 }
1505 if (m_comMachine.GetState() == KMachineState_Paused)
1506 {
1507 m_enmState = State_MachinePaused;
1508 return;
1509 }
1510 if (m_comMachine.GetState() != KMachineState_Running)
1511 {
1512 m_enmState = State_MachineNotRunning;
1513 return;
1514 }
1515
1516 int iGADetectCode = isGuestAdditionsAvailable(pszMinimumGuestAdditionVersion);
1517 if (iGADetectCode == 0)
1518 {
1519 m_enmState = State_NoGuestAdditions;
1520 return;
1521 }
1522 else if (iGADetectCode == -1)
1523 {
1524 m_enmState = State_GuestAdditionsTooOld;
1525 return;
1526 }
1527
1528 if (!m_comGuestSession.isNull() && m_comGuestSession.GetStatus() == KGuestSessionStatus_Started)
1529 {
1530 m_enmState = State_SessionRunning;
1531 return;
1532 }
1533 if (!m_comGuestSession.isNull() && m_comGuestSession.GetStatus() == KGuestSessionStatus_Error)
1534 {
1535 m_enmState = State_SessionError;
1536 return;
1537 }
1538 m_enmState = State_SessionPossible;
1539}
1540
1541void UIFileManagerGuestTable::setStateAndEnableWidgets()
1542{
1543 setState();
1544 setSessionDependentWidgetsEnabled();
1545 retranslateUi();
1546}
1547
1548void UIFileManagerGuestTable::sltHandleCloseSessionRequest()
1549{
1550 cleanupGuestSessionListener();
1551 closeGuestSession();
1552 setStateAndEnableWidgets();
1553}
1554
1555void UIFileManagerGuestTable::sltCommitDataSignalReceived()
1556{
1557 cleanAll();
1558 if (!m_comMachine.isNull())
1559 m_comMachine.detach();
1560}
1561
1562void UIFileManagerGuestTable::sltAdditionsStateChange()
1563{
1564 setStateAndEnableWidgets();
1565}
1566
1567void UIFileManagerGuestTable::setSessionDependentWidgetsEnabled()
1568{
1569 /* Disable menu actions if guest session is not running: */
1570 UIMenu *pGuestSubmenu = m_pActionPool->action(UIActionIndex_M_FileManager_M_GuestSubmenu)->menu();
1571 if (pGuestSubmenu)
1572 pGuestSubmenu->setEnabled(m_enmState == State_SessionRunning);
1573 UIMenu *pHostSubmenu = m_pActionPool->action(UIActionIndex_M_FileManager_M_HostSubmenu)->menu();
1574 if (pHostSubmenu)
1575 pHostSubmenu->setEnabled(m_enmState == State_SessionRunning);
1576
1577 /*Manage the guest session (login) widget: */
1578 if (m_pGuestSessionWidget)
1579 {
1580 m_pGuestSessionWidget->setLoginWidgetsEnabled(m_enmState == State_SessionPossible ||
1581 m_enmState == State_SessionRunning ||
1582 m_enmState == State_SessionError);
1583 if (m_enmState == State_SessionPossible)
1584 m_pGuestSessionWidget->switchSessionOpenMode();
1585 else if (m_enmState == State_SessionRunning)
1586 m_pGuestSessionWidget->switchSessionCloseMode();
1587 }
1588 /* Call to parent: */
1589 setSessionWidgetsEnabled(m_enmState == State_SessionRunning);
1590
1591 emit sigStateChanged(m_enmState == State_SessionRunning);
1592}
1593
1594bool UIFileManagerGuestTable::openGuestSession(const QString &strUserName, const QString &strPassword)
1595{
1596 if (m_comGuest.isNull())
1597 {
1598 emit sigLogOutput("Guest reference is invalid", m_strTableName, FileManagerLogType_Error);
1599 return false;
1600 }
1601
1602 int iGADetectCode = isGuestAdditionsAvailable(pszMinimumGuestAdditionVersion);
1603 if (iGADetectCode == 0)
1604 {
1605 emit sigLogOutput("Could not find Guest Additions",
1606 m_strTableName, FileManagerLogType_Error);
1607 if (m_pGuestSessionWidget)
1608 m_pGuestSessionWidget->markForError(true);
1609 return false;
1610 }
1611 else if (iGADetectCode == -1)
1612 {
1613 emit sigLogOutput(QString("%1 %2").arg("The Guest Additions are older than ").arg(pszMinimumGuestAdditionVersion),
1614 m_strTableName, FileManagerLogType_Error);
1615 if (m_pGuestSessionWidget)
1616 m_pGuestSessionWidget->markForError(true);
1617 return false;
1618 }
1619
1620 m_comGuestSession = m_comGuest.CreateSession(strUserName, strPassword,
1621 QString() /* Domain */, "File Manager Session");
1622 if (m_comGuestSession.isNull())
1623 {
1624 emit sigLogOutput("Could not create guest session", m_strTableName, FileManagerLogType_Error);
1625 return false;
1626 }
1627
1628 if (!m_comGuestSession.isOk())
1629 {
1630 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error);
1631 return false;
1632 }
1633
1634 QVector<KVBoxEventType> eventTypes(QVector<KVBoxEventType>() << KVBoxEventType_OnGuestSessionStateChanged);
1635 prepareListener(m_pQtSessionListener, m_comSessionListener, m_comGuestSession.GetEventSource(), eventTypes);
1636 qRegisterMetaType<CGuestSessionStateChangedEvent>();
1637 connect(m_pQtSessionListener->getWrapped(), &UIMainEventListener::sigGuestSessionStatedChanged,
1638 this, &UIFileManagerGuestTable::sltGuestSessionStateChanged);
1639
1640 return true;
1641}
1642
1643void UIFileManagerGuestTable::closeGuestSession()
1644{
1645 if (!m_comGuestSession.isNull())
1646 {
1647 m_comGuestSession.Close();
1648 m_comGuestSession.detach();
1649 emit sigLogOutput("Guest session is closed", m_strTableName, FileManagerLogType_Info);
1650 }
1651 reset();
1652}
1653
1654void UIFileManagerGuestTable::cleanAll()
1655{
1656 cleanupConsoleListener();
1657 cleanupGuestListener();
1658 cleanupGuestSessionListener();
1659
1660 closeGuestSession();
1661 closeMachineSession();
1662}
1663
1664#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