Add management app
This commit is contained in:
parent
a8c1fab1d5
commit
211a442d90
12 changed files with 860 additions and 21 deletions
|
@ -38,6 +38,10 @@ add_executable(cutefish-filemanager
|
|||
helper/pathhistory.cpp
|
||||
helper/fm.cpp
|
||||
helper/shortcut.cpp
|
||||
helper/filelauncher.cpp
|
||||
|
||||
mimetype/mimeappmanager.cpp
|
||||
mimetype/xdgdesktopfile.cpp
|
||||
|
||||
thumbnailer/thumbnailprovider.cpp
|
||||
thumbnailer/thumbnailcache.cpp
|
||||
|
|
78
helper/filelauncher.cpp
Normal file
78
helper/filelauncher.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reionwong@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "filelauncher.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QProcess>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
FileLauncher *SELF = nullptr;
|
||||
|
||||
FileLauncher *FileLauncher::self()
|
||||
{
|
||||
if (SELF == nullptr)
|
||||
SELF = new FileLauncher;
|
||||
|
||||
return SELF;
|
||||
}
|
||||
|
||||
FileLauncher::FileLauncher(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool FileLauncher::launchApp(const QString &desktopFile, const QString &fileName)
|
||||
{
|
||||
QSettings settings(desktopFile, QSettings::IniFormat);
|
||||
settings.beginGroup("Desktop Entry");
|
||||
|
||||
QStringList list = settings.value("Exec").toString().split(' ');
|
||||
QStringList args;
|
||||
|
||||
if (list.isEmpty() || list.size() < 0)
|
||||
return false;
|
||||
|
||||
QString exec = list.first();
|
||||
list.removeOne(exec);
|
||||
|
||||
for (const QString &arg : list) {
|
||||
QString newArg = arg;
|
||||
|
||||
if (newArg.startsWith("%F", Qt::CaseInsensitive))
|
||||
newArg.replace("%F", fileName, Qt::CaseInsensitive);
|
||||
|
||||
if (newArg.startsWith("%U", Qt::CaseInsensitive))
|
||||
newArg.replace("%U", fileName, Qt::CaseInsensitive);
|
||||
|
||||
args.append(newArg);
|
||||
}
|
||||
|
||||
qDebug() << "launchApp()" << exec << args;
|
||||
|
||||
return QProcess::startDetached(exec, args);
|
||||
}
|
||||
|
||||
bool FileLauncher::launchExecutable(const QString &fileName)
|
||||
{
|
||||
return QProcess::startDetached(fileName, QStringList());
|
||||
}
|
37
helper/filelauncher.h
Normal file
37
helper/filelauncher.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reionwong@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FILELAUNCHER_H
|
||||
#define FILELAUNCHER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class FileLauncher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static FileLauncher *self();
|
||||
explicit FileLauncher(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE bool launchApp(const QString &desktopFile, const QString &fileName);
|
||||
Q_INVOKABLE bool launchExecutable(const QString &fileName);
|
||||
};
|
||||
|
||||
#endif // FILELAUNCHER_H
|
433
mimetype/mimeappmanager.cpp
Normal file
433
mimetype/mimeappmanager.cpp
Normal file
|
@ -0,0 +1,433 @@
|
|||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reionwong@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mimeappmanager.h"
|
||||
|
||||
#include <QDirIterator>
|
||||
#include <QUrl>
|
||||
#include <QDir>
|
||||
|
||||
#include <QMimeDatabase>
|
||||
#include <QMimeType>
|
||||
#include <QProcess>
|
||||
#include <QSettings>
|
||||
#include <QDateTime>
|
||||
#include <QThread>
|
||||
#include <QDebug>
|
||||
#include <QSet>
|
||||
|
||||
static MimeAppManager *SELF = nullptr;
|
||||
|
||||
MimeAppManager *MimeAppManager::self()
|
||||
{
|
||||
if (!SELF)
|
||||
SELF = new MimeAppManager;
|
||||
|
||||
return SELF;
|
||||
}
|
||||
|
||||
MimeAppManager::MimeAppManager(QObject *parent)
|
||||
: QObject(parent),
|
||||
m_fileSystemWatcher(new QFileSystemWatcher),
|
||||
m_updateTimer(new QTimer(this))
|
||||
{
|
||||
m_updateTimer->setInterval(100);
|
||||
m_updateTimer->setSingleShot(true);
|
||||
|
||||
m_fileSystemWatcher->addPaths(desktopPaths());
|
||||
|
||||
connect(m_fileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &MimeAppManager::onFileChanged);
|
||||
connect(m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, this, &MimeAppManager::onFileChanged);
|
||||
connect(m_updateTimer, &QTimer::timeout, this, &MimeAppManager::initApplications);
|
||||
|
||||
m_updateTimer->start();
|
||||
}
|
||||
|
||||
QStringList MimeAppManager::desktopPaths()
|
||||
{
|
||||
QStringList folders;
|
||||
folders << QString("/usr/share/applications")
|
||||
<< QString("/usr/local/share/applications/")
|
||||
<< QDir::homePath() + QString("/.local/share/applications");
|
||||
|
||||
return folders;
|
||||
}
|
||||
|
||||
QString MimeAppManager::mimeAppsListFilePath()
|
||||
{
|
||||
return QString("%1/.config/mimeapps.list").arg(QDir::homePath());
|
||||
}
|
||||
|
||||
void MimeAppManager::initApplications()
|
||||
{
|
||||
m_desktopFiles.clear();
|
||||
m_desktopObjects.clear();
|
||||
|
||||
QMap<QString, QSet<QString>> mimeAppsSet;
|
||||
|
||||
for (const QString &folder : desktopPaths()) {
|
||||
QDirIterator itor(folder, QStringList("*.desktop"), QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
while (itor.hasNext()) {
|
||||
itor.next();
|
||||
QString filePath = itor.filePath();
|
||||
XdgDesktopFile desktopFile(filePath);
|
||||
|
||||
if (!desktopFile.valid())
|
||||
continue;
|
||||
|
||||
m_desktopFiles.append(filePath);
|
||||
m_desktopObjects.insert(filePath, desktopFile);
|
||||
|
||||
// Load terminal
|
||||
QStringList categories = desktopFile.value("Categories").toString().split(";");
|
||||
if (categories.contains("TerminalEmulator")) {
|
||||
m_terminalApps.append(desktopFile);
|
||||
}
|
||||
|
||||
QStringList mimeTypes = desktopFile.value("MimeType").toString().trimmed().split(";");
|
||||
for (const QString &mimeType : mimeTypes) {
|
||||
if (!mimeType.isEmpty()) {
|
||||
QSet<QString> apps;
|
||||
if (mimeAppsSet.contains(mimeType)) {
|
||||
apps = mimeAppsSet.value(mimeType);
|
||||
apps.insert(filePath);
|
||||
} else {
|
||||
apps.insert(filePath);
|
||||
}
|
||||
|
||||
mimeAppsSet.insert(mimeType, apps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const QString &key : mimeAppsSet.keys()) {
|
||||
QSet<QString> apps = mimeAppsSet.value(key);
|
||||
QStringList orderApps;
|
||||
|
||||
if (apps.count() > 1) {
|
||||
QFileInfoList fileInfos;
|
||||
for (const QString &app : apps) {
|
||||
QFileInfo info(app);
|
||||
fileInfos.append(info);
|
||||
}
|
||||
|
||||
std::sort(fileInfos.begin(), fileInfos.end(), [=] (const QFileInfo &f1, const QFileInfo &f2) {
|
||||
return f1.birthTime() < f2.birthTime();
|
||||
});
|
||||
|
||||
for (QFileInfo info : fileInfos) {
|
||||
orderApps.append(info.absoluteFilePath());
|
||||
}
|
||||
} else {
|
||||
orderApps.append(apps.values());
|
||||
}
|
||||
|
||||
m_mimeApps.insert(key, orderApps);
|
||||
}
|
||||
|
||||
// Check from cache.
|
||||
// ref: https://specifications.freedesktop.org/desktop-entry-spec/0.9.5/ar01s07.html
|
||||
|
||||
QFile file("/usr/share/applications/mimeinfo.cache");
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
|
||||
QStringList audioDesktopList;
|
||||
QStringList imageDeksopList;
|
||||
QStringList textDekstopList;
|
||||
QStringList videoDesktopList;
|
||||
|
||||
while (!file.atEnd()) {
|
||||
QString line = file.readLine();
|
||||
QString mimeType = line.split("=").first();
|
||||
QString _desktops = line.split("=").last();
|
||||
QStringList desktops = _desktops.split(";");
|
||||
|
||||
for (const QString &desktop : desktops) {
|
||||
if (desktop.isEmpty() || audioDesktopList.contains(desktop))
|
||||
continue;
|
||||
|
||||
if (mimeType.startsWith("audio")) {
|
||||
if (!audioDesktopList.contains(desktop))
|
||||
audioDesktopList.append(desktop);
|
||||
} else if (mimeType.startsWith("image")) {
|
||||
if (!imageDeksopList.contains(desktop))
|
||||
imageDeksopList.append(desktop);
|
||||
} else if (mimeType.startsWith("text")) {
|
||||
if (!textDekstopList.contains(desktop))
|
||||
textDekstopList.append(desktop);
|
||||
} else if (mimeType.startsWith("video")) {
|
||||
if (!videoDesktopList.contains(desktop))
|
||||
videoDesktopList.append(desktop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
const QString mimeInfoCacheRootPath = "/usr/share/applications";
|
||||
for (const QString &desktop : audioDesktopList) {
|
||||
const QString &path = QString("%1/%2").arg(mimeInfoCacheRootPath, desktop);
|
||||
if (!QFile::exists(path))
|
||||
continue;
|
||||
|
||||
XdgDesktopFile desktopFile(path);
|
||||
if (desktopFile.valid())
|
||||
m_audioMimeApps.insert(path, desktopFile);
|
||||
}
|
||||
|
||||
for (const QString &desktop : imageDeksopList) {
|
||||
const QString &path = QString("%1/%2").arg(mimeInfoCacheRootPath, desktop);
|
||||
if (!QFile::exists(path))
|
||||
continue;
|
||||
|
||||
XdgDesktopFile desktopFile(path);
|
||||
if (desktopFile.valid())
|
||||
m_imageMimeApps.insert(path, desktopFile);
|
||||
}
|
||||
|
||||
for (const QString &desktop : textDekstopList) {
|
||||
const QString &path = QString("%1/%2").arg(mimeInfoCacheRootPath, desktop);
|
||||
if (!QFile::exists(path))
|
||||
continue;
|
||||
|
||||
XdgDesktopFile desktopFile(path);
|
||||
if (desktopFile.valid())
|
||||
m_textMimeApps.insert(path, desktopFile);
|
||||
}
|
||||
|
||||
for (const QString &desktop : videoDesktopList) {
|
||||
const QString &path = QString("%1/%2").arg(mimeInfoCacheRootPath, desktop);
|
||||
if (!QFile::exists(path))
|
||||
continue;
|
||||
|
||||
XdgDesktopFile desktopFile(path);
|
||||
if (desktopFile.valid())
|
||||
m_videoMimeApps.insert(path, desktopFile);
|
||||
}
|
||||
}
|
||||
|
||||
QString MimeAppManager::getDefaultAppByFilePath(const QString &filePath)
|
||||
{
|
||||
return getDefaultAppByMimeType(QMimeDatabase().mimeTypeForFile(filePath));
|
||||
}
|
||||
|
||||
QString MimeAppManager::getDefaultAppByMimeType(const QMimeType &mimeType)
|
||||
{
|
||||
QString mimeappsFile = mimeAppsListFilePath();
|
||||
|
||||
if (!QFile::exists(mimeappsFile))
|
||||
return QString();
|
||||
|
||||
QSettings settings(mimeappsFile, QSettings::IniFormat);
|
||||
|
||||
// for (const QString group : settings.childGroups()) {
|
||||
// settings.beginGroup(group);
|
||||
// for (const QString &key : settings.allKeys()) {
|
||||
// if (key == mimeType.name())
|
||||
// return settings.value(key).toString();
|
||||
// }
|
||||
// settings.endGroup();
|
||||
// }
|
||||
|
||||
settings.beginGroup("Default Applications");
|
||||
// TODO: User applications directory?
|
||||
if (settings.contains(mimeType.name()))
|
||||
return QString("/usr/share/applications/%1").arg(settings.value(mimeType.name()).toString());
|
||||
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup("Added Associations");
|
||||
if (settings.contains(mimeType.name()))
|
||||
return QString("/usr/share/applications/%1").arg(settings.value(mimeType.name()).toString());
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString MimeAppManager::getDefaultAppDesktopByMimeType(const QString &mimeType)
|
||||
{
|
||||
return getDefaultAppByMimeType(QMimeDatabase().mimeTypeForName(mimeType));
|
||||
}
|
||||
|
||||
bool MimeAppManager::setDefaultAppForType(const QString &mimeType, const QString &app)
|
||||
{
|
||||
// ref: https://specifications.freedesktop.org/mime-apps-spec/1.0.1/ar01s03.html
|
||||
|
||||
QString mimeappsFile = mimeAppsListFilePath();
|
||||
QString desktop = app;
|
||||
|
||||
if (QFile::exists(desktop)) {
|
||||
QFileInfo info(desktop);
|
||||
desktop = info.completeBaseName();
|
||||
}
|
||||
|
||||
// QSettings settings(mimeappsFile, QSettings::IniFormat);
|
||||
// settings.setIniCodec("UTF-8");
|
||||
|
||||
// if (!settings.isWritable())
|
||||
// return false;
|
||||
|
||||
// settings.beginGroup("Default Applications");
|
||||
// settings.setValue(mimeType, desktop);
|
||||
// settings.sync();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MimeAppManager::setDefaultAppForFile(const QString &filePath, const QString &desktop)
|
||||
{
|
||||
// ref: https://specifications.freedesktop.org/mime-apps-spec/1.0.1/ar01s03.html
|
||||
|
||||
QString mimeappsFile = mimeAppsListFilePath();
|
||||
QMimeType mimeType;
|
||||
QString value = desktop;
|
||||
|
||||
if (!QFile::exists(filePath))
|
||||
return false;
|
||||
else
|
||||
mimeType = QMimeDatabase().mimeTypeForFile(filePath);
|
||||
|
||||
if (QFile::exists(value)) {
|
||||
QFileInfo info(value);
|
||||
value = info.fileName();
|
||||
}
|
||||
|
||||
// QSettings settings(mimeappsFile, QSettings::IniFormat);
|
||||
// settings.setIniCodec("UTF-8");
|
||||
|
||||
// if (!settings.isWritable())
|
||||
// return false;
|
||||
|
||||
// settings.beginGroup("Default Applications"); // Added Associations
|
||||
// settings.setValue(mimeType.name(), value);
|
||||
// settings.sync();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList MimeAppManager::getRecommendedAppsByFilePath(const QString &filePath)
|
||||
{
|
||||
return getRecommendedAppsByMimeType(QMimeDatabase().mimeTypeForFile(filePath));
|
||||
}
|
||||
|
||||
QStringList MimeAppManager::getRecommendedAppsByMimeType(const QMimeType &mimeType)
|
||||
{
|
||||
QStringList recommendApps;
|
||||
QList<QMimeType> mimeTypeList;
|
||||
QMimeDatabase mimeDatabase;
|
||||
|
||||
mimeTypeList.append(mimeType);
|
||||
|
||||
while (recommendApps.isEmpty()) {
|
||||
for (const QMimeType &type : mimeTypeList) {
|
||||
QStringList typeNameList;
|
||||
|
||||
typeNameList.append(type.name());
|
||||
typeNameList.append(type.aliases());
|
||||
|
||||
for (const QString &name : typeNameList) {
|
||||
for (const QString &app : m_mimeApps.value(name)) {
|
||||
bool exists = false;
|
||||
|
||||
for (const QString &other : recommendApps) {
|
||||
const XdgDesktopFile &appDesktop = m_desktopObjects.value(app);
|
||||
const XdgDesktopFile &otherDesktop = m_desktopObjects.value(other);
|
||||
|
||||
if (appDesktop.value("Exec").toString() == otherDesktop.value("Exec").toString() &&
|
||||
appDesktop.localeName() == otherDesktop.localeName()) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if desktop file was not existed do not recommend!!
|
||||
if (!QFileInfo::exists(app)) {
|
||||
qWarning() << app << "not exist anymore";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!exists)
|
||||
recommendApps.append(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!recommendApps.isEmpty())
|
||||
break;
|
||||
|
||||
QList<QMimeType> newMimeTypeList;
|
||||
for (const QMimeType &type : mimeTypeList) {
|
||||
for (const QString &name : type.parentMimeTypes())
|
||||
newMimeTypeList.append(mimeDatabase.mimeTypeForName(name));
|
||||
}
|
||||
|
||||
mimeTypeList = newMimeTypeList;
|
||||
|
||||
if (mimeTypeList.isEmpty())
|
||||
break;
|
||||
}
|
||||
|
||||
return recommendApps;
|
||||
}
|
||||
|
||||
QVariantList MimeAppManager::recommendedApps(const QUrl &url)
|
||||
{
|
||||
QVariantList list;
|
||||
|
||||
if (url.isValid()) {
|
||||
const QString &filePath = url.toString();
|
||||
|
||||
for (const QString &path : getRecommendedAppsByFilePath(filePath)) {
|
||||
XdgDesktopFile desktop(path);
|
||||
|
||||
if (desktop.valid())
|
||||
continue;
|
||||
|
||||
QVariantMap item;
|
||||
item["icon"] = desktop.value("IconName").toString();
|
||||
item["name"] = desktop.localeName();
|
||||
item["desktopFile"] = path;
|
||||
|
||||
list << item;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void MimeAppManager::launchTerminal(const QString &path)
|
||||
{
|
||||
if (m_terminalApps.isEmpty())
|
||||
return;
|
||||
|
||||
QString command = m_terminalApps.first().value("Exec").toString();
|
||||
QProcess process;
|
||||
process.setProgram(command);
|
||||
// Launch terminal with working directory set.
|
||||
process.setWorkingDirectory(path);
|
||||
process.startDetached();
|
||||
}
|
||||
|
||||
void MimeAppManager::onFileChanged(const QString &path)
|
||||
{
|
||||
Q_UNUSED(path);
|
||||
|
||||
m_updateTimer->start();
|
||||
}
|
76
mimetype/mimeappmanager.h
Normal file
76
mimetype/mimeappmanager.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reionwong@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MIMEAPPMANAGER_H
|
||||
#define MIMEAPPMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QFileInfo>
|
||||
#include <QTimer>
|
||||
#include <QMap>
|
||||
|
||||
#include "xdgdesktopfile.h"
|
||||
|
||||
class QMimeType;
|
||||
class MimeAppManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static MimeAppManager *self();
|
||||
explicit MimeAppManager(QObject *parent = nullptr);
|
||||
|
||||
QStringList desktopPaths();
|
||||
QString mimeAppsListFilePath();
|
||||
void initApplications();
|
||||
|
||||
QString getDefaultAppByFilePath(const QString &filePath);
|
||||
QString getDefaultAppByMimeType(const QMimeType &mimeType);
|
||||
QString getDefaultAppDesktopByMimeType(const QString &mimeType);
|
||||
Q_INVOKABLE bool setDefaultAppForType(const QString &mimeType, const QString &app);
|
||||
Q_INVOKABLE bool setDefaultAppForFile(const QString &filePath, const QString &desktop);
|
||||
|
||||
QStringList getRecommendedAppsByFilePath(const QString &filePath);
|
||||
QStringList getRecommendedAppsByMimeType(const QMimeType &mimeType);
|
||||
|
||||
Q_INVOKABLE QVariantList recommendedApps(const QUrl &url);
|
||||
|
||||
Q_INVOKABLE void launchTerminal(const QString &path);
|
||||
|
||||
private slots:
|
||||
void onFileChanged(const QString &path);
|
||||
|
||||
private:
|
||||
QStringList m_desktopFiles;
|
||||
QMap<QString, QStringList> m_mimeApps;
|
||||
|
||||
QMap<QString, XdgDesktopFile> m_videoMimeApps;
|
||||
QMap<QString, XdgDesktopFile> m_imageMimeApps;
|
||||
QMap<QString, XdgDesktopFile> m_textMimeApps;
|
||||
QMap<QString, XdgDesktopFile> m_audioMimeApps;
|
||||
QMap<QString, XdgDesktopFile> m_desktopObjects;
|
||||
|
||||
QList<XdgDesktopFile> m_terminalApps;
|
||||
|
||||
QFileSystemWatcher *m_fileSystemWatcher;
|
||||
QTimer *m_updateTimer;
|
||||
};
|
||||
|
||||
#endif // MIMEAPPMANAGER_H
|
153
mimetype/xdgdesktopfile.cpp
Normal file
153
mimetype/xdgdesktopfile.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reionwong@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "xdgdesktopfile.h"
|
||||
#include <QTextStream>
|
||||
#include <QFile>
|
||||
#include <QLocale>
|
||||
|
||||
XdgDesktopFile::XdgDesktopFile(const QString &fileName)
|
||||
: m_isValid(false)
|
||||
, m_fileName(fileName)
|
||||
{
|
||||
if (!m_fileName.isEmpty())
|
||||
load();
|
||||
}
|
||||
|
||||
bool XdgDesktopFile::valid() const
|
||||
{
|
||||
return m_isValid;
|
||||
}
|
||||
|
||||
QVariant XdgDesktopFile::value(const QString &key, const QVariant &defaultValue) const
|
||||
{
|
||||
QString path = (!prefix().isEmpty()) ? prefix() + QLatin1Char('/') + key : key;
|
||||
QVariant res = m_items.value(path, defaultValue);
|
||||
return res;
|
||||
}
|
||||
|
||||
void XdgDesktopFile::setValue(const QString &key, const QVariant &value)
|
||||
{
|
||||
QString path = (!prefix().isEmpty()) ? prefix() + QLatin1Char('/') + key : key;
|
||||
|
||||
if (value.type() == QVariant::String) {
|
||||
QString s = value.toString();
|
||||
m_items[path] = QVariant(s);
|
||||
} else {
|
||||
m_items[path] = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool XdgDesktopFile::load()
|
||||
{
|
||||
if (!QFile::exists(m_fileName))
|
||||
return false;
|
||||
|
||||
m_items.clear();
|
||||
|
||||
read("Desktop Entry");
|
||||
|
||||
return m_isValid;
|
||||
}
|
||||
|
||||
bool XdgDesktopFile::save()
|
||||
{
|
||||
QFile file(m_fileName);
|
||||
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
return false;
|
||||
|
||||
QTextStream stream(&file);
|
||||
QMap<QString, QVariant>::const_iterator i = m_items.constBegin();
|
||||
QString section;
|
||||
|
||||
while (i != m_items.constBegin()) {
|
||||
QString path = i.key();
|
||||
QString sect = path.section(QChar('/'), 0, 0);
|
||||
|
||||
if (sect != section) {
|
||||
section = sect;
|
||||
stream << QLatin1Char('[') << section << QChar(']') << Qt::endl;
|
||||
}
|
||||
|
||||
QString key = path.section(QChar('/'), 1);
|
||||
stream << key << QLatin1Char('=') << i.value().toString() << Qt::endl;
|
||||
++i;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString XdgDesktopFile::localeName() const
|
||||
{
|
||||
QString localeKey = QString("Name[%1]").arg(QLocale::system().name());
|
||||
|
||||
if (m_items.contains(localeKey)) {
|
||||
return m_items[localeKey].toString();
|
||||
}
|
||||
|
||||
return m_items["Name"].toString();
|
||||
}
|
||||
|
||||
QString XdgDesktopFile::prefix() const
|
||||
{
|
||||
return QLatin1String("Desktop Entry");
|
||||
}
|
||||
|
||||
bool XdgDesktopFile::read(const QString &prefix)
|
||||
{
|
||||
QFile file(m_fileName);
|
||||
|
||||
// Can't open file.
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return false;
|
||||
|
||||
QTextStream stream(&file);
|
||||
QString section;
|
||||
bool prefixExists = false;
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine().trimmed();
|
||||
|
||||
// Skip comments.
|
||||
if (line.startsWith("#"))
|
||||
continue;
|
||||
|
||||
// Find the prefix string.
|
||||
if (line.startsWith(QChar('[')) && line.endsWith(QChar(']'))) {
|
||||
section = line.mid(1, line.length() - 2);
|
||||
|
||||
if (section == prefix)
|
||||
prefixExists = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
QString key = line.section(QLatin1Char('='), 0, 0).trimmed();
|
||||
QString value = line.section(QLatin1Char('='), 1).trimmed();
|
||||
|
||||
if (key.isEmpty())
|
||||
continue;
|
||||
|
||||
m_items[section + QLatin1Char('/') + key] = QVariant(value);
|
||||
}
|
||||
|
||||
m_isValid = (prefix.isEmpty()) || prefixExists;
|
||||
return m_isValid;
|
||||
}
|
53
mimetype/xdgdesktopfile.h
Normal file
53
mimetype/xdgdesktopfile.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reionwong@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XDGDESKTOPFILE_H
|
||||
#define XDGDESKTOPFILE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
#include <QMap>
|
||||
|
||||
class XdgDesktopFile
|
||||
{
|
||||
public:
|
||||
explicit XdgDesktopFile(const QString &fileName = QString());
|
||||
|
||||
bool valid() const;
|
||||
|
||||
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
||||
void setValue(const QString &key, const QVariant &value);
|
||||
|
||||
bool load();
|
||||
bool save();
|
||||
|
||||
QString localeName() const;
|
||||
|
||||
QString prefix() const;
|
||||
|
||||
private:
|
||||
bool read(const QString &prefix);
|
||||
|
||||
private:
|
||||
bool m_isValid;
|
||||
QString m_fileName;
|
||||
QMap<QString, QVariant> m_items;
|
||||
};
|
||||
|
||||
#endif // XDGDESKTOPFILE_H
|
|
@ -29,6 +29,7 @@
|
|||
#include "../dialogs/createfolderdialog.h"
|
||||
|
||||
#include "../helper/datehelper.h"
|
||||
#include "../helper/filelauncher.h"
|
||||
|
||||
// Qt
|
||||
#include <QDir>
|
||||
|
@ -45,6 +46,7 @@
|
|||
#include <QDrag>
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
#include <QDesktopServices>
|
||||
|
||||
// Qt Quick
|
||||
#include <QQuickItem>
|
||||
|
@ -63,8 +65,6 @@
|
|||
#include <KUrlMimeData>
|
||||
#include <KFileItemListProperties>
|
||||
#include <KDesktopFile>
|
||||
#include <KRun>
|
||||
#include <KToolInvocation>
|
||||
|
||||
FolderModel::FolderModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
|
@ -77,6 +77,7 @@ FolderModel::FolderModel(QObject *parent)
|
|||
, m_actionCollection(this)
|
||||
, m_dragInProgress(false)
|
||||
, m_viewAdapter(nullptr)
|
||||
, m_mimeAppManager(MimeAppManager::self())
|
||||
{
|
||||
DirLister *dirLister = new DirLister(this);
|
||||
dirLister->setDelayedMimeTypes(true);
|
||||
|
@ -714,7 +715,24 @@ void FolderModel::openSelected()
|
|||
}
|
||||
|
||||
for (const QUrl &url : urls) {
|
||||
(void)new KRun(url, nullptr);
|
||||
KFileItem item(url);
|
||||
QString defaultAppDesktopFile = m_mimeAppManager->getDefaultAppByMimeType(item.currentMimeType());
|
||||
|
||||
// If no default application is found,
|
||||
// look for the first one of the frequently used applications.
|
||||
if (defaultAppDesktopFile.isEmpty()) {
|
||||
QStringList recommendApps = m_mimeAppManager->getRecommendedAppsByMimeType(item.currentMimeType());
|
||||
if (recommendApps.count() > 0) {
|
||||
defaultAppDesktopFile = recommendApps.first();
|
||||
}
|
||||
}
|
||||
|
||||
if (!defaultAppDesktopFile.isEmpty()) {
|
||||
FileLauncher::self()->launchApp(defaultAppDesktopFile, url.toLocalFile());
|
||||
continue;
|
||||
}
|
||||
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -928,7 +946,7 @@ void FolderModel::openInTerminal()
|
|||
url = rootItem().url().toLocalFile();
|
||||
}
|
||||
|
||||
KToolInvocation::invokeTerminal(QString(), url);
|
||||
m_mimeAppManager->launchTerminal(url);
|
||||
}
|
||||
|
||||
void FolderModel::openChangeWallpaperDialog()
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "../widgets/itemviewadapter.h"
|
||||
#include "../helper/pathhistory.h"
|
||||
#include "../mimetype/mimeappmanager.h"
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QItemSelectionModel>
|
||||
|
@ -237,6 +238,7 @@ private:
|
|||
|
||||
// Save path history
|
||||
PathHistory m_pathHistory;
|
||||
MimeAppManager *m_mimeAppManager;
|
||||
};
|
||||
|
||||
#endif // FOLDERMODEL_H
|
||||
|
|
|
@ -126,7 +126,7 @@ Item {
|
|||
sourceSize.height: height
|
||||
source: model.thumbnail ? model.thumbnail : ""
|
||||
asynchronous: true
|
||||
cache: true
|
||||
cache: false
|
||||
|
||||
// Because of the effect of OpacityMask.
|
||||
ColorOverlay {
|
||||
|
|
|
@ -99,6 +99,7 @@ Item {
|
|||
fillMode: Image.PreserveAspectFit
|
||||
asynchronous: true
|
||||
smooth: false
|
||||
cache: false
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
|
|
|
@ -31,22 +31,6 @@
|
|||
|
||||
static ThumbnailCache *SELF = nullptr;
|
||||
|
||||
QImage scaleImage(const QImage &image, const QSize &requestedSize, bool crop, Qt::TransformationMode mode)
|
||||
{
|
||||
const QImage scaledImage(image.size() != requestedSize
|
||||
? image.scaled(requestedSize, crop ? Qt::KeepAspectRatioByExpanding : Qt::KeepAspectRatio, mode)
|
||||
: image);
|
||||
|
||||
if (crop && scaledImage.size() != requestedSize) {
|
||||
QRect cropRect(0, 0, requestedSize.width(), requestedSize.height());
|
||||
cropRect.moveCenter(QPoint(scaledImage.width() / 2, scaledImage.height() / 2));
|
||||
|
||||
return scaledImage.copy(cropRect);
|
||||
} else {
|
||||
return scaledImage;
|
||||
}
|
||||
}
|
||||
|
||||
ThumbnailCache *ThumbnailCache::self()
|
||||
{
|
||||
if (!SELF) {
|
||||
|
|
Loading…
Reference in a new issue