You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libfm-qt-packaging/debian/patches/move-in-file-dialog.patch

374 lines
12 KiB

Description: Move the Qt file dialog helper into libfm-qt.
Author: Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
Origin: upstream
Applied-Upstream: commit:cc63bc7
Last-Update: 2018-07-30
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -83,6 +83,7 @@ set(libfm_SRCS
filedialog.cpp
fm-search.c # might be moved to libfm later
xdndworkaround.cpp
+ filedialoghelper.cpp
)
set(libfm_UIS
--- /dev/null
+++ b/src/filedialoghelper.cpp
@@ -0,0 +1,290 @@
+#include "filedialoghelper.h"
+
+#include "libfmqt.h"
+#include "filedialog.h"
+
+#include <QWindow>
+#include <QDebug>
+#include <QTimer>
+#include <QSettings>
+#include <QtGlobal>
+
+#include <memory>
+
+namespace Fm {
+
+inline static const QString viewModeToString(Fm::FolderView::ViewMode value);
+inline static Fm::FolderView::ViewMode viewModeFromString(const QString& str);
+
+FileDialogHelper::FileDialogHelper() {
+ // can only be used after libfm-qt initialization
+ dlg_ = std::unique_ptr<Fm::FileDialog>(new Fm::FileDialog());
+ connect(dlg_.get(), &Fm::FileDialog::accepted, [this]() {
+ saveSettings();
+ accept();
+ });
+ connect(dlg_.get(), &Fm::FileDialog::rejected, [this]() {
+ saveSettings();
+ reject();
+ });
+
+ connect(dlg_.get(), &Fm::FileDialog::fileSelected, this, &FileDialogHelper::fileSelected);
+ connect(dlg_.get(), &Fm::FileDialog::filesSelected, this, &FileDialogHelper::filesSelected);
+ connect(dlg_.get(), &Fm::FileDialog::currentChanged, this, &FileDialogHelper::currentChanged);
+ connect(dlg_.get(), &Fm::FileDialog::directoryEntered, this, &FileDialogHelper::directoryEntered);
+ connect(dlg_.get(), &Fm::FileDialog::filterSelected, this, &FileDialogHelper::filterSelected);
+}
+
+FileDialogHelper::~FileDialogHelper() {
+}
+
+void FileDialogHelper::exec() {
+ dlg_->exec();
+}
+
+bool FileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow* parent) {
+ dlg_->setAttribute(Qt::WA_NativeWindow, true); // without this, sometimes windowHandle() will return nullptr
+
+ dlg_->setWindowFlags(windowFlags);
+ dlg_->setWindowModality(windowModality);
+
+ // Reference: KDE implementation
+ // https://github.com/KDE/plasma-integration/blob/master/src/platformtheme/kdeplatformfiledialoghelper.cpp
+ dlg_->windowHandle()->setTransientParent(parent);
+
+ applyOptions();
+
+ loadSettings();
+ // central positioning with respect to the parent window
+ if(parent && parent->isVisible()) {
+ dlg_->move(parent->x() + (parent->width() - dlg_->width()) / 2,
+ parent->y() + (parent->height() - dlg_->height()) / 2);
+ }
+
+ // NOTE: the timer here is required as a workaround borrowed from KDE. Without this, the dialog UI will be blocked.
+ // QFileDialog calls our platform plugin to show our own native file dialog instead of showing its widget.
+ // However, it still creates a hidden dialog internally, and then make it modal.
+ // So user input from all other windows that are not the children of the QFileDialog widget will be blocked.
+ // This includes our own dialog. After the return of this show() method, QFileDialog creates its own window and
+ // then make it modal, which blocks our UI. The timer schedule a delayed popup of our file dialog, so we can
+ // show again after QFileDialog and override the modal state. Then our UI can be unblocked.
+ QTimer::singleShot(0, dlg_.get(), &QDialog::show);
+ dlg_->setFocus();
+ return true;
+}
+
+void FileDialogHelper::hide() {
+ dlg_->hide();
+}
+
+bool FileDialogHelper::defaultNameFilterDisables() const {
+ return false;
+}
+
+void FileDialogHelper::setDirectory(const QUrl& directory) {
+ dlg_->setDirectory(directory);
+}
+
+QUrl FileDialogHelper::directory() const {
+ return dlg_->directory();
+}
+
+void FileDialogHelper::selectFile(const QUrl& filename) {
+ dlg_->selectFile(filename);
+}
+
+QList<QUrl> FileDialogHelper::selectedFiles() const {
+ return dlg_->selectedFiles();
+}
+
+void FileDialogHelper::setFilter() {
+ // FIXME: what's this?
+ // The gtk+ 3 file dialog helper in Qt5 update options in this method.
+ applyOptions();
+}
+
+void FileDialogHelper::selectNameFilter(const QString& filter) {
+ dlg_->selectNameFilter(filter);
+}
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
+QString FileDialogHelper::selectedMimeTypeFilter() const {
+ return dlg_->selectedMimeTypeFilter();
+}
+
+void FileDialogHelper::selectMimeTypeFilter(const QString& filter) {
+ dlg_->selectMimeTypeFilter(filter);
+}
+#endif
+
+QString FileDialogHelper::selectedNameFilter() const {
+ return dlg_->selectedNameFilter();
+}
+
+bool FileDialogHelper::isSupportedUrl(const QUrl& url) const {
+ return dlg_->isSupportedUrl(url);
+}
+
+void FileDialogHelper::applyOptions() {
+ auto& opt = options();
+
+ // set title
+ if(opt->windowTitle().isEmpty()) {
+ dlg_->setWindowTitle(opt->acceptMode() == QFileDialogOptions::AcceptOpen ? tr("Open File")
+ : tr("Save File"));
+ }
+ else {
+ dlg_->setWindowTitle(opt->windowTitle());
+ }
+
+ dlg_->setFilter(opt->filter());
+ dlg_->setFileMode(QFileDialog::FileMode(opt->fileMode()));
+ dlg_->setAcceptMode(QFileDialog::AcceptMode(opt->acceptMode())); // also sets a default label for accept button
+ // bool useDefaultNameFilters() const;
+ dlg_->setNameFilters(opt->nameFilters());
+ if(!opt->mimeTypeFilters().empty()) {
+ dlg_->setMimeTypeFilters(opt->mimeTypeFilters());
+ }
+
+ dlg_->setDefaultSuffix(opt->defaultSuffix());
+ // QStringList history() const;
+
+ // explicitly set labels
+ for(int i = 0; i < QFileDialogOptions::DialogLabelCount; ++i) {
+ auto label = static_cast<QFileDialogOptions::DialogLabel>(i);
+ if(opt->isLabelExplicitlySet(label)) {
+ dlg_->setLabelText(static_cast<QFileDialog::DialogLabel>(label), opt->labelText(label));
+ }
+ }
+
+ auto url = opt->initialDirectory();
+ if(url.isValid()) {
+ dlg_->setDirectory(url);
+ }
+
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
+ auto filter = opt->initiallySelectedMimeTypeFilter();
+ if(!filter.isEmpty()) {
+ selectMimeTypeFilter(filter);
+ }
+ else {
+ filter = opt->initiallySelectedNameFilter();
+ if(!filter.isEmpty()) {
+ selectNameFilter(opt->initiallySelectedNameFilter());
+ }
+ }
+#else
+ auto filter = opt->initiallySelectedNameFilter();
+ if(!filter.isEmpty()) {
+ selectNameFilter(filter);
+ }
+#endif
+
+ auto selectedFiles = opt->initiallySelectedFiles();
+ for(const auto& selectedFile: selectedFiles) {
+ selectFile(selectedFile);
+ }
+ // QStringList supportedSchemes() const;
+}
+
+static const QString viewModeToString(Fm::FolderView::ViewMode value) {
+ QString ret;
+ switch(value) {
+ case Fm::FolderView::DetailedListMode:
+ default:
+ ret = QLatin1String("Detailed");
+ break;
+ case Fm::FolderView::CompactMode:
+ ret = QLatin1String("Compact");
+ break;
+ case Fm::FolderView::IconMode:
+ ret = QLatin1String("Icon");
+ break;
+ case Fm::FolderView::ThumbnailMode:
+ ret = QLatin1String("Thumbnail");
+ break;
+ }
+ return ret;
+}
+
+Fm::FolderView::ViewMode viewModeFromString(const QString& str) {
+ Fm::FolderView::ViewMode ret;
+ if(str == QLatin1String("Detailed")) {
+ ret = Fm::FolderView::DetailedListMode;
+ }
+ else if(str == QLatin1String("Compact")) {
+ ret = Fm::FolderView::CompactMode;
+ }
+ else if(str == QLatin1String("Icon")) {
+ ret = Fm::FolderView::IconMode;
+ }
+ else if(str == QLatin1String("Thumbnail")) {
+ ret = Fm::FolderView::ThumbnailMode;
+ }
+ else {
+ ret = Fm::FolderView::DetailedListMode;
+ }
+ return ret;
+}
+
+void FileDialogHelper::loadSettings() {
+ QSettings settings(QSettings::UserScope, "lxqt", "filedialog");
+ settings.beginGroup ("Sizes");
+ dlg_->resize(settings.value("WindowSize", QSize(700, 500)).toSize());
+ dlg_->setSplitterPos(settings.value("SplitterPos", 200).toInt());
+ settings.endGroup();
+
+ settings.beginGroup ("View");
+ dlg_->setViewMode(viewModeFromString(settings.value("Mode", "Detailed").toString()));
+ settings.endGroup();
+}
+
+void FileDialogHelper::saveSettings() {
+ QSettings settings(QSettings::UserScope, "lxqt", "filedialog");
+ settings.beginGroup ("Sizes");
+ QSize windowSize = dlg_->size();
+ if(settings.value("WindowSize") != windowSize) { // no redundant write
+ settings.setValue("WindowSize", windowSize);
+ }
+ int splitterPos = dlg_->splitterPos();
+ if(settings.value("SplitterPos") != splitterPos) {
+ settings.setValue("SplitterPos", splitterPos);
+ }
+ settings.endGroup();
+
+ settings.beginGroup ("View");
+ QString mode = viewModeToString(dlg_->viewMode());
+ if(settings.value("Mode") != mode) {
+ settings.setValue("Mode", mode);
+ }
+ settings.endGroup();
+}
+
+/*
+FileDialogPlugin::FileDialogPlugin() {
+
+}
+
+QPlatformFileDialogHelper *FileDialogPlugin::createHelper() {
+ return new FileDialogHelper();
+}
+*/
+
+} // namespace Fm
+
+
+QPlatformFileDialogHelper *createFileDialogHelper() {
+ // When a process has this environment set, that means glib event loop integration is disabled.
+ // In this case, libfm just won't work. So let's disable the file dialog helper and return nullptr.
+ if(qgetenv("QT_NO_GLIB") == "1") {
+ return nullptr;
+ }
+
+ static std::unique_ptr<Fm::LibFmQt> libfmQtContext_;
+ if(!libfmQtContext_) {
+ // initialize libfm-qt only once
+ libfmQtContext_ = std::unique_ptr<Fm::LibFmQt>{new Fm::LibFmQt()};
+ }
+ return new Fm::FileDialogHelper{};
+}
--- /dev/null
+++ b/src/filedialoghelper.h
@@ -0,0 +1,62 @@
+#ifndef FILEDIALOGHELPER_H
+#define FILEDIALOGHELPER_H
+
+#include "libfmqtglobals.h"
+#include <qpa/qplatformdialoghelper.h> // this private header is subject to changes
+#include <memory>
+
+namespace Fm {
+
+class FileDialog;
+
+class LIBFM_QT_API FileDialogHelper : public QPlatformFileDialogHelper {
+ Q_OBJECT
+
+public:
+ FileDialogHelper();
+
+ virtual ~FileDialogHelper();
+
+ // QPlatformDialogHelper
+ void exec() override;
+ bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;
+ void hide() override;
+
+ // QPlatformFileDialogHelper
+ bool defaultNameFilterDisables() const override;
+ void setDirectory(const QUrl &directory) override;
+ QUrl directory() const override;
+ void selectFile(const QUrl &filename) override;
+ QList<QUrl> selectedFiles() const override;
+ void setFilter() override;
+ void selectNameFilter(const QString &filter) override;
+#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
+ QString selectedMimeTypeFilter() const override;
+ void selectMimeTypeFilter(const QString &filter) override;
+#endif
+ QString selectedNameFilter() const override;
+
+ bool isSupportedUrl(const QUrl &url) const override;
+
+private:
+ void applyOptions();
+ void loadSettings();
+ void saveSettings();
+
+private:
+ std::unique_ptr<Fm::FileDialog> dlg_;
+};
+
+} // namespace Fm
+
+// export a C API without C++ name mangling so others can dynamically load libfm-qt at runtime
+// to call this API and get a new QPlatformFileDialogHelper object.
+
+extern "C" {
+
+// if the process calling this API fail to load libfm-qt, nullptr will be returned instead.
+LIBFM_QT_API QPlatformFileDialogHelper* createFileDialogHelper();
+
+}
+
+#endif // FILEDIALOGHELPER_H