实现最近文件右键菜单功能

This commit is contained in:
gjq 2023-03-16 14:14:16 +08:00 committed by hewenfei
parent ee126378d2
commit 2c77395f40
3 changed files with 163 additions and 22 deletions

View File

@ -99,6 +99,7 @@ UkuiMenuExtension {
MouseArea { MouseArea {
id: itemArea id: itemArea
property bool hovered property bool hovered
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onEntered: { onEntered: {
@ -109,8 +110,10 @@ UkuiMenuExtension {
} }
onClicked: { onClicked: {
var data = { var data = {
"url": model.uri "url": model.uri,
"index": model.index
} }
data["action"] = mouse.button === Qt.RightButton ? "right" : ""
send(data) send(data)
} }
} }

View File

@ -21,15 +21,18 @@
#include <QDebug> #include <QDebug>
#include <QDateTime> #include <QDateTime>
#include <QDBusReply> #include <QDBusReply>
#include <QStandardPaths>
#include <gio/gdesktopappinfo.h> #include <gio/gdesktopappinfo.h>
#include <QDesktopServices> #include <QDesktopServices>
#include <QMenu>
#include "recent-file-extension.h" #include "recent-file-extension.h"
#define KYLIN_APP_MANAGER_NAME "com.kylin.AppManager" #define KYLIN_APP_MANAGER_NAME "com.kylin.AppManager"
#define KYLIN_APP_MANAGER_PATH "/com/kylin/AppManager" #define KYLIN_APP_MANAGER_PATH "/com/kylin/AppManager"
#define KYLIN_APP_MANAGER_INTERFACE "com.kylin.AppManager" #define KYLIN_APP_MANAGER_INTERFACE "com.kylin.AppManager"
#define FREEDESKTOP_FILEMANAGER_NAME "org.freedesktop.FileManager1"
#define FREEDESKTOP_FILEMANAGER_PATH "/org/freedesktop/FileManager1"
#define FREEDESKTOP_FILEMANAGER_INTERFACE "org.freedesktop.FileManager1"
namespace UkuiMenu { namespace UkuiMenu {
@ -38,18 +41,76 @@ class GVFSRecentFileData
{ {
public: public:
static int s_queryFileNum; static int s_queryFileNum;
static GCancellable *s_cancellable; static GFile *s_recentFileRootDir;
static GFileMonitor *s_recentFileMonitor;
static void loadRecentFileASync(RecentFileProvider *p_recentFileProvider); static void loadRecentFileASync(RecentFileProvider *p_recentFileProvider);
static void fileMonitor(RecentFileProvider *p_recentFileProvider);
static void removeRecentFileByInfoId(const QString &infoId);
private: private:
static GFile *s_recentFileRootDir;
static GAsyncReadyCallback enumerateFinish(GFile *file, GAsyncResult *res, RecentFileProvider *p_recentFileProvider); static GAsyncReadyCallback enumerateFinish(GFile *file, GAsyncResult *res, RecentFileProvider *p_recentFileProvider);
static GAsyncReadyCallback parseRecentFiles(GFileEnumerator *enumerator, GAsyncResult *res, RecentFileProvider *p_recentFileProvider); static GAsyncReadyCallback parseRecentFiles(GFileEnumerator *enumerator, GAsyncResult *res, RecentFileProvider *p_recentFileProvider);
static void fileChangedCallback(GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
RecentFileProvider *p_recentFileProvider);
}; };
int GVFSRecentFileData::s_queryFileNum = 100; int GVFSRecentFileData::s_queryFileNum = 100;
GCancellable *GVFSRecentFileData::s_cancellable = g_cancellable_new();
GFile *GVFSRecentFileData::s_recentFileRootDir = g_file_new_for_uri("recent:///"); GFile *GVFSRecentFileData::s_recentFileRootDir = g_file_new_for_uri("recent:///");
GFileMonitor *GVFSRecentFileData::s_recentFileMonitor = nullptr;
void GVFSRecentFileData::fileMonitor(RecentFileProvider *p_recentFileProvider)
{
GError *error = nullptr;
s_recentFileMonitor = g_file_monitor_directory(GVFSRecentFileData::s_recentFileRootDir,
G_FILE_MONITOR_NONE,
nullptr,
&error);
if (error) {
qWarning() << "recentFile monitor creat error";
g_error_free(error);
return;
}
g_signal_connect(s_recentFileMonitor, "changed", G_CALLBACK(fileChangedCallback), p_recentFileProvider);
}
void GVFSRecentFileData::fileChangedCallback(GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
RecentFileProvider *p_recentFileProvider)
{
Q_UNUSED(monitor);
Q_UNUSED(file);
Q_UNUSED(other_file);
switch (event_type) {
case G_FILE_MONITOR_EVENT_DELETED:
case G_FILE_MONITOR_EVENT_CREATED: {
loadRecentFileASync(p_recentFileProvider);
break;
}
default:
break;
}
}
void GVFSRecentFileData::removeRecentFileByInfoId(const QString &infoId)
{
GFile *file = g_file_new_for_uri(infoId.toUtf8().constData());
GError *err = nullptr;
g_file_delete(file, nullptr, &err);
g_object_unref(file);
if (err) {
qWarning() << "Recentfile Delete Error";
}
}
void GVFSRecentFileData::loadRecentFileASync(RecentFileProvider *p_recentFileProvider) void GVFSRecentFileData::loadRecentFileASync(RecentFileProvider *p_recentFileProvider)
{ {
@ -61,7 +122,7 @@ void GVFSRecentFileData::loadRecentFileASync(RecentFileProvider *p_recentFilePro
g_file_enumerate_children_async(s_recentFileRootDir, g_file_enumerate_children_async(s_recentFileRootDir,
"*", "*",
G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT,
s_cancellable, GAsyncReadyCallback(enumerateFinish), nullptr, GAsyncReadyCallback(enumerateFinish),
p_recentFileProvider); p_recentFileProvider);
} }
@ -77,7 +138,7 @@ GVFSRecentFileData::enumerateFinish(GFile *file, GAsyncResult *res, RecentFilePr
} }
g_file_enumerator_next_files_async(enumerator, s_queryFileNum, G_PRIORITY_DEFAULT, g_file_enumerator_next_files_async(enumerator, s_queryFileNum, G_PRIORITY_DEFAULT,
s_cancellable, GAsyncReadyCallback(parseRecentFiles), p_recentFileProvider); nullptr, GAsyncReadyCallback(parseRecentFiles), p_recentFileProvider);
g_object_unref(enumerator); g_object_unref(enumerator);
@ -95,15 +156,19 @@ GVFSRecentFileData::parseRecentFiles(GFileEnumerator *enumerator, GAsyncResult *
return nullptr; return nullptr;
} }
QVector<RecentFile> recentFiles;
if (!fileList) { if (!fileList) {
p_recentFileProvider->dataProcess(recentFiles);
return nullptr; return nullptr;
} }
QVector<RecentFile> recentFiles;
auto listIterator = fileList; auto listIterator = fileList;
while (listIterator) { while (listIterator) {
RecentFile recentFile; RecentFile recentFile;
GFileInfo *info = static_cast<GFileInfo *>(listIterator->data); GFileInfo *info = static_cast<GFileInfo *>(listIterator->data);
GFile *file = g_file_enumerator_get_child(enumerator, info);
recentFile.infoId = g_file_get_uri(file);
g_object_unref(file);
char *attribute = g_file_info_get_attribute_as_string(info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI); char *attribute = g_file_info_get_attribute_as_string(info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
if (attribute) { if (attribute) {
@ -141,7 +206,7 @@ GVFSRecentFileData::parseRecentFiles(GFileEnumerator *enumerator, GAsyncResult *
} }
recentFiles.append(recentFile); recentFiles.append(recentFile);
g_object_unref(info); info = nullptr;
listIterator = listIterator->next; listIterator = listIterator->next;
} }
g_list_free(fileList); g_list_free(fileList);
@ -177,6 +242,7 @@ RecentFileExtension::RecentFileExtension(QObject *parent) : MenuExtensionIFace(p
m_data.insert("recentFilesModel", QVariant::fromValue(m_recentFilesModel)); m_data.insert("recentFilesModel", QVariant::fromValue(m_recentFilesModel));
initFileDbus(); initFileDbus();
GVFSRecentFileData::fileMonitor(m_recentFileProvider);
Q_EMIT loadRecentFiles(); Q_EMIT loadRecentFiles();
} }
@ -191,6 +257,14 @@ RecentFileExtension::~RecentFileExtension()
delete m_recentFileProvider; delete m_recentFileProvider;
m_recentFileProvider = nullptr; m_recentFileProvider = nullptr;
} }
if (GVFSRecentFileData::s_recentFileRootDir) {
g_object_unref(GVFSRecentFileData::s_recentFileRootDir);
}
if (GVFSRecentFileData::s_recentFileMonitor) {
g_object_unref(GVFSRecentFileData::s_recentFileMonitor);
}
} }
int RecentFileExtension::index() int RecentFileExtension::index()
@ -216,6 +290,11 @@ QVariantMap RecentFileExtension::data()
void RecentFileExtension::receive(QVariantMap data) void RecentFileExtension::receive(QVariantMap data)
{ {
QString path = data.value("url").toString(); QString path = data.value("url").toString();
if (data.value("action").toString() == "right") {
int index = data.value("index").toInt();
creatMenu(path, index);
return;
}
if (!openFile(path)) { if (!openFile(path)) {
Q_EMIT openFileASync(path); Q_EMIT openFileASync(path);
} }
@ -228,9 +307,17 @@ void RecentFileExtension::initFileDbus()
KYLIN_APP_MANAGER_INTERFACE, KYLIN_APP_MANAGER_INTERFACE,
QDBusConnection::sessionBus()); QDBusConnection::sessionBus());
m_fileManagerDbusInterface = new QDBusInterface(FREEDESKTOP_FILEMANAGER_NAME,
FREEDESKTOP_FILEMANAGER_PATH,
FREEDESKTOP_FILEMANAGER_INTERFACE,
QDBusConnection::sessionBus());
if (!m_appManagerDbusInterface) { if (!m_appManagerDbusInterface) {
qWarning() << "recentfile open failed: appmanager dbus does not exists."; qWarning() << "recentfile open failed: appmanager dbus does not exists.";
} }
if (!m_fileManagerDbusInterface) {
qWarning() << "recentfile directory open failed: filemanager dbus does not exists.";
}
} }
bool RecentFileExtension::openFile(const QString &desktopFile) bool RecentFileExtension::openFile(const QString &desktopFile)
@ -244,6 +331,48 @@ bool RecentFileExtension::openFile(const QString &desktopFile)
} }
} }
void RecentFileExtension::creatMenu(const QString &path, const int &index)
{
QMenu menu;
QAction open(QIcon::fromTheme("document-open-symbolic"), tr("Open"));
QAction remove(QIcon::fromTheme("edit-clear-symbolic"), tr("Remove from recent"));
QAction clear(QIcon::fromTheme("edit-delete-symbolic"), tr("Clear list"));
QAction directory(tr("Open the directory where the file is located"));
connect(&open, &QAction::triggered, this, [this, path]() {
if (!openFile(path)) {
Q_EMIT openFileASync(path);
}
});
connect(&remove, &QAction::triggered, this, [this, index]() {
GVFSRecentFileData::removeRecentFileByInfoId(m_recentFilesModel->getInfoId(index));
});
connect(&clear, &QAction::triggered, this, [this]() {
QStringList infoIdList = m_recentFilesModel->getAllInfoId();
for (const QString &infoId : infoIdList) {
GVFSRecentFileData::removeRecentFileByInfoId(infoId);
}
});
connect(&directory, &QAction::triggered, this, [this, path]() {
if (!m_fileManagerDbusInterface) { return; }
QStringList pathList;
pathList.append(path);
m_fileManagerDbusInterface->call("ShowFolders", pathList, "arg");
});
menu.addAction(&open);
menu.addSeparator();
menu.addAction(&remove);
menu.addAction(&clear);
menu.addSeparator();
menu.addAction(&directory);
menu.exec(QCursor::pos());
}
RecentFilesModel::RecentFilesModel(QObject *parent) : QAbstractListModel(parent) RecentFilesModel::RecentFilesModel(QObject *parent) : QAbstractListModel(parent)
{ {
@ -284,6 +413,20 @@ QHash<int, QByteArray> RecentFilesModel::roleNames() const
return names; return names;
} }
QString RecentFilesModel::getInfoId(const int &index)
{
return m_recentFileData.at(index).infoId;
}
QStringList RecentFilesModel::getAllInfoId()
{
QStringList infoIdList;
for (const RecentFile &data : m_recentFileData) {
infoIdList.append(data.infoId);
}
return infoIdList;
}
void RecentFilesModel::updateData() void RecentFilesModel::updateData()
{ {
Q_EMIT updateRecentData(); Q_EMIT updateRecentData();

View File

@ -29,21 +29,12 @@ namespace UkuiMenu {
class RecentFile class RecentFile
{ {
Q_GADGET
Q_PROPERTY(QString uri READ getUri)
Q_PROPERTY(QString name READ getName)
Q_PROPERTY(QString icon READ getIcon)
public:
QString getUri() { return uri; }
QString getName() { return name; }
QString getIcon() { return icon; }
public: public:
quint64 accessTime{0}; quint64 accessTime{0};
QString uri; QString uri;
QString name; QString name;
QString icon; QString icon;
QString infoId;
}; };
class RecentFileProvider : public QObject class RecentFileProvider : public QObject
@ -77,6 +68,8 @@ public:
QVariant data(const QModelIndex &index, int role) const override; QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
QString getInfoId(const int &index);
QStringList getAllInfoId();
Q_INVOKABLE void updateData(); Q_INVOKABLE void updateData();
public Q_SLOT: public Q_SLOT:
@ -109,9 +102,11 @@ private:
RecentFilesModel *m_recentFilesModel = nullptr; RecentFilesModel *m_recentFilesModel = nullptr;
QThread *m_recentFilesProviderThread = nullptr; QThread *m_recentFilesProviderThread = nullptr;
RecentFileProvider *m_recentFileProvider = nullptr; RecentFileProvider *m_recentFileProvider = nullptr;
QDBusInterface *m_fileManagerDbusInterface = nullptr;
void initFileDbus(); void initFileDbus();
bool openFile(const QString& desktopFile); bool openFile(const QString& desktopFile);
void creatMenu(const QString &path, const int &index);
Q_SIGNALS: Q_SIGNALS:
void loadRecentFiles(); void loadRecentFiles();