实现最近文件右键菜单功能
This commit is contained in:
parent
ee126378d2
commit
2c77395f40
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue