FileList: support drag&drop to copy/move files

This commit is contained in:
Le Tan 2018-10-12 20:20:24 +08:00
parent d1e7926630
commit ba75c94f40
8 changed files with 192 additions and 13 deletions

View File

@ -148,7 +148,8 @@ SOURCES += main.cpp\
peghighlighterresult.cpp \
vtexteditcompleter.cpp \
utils/vkeyboardlayoutmanager.cpp \
dialog/vkeyboardlayoutmappingdialog.cpp
dialog/vkeyboardlayoutmappingdialog.cpp \
vfilelistwidget.cpp
HEADERS += vmainwindow.h \
vdirectorytree.h \
@ -289,7 +290,8 @@ HEADERS += vmainwindow.h \
vtexteditcompleter.h \
vtextdocumentlayoutdata.h \
utils/vkeyboardlayoutmanager.h \
dialog/vkeyboardlayoutmappingdialog.h
dialog/vkeyboardlayoutmappingdialog.h \
vfilelistwidget.h
RESOURCES += \
vnote.qrc \

View File

@ -25,6 +25,7 @@ namespace ClipboardConfig
static const QString c_isCut = "is_cut";
static const QString c_files = "files";
static const QString c_dirs = "dirs";
static const QString c_format = "text/json";
}
enum class OpenFileMode {Read = 0, Edit, Invalid };

View File

@ -30,6 +30,9 @@ VDirectoryTree::VDirectoryTree(QWidget *parent)
setContextMenuPolicy(Qt::CustomContextMenu);
setFitContent(true);
viewport()->setAcceptDrops(true);
setDropIndicatorShown(true);
initShortcuts();
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)),
@ -1229,3 +1232,69 @@ void VDirectoryTree::pinDirectoryToHistory()
g_mainWin->getHistoryList()->pinFolder(getVDirectory(curItem)->fetchPath());
g_mainWin->showStatusMessage(tr("1 folder pinned to History"));
}
Qt::DropActions VDirectoryTree::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
bool VDirectoryTree::dropMimeData(QTreeWidgetItem *p_parent,
int p_index,
const QMimeData *p_data,
Qt::DropAction p_action)
{
Q_UNUSED(p_index);
if (p_data->hasFormat(ClipboardConfig::c_format)) {
VDirectory *dir = getVDirectory(p_parent);
if (!dir) {
return false;
}
QByteArray ba = p_data->data(ClipboardConfig::c_format);
QJsonObject obj = QJsonDocument::fromJson(ba).object();
if (obj.isEmpty()) {
return false;
}
if (obj[ClipboardConfig::c_type] != (int)ClipboardOpType::CopyFile) {
return false;
}
QJsonArray files = obj[ClipboardConfig::c_files].toArray();
if (files.isEmpty()) {
return false;
}
QVector<QString> filesToPaste;
for (auto const & file : files) {
filesToPaste.append(file.toString());
}
qDebug() << "paste files from dropped mime data" << dir->getName() << filesToPaste;
g_mainWin->getFileList()->pasteFiles(dir, filesToPaste, p_action == Qt::MoveAction);
return true;
}
return false;
}
void VDirectoryTree::dropEvent(QDropEvent *p_event)
{
// Distinguish copy and cut.
int modifiers = p_event->keyboardModifiers();
if (modifiers & Qt::ControlModifier) {
p_event->setDropAction(Qt::CopyAction);
} else {
// Cut.
// Will pass to dropMimeData().
p_event->setDropAction(Qt::MoveAction);
}
QTreeWidget::dropEvent(p_event);
}
QStringList VDirectoryTree::mimeTypes() const
{
return QStringList(ClipboardConfig::c_format);
}

View File

@ -101,6 +101,19 @@ protected:
void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
QStringList mimeTypes() const Q_DECL_OVERRIDE;
Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE;
// Will be called inside dropEvent().
bool dropMimeData(QTreeWidgetItem *p_parent,
int p_index,
const QMimeData *p_data,
Qt::DropAction p_action) Q_DECL_OVERRIDE;
// Drop the data.
void dropEvent(QDropEvent *p_event) Q_DECL_OVERRIDE;
private:
// Build the subtree of @p_parent recursively to the depth @p_depth.
// @p_depth: negative - infinite levels.

View File

@ -83,12 +83,14 @@ void VFileList::setupUI()
titleLayout->setContentsMargins(0, 0, 0, 0);
fileList = new VListWidget(this);
fileList = new VFileListWidget(this);
fileList->setContextMenuPolicy(Qt::CustomContextMenu);
fileList->setSelectionMode(QAbstractItemView::ExtendedSelection);
fileList->setObjectName("FileList");
fileList->setAttribute(Qt::WA_MacShowFocusRect, false);
fileList->setMouseTracking(true);
fileList->setMimeDataGetter([this](const QString &p_format,
const QList<QListWidgetItem *> &p_items) {
return getMimeData(p_format, p_items);
});
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(titleLayout);
@ -1502,3 +1504,22 @@ void VFileList::selectFiles(const QVector<VNoteFile *> &p_files)
}
}
}
QByteArray VFileList::getMimeData(const QString &p_format,
const QList<QListWidgetItem *> &p_items) const
{
Q_UNUSED(p_format);
Q_ASSERT(p_format ==ClipboardConfig::c_format);
QJsonArray files;
for (int i = 0; i < p_items.size(); ++i) {
VNoteFile *file = getVFile(p_items[i]);
files.append(file->fetchPath());
}
QJsonObject obj;
obj[ClipboardConfig::c_type] = (int)ClipboardOpType::CopyFile;
obj[ClipboardConfig::c_files] = files;
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
}

View File

@ -13,10 +13,9 @@
#include "vdirectory.h"
#include "vnotefile.h"
#include "vnavigationmode.h"
#include "vlistwidget.h"
#include "vfilelistwidget.h"
class VNote;
class QListWidget;
class QPushButton;
class VEditArea;
class QFocusEvent;
@ -50,6 +49,11 @@ public:
QWidget *getContentWidget() const;
// Paste files given path by @p_files to destination directory @p_destDir.
void pasteFiles(VDirectory *p_destDir,
const QVector<QString> &p_files,
bool p_isCut);
// Implementations for VNavigationMode.
void showNavigation() Q_DECL_OVERRIDE;
bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;
@ -155,11 +159,6 @@ private:
// Return the corresponding QListWidgetItem of @p_file.
QListWidgetItem *findItem(const VNoteFile *p_file);
// Paste files given path by @p_files to destination directory @p_destDir.
void pasteFiles(VDirectory *p_destDir,
const QVector<QString> &p_files,
bool p_isCut);
inline QPointer<VNoteFile> getVFile(QListWidgetItem *p_item) const;
// Fill the info of @p_item according to @p_file.
@ -190,9 +189,11 @@ private:
void selectFiles(const QVector<VNoteFile *> &p_files);
QByteArray getMimeData(const QString &p_format, const QList<QListWidgetItem *> &p_items) const;
VEditArea *editArea;
VListWidget *fileList;
VFileListWidget *fileList;
QLabel *m_numLabel;

44
src/vfilelistwidget.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "vfilelistwidget.h"
#include <QDebug>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
#include <QMimeData>
#include "vconstants.h"
VFileListWidget::VFileListWidget(QWidget *p_parent)
: VListWidget(p_parent)
{
setSelectionMode(QAbstractItemView::ExtendedSelection);
setDragEnabled(true);
setMouseTracking(true);
}
QStringList VFileListWidget::mimeTypes() const
{
return QStringList(ClipboardConfig::c_format);
}
QMimeData *VFileListWidget::mimeData(const QList<QListWidgetItem *> p_items) const
{
const QString format(ClipboardConfig::c_format);
QStringList types = mimeTypes();
if (!types.contains(format) || p_items.isEmpty()) {
return NULL;
}
if (m_mimeDataGetter) {
QMimeData *data = new QMimeData();
data->setData(format, m_mimeDataGetter(format, p_items));
return data;
}
return NULL;
}
void VFileListWidget::setMimeDataGetter(const MimeDataGetterFunc &p_getter)
{
m_mimeDataGetter = p_getter;
}

28
src/vfilelistwidget.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef VFILELISTWIDGET_H
#define VFILELISTWIDGET_H
#include "vlistwidget.h"
#include <functional>
#include <QList>
typedef std::function<QByteArray(const QString &, const QList<QListWidgetItem *> &)> MimeDataGetterFunc;
class VFileListWidget : public VListWidget
{
Q_OBJECT
public:
explicit VFileListWidget(QWidget *p_parent = nullptr);
void setMimeDataGetter(const MimeDataGetterFunc &p_getter);
protected:
QStringList mimeTypes() const Q_DECL_OVERRIDE;
QMimeData *mimeData(const QList<QListWidgetItem *> p_items) const Q_DECL_OVERRIDE;
private:
MimeDataGetterFunc m_mimeDataGetter;
};
#endif // VFILELISTWIDGET_H