mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 05:49:53 +08:00
245 lines
7.2 KiB
C++
245 lines
7.2 KiB
C++
#include "filesystemviewer.h"
|
|
|
|
#include <QVBoxLayout>
|
|
#include <QFileSystemModel>
|
|
#include <QDir>
|
|
#include <QDebug>
|
|
#include <QSharedPointer>
|
|
#include <QMenu>
|
|
|
|
#include <utils/iconutils.h>
|
|
#include <utils/clipboardutils.h>
|
|
#include <utils/pathutils.h>
|
|
#include <core/vnotex.h>
|
|
#include <core/thememgr.h>
|
|
#include "widgetsfactory.h"
|
|
#include "dialogs/filepropertiesdialog.h"
|
|
#include "treeview.h"
|
|
|
|
using namespace vnotex;
|
|
|
|
FileSystemViewer::FileSystemViewer(QWidget *p_parent)
|
|
: QWidget(p_parent)
|
|
{
|
|
setupUI();
|
|
}
|
|
|
|
void FileSystemViewer::setupUI()
|
|
{
|
|
auto mainLayout = new QVBoxLayout(this);
|
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
auto fileModel = new QFileSystemModel(this);
|
|
|
|
m_viewer = new TreeView(this);
|
|
m_viewer->setModel(fileModel);
|
|
m_viewer->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
m_viewer->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
m_viewer->setHeaderHidden(true);
|
|
// Show only the Name column.
|
|
for (int i = 1; i < fileModel->columnCount(); ++i) {
|
|
m_viewer->hideColumn(i);
|
|
}
|
|
|
|
connect(m_viewer, &QTreeView::customContextMenuRequested,
|
|
this, &FileSystemViewer::handleContextMenuRequested);
|
|
connect(m_viewer, &QTreeView::activated,
|
|
this, [this](const QModelIndex &p_index) {
|
|
if (!this->fileModel()->isDir(p_index)) {
|
|
QStringList files;
|
|
files << this->fileModel()->filePath(p_index);
|
|
emit openFiles(files);
|
|
}
|
|
});
|
|
|
|
auto index = fileModel->setRootPath(QDir::homePath());
|
|
m_viewer->setRootIndex(index);
|
|
|
|
mainLayout->addWidget(m_viewer);
|
|
|
|
setFocusProxy(m_viewer);
|
|
|
|
connect(m_viewer, &QTreeView::expanded,
|
|
this, &FileSystemViewer::resizeTreeToContents);
|
|
connect(m_viewer, &QTreeView::collapsed,
|
|
this, &FileSystemViewer::resizeTreeToContents);
|
|
connect(fileModel, &QFileSystemModel::directoryLoaded,
|
|
this, &FileSystemViewer::resizeTreeToContents);
|
|
}
|
|
|
|
void FileSystemViewer::resizeTreeToContents()
|
|
{
|
|
m_viewer->resizeColumnToContents(0);
|
|
}
|
|
|
|
QFileSystemModel *FileSystemViewer::fileModel() const
|
|
{
|
|
return static_cast<QFileSystemModel *>(m_viewer->model());
|
|
}
|
|
|
|
int FileSystemViewer::selectedCount() const
|
|
{
|
|
return m_viewer->selectionModel()->selectedRows().size();
|
|
}
|
|
|
|
QModelIndex FileSystemViewer::getSelectedIndex() const
|
|
{
|
|
const auto modelIndexList = m_viewer->selectionModel()->selectedRows();
|
|
return modelIndexList.size() == 1 ? modelIndexList[0] : QModelIndex();
|
|
}
|
|
|
|
void FileSystemViewer::setRootPath(const QString &p_rootPath)
|
|
{
|
|
auto model = fileModel();
|
|
auto index = model->setRootPath(p_rootPath);
|
|
if (!index.isValid()) {
|
|
qWarning() << "failed to set root path to" << p_rootPath;
|
|
index = model->setRootPath("");
|
|
}
|
|
|
|
m_viewer->setRootIndex(index);
|
|
resizeTreeToContents();
|
|
}
|
|
|
|
QString FileSystemViewer::rootPath() const
|
|
{
|
|
return fileModel()->rootPath();
|
|
}
|
|
|
|
QStringList FileSystemViewer::getSelectedPaths() const
|
|
{
|
|
const auto modelIndexList = m_viewer->selectionModel()->selectedRows();
|
|
auto model = fileModel();
|
|
QStringList filePaths;
|
|
for (const auto &index : modelIndexList) {
|
|
filePaths << model->filePath(index);
|
|
}
|
|
|
|
return filePaths;
|
|
}
|
|
|
|
void FileSystemViewer::createContextMenuOnItem(QMenu *p_menu)
|
|
{
|
|
auto act = createAction(Action::Open, p_menu);
|
|
p_menu->addAction(act);
|
|
|
|
act = createAction(Action::Delete, p_menu);
|
|
p_menu->addAction(act);
|
|
|
|
if (selectedCount() == 1) {
|
|
act = createAction(Action::CopyPath, p_menu);
|
|
p_menu->addAction(act);
|
|
|
|
act = createAction(Action::Properties, p_menu);
|
|
p_menu->addAction(act);
|
|
}
|
|
}
|
|
|
|
QAction *FileSystemViewer::createAction(Action p_act, QObject *p_parent)
|
|
{
|
|
QAction *act = nullptr;
|
|
const auto &themeMgr = VNoteX::getInst().getThemeMgr();
|
|
switch (p_act) {
|
|
case Action::Open:
|
|
act = new QAction(tr("&Open"), p_parent);
|
|
connect(act, &QAction::triggered,
|
|
this, [this]() {
|
|
auto paths = getSelectedPaths();
|
|
Q_ASSERT(paths.size() > 0);
|
|
emit openFiles(paths);
|
|
});
|
|
break;
|
|
|
|
case Action::Delete:
|
|
act = new QAction(tr("&Delete"), p_parent);
|
|
connect(act, &QAction::triggered,
|
|
this, [this]() {
|
|
auto paths = getSelectedPaths();
|
|
emit removeFiles(paths);
|
|
});
|
|
break;
|
|
|
|
case Action::Properties:
|
|
act = new QAction(IconUtils::fetchIconWithDisabledState(themeMgr.getIconFile("properties.svg")),
|
|
tr("&Properties"),
|
|
p_parent);
|
|
connect(act, &QAction::triggered,
|
|
this, [this]() {
|
|
auto paths = getSelectedPaths();
|
|
Q_ASSERT(paths.size() == 1);
|
|
FilePropertiesDialog dialog(paths[0], this);
|
|
int ret = dialog.exec();
|
|
if (ret) {
|
|
auto newName = dialog.getFileName();
|
|
if (newName != PathUtils::fileName(paths[0])) {
|
|
// Rename.
|
|
emit renameFile(paths[0], newName);
|
|
}
|
|
}
|
|
});
|
|
break;
|
|
|
|
case Action::CopyPath:
|
|
act = new QAction(tr("Cop&y Path"), p_parent);
|
|
connect(act, &QAction::triggered,
|
|
this, [this]() {
|
|
auto paths = getSelectedPaths();
|
|
Q_ASSERT(paths.size() == 1);
|
|
ClipboardUtils::setTextToClipboard(paths[0]);
|
|
VNoteX::getInst().showStatusMessageShort(tr("Copied path: %1").arg(paths[0]));
|
|
});
|
|
break;
|
|
}
|
|
return act;
|
|
}
|
|
|
|
void FileSystemViewer::scrollToAndSelect(const QStringList &p_paths)
|
|
{
|
|
auto selectionModel = m_viewer->selectionModel();
|
|
selectionModel->clear();
|
|
|
|
bool isFirst = true;
|
|
auto model = fileModel();
|
|
for (const auto &pa : p_paths) {
|
|
auto index = model->index(pa);
|
|
if (index.isValid()) {
|
|
if (isFirst) {
|
|
m_viewer->scrollTo(index);
|
|
isFirst = false;
|
|
}
|
|
selectionModel->select(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FileSystemViewer::handleContextMenuRequested(const QPoint &p_pos)
|
|
{
|
|
// @p_pos is the position in the coordinate of parent widget if parent is a popup.
|
|
auto pos = p_pos;
|
|
if (m_fixContextMenuPos) {
|
|
pos = mapFromParent(p_pos);
|
|
pos = m_viewer->mapFromParent(pos);
|
|
}
|
|
|
|
QScopedPointer<QMenu> menu(WidgetsFactory::createMenu());
|
|
|
|
auto index = m_viewer->indexAt(pos);
|
|
if (index.isValid()) {
|
|
auto selectionModel = m_viewer->selectionModel();
|
|
if (!selectionModel->isSelected(index)) {
|
|
// Must select entire row since we use selectedRows() to count.
|
|
selectionModel->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
|
}
|
|
|
|
m_viewer->update();
|
|
|
|
createContextMenuOnItem(menu.data());
|
|
}
|
|
|
|
m_viewer->update();
|
|
|
|
if (!menu->isEmpty()) {
|
|
menu->exec(m_viewer->mapToGlobal(pos));
|
|
}
|
|
}
|