VirtualBox

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

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

FE/Qt: bugref:6699. Adding icons and slots to go forward and backward actions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.9 KB
Line 
1/* $Id: UIFileManagerTable.cpp 100304 2023-06-27 19:44:47Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIFileManagerTable 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 <QAction>
30#include <QCheckBox>
31#include <QHBoxLayout>
32#include <QHeaderView>
33#include <QItemDelegate>
34#include <QGridLayout>
35#include <QTextEdit>
36
37/* GUI includes: */
38#include "QIDialog.h"
39#include "QIDialogButtonBox.h"
40#include "QILabel.h"
41#include "QILineEdit.h"
42#include "QIToolBar.h"
43#include "UIActionPool.h"
44#include "UICommon.h"
45#include "UICustomFileSystemModel.h"
46#include "UIErrorString.h"
47#include "UIFileManager.h"
48#include "UIFileManagerTable.h"
49#include "UIFileTableNavigationWidget.h"
50#include "UIIconPool.h"
51#include "UIPathOperations.h"
52#include "UITranslator.h"
53
54/* COM includes: */
55#include "CFsObjInfo.h"
56#include "CGuestFsObjInfo.h"
57#include "CGuestDirectory.h"
58#include "CProgress.h"
59
60
61/*********************************************************************************************************************************
62* UIGuestControlFileView definition. *
63*********************************************************************************************************************************/
64
65/** Using QITableView causes the following problem when I click on the table items
66 Qt WARNING: Cannot creat accessible child interface for object: UIGuestControlFileView.....
67 so for now subclass QTableView */
68class UIGuestControlFileView : public QTableView
69{
70
71 Q_OBJECT;
72
73signals:
74
75 void sigSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected);
76
77public:
78
79 UIGuestControlFileView(QWidget * parent = 0);
80 bool hasSelection() const;
81 bool isInEditState() const;
82
83protected:
84
85 virtual void selectionChanged(const QItemSelection & selected, const QItemSelection & deselected) /*override */;
86
87private:
88
89 void configure();
90 QWidget *m_pParent;
91};
92
93
94/*********************************************************************************************************************************
95* UIFileDelegate definition. *
96*********************************************************************************************************************************/
97/** A QItemDelegate child class to disable dashed lines drawn around selected cells in QTableViews */
98class UIFileDelegate : public QItemDelegate
99{
100
101 Q_OBJECT;
102
103public:
104
105 UIFileDelegate(QObject *pParent)
106 : QItemDelegate(pParent){}
107
108protected:
109
110 virtual void drawFocus ( QPainter * /*painter*/, const QStyleOptionViewItem & /*option*/, const QRect & /*rect*/ ) const {}
111};
112
113
114/*********************************************************************************************************************************
115* UStringInputDialog definition. *
116*********************************************************************************************************************************/
117
118/** A QIDialog child including a line edit whose text exposed when the dialog is accepted */
119class UIStringInputDialog : public QIDialog
120{
121
122 Q_OBJECT;
123
124public:
125
126 UIStringInputDialog(QWidget *pParent = 0, Qt::WindowFlags enmFlags = Qt::WindowFlags());
127 QString getString() const;
128
129private:
130
131 QILineEdit *m_pLineEdit;
132};
133
134
135/*********************************************************************************************************************************
136* UIFileDeleteConfirmationDialog definition. *
137*********************************************************************************************************************************/
138
139/** A QIDialog child including a line edit whose text exposed when the dialog is accepted */
140class UIFileDeleteConfirmationDialog : public QIDialog
141{
142
143 Q_OBJECT;
144
145public:
146
147 UIFileDeleteConfirmationDialog(QWidget *pParent = 0, Qt::WindowFlags enmFlags = Qt::WindowFlags());
148 /** Returns whether m_pAskNextTimeCheckBox is checked or not. */
149 bool askDeleteConfirmationNextTime() const;
150
151private:
152
153 QCheckBox *m_pAskNextTimeCheckBox;
154 QILabel *m_pQuestionLabel;
155};
156
157
158/*********************************************************************************************************************************
159* UIHostDirectoryDiskUsageComputer implementation. *
160*********************************************************************************************************************************/
161
162UIDirectoryDiskUsageComputer::UIDirectoryDiskUsageComputer(QObject *parent, QStringList pathList)
163 :QThread(parent)
164 , m_pathList(pathList)
165 , m_fOkToContinue(true)
166{
167}
168
169void UIDirectoryDiskUsageComputer::run()
170{
171 for (int i = 0; i < m_pathList.size(); ++i)
172 directoryStatisticsRecursive(m_pathList[i], m_resultStatistics);
173}
174
175void UIDirectoryDiskUsageComputer::stopRecursion()
176{
177 m_mutex.lock();
178 m_fOkToContinue = false;
179 m_mutex.unlock();
180}
181
182bool UIDirectoryDiskUsageComputer::isOkToContinue() const
183{
184 return m_fOkToContinue;
185}
186
187
188/*********************************************************************************************************************************
189* UIGuestControlFileView implementation. *
190*********************************************************************************************************************************/
191
192UIGuestControlFileView::UIGuestControlFileView(QWidget *parent)
193 :QTableView(parent)
194 , m_pParent(parent)
195{
196 configure();
197}
198
199void UIGuestControlFileView::configure()
200{
201 setContextMenuPolicy(Qt::CustomContextMenu);
202 setShowGrid(false);
203 setSelectionBehavior(QAbstractItemView::SelectRows);
204 verticalHeader()->setVisible(false);
205 setEditTriggers(QAbstractItemView::NoEditTriggers);
206 /* Minimize the row height: */
207 verticalHeader()->setDefaultSectionSize(verticalHeader()->minimumSectionSize());
208 setAlternatingRowColors(true);
209 installEventFilter(m_pParent);
210}
211
212bool UIGuestControlFileView::hasSelection() const
213{
214 QItemSelectionModel *pSelectionModel = selectionModel();
215 if (!pSelectionModel)
216 return false;
217 return pSelectionModel->hasSelection();
218}
219
220bool UIGuestControlFileView::isInEditState() const
221{
222 return state() == QAbstractItemView::EditingState;
223}
224
225void UIGuestControlFileView::selectionChanged(const QItemSelection & selected, const QItemSelection & deselected)
226{
227 emit sigSelectionChanged(selected, deselected);
228 QTableView::selectionChanged(selected, deselected);
229}
230
231
232/*********************************************************************************************************************************
233* UIFileStringInputDialog implementation. *
234*********************************************************************************************************************************/
235
236UIStringInputDialog::UIStringInputDialog(QWidget *pParent /* = 0 */, Qt::WindowFlags enmFlags /* = Qt::WindowFlags() */)
237 :QIDialog(pParent, enmFlags)
238{
239 QVBoxLayout *layout = new QVBoxLayout(this);
240 m_pLineEdit = new QILineEdit(this);
241 layout->addWidget(m_pLineEdit);
242
243 QIDialogButtonBox *pButtonBox =
244 new QIDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
245 layout->addWidget(pButtonBox);
246 connect(pButtonBox, &QIDialogButtonBox::accepted, this, &UIStringInputDialog::accept);
247 connect(pButtonBox, &QIDialogButtonBox::rejected, this, &UIStringInputDialog::reject);
248}
249
250QString UIStringInputDialog::getString() const
251{
252 if (!m_pLineEdit)
253 return QString();
254 return m_pLineEdit->text();
255}
256
257
258/*********************************************************************************************************************************
259* UIPropertiesDialog implementation. *
260*********************************************************************************************************************************/
261
262UIPropertiesDialog::UIPropertiesDialog(QWidget *pParent, Qt::WindowFlags enmFlags)
263 :QIDialog(pParent, enmFlags)
264 , m_pMainLayout(new QVBoxLayout)
265 , m_pInfoEdit(new QTextEdit)
266{
267 setLayout(m_pMainLayout);
268
269 if (m_pMainLayout)
270 m_pMainLayout->addWidget(m_pInfoEdit);
271 if (m_pInfoEdit)
272 {
273 m_pInfoEdit->setReadOnly(true);
274 m_pInfoEdit->setFrameStyle(QFrame::NoFrame);
275 }
276 QIDialogButtonBox *pButtonBox =
277 new QIDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, this);
278 m_pMainLayout->addWidget(pButtonBox);
279 connect(pButtonBox, &QIDialogButtonBox::accepted, this, &UIStringInputDialog::accept);
280}
281
282void UIPropertiesDialog::setPropertyText(const QString &strProperty)
283{
284 if (!m_pInfoEdit)
285 return;
286 m_strProperty = strProperty;
287 m_pInfoEdit->setHtml(strProperty);
288}
289
290void UIPropertiesDialog::addDirectoryStatistics(UIDirectoryStatistics directoryStatistics)
291{
292 if (!m_pInfoEdit)
293 return;
294 // QString propertyString = m_pInfoEdit->toHtml();
295 // propertyString += "<b>Total Size:</b> " + QString::number(directoryStatistics.m_totalSize) + QString(" bytes");
296 // if (directoryStatistics.m_totalSize >= UIFileManagerTable::m_iKiloByte)
297 // propertyString += " (" + UIFileManagerTable::humanReadableSize(directoryStatistics.m_totalSize) + ")";
298 // propertyString += "<br/>";
299 // propertyString += "<b>File Count:</b> " + QString::number(directoryStatistics.m_uFileCount);
300
301 // m_pInfoEdit->setHtml(propertyString);
302
303 QString detailsString(m_strProperty);
304 detailsString += "<br/>";
305 detailsString += "<b>" + UIFileManager::tr("Total Size") + "</b> " +
306 QString::number(directoryStatistics.m_totalSize) + UIFileManager::tr(" bytes");
307 if (directoryStatistics.m_totalSize >= UIFileManagerTable::m_iKiloByte)
308 detailsString += " (" + UIFileManagerTable::humanReadableSize(directoryStatistics.m_totalSize) + ")";
309 detailsString += "<br/>";
310
311 detailsString += "<b>" + UIFileManager::tr("File Count") + ":</b> " +
312 QString::number(directoryStatistics.m_uFileCount);
313
314 m_pInfoEdit->setHtml(detailsString);
315}
316
317
318/*********************************************************************************************************************************
319* UIDirectoryStatistics implementation. *
320*********************************************************************************************************************************/
321
322UIDirectoryStatistics::UIDirectoryStatistics()
323 : m_totalSize(0)
324 , m_uFileCount(0)
325 , m_uDirectoryCount(0)
326 , m_uSymlinkCount(0)
327{
328}
329
330/*********************************************************************************************************************************
331+* UIFileDeleteConfirmationDialog implementation. *
332+*********************************************************************************************************************************/
333
334UIFileDeleteConfirmationDialog::UIFileDeleteConfirmationDialog(QWidget *pParent /* = 0 */, Qt::WindowFlags enmFlags /* = Qt::WindowFlags() */)
335 :QIDialog(pParent, enmFlags)
336 , m_pAskNextTimeCheckBox(0)
337 , m_pQuestionLabel(0)
338{
339 QVBoxLayout *pLayout = new QVBoxLayout(this);
340
341 m_pQuestionLabel = new QILabel;
342 if (m_pQuestionLabel)
343 {
344 pLayout->addWidget(m_pQuestionLabel);
345 m_pQuestionLabel->setText(UIFileManager::tr("Delete the selected file(s) and/or folder(s)"));
346 }
347
348 QIDialogButtonBox *pButtonBox =
349 new QIDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
350 if (pButtonBox)
351 {
352 pLayout->addWidget(pButtonBox, 0, Qt::AlignCenter);
353 connect(pButtonBox, &QIDialogButtonBox::accepted, this, &UIStringInputDialog::accept);
354 connect(pButtonBox, &QIDialogButtonBox::rejected, this, &UIStringInputDialog::reject);
355 }
356
357 m_pAskNextTimeCheckBox = new QCheckBox;
358
359 if (m_pAskNextTimeCheckBox)
360 {
361 UIFileManagerOptions *pFileManagerOptions = UIFileManagerOptions::instance();
362 if (pFileManagerOptions)
363 m_pAskNextTimeCheckBox->setChecked(pFileManagerOptions->fAskDeleteConfirmation);
364
365 pLayout->addWidget(m_pAskNextTimeCheckBox);
366 m_pAskNextTimeCheckBox->setText(UIFileManager::tr("Ask for this confirmation next time"));
367 m_pAskNextTimeCheckBox->setToolTip(UIFileManager::tr("Delete confirmation can be "
368 "disabled/enabled also from the Options panel."));
369 }
370}
371
372bool UIFileDeleteConfirmationDialog::askDeleteConfirmationNextTime() const
373{
374 if (!m_pAskNextTimeCheckBox)
375 return true;
376 return m_pAskNextTimeCheckBox->isChecked();
377}
378
379
380/*********************************************************************************************************************************
381* UIFileManagerTable implementation. *
382*********************************************************************************************************************************/
383const unsigned UIFileManagerTable::m_iKiloByte = 1024; /**< Our kilo bytes are a power of two! (bird) */
384
385UIFileManagerTable::UIFileManagerTable(UIActionPool *pActionPool, QWidget *pParent /* = 0 */)
386 :QIWithRetranslateUI<QWidget>(pParent)
387 , m_eFileOperationType(FileOperationType_None)
388 , m_pLocationLabel(0)
389 , m_pPropertiesDialog(0)
390 , m_pActionPool(pActionPool)
391 , m_pToolBar(0)
392 , m_pMainLayout(0)
393 , m_pNavigationWidget(0)
394 , m_pModel(0)
395 , m_pView(0)
396 , m_pProxyModel(0)
397 , m_pathSeparator('/')
398 , m_pToolBarLayout(0)
399{
400 prepareObjects();
401}
402
403UIFileManagerTable::~UIFileManagerTable()
404{
405}
406
407void UIFileManagerTable::reset()
408{
409 if (m_pModel)
410 m_pModel->reset();
411
412 if (m_pNavigationWidget)
413 m_pNavigationWidget->reset();
414}
415
416void UIFileManagerTable::prepareObjects()
417{
418 m_pMainLayout = new QGridLayout();
419 if (!m_pMainLayout)
420 return;
421 m_pMainLayout->setSpacing(0);
422 m_pMainLayout->setContentsMargins(0, 0, 0, 0);
423 setLayout(m_pMainLayout);
424
425 m_pToolBarLayout = new QHBoxLayout;
426 if (m_pToolBarLayout)
427 {
428 m_pToolBarLayout->setSpacing(0);
429 m_pToolBarLayout->setContentsMargins(0, 0, 0, 0);
430
431 m_pToolBar = new QIToolBar;
432 if (m_pToolBar)
433 {
434 m_pToolBarLayout->addWidget(m_pToolBar);
435 m_sessionWidgets << m_pToolBar;
436 }
437
438 m_pMainLayout->addLayout(m_pToolBarLayout, 0, 0, 1, 7);
439 }
440
441 m_pLocationLabel = new QILabel;
442 if (m_pLocationLabel)
443 {
444 m_pMainLayout->addWidget(m_pLocationLabel, 1, 0, 1, 1);
445 m_sessionWidgets << m_pLocationLabel;
446 }
447
448 m_pNavigationWidget = new UIFileTableNavigationWidget;
449 if (m_pNavigationWidget)
450 {
451 m_pNavigationWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
452 connect(m_pNavigationWidget, &UIFileTableNavigationWidget::sigPathChanged,
453 this, &UIFileManagerTable::sltHandleNavigationWidgetPathChange);
454 connect(m_pNavigationWidget, &UIFileTableNavigationWidget::sigHistoryListChanged,
455 this, &UIFileManagerTable::sltHandleNavigationWidgetHistoryListChanged);
456 m_pMainLayout->addWidget(m_pNavigationWidget, 1, 1, 1, 6);
457 m_sessionWidgets << m_pNavigationWidget;
458 }
459
460 m_pModel = new UICustomFileSystemModel(this);
461 if (!m_pModel)
462 return;
463 connect(m_pModel, &UICustomFileSystemModel::sigItemRenamed,
464 this, &UIFileManagerTable::sltHandleItemRenameAttempt);
465
466 m_pProxyModel = new UICustomFileSystemProxyModel(this);
467 if (!m_pProxyModel)
468 return;
469 m_pProxyModel->setSourceModel(m_pModel);
470
471 m_pView = new UIGuestControlFileView(this);
472 if (m_pView)
473 {
474 m_pView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
475 m_pMainLayout->addWidget(m_pView, 2, 0, 5, 7);
476
477 QHeaderView *pHorizontalHeader = m_pView->horizontalHeader();
478 if (pHorizontalHeader)
479 {
480 pHorizontalHeader->setHighlightSections(false);
481 pHorizontalHeader->setSectionResizeMode(QHeaderView::ResizeToContents);
482 pHorizontalHeader->setStretchLastSection(true);
483 }
484
485 m_pView->setModel(m_pProxyModel);
486 m_pView->setItemDelegate(new UIFileDelegate(this));
487 m_pView->setSortingEnabled(true);
488 m_pView->sortByColumn(0, Qt::AscendingOrder);
489
490 connect(m_pView, &UIGuestControlFileView::doubleClicked,
491 this, &UIFileManagerTable::sltItemDoubleClicked);
492 connect(m_pView, &UIGuestControlFileView::clicked,
493 this, &UIFileManagerTable::sltItemClicked);
494 connect(m_pView, &UIGuestControlFileView::sigSelectionChanged,
495 this, &UIFileManagerTable::sltSelectionChanged);
496 connect(m_pView, &UIGuestControlFileView::customContextMenuRequested,
497 this, &UIFileManagerTable::sltCreateFileViewContextMenu);
498 m_pView->hideColumn(UICustomFileSystemModelData_VISOPath);
499 m_pView->hideColumn(UICustomFileSystemModelData_LocalPath);
500 m_sessionWidgets << m_pView;
501 }
502
503 m_pSearchLineEdit = new QILineEdit;
504 if (m_pSearchLineEdit)
505 {
506 m_pMainLayout->addWidget(m_pSearchLineEdit, 8, 0, 1, 7);
507 m_pSearchLineEdit->hide();
508 m_pSearchLineEdit->setClearButtonEnabled(true);
509 m_searchLineUnmarkColor = m_pSearchLineEdit->palette().color(QPalette::Base);
510 m_searchLineMarkColor = QColor(m_searchLineUnmarkColor.green(),
511 0.5 * m_searchLineUnmarkColor.green(),
512 0.5 * m_searchLineUnmarkColor.blue());
513 connect(m_pSearchLineEdit, &QLineEdit::textChanged,
514 this, &UIFileManagerTable::sltSearchTextChanged);
515 }
516 optionsUpdated();
517}
518
519void UIFileManagerTable::updateCurrentLocationEdit(const QString& strLocation)
520{
521 if (m_pNavigationWidget)
522 {
523 m_pNavigationWidget->setPath(strLocation);
524 }
525}
526
527void UIFileManagerTable::changeLocation(const QModelIndex &index)
528{
529 if (!index.isValid() || !m_pView)
530 return;
531 m_pView->setRootIndex(m_pProxyModel->mapFromSource(index));
532
533 if (m_pView->selectionModel())
534 m_pView->selectionModel()->reset();
535
536 UICustomFileSystemItem *item = static_cast<UICustomFileSystemItem*>(index.internalPointer());
537 if (item)
538 {
539 updateCurrentLocationEdit(item->path());
540 }
541 setSelectionDependentActionsEnabled(false);
542
543 m_pView->scrollToTop();
544}
545
546void UIFileManagerTable::initializeFileTree()
547{
548 if (m_pModel)
549 m_pModel->reset();
550 if (!rootItem())
551 return;
552
553 const QString startPath("/");
554 UICustomFileSystemItem* startItem = new UICustomFileSystemItem(startPath, rootItem(), KFsObjType_Directory);
555 startItem->setPath(startPath);
556 startItem->setIsOpened(false);
557 populateStartDirectory(startItem);
558
559 m_pModel->signalUpdate();
560 updateCurrentLocationEdit(startPath);
561 m_pView->setRootIndex(m_pProxyModel->mapFromSource(m_pModel->rootIndex()));
562}
563
564void UIFileManagerTable::populateStartDirectory(UICustomFileSystemItem *startItem)
565{
566 determineDriveLetters();
567 if (m_driveLetterList.isEmpty())
568 {
569 /* Read the root directory and get the list: */
570 readDirectory(startItem->path(), startItem, true);
571 }
572 else
573 {
574 for (int i = 0; i < m_driveLetterList.size(); ++i)
575 {
576 UICustomFileSystemItem* driveItem = new UICustomFileSystemItem(UIPathOperations::removeTrailingDelimiters(m_driveLetterList[i]),
577 startItem, KFsObjType_Directory);
578 driveItem->setPath(m_driveLetterList[i]);
579 driveItem->setIsOpened(false);
580 driveItem->setIsDriveItem(true);
581 startItem->setIsOpened(true);
582 }
583 }
584}
585
586void UIFileManagerTable::checkDotDot(QMap<QString,UICustomFileSystemItem*> &map,
587 UICustomFileSystemItem *parent, bool isStartDir)
588{
589 if (!parent)
590 return;
591 /* Make sure we have an item representing up directory, and make sure it is not there for the start dir: */
592 if (!map.contains(UICustomFileSystemModel::strUpDirectoryString) && !isStartDir)
593 {
594 UICustomFileSystemItem *item = new UICustomFileSystemItem(UICustomFileSystemModel::strUpDirectoryString,
595 parent, KFsObjType_Directory);
596 item->setIsOpened(false);
597 map.insert(UICustomFileSystemModel::strUpDirectoryString, item);
598 }
599 else if (map.contains(UICustomFileSystemModel::strUpDirectoryString) && isStartDir)
600 {
601 map.remove(UICustomFileSystemModel::strUpDirectoryString);
602 }
603}
604
605void UIFileManagerTable::sltItemDoubleClicked(const QModelIndex &index)
606{
607 if (!index.isValid() || !m_pModel || !m_pView)
608 return;
609 QModelIndex nIndex = m_pProxyModel ? m_pProxyModel->mapToSource(index) : index;
610 goIntoDirectory(nIndex);
611}
612
613void UIFileManagerTable::sltItemClicked(const QModelIndex &index)
614{
615 Q_UNUSED(index);
616 disableSelectionSearch();
617}
618
619void UIFileManagerTable::sltGoUp()
620{
621 if (!m_pView || !m_pModel)
622 return;
623 QModelIndex currentRoot = currentRootIndex();
624
625 if (!currentRoot.isValid())
626 return;
627 if (currentRoot != m_pModel->rootIndex())
628 {
629 QModelIndex parentIndex = currentRoot.parent();
630 if (parentIndex.isValid())
631 {
632 changeLocation(currentRoot.parent());
633 m_pView->selectRow(currentRoot.row());
634 }
635 }
636}
637
638void UIFileManagerTable::sltGoHome()
639{
640 goToHomeDirectory();
641}
642
643void UIFileManagerTable::sltGoForward()
644{
645 if (m_pNavigationWidget)
646 m_pNavigationWidget->goForwardInHistory();
647}
648
649void UIFileManagerTable::sltGoBackward()
650{
651 if (m_pNavigationWidget)
652 m_pNavigationWidget->goBackwardInHistory();
653}
654
655void UIFileManagerTable::sltRefresh()
656{
657 refresh();
658}
659
660void UIFileManagerTable::goIntoDirectory(const QModelIndex &itemIndex)
661{
662 if (!m_pModel)
663 return;
664
665 /* Make sure the colum is 0: */
666 QModelIndex index = m_pModel->index(itemIndex.row(), 0, itemIndex.parent());
667 if (!index.isValid())
668 return;
669
670 UICustomFileSystemItem *item = static_cast<UICustomFileSystemItem*>(index.internalPointer());
671 if (!item)
672 return;
673
674 /* check if we need to go up: */
675 if (item->isUpDirectory())
676 {
677 QModelIndex parentIndex = m_pModel->parent(m_pModel->parent(index));
678 if (parentIndex.isValid())
679 changeLocation(parentIndex);
680 return;
681 }
682
683 if (item->isDirectory() || item->isSymLinkToADirectory())
684 {
685 if (!item->isOpened())
686 readDirectory(item->path(),item);
687 changeLocation(index);
688 }
689}
690
691void UIFileManagerTable::goIntoDirectory(const QStringList &pathTrail)
692{
693 UICustomFileSystemItem *parent = getStartDirectoryItem();
694
695 for(int i = 0; i < pathTrail.size(); ++i)
696 {
697 if (!parent)
698 return;
699 /* Make sure parent is already opened: */
700 if (!parent->isOpened())
701 readDirectory(parent->path(), parent, parent == getStartDirectoryItem());
702 /* search the current path item among the parent's children: */
703 UICustomFileSystemItem *item = parent->child(pathTrail.at(i));
704 if (!item)
705 return;
706 parent = item;
707 }
708 if (!parent)
709 return;
710 if (!parent->isOpened())
711 readDirectory(parent->path(), parent, parent == getStartDirectoryItem());
712 goIntoDirectory(parent);
713}
714
715void UIFileManagerTable::goIntoDirectory(UICustomFileSystemItem *item)
716{
717 if (!item || !m_pModel)
718 return;
719 goIntoDirectory(m_pModel->index(item));
720}
721
722UICustomFileSystemItem* UIFileManagerTable::indexData(const QModelIndex &index) const
723{
724 if (!index.isValid())
725 return 0;
726 return static_cast<UICustomFileSystemItem*>(index.internalPointer());
727}
728
729void UIFileManagerTable::refresh()
730{
731 if (!m_pView || !m_pModel)
732 return;
733 QModelIndex currentIndex = currentRootIndex();
734
735 UICustomFileSystemItem *treeItem = indexData(currentIndex);
736 if (!treeItem)
737 return;
738 bool isRootDir = (m_pModel->rootIndex() == currentIndex);
739 m_pModel->beginReset();
740 /* For now we clear the whole subtree (that isrecursively) which is an overkill: */
741 treeItem->clearChildren();
742 if (isRootDir)
743 populateStartDirectory(treeItem);
744 else
745 readDirectory(treeItem->path(), treeItem, isRootDir);
746 m_pModel->endReset();
747 m_pView->setRootIndex(m_pProxyModel->mapFromSource(currentIndex));
748 setSelectionDependentActionsEnabled(m_pView->hasSelection());
749}
750
751void UIFileManagerTable::relist()
752{
753 if (!m_pProxyModel)
754 return;
755 m_pProxyModel->invalidate();
756}
757
758void UIFileManagerTable::sltDelete()
759{
760 if (!checkIfDeleteOK())
761 return;
762
763 if (!m_pView || !m_pModel)
764 return;
765
766 if (!m_pView || !m_pModel)
767 return;
768 QItemSelectionModel *selectionModel = m_pView->selectionModel();
769 if (!selectionModel)
770 return;
771
772 QModelIndexList selectedItemIndices = selectionModel->selectedRows();
773 for(int i = 0; i < selectedItemIndices.size(); ++i)
774 {
775 QModelIndex index =
776 m_pProxyModel ? m_pProxyModel->mapToSource(selectedItemIndices.at(i)) : selectedItemIndices.at(i);
777 deleteByIndex(index);
778 }
779 /** @todo dont refresh here, just delete the rows and update the table view: */
780 refresh();
781}
782
783void UIFileManagerTable::sltRename()
784{
785 if (!m_pView || !m_pModel)
786 return;
787 QItemSelectionModel *selectionModel = m_pView->selectionModel();
788 if (!selectionModel)
789 return;
790
791 QModelIndexList selectedItemIndices = selectionModel->selectedRows();
792 if (selectedItemIndices.size() == 0)
793 return;
794 QModelIndex modelIndex =
795 m_pProxyModel ? m_pProxyModel->mapToSource(selectedItemIndices.at(0)) : selectedItemIndices.at(0);
796 UICustomFileSystemItem *item = indexData(modelIndex);
797 if (!item || item->isUpDirectory())
798 return;
799 m_pView->edit(selectedItemIndices.at(0));
800}
801
802void UIFileManagerTable::sltCreateNewDirectory()
803{
804 if (!m_pModel || !m_pView)
805 return;
806 QModelIndex currentIndex = currentRootIndex();
807 if (!currentIndex.isValid())
808 return;
809 UICustomFileSystemItem *parentFolderItem = static_cast<UICustomFileSystemItem*>(currentIndex.internalPointer());
810 if (!parentFolderItem)
811 return;
812
813 QString newDirectoryName(UICustomFileSystemModel::tr("New Directory"));
814
815 if (!createDirectory(parentFolderItem->path(), newDirectoryName))
816 return;
817
818 /* Refesh the current directory so that we correctly populate the child list of parentFolderItem: */
819 /** @todo instead of refreshing here (an overkill) just add the
820 rows and update the tabel view: */
821 sltRefresh();
822
823 /* Now we try to edit the newly created item thereby enabling the user to rename the new item: */
824 QList<UICustomFileSystemItem*> content = parentFolderItem->children();
825 UICustomFileSystemItem* newItem = 0;
826 /* Search the new item: */
827 foreach (UICustomFileSystemItem* childItem, content)
828 {
829
830 if (childItem && newDirectoryName == childItem->name())
831 newItem = childItem;
832 }
833
834 if (!newItem)
835 return;
836 QModelIndex newItemIndex = m_pProxyModel->mapFromSource(m_pModel->index(newItem));
837 if (!newItemIndex.isValid())
838 return;
839 m_pView->edit(newItemIndex);
840}
841
842void UIFileManagerTable::sltCopy()
843{
844 m_copyCutBuffer = selectedItemPathList();
845 m_eFileOperationType = FileOperationType_Copy;
846 setPasteActionEnabled(true);
847}
848
849void UIFileManagerTable::sltCut()
850{
851 m_copyCutBuffer = selectedItemPathList();
852 m_eFileOperationType = FileOperationType_Cut;
853 setPasteActionEnabled(true);
854}
855
856void UIFileManagerTable::sltPaste()
857{
858 m_copyCutBuffer.clear();
859
860 m_eFileOperationType = FileOperationType_None;
861 setPasteActionEnabled(false);
862}
863
864void UIFileManagerTable::sltShowProperties()
865{
866 showProperties();
867}
868
869void UIFileManagerTable::sltSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected)
870{
871 Q_UNUSED(selected);
872 Q_UNUSED(deselected);
873 setSelectionDependentActionsEnabled(m_pView->hasSelection());
874}
875
876void UIFileManagerTable::sltSelectAll()
877{
878 if (!m_pModel || !m_pView)
879 return;
880 m_pView->selectAll();
881 deSelectUpDirectoryItem();
882}
883
884void UIFileManagerTable::sltInvertSelection()
885{
886 setSelectionForAll(QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
887 deSelectUpDirectoryItem();
888}
889
890void UIFileManagerTable::sltSearchTextChanged(const QString &strText)
891{
892 performSelectionSearch(strText);
893}
894
895void UIFileManagerTable::sltHandleItemRenameAttempt(UICustomFileSystemItem *pItem, QString strOldName, QString strNewName)
896{
897 if (!pItem)
898 return;
899 /* Attempt to chage item name in the file system: */
900 if (!renameItem(pItem, strNewName))
901 {
902 /* Restore the previous name. relist the view: */
903 pItem->setData(strOldName, static_cast<int>(UICustomFileSystemModelData_Name));
904 relist();
905 emit sigLogOutput(QString(pItem->path()).append(" could not be renamed"), QString(), FileManagerLogType_Error);
906 }
907}
908
909void UIFileManagerTable::sltCreateFileViewContextMenu(const QPoint &point)
910{
911 QWidget *pSender = qobject_cast<QWidget*>(sender());
912 if (!pSender)
913 return;
914 createFileViewContextMenu(pSender, point);
915}
916
917void UIFileManagerTable::sltHandleNavigationWidgetPathChange(const QString& strPath)
918{
919 goIntoDirectory(UIPathOperations::pathTrail(strPath));
920}
921
922void UIFileManagerTable::sltHandleNavigationWidgetHistoryListChanged()
923{
924 toggleForwardBackwardActions();
925}
926
927void UIFileManagerTable::deSelectUpDirectoryItem()
928{
929 if (!m_pView)
930 return;
931 QItemSelectionModel *pSelectionModel = m_pView->selectionModel();
932 if (!pSelectionModel)
933 return;
934 QModelIndex currentRoot = currentRootIndex();
935 if (!currentRoot.isValid())
936 return;
937
938 /* Make sure that "up directory item" (if exists) is deselected: */
939 for (int i = 0; i < m_pModel->rowCount(currentRoot); ++i)
940 {
941 QModelIndex index = m_pModel->index(i, 0, currentRoot);
942 if (!index.isValid())
943 continue;
944
945 UICustomFileSystemItem *item = static_cast<UICustomFileSystemItem*>(index.internalPointer());
946 if (item && item->isUpDirectory())
947 {
948 QModelIndex indexToDeselect = m_pProxyModel ? m_pProxyModel->mapFromSource(index) : index;
949 pSelectionModel->select(indexToDeselect, QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
950 }
951 }
952}
953
954void UIFileManagerTable::setSelectionForAll(QItemSelectionModel::SelectionFlags flags)
955{
956 if (!m_pView)
957 return;
958 QItemSelectionModel *pSelectionModel = m_pView->selectionModel();
959 if (!pSelectionModel)
960 return;
961 QModelIndex currentRoot = currentRootIndex();
962 if (!currentRoot.isValid())
963 return;
964
965 for (int i = 0; i < m_pModel->rowCount(currentRoot); ++i)
966 {
967 QModelIndex index = m_pModel->index(i, 0, currentRoot);
968 if (!index.isValid())
969 continue;
970 QModelIndex indexToSelect = m_pProxyModel ? m_pProxyModel->mapFromSource(index) : index;
971 pSelectionModel->select(indexToSelect, flags);
972 }
973}
974
975void UIFileManagerTable::setSelection(const QModelIndex &indexInProxyModel)
976{
977 if (!m_pView)
978 return;
979 QItemSelectionModel *selectionModel = m_pView->selectionModel();
980 if (!selectionModel)
981 return;
982 selectionModel->select(indexInProxyModel, QItemSelectionModel::Current | QItemSelectionModel::Rows | QItemSelectionModel::Select);
983 m_pView->scrollTo(indexInProxyModel, QAbstractItemView::EnsureVisible);
984}
985
986void UIFileManagerTable::deleteByIndex(const QModelIndex &itemIndex)
987{
988 UICustomFileSystemItem *treeItem = indexData(itemIndex);
989 if (!treeItem)
990 return;
991 deleteByItem(treeItem);
992}
993
994void UIFileManagerTable::retranslateUi()
995{
996 UICustomFileSystemItem *pRootItem = rootItem();
997 if (pRootItem)
998 {
999 pRootItem->setData(UIFileManager::tr("Name"), UICustomFileSystemModelData_Name);
1000 pRootItem->setData(UIFileManager::tr("Size"), UICustomFileSystemModelData_Size);
1001 pRootItem->setData(UIFileManager::tr("Change Time"), UICustomFileSystemModelData_ChangeTime);
1002 pRootItem->setData(UIFileManager::tr("Owner"), UICustomFileSystemModelData_Owner);
1003 pRootItem->setData(UIFileManager::tr("Permissions"), UICustomFileSystemModelData_Permissions);
1004 }
1005}
1006
1007bool UIFileManagerTable::eventFilter(QObject *pObject, QEvent *pEvent) /* override */
1008{
1009 /* Handle only events sent to m_pView: */
1010 if (pObject != m_pView)
1011 return QIWithRetranslateUI<QWidget>::eventFilter(pObject, pEvent);
1012
1013 if (pEvent->type() == QEvent::KeyPress)
1014 {
1015 QKeyEvent *pKeyEvent = dynamic_cast<QKeyEvent*>(pEvent);
1016 if (pKeyEvent)
1017 {
1018 if (pKeyEvent->key() == Qt::Key_Enter || pKeyEvent->key() == Qt::Key_Return)
1019 {
1020 if (m_pView && m_pModel && !m_pView->isInEditState())
1021 {
1022 /* Get the selected item. If there are 0 or more than 1 selection do nothing: */
1023 QItemSelectionModel *selectionModel = m_pView->selectionModel();
1024 if (selectionModel)
1025 {
1026 QModelIndexList selectedItemIndices = selectionModel->selectedRows();
1027 if (selectedItemIndices.size() == 1 && m_pModel)
1028 goIntoDirectory( m_pProxyModel->mapToSource(selectedItemIndices.at(0)));
1029 }
1030 }
1031 return true;
1032 }
1033 else if (pKeyEvent->key() == Qt::Key_Delete)
1034 {
1035 sltDelete();
1036 return true;
1037 }
1038 else if (pKeyEvent->key() == Qt::Key_Backspace)
1039 {
1040 sltGoUp();
1041 return true;
1042 }
1043 else if (pKeyEvent->text().length() == 1 &&
1044 (pKeyEvent->text().at(0).isDigit() ||
1045 pKeyEvent->text().at(0).isLetter()))
1046 {
1047 if (m_pSearchLineEdit)
1048 {
1049 markUnmarkSearchLineEdit(false);
1050 m_pSearchLineEdit->clear();
1051 m_pSearchLineEdit->show();
1052 m_pSearchLineEdit->setFocus();
1053 m_pSearchLineEdit->setText(pKeyEvent->text());
1054 }
1055 }
1056 else if (pKeyEvent->key() == Qt::Key_Tab)
1057 {
1058 return true;
1059 }
1060 }
1061 }
1062 else if (pEvent->type() == QEvent::FocusOut)
1063 {
1064 disableSelectionSearch();
1065 }
1066
1067 /* Call to base-class: */
1068 return QIWithRetranslateUI<QWidget>::eventFilter(pObject, pEvent);
1069}
1070
1071UICustomFileSystemItem *UIFileManagerTable::getStartDirectoryItem()
1072{
1073 UICustomFileSystemItem* pRootItem = rootItem();
1074 if (!pRootItem)
1075 return 0;
1076 if (pRootItem->childCount() <= 0)
1077 return 0;
1078 return pRootItem->child(0);
1079}
1080
1081QString UIFileManagerTable::currentDirectoryPath() const
1082{
1083 if (!m_pView)
1084 return QString();
1085 QModelIndex currentRoot = currentRootIndex();
1086 if (!currentRoot.isValid())
1087 return QString();
1088 UICustomFileSystemItem *item = static_cast<UICustomFileSystemItem*>(currentRoot.internalPointer());
1089 if (!item)
1090 return QString();
1091 /* be paranoid: */
1092 if (!item->isDirectory())
1093 return QString();
1094 return item->path();
1095}
1096
1097QStringList UIFileManagerTable::selectedItemPathList()
1098{
1099 QItemSelectionModel *selectionModel = m_pView->selectionModel();
1100 if (!selectionModel)
1101 return QStringList();
1102
1103 QStringList pathList;
1104 QModelIndexList selectedItemIndices = selectionModel->selectedRows();
1105 for(int i = 0; i < selectedItemIndices.size(); ++i)
1106 {
1107 QModelIndex index =
1108 m_pProxyModel ? m_pProxyModel->mapToSource(selectedItemIndices.at(i)) : selectedItemIndices.at(i);
1109 UICustomFileSystemItem *item = static_cast<UICustomFileSystemItem*>(index.internalPointer());
1110 if (!item)
1111 continue;
1112
1113 /* Make sure to remove any trailing delimiters for directory paths here (e.g. "C:\foo\bar\" -> "C:\foo\bar"),
1114 * as we want to copy entire directories, not only its contents (see Guest Control SDK docs). */
1115 pathList.push_back(item->path(true /* fRemoveTrailingDelimiters */));
1116 }
1117 return pathList;
1118}
1119
1120CGuestFsObjInfo UIFileManagerTable::guestFsObjectInfo(const QString& path, CGuestSession &comGuestSession) const
1121{
1122 if (comGuestSession.isNull())
1123 return CGuestFsObjInfo();
1124 CGuestFsObjInfo comFsObjInfo = comGuestSession.FsObjQueryInfo(path, true /*aFollowSymlinks*/);
1125 if (!comFsObjInfo.isOk())
1126 return CGuestFsObjInfo();
1127 return comFsObjInfo;
1128}
1129
1130void UIFileManagerTable::setSelectionDependentActionsEnabled(bool fIsEnabled)
1131{
1132 foreach (QAction *pAction, m_selectionDependentActions)
1133 pAction->setEnabled(fIsEnabled);
1134 if (m_pView)
1135 emit sigSelectionChanged(m_pView->hasSelection());
1136}
1137
1138UICustomFileSystemItem* UIFileManagerTable::rootItem()
1139{
1140 if (!m_pModel)
1141 return 0;
1142 return m_pModel->rootItem();
1143}
1144
1145void UIFileManagerTable::setPathSeparator(const QChar &separator)
1146{
1147 m_pathSeparator = separator;
1148 if (m_pNavigationWidget)
1149 m_pNavigationWidget->setPathSeparator(m_pathSeparator);
1150}
1151
1152QHBoxLayout* UIFileManagerTable::toolBarLayout()
1153{
1154 return m_pToolBarLayout;
1155}
1156
1157bool UIFileManagerTable::event(QEvent *pEvent)
1158{
1159 if (pEvent->type() == QEvent::EnabledChange)
1160 retranslateUi();
1161 return QIWithRetranslateUI<QWidget>::event(pEvent);
1162}
1163
1164QString UIFileManagerTable::fileTypeString(KFsObjType type)
1165{
1166 QString strType = UIFileManager::tr("Unknown");
1167 switch (type)
1168 {
1169 case KFsObjType_File:
1170 strType = UIFileManager::tr("File");
1171 break;
1172 case KFsObjType_Directory:
1173 strType = UIFileManager::tr("Directory");
1174 break;
1175 case KFsObjType_Symlink:
1176 strType = UIFileManager::tr("Symbolic Link");
1177 break;
1178 case KFsObjType_Unknown:
1179 default:
1180 strType = UIFileManager::tr("Unknown");
1181 break;
1182 }
1183 return strType;
1184}
1185
1186/* static */ QString UIFileManagerTable::humanReadableSize(ULONG64 size)
1187{
1188 return UITranslator::formatSize(size);
1189}
1190
1191void UIFileManagerTable::optionsUpdated()
1192{
1193 UIFileManagerOptions *pOptions = UIFileManagerOptions::instance();
1194 if (pOptions)
1195 {
1196 if (m_pProxyModel)
1197 {
1198 m_pProxyModel->setListDirectoriesOnTop(pOptions->fListDirectoriesOnTop);
1199 m_pProxyModel->setShowHiddenObjects(pOptions->fShowHiddenObjects);
1200 }
1201 if (m_pModel)
1202 m_pModel->setShowHumanReadableSizes(pOptions->fShowHumanReadableSizes);
1203 }
1204 relist();
1205}
1206
1207bool UIFileManagerTable::hasSelection() const
1208{
1209 if (m_pView)
1210 return m_pView->hasSelection();
1211 return false;
1212}
1213
1214void UIFileManagerTable::sltReceiveDirectoryStatistics(UIDirectoryStatistics statistics)
1215{
1216 if (!m_pPropertiesDialog)
1217 return;
1218 m_pPropertiesDialog->addDirectoryStatistics(statistics);
1219}
1220
1221QModelIndex UIFileManagerTable::currentRootIndex() const
1222{
1223 if (!m_pView)
1224 return QModelIndex();
1225 if (!m_pProxyModel)
1226 return m_pView->rootIndex();
1227 return m_pProxyModel->mapToSource(m_pView->rootIndex());
1228}
1229
1230void UIFileManagerTable::performSelectionSearch(const QString &strSearchText)
1231{
1232 if (!m_pProxyModel | !m_pView)
1233 return;
1234
1235 if (strSearchText.isEmpty())
1236 {
1237 markUnmarkSearchLineEdit(false);
1238 return;
1239 }
1240
1241 int rowCount = m_pProxyModel->rowCount(m_pView->rootIndex());
1242 UICustomFileSystemItem *pFoundItem = 0;
1243 QModelIndex index;
1244 for (int i = 0; i < rowCount && !pFoundItem; ++i)
1245 {
1246 index = m_pProxyModel->index(i, 0, m_pView->rootIndex());
1247 if (!index.isValid())
1248 continue;
1249 pFoundItem = static_cast<UICustomFileSystemItem*>(m_pProxyModel->mapToSource(index).internalPointer());
1250 if (!pFoundItem)
1251 continue;
1252 const QString &strName = pFoundItem->name();
1253 if (!strName.startsWith(m_pSearchLineEdit->text(), Qt::CaseInsensitive))
1254 pFoundItem = 0;
1255 }
1256 if (pFoundItem)
1257 {
1258 /* Deselect anything that is already selected: */
1259 m_pView->clearSelection();
1260 setSelection(index);
1261 }
1262 markUnmarkSearchLineEdit(!pFoundItem);
1263}
1264
1265void UIFileManagerTable::disableSelectionSearch()
1266{
1267 if (!m_pSearchLineEdit)
1268 return;
1269 m_pSearchLineEdit->blockSignals(true);
1270 m_pSearchLineEdit->clear();
1271 m_pSearchLineEdit->hide();
1272 m_pSearchLineEdit->blockSignals(false);
1273}
1274
1275bool UIFileManagerTable::checkIfDeleteOK()
1276{
1277 UIFileManagerOptions *pFileManagerOptions = UIFileManagerOptions::instance();
1278 if (!pFileManagerOptions)
1279 return true;
1280 if (!pFileManagerOptions->fAskDeleteConfirmation)
1281 return true;
1282 UIFileDeleteConfirmationDialog *pDialog =
1283 new UIFileDeleteConfirmationDialog(this);
1284
1285 bool fContinueWithDelete = (pDialog->execute() == QDialog::Accepted);
1286 bool bAskNextTime = pDialog->askDeleteConfirmationNextTime();
1287
1288 /* Update the file manager options only if it is necessary: */
1289 if (pFileManagerOptions->fAskDeleteConfirmation != bAskNextTime)
1290 {
1291 pFileManagerOptions->fAskDeleteConfirmation = bAskNextTime;
1292 /* Notify file manager options panel so that the check box there is updated: */
1293 emit sigDeleteConfirmationOptionChanged();
1294 }
1295
1296 delete pDialog;
1297
1298 return fContinueWithDelete;
1299
1300}
1301
1302void UIFileManagerTable::markUnmarkSearchLineEdit(bool fMark)
1303{
1304 if (!m_pSearchLineEdit)
1305 return;
1306 QPalette palette = m_pSearchLineEdit->palette();
1307
1308 if (fMark)
1309 palette.setColor(QPalette::Base, m_searchLineMarkColor);
1310 else
1311 palette.setColor(QPalette::Base, m_searchLineUnmarkColor);
1312 m_pSearchLineEdit->setPalette(palette);
1313}
1314
1315void UIFileManagerTable::setSessionWidgetsEnabled(bool fEnabled)
1316{
1317 foreach (QWidget *pWidget, m_sessionWidgets)
1318 {
1319 if (pWidget)
1320 pWidget->setEnabled(fEnabled);
1321 }
1322}
1323#include "UIFileManagerTable.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