forked from openkylin/ukui-menu
实现最近文件右键菜单功能
This commit is contained in:
parent
ee126378d2
commit
2c77395f40
|
@ -99,6 +99,7 @@ UkuiMenuExtension {
|
|||
MouseArea {
|
||||
id: itemArea
|
||||
property bool hovered
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
|
@ -109,8 +110,10 @@ UkuiMenuExtension {
|
|||
}
|
||||
onClicked: {
|
||||
var data = {
|
||||
"url": model.uri
|
||||
"url": model.uri,
|
||||
"index": model.index
|
||||
}
|
||||
data["action"] = mouse.button === Qt.RightButton ? "right" : ""
|
||||
send(data)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,18 @@
|
|||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
#include <QDBusReply>
|
||||
#include <QStandardPaths>
|
||||
#include <gio/gdesktopappinfo.h>
|
||||
#include <QDesktopServices>
|
||||
#include <QMenu>
|
||||
|
||||
#include "recent-file-extension.h"
|
||||
|
||||
#define KYLIN_APP_MANAGER_NAME "com.kylin.AppManager"
|
||||
#define KYLIN_APP_MANAGER_PATH "/com/kylin/AppManager"
|
||||
#define KYLIN_APP_MANAGER_INTERFACE "com.kylin.AppManager"
|
||||
#define KYLIN_APP_MANAGER_NAME "com.kylin.AppManager"
|
||||
#define KYLIN_APP_MANAGER_PATH "/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 {
|
||||
|
||||
|
@ -38,18 +41,76 @@ class GVFSRecentFileData
|
|||
{
|
||||
public:
|
||||
static int s_queryFileNum;
|
||||
static GCancellable *s_cancellable;
|
||||
static GFile *s_recentFileRootDir;
|
||||
static GFileMonitor *s_recentFileMonitor;
|
||||
static void loadRecentFileASync(RecentFileProvider *p_recentFileProvider);
|
||||
static void fileMonitor(RecentFileProvider *p_recentFileProvider);
|
||||
static void removeRecentFileByInfoId(const QString &infoId);
|
||||
|
||||
private:
|
||||
static GFile *s_recentFileRootDir;
|
||||
static GAsyncReadyCallback enumerateFinish(GFile *file, 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;
|
||||
GCancellable *GVFSRecentFileData::s_cancellable = g_cancellable_new();
|
||||
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)
|
||||
{
|
||||
|
@ -61,7 +122,7 @@ void GVFSRecentFileData::loadRecentFileASync(RecentFileProvider *p_recentFilePro
|
|||
g_file_enumerate_children_async(s_recentFileRootDir,
|
||||
"*",
|
||||
G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT,
|
||||
s_cancellable, GAsyncReadyCallback(enumerateFinish),
|
||||
nullptr, GAsyncReadyCallback(enumerateFinish),
|
||||
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,
|
||||
s_cancellable, GAsyncReadyCallback(parseRecentFiles), p_recentFileProvider);
|
||||
nullptr, GAsyncReadyCallback(parseRecentFiles), p_recentFileProvider);
|
||||
|
||||
g_object_unref(enumerator);
|
||||
|
||||
|
@ -95,15 +156,19 @@ GVFSRecentFileData::parseRecentFiles(GFileEnumerator *enumerator, GAsyncResult *
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
QVector<RecentFile> recentFiles;
|
||||
if (!fileList) {
|
||||
p_recentFileProvider->dataProcess(recentFiles);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QVector<RecentFile> recentFiles;
|
||||
auto listIterator = fileList;
|
||||
while (listIterator) {
|
||||
RecentFile recentFile;
|
||||
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);
|
||||
if (attribute) {
|
||||
|
@ -141,7 +206,7 @@ GVFSRecentFileData::parseRecentFiles(GFileEnumerator *enumerator, GAsyncResult *
|
|||
}
|
||||
|
||||
recentFiles.append(recentFile);
|
||||
g_object_unref(info);
|
||||
info = nullptr;
|
||||
listIterator = listIterator->next;
|
||||
}
|
||||
g_list_free(fileList);
|
||||
|
@ -177,6 +242,7 @@ RecentFileExtension::RecentFileExtension(QObject *parent) : MenuExtensionIFace(p
|
|||
m_data.insert("recentFilesModel", QVariant::fromValue(m_recentFilesModel));
|
||||
initFileDbus();
|
||||
|
||||
GVFSRecentFileData::fileMonitor(m_recentFileProvider);
|
||||
Q_EMIT loadRecentFiles();
|
||||
}
|
||||
|
||||
|
@ -191,6 +257,14 @@ RecentFileExtension::~RecentFileExtension()
|
|||
delete m_recentFileProvider;
|
||||
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()
|
||||
|
@ -216,6 +290,11 @@ QVariantMap RecentFileExtension::data()
|
|||
void RecentFileExtension::receive(QVariantMap data)
|
||||
{
|
||||
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)) {
|
||||
Q_EMIT openFileASync(path);
|
||||
}
|
||||
|
@ -228,9 +307,17 @@ void RecentFileExtension::initFileDbus()
|
|||
KYLIN_APP_MANAGER_INTERFACE,
|
||||
QDBusConnection::sessionBus());
|
||||
|
||||
m_fileManagerDbusInterface = new QDBusInterface(FREEDESKTOP_FILEMANAGER_NAME,
|
||||
FREEDESKTOP_FILEMANAGER_PATH,
|
||||
FREEDESKTOP_FILEMANAGER_INTERFACE,
|
||||
QDBusConnection::sessionBus());
|
||||
|
||||
if (!m_appManagerDbusInterface) {
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
||||
|
@ -284,6 +413,20 @@ QHash<int, QByteArray> RecentFilesModel::roleNames() const
|
|||
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()
|
||||
{
|
||||
Q_EMIT updateRecentData();
|
||||
|
|
|
@ -29,21 +29,12 @@ namespace UkuiMenu {
|
|||
|
||||
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:
|
||||
quint64 accessTime{0};
|
||||
QString uri;
|
||||
QString name;
|
||||
QString icon;
|
||||
QString infoId;
|
||||
};
|
||||
|
||||
class RecentFileProvider : public QObject
|
||||
|
@ -77,6 +68,8 @@ public:
|
|||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
QString getInfoId(const int &index);
|
||||
QStringList getAllInfoId();
|
||||
Q_INVOKABLE void updateData();
|
||||
|
||||
public Q_SLOT:
|
||||
|
@ -109,9 +102,11 @@ private:
|
|||
RecentFilesModel *m_recentFilesModel = nullptr;
|
||||
QThread *m_recentFilesProviderThread = nullptr;
|
||||
RecentFileProvider *m_recentFileProvider = nullptr;
|
||||
QDBusInterface *m_fileManagerDbusInterface = nullptr;
|
||||
|
||||
void initFileDbus();
|
||||
bool openFile(const QString& desktopFile);
|
||||
void creatMenu(const QString &path, const int &index);
|
||||
|
||||
Q_SIGNALS:
|
||||
void loadRecentFiles();
|
||||
|
|
Loading…
Reference in New Issue