From a57f67cba23d322aac0ff2cc70dc9724dbd25f58 Mon Sep 17 00:00:00 2001 From: reionwong Date: Thu, 29 Jul 2021 17:38:47 +0800 Subject: [PATCH] Add open with dialog --- CMakeLists.txt | 1 + dialogs/openwithdialog.cpp | 45 ++++++ dialogs/openwithdialog.h | 39 +++++ mimetype/mimeappmanager.cpp | 6 +- mimetype/xdgdesktopfile.cpp | 9 +- mimetype/xdgdesktopfile.h | 3 +- model/foldermodel.cpp | 21 +++ model/foldermodel.h | 1 + qml.qrc | 1 + qml/Dialogs/OpenWithDialog.qml | 167 ++++++++++++++++++++ translations/en_US.ts | 274 +++++++++++++++++++++------------ translations/zh_CN.ts | 270 ++++++++++++++++++++------------ 12 files changed, 636 insertions(+), 201 deletions(-) create mode 100644 dialogs/openwithdialog.cpp create mode 100644 dialogs/openwithdialog.h create mode 100644 qml/Dialogs/OpenWithDialog.qml diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b5b680..d6400de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ add_executable(cutefish-filemanager dialogs/createfolderdialog.cpp dialogs/filepropertiesdialog.cpp + dialogs/openwithdialog.cpp widgets/rubberband.cpp widgets/itemviewadapter.cpp diff --git a/dialogs/openwithdialog.cpp b/dialogs/openwithdialog.cpp new file mode 100644 index 0000000..58c3842 --- /dev/null +++ b/dialogs/openwithdialog.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 . + */ + +#include "openwithdialog.h" +#include "../mimetype/mimeappmanager.h" +#include "../helper/filelauncher.h" + +#include +#include + +OpenWithDialog::OpenWithDialog(const QUrl &url, QQuickView *parent) + : QQuickView(parent) + , m_url(url.toLocalFile()) +{ + setFlag(Qt::Dialog); + setTitle(tr("Open With")); + setResizeMode(QQuickView::SizeViewToRootObject); + + engine()->rootContext()->setContextProperty("main", this); + engine()->rootContext()->setContextProperty("mimeAppManager", MimeAppManager::self()); + engine()->rootContext()->setContextProperty("launcher", FileLauncher::self()); + + setSource(QUrl("qrc:/qml/Dialogs/OpenWithDialog.qml")); +} + +QString OpenWithDialog::url() const +{ + return m_url; +} diff --git a/dialogs/openwithdialog.h b/dialogs/openwithdialog.h new file mode 100644 index 0000000..7c1d464 --- /dev/null +++ b/dialogs/openwithdialog.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 . + */ + +#ifndef OPENWITHDIALOG_H +#define OPENWITHDIALOG_H + +#include + +class OpenWithDialog : public QQuickView +{ + Q_OBJECT + Q_PROPERTY(QString url READ url CONSTANT) + +public: + explicit OpenWithDialog(const QUrl &url, QQuickView *parent = nullptr); + + QString url() const; + +private: + QString m_url; +}; + +#endif // OPENWITHDIALOG_H diff --git a/mimetype/mimeappmanager.cpp b/mimetype/mimeappmanager.cpp index 46b39b8..a4f4357 100644 --- a/mimetype/mimeappmanager.cpp +++ b/mimetype/mimeappmanager.cpp @@ -268,6 +268,8 @@ QString MimeAppManager::getDefaultAppDesktopByMimeType(const QString &mimeType) bool MimeAppManager::setDefaultAppForType(const QString &mimeType, const QString &app) { + Q_UNUSED(mimeType); + // ref: https://specifications.freedesktop.org/mime-apps-spec/1.0.1/ar01s03.html QString mimeappsFile = mimeAppsListFilePath(); @@ -397,11 +399,11 @@ QVariantList MimeAppManager::recommendedApps(const QUrl &url) for (const QString &path : getRecommendedAppsByFilePath(filePath)) { XdgDesktopFile desktop(path); - if (desktop.valid()) + if (!desktop.valid()) continue; QVariantMap item; - item["icon"] = desktop.value("IconName").toString(); + item["icon"] = desktop.value("Icon").toString(); item["name"] = desktop.localeName(); item["desktopFile"] = path; diff --git a/mimetype/xdgdesktopfile.cpp b/mimetype/xdgdesktopfile.cpp index 1c3ec18..bbdc3ff 100644 --- a/mimetype/xdgdesktopfile.cpp +++ b/mimetype/xdgdesktopfile.cpp @@ -94,15 +94,20 @@ bool XdgDesktopFile::save() return true; } +QStringList XdgDesktopFile::keys() const +{ + return m_items.keys(); +} + QString XdgDesktopFile::localeName() const { QString localeKey = QString("Name[%1]").arg(QLocale::system().name()); if (m_items.contains(localeKey)) { - return m_items[localeKey].toString(); + return XdgDesktopFile::value("Name").toString(); } - return m_items["Name"].toString(); + return XdgDesktopFile::value("Name").toString(); } QString XdgDesktopFile::prefix() const diff --git a/mimetype/xdgdesktopfile.h b/mimetype/xdgdesktopfile.h index 44abe35..2513c49 100644 --- a/mimetype/xdgdesktopfile.h +++ b/mimetype/xdgdesktopfile.h @@ -37,8 +37,9 @@ public: bool load(); bool save(); - QString localeName() const; + QStringList keys() const; + QString localeName() const; QString prefix() const; private: diff --git a/model/foldermodel.cpp b/model/foldermodel.cpp index 48f2be4..6022eed 100644 --- a/model/foldermodel.cpp +++ b/model/foldermodel.cpp @@ -27,6 +27,7 @@ #include "../dialogs/filepropertiesdialog.h" #include "../dialogs/createfolderdialog.h" +#include "../dialogs/openwithdialog.h" #include "../helper/datehelper.h" #include "../helper/filelauncher.h" @@ -754,6 +755,17 @@ void FolderModel::openSelected() } } +void FolderModel::showOpenWithDialog() +{ + if (!m_selectionModel->hasSelection()) + return; + + const QList urls = selectedUrls(); + + OpenWithDialog *dlg = new OpenWithDialog(urls.first()); + dlg->show(); +} + void FolderModel::deleteSelected() { if (!m_selectionModel->hasSelection()) { @@ -899,6 +911,7 @@ void FolderModel::openContextMenu(QQuickItem *visualParent, Qt::KeyboardModifier } else { // Open the items menu. menu->addAction(m_actionCollection.action("open")); + menu->addAction(m_actionCollection.action("openWith")); menu->addAction(m_actionCollection.action("cut")); menu->addAction(m_actionCollection.action("copy")); menu->addAction(m_actionCollection.action("trash")); @@ -1094,6 +1107,9 @@ void FolderModel::createActions() QAction *open = new QAction(tr("Open"), this); connect(open, &QAction::triggered, this, &FolderModel::openSelected); + QAction *openWith = new QAction(tr("Open with"), this); + connect(openWith, &QAction::triggered, this, &FolderModel::showOpenWithDialog); + QAction *cut = new QAction(tr("Cut"), this); connect(cut, &QAction::triggered, this, &FolderModel::cut); @@ -1131,6 +1147,7 @@ void FolderModel::createActions() QObject::connect(changeBackground, &QAction::triggered, this, &FolderModel::openChangeWallpaperDialog); m_actionCollection.addAction(QStringLiteral("open"), open); + m_actionCollection.addAction(QStringLiteral("openWith"), openWith); m_actionCollection.addAction(QStringLiteral("cut"), cut); m_actionCollection.addAction(QStringLiteral("copy"), copy); m_actionCollection.addAction(QStringLiteral("paste"), paste); @@ -1179,6 +1196,10 @@ void FolderModel::updateActions() } } + if (QAction *openWith = m_actionCollection.action(QStringLiteral("openWith"))) { + openWith->setVisible(items.count() == 1); + } + if (QAction *newFolder = m_actionCollection.action(QStringLiteral("newFolder"))) { newFolder->setVisible(!isTrash); newFolder->setEnabled(rootItem().isWritable()); diff --git a/model/foldermodel.h b/model/foldermodel.h index 8fa92a6..e1cbb59 100644 --- a/model/foldermodel.h +++ b/model/foldermodel.h @@ -164,6 +164,7 @@ public: Q_INVOKABLE void paste(); Q_INVOKABLE void cut(); Q_INVOKABLE void openSelected(); + Q_INVOKABLE void showOpenWithDialog(); Q_INVOKABLE void deleteSelected(); Q_INVOKABLE void moveSelectedToTrash(); Q_INVOKABLE void emptyTrash(); diff --git a/qml.qrc b/qml.qrc index 62d532c..2190f34 100644 --- a/qml.qrc +++ b/qml.qrc @@ -57,5 +57,6 @@ images/dark/user-trash.svg images/dark/drive-optical.svg images/light/drive-optical.svg + qml/Dialogs/OpenWithDialog.qml diff --git a/qml/Dialogs/OpenWithDialog.qml b/qml/Dialogs/OpenWithDialog.qml new file mode 100644 index 0000000..ea323e5 --- /dev/null +++ b/qml/Dialogs/OpenWithDialog.qml @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 . + */ + +import QtQuick 2.12 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 +import FishUI 1.0 as FishUI + +Item { + id: control + + property string url: main.url + + width: 320 + FishUI.Units.largeSpacing * 2 + height: _mainLayout.implicitHeight + FishUI.Units.largeSpacing * 2 + + Rectangle { + anchors.fill: parent + color: FishUI.Theme.secondBackgroundColor + } + + Component.onCompleted: { + var items = mimeAppManager.recommendedApps(control.url) + + for (var i in items) { + listView.model.append(items[i]) + } + + defaultCheckBox.checked = false + doneButton.focus = true + } + + Keys.enabled: true + Keys.onEscapePressed: main.close() + + ColumnLayout { + id: _mainLayout + anchors.fill: parent + anchors.margins: FishUI.Units.largeSpacing + spacing: FishUI.Units.largeSpacing * 2 + + ListView { + id: listView + Layout.fillWidth: true + Layout.preferredHeight: 200 + model: ListModel {} + clip: true + spacing: FishUI.Units.largeSpacing + ScrollBar.vertical: ScrollBar {} + + Label { + anchors.centerIn: parent + text: qsTr("No applications") + visible: listView.count === 0 + } + + delegate: Item { + id: item + width: ListView.view.width + height: 45 + scale: mouseArea.pressed ? 0.95 : 1.0 + + Behavior on scale { + NumberAnimation { + duration: 100 + } + } + + property bool isSelected: listView.currentIndex === index + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + onClicked: { + listView.currentIndex = index + } + } + + Rectangle { + anchors.fill: parent + radius: FishUI.Theme.bigRadius + color: isSelected ? FishUI.Theme.highlightColor + : mouseArea.containsMouse ? Qt.rgba(FishUI.Theme.textColor.r, + FishUI.Theme.textColor.g, + FishUI.Theme.textColor.b, + 0.1) : "transparent" + smooth: true + } + + RowLayout { + anchors.fill: parent + anchors.margins: FishUI.Units.smallSpacing + spacing: FishUI.Units.largeSpacing + + Image { + id: icon + source: "image://icontheme/" + model.icon + width: item.height * 0.7 + height: width + sourceSize: Qt.size(width, height) + Layout.alignment: Qt.AlignLeft + } + + Label { + text: model.name + Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft + color: isSelected ? FishUI.Theme.highlightedTextColor : FishUI.Theme.textColor + } + } + } + } + + CheckBox { + id: defaultCheckBox + focusPolicy: Qt.NoFocus + text: qsTr("Set as default") + enabled: listView.count >= 1 + padding: 0 + } + + RowLayout { + spacing: FishUI.Units.largeSpacing + + Button { + text: qsTr("Cancel") + Layout.fillWidth: true + onClicked: main.close() + } + + Button { + id: doneButton + focus: true + flat: true + text: qsTr("Open") + Layout.fillWidth: true + onClicked: { + if (defaultCheckBox.checked) + mimeAppManager.setDefaultAppForFile(control.url, listView.model.get(listView.currentIndex).desktopFile) + + launcher.launchApp(listView.model.get(listView.currentIndex).desktopFile, control.url) + main.close() + } + } + + } + } +} diff --git a/translations/en_US.ts b/translations/en_US.ts index 1ca0212..00fb279 100644 --- a/translations/en_US.ts +++ b/translations/en_US.ts @@ -14,12 +14,12 @@ - + Cancel - + OK @@ -94,84 +94,102 @@ - FolderModel + FilePropertiesDialog - - %1 item - - - - - %1 items - - - - - Select All - - - - - Open - - - - - Cut - - - - - Copy - - - - - Paste - - - - - New Folder - - - - - Move To Trash - - - - - Empty Trash - - - - - Delete - - - - - Rename - - - - - Open in Terminal - - - - - Set as Wallpaper - - - - + Properties - + + %1 files + + + + + FolderModel + + + %1 item + + + + + %1 items + + + + + Select All + + + + + Open + + + + + Open with + + + + + Cut + + + + + Copy + + + + + Paste + + + + + New Folder + + + + + Move To Trash + + + + + Empty Trash + + + + + Delete + + + + + Rename + + + + + Open in Terminal + + + + + Set as Wallpaper + + + + + Properties + + + + Change background @@ -179,41 +197,105 @@ FolderPage - + Empty folder - + Open - + + Properties - + + File + + + + + New Folder + + + + + Quit + + + + + Edit + + + + + Select All + + + + + Help + + + + + About + + + + %1 item - + %1 items - + %1 selected - + Empty Trash + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + + + + + Open + + + + + Open With + + + OptionsMenu @@ -288,60 +370,50 @@ PropertiesDialog - - Properties - - - - + Type: - + Location: - + Size: - + Calculating... - + Created: - + Modified: - + Accessed: - + Cancel - + OK - - - %1 files - - main diff --git a/translations/zh_CN.ts b/translations/zh_CN.ts index a12d52a..2fb99ff 100644 --- a/translations/zh_CN.ts +++ b/translations/zh_CN.ts @@ -14,12 +14,12 @@ 新建文件夹 - + Cancel 取消 - + OK 确定 @@ -94,84 +94,102 @@ - FolderModel + FilePropertiesDialog - - %1 item - %1 项 - - - - %1 items - %1 项 - - - - Select All - 全选 - - - - Open - 打开 - - - - Cut - 剪切 - - - - Copy - 复制 - - - - Paste - 粘贴 - - - - New Folder - 新建文件夹 - - - - Move To Trash - 移动到回收站 - - - - Empty Trash - 清空回收站 - - - - Delete - 删除 - - - - Rename - 重命名 - - - - Open in Terminal - 在终端中打开 - - - - Set as Wallpaper - 设置为壁纸 - - - + Properties 属性 - + + %1 files + %1 项 + + + + FolderModel + + + %1 item + %1 项 + + + + %1 items + %1 项 + + + + Select All + 全选 + + + + Open + 打开 + + + + Open with + 打开方式 + + + + Cut + 剪切 + + + + Copy + 复制 + + + + Paste + 粘贴 + + + + New Folder + 新建文件夹 + + + + Move To Trash + 移动到回收站 + + + + Empty Trash + 清空回收站 + + + + Delete + 删除 + + + + Rename + 重命名 + + + + Open in Terminal + 在终端中打开 + + + + Set as Wallpaper + 设置为壁纸 + + + + Properties + 属性 + + + Change background 更改桌面背景 @@ -179,41 +197,105 @@ FolderPage - + Empty folder 空文件夹 - + Open 打开 - + + Properties 属性 - + + File + 文件 + + + + New Folder + 新建文件夹 + + + + Quit + 退出 + + + + Edit + 编辑 + + + + Select All + 全选 + + + + Help + 帮助 + + + + About + 关于 + + + %1 item %1 项 - + %1 items %1 项 - + %1 selected 选中了 %1 项 - + Empty Trash 清空回收站 + + OpenWithDialog + + + No applications + 没有应用程序 + + + + Set as default + 设置为默认 + + + + Cancel + 取消 + + + + Open + 打开 + + + + Open With + 打开方式 + + OptionsMenu @@ -288,59 +370,57 @@ PropertiesDialog - Properties - 属性 + 属性 - + Type: 类型: - + Location: 位置: - + Size: 大小: - + Calculating... 计算中... - + Created: 创建时间: - + Modified: 修改时间: - + Accessed: 访问时间: - + Cancel 取消 - + OK 确定 - %1 files - %1 项 + %1 项