diff --git a/CMakeLists.txt b/CMakeLists.txt
index 39317a4..329b594 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,78 +1,79 @@
cmake_minimum_required(VERSION 3.0)
project(xdg-desktop-portal-kde)
set(PROJECT_VERSION "5.14.80")
set(PROJECT_VERSION_MAJOR 5)
set(QT_MIN_VERSION "5.11.0")
set(KF5_MIN_VERSION "5.48.0")
################# set KDE specific information #################
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
include(FeatureSummary)
find_package(GLIB2)
set_package_properties(GLIB2 PROPERTIES
TYPE OPTIONAL
PURPOSE "Required for screencast portal"
)
find_package(PipeWire)
set_package_properties(PipeWire PROPERTIES
TYPE OPTIONAL
PURPOSE "Required for screencast portal"
)
find_package(GBM)
set_package_properties(GBM PROPERTIES
TYPE OPTIONAL
PURPOSE "Required for screencast portal"
)
find_package(Epoxy)
set_package_properties(Epoxy PROPERTIES DESCRIPTION "libepoxy"
URL "http://github.com/anholt/libepoxy"
TYPE OPTIONAL
PURPOSE "Required for screencast portal"
)
if (PipeWire_FOUND AND GLIB2_FOUND AND GBM_FOUND AND Epoxy_FOUND)
set (SCREENCAST_ENABLED true)
else()
set (SCREENCAST_ENABLED false)
endif()
add_definitions(-DSCREENCAST_ENABLED=${SCREENCAST_ENABLED})
add_feature_info ("Screencast portal" ${SCREENCAST_ENABLED} "Support for screen sharing")
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
Core
Concurrent
DBus
PrintSupport
Widgets
)
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED
CoreAddons
Config
I18n
+ KIO
Notifications
Wayland
WidgetsAddons
)
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0)
add_subdirectory(data)
add_subdirectory(src)
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c59c598..38fd2ce 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,70 +1,71 @@
add_definitions(-DTRANSLATION_DOMAIN="xdg-desktop-portal-kde")
include_directories(${Qt5PrintSupport_PRIVATE_INCLUDE_DIRS})
set(xdg_desktop_portal_kde_SRCS
xdg-desktop-portal-kde.cpp
access.cpp
accessdialog.cpp
appchooser.cpp
appchooserdialog.cpp
appchooserdialogitem.cpp
desktopportal.cpp
email.cpp
filechooser.cpp
inhibit.cpp
notification.cpp
print.cpp
request.cpp
session.cpp
screenshot.cpp
screenshotdialog.cpp
settings.cpp
)
if (SCREENCAST_ENABLED)
set (xdg_desktop_portal_kde_SRCS
${xdg_desktop_portal_kde_SRCS}
screencast.cpp
screencaststream.cpp
screencastwidget.cpp
screenchooserdialog.cpp
remotedesktop.cpp
remotedesktopdialog.cpp
waylandintegration.cpp)
ki18n_wrap_ui(xdg_desktop_portal_kde_SRCS
screenchooserdialog.ui
remotedesktopdialog.ui)
endif()
ki18n_wrap_ui(xdg_desktop_portal_kde_SRCS
accessdialog.ui
screenshotdialog.ui
)
add_executable(xdg-desktop-portal-kde ${xdg_desktop_portal_kde_SRCS})
target_link_libraries(xdg-desktop-portal-kde
Qt5::Core
Qt5::DBus
Qt5::Concurrent
Qt5::PrintSupport
Qt5::Widgets
KF5::CoreAddons
KF5::ConfigCore
KF5::I18n
+ KF5::KIOFileWidgets
KF5::Notifications
KF5::WaylandClient
KF5::WidgetsAddons
)
if (SCREENCAST_ENABLED)
target_link_libraries(xdg-desktop-portal-kde
PipeWire::PipeWire
GLIB2::GLIB2
${Epoxy_LIBRARIES}
GBM::GBM)
endif()
install(TARGETS xdg-desktop-portal-kde DESTINATION ${KDE_INSTALL_LIBEXECDIR})
diff --git a/src/filechooser.cpp b/src/filechooser.cpp
index 19f4d42..23c663b 100644
--- a/src/filechooser.cpp
+++ b/src/filechooser.cpp
@@ -1,290 +1,312 @@
/*
- * Copyright © 2016 Red Hat, Inc
+ * Copyright © 2016-2018 Red Hat, Inc
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors:
* Jan Grulich
*/
#include "filechooser.h"
+#include
#include
#include
#include
-#include
+#include
+#include
+#include
+
#include
+#include
Q_LOGGING_CATEGORY(XdgDesktopPortalKdeFileChooser, "xdp-kde-file-chooser")
// Keep in sync with qflatpakfiledialog from flatpak-platform-plugin
Q_DECLARE_METATYPE(FileChooserPortal::Filter)
Q_DECLARE_METATYPE(FileChooserPortal::Filters)
Q_DECLARE_METATYPE(FileChooserPortal::FilterList)
Q_DECLARE_METATYPE(FileChooserPortal::FilterListList)
QDBusArgument &operator << (QDBusArgument &arg, const FileChooserPortal::Filter &filter)
{
arg.beginStructure();
arg << filter.type << filter.filterString;
arg.endStructure();
return arg;
}
const QDBusArgument &operator >> (const QDBusArgument &arg, FileChooserPortal::Filter &filter)
{
uint type;
QString filterString;
arg.beginStructure();
arg >> type >> filterString;
filter.type = type;
filter.filterString = filterString;
arg.endStructure();
return arg;
}
QDBusArgument &operator << (QDBusArgument &arg, const FileChooserPortal::FilterList &filterList)
{
arg.beginStructure();
arg << filterList.userVisibleName << filterList.filters;
arg.endStructure();
return arg;
}
const QDBusArgument &operator >> (const QDBusArgument &arg, FileChooserPortal::FilterList &filterList)
{
QString userVisibleName;
FileChooserPortal::Filters filters;
arg.beginStructure();
arg >> userVisibleName >> filters;
filterList.userVisibleName = userVisibleName;
filterList.filters = filters;
arg.endStructure();
return arg;
}
+FileDialog::FileDialog(QDialog *parent, Qt::WindowFlags flags)
+ : QDialog(parent, flags)
+ , m_fileWidget(new KFileWidget(QUrl(), this))
+{
+ setLayout(new QVBoxLayout);
+ layout()->addWidget(m_fileWidget);
+
+ m_buttons = new QDialogButtonBox(this);
+ m_buttons->addButton(m_fileWidget->okButton(), QDialogButtonBox::AcceptRole);
+ m_buttons->addButton(m_fileWidget->cancelButton(), QDialogButtonBox::RejectRole);
+ connect(m_buttons, SIGNAL(rejected()), m_fileWidget, SLOT(slotCancel()));
+ connect(m_fileWidget->okButton(), SIGNAL(clicked(bool)), m_fileWidget, SLOT(slotOk()));
+ connect(m_fileWidget, SIGNAL(accepted()), m_fileWidget, SLOT(accept()));
+ connect(m_fileWidget, SIGNAL(accepted()), SLOT(accept()));
+ connect(m_fileWidget->cancelButton(), SIGNAL(clicked(bool)), SLOT(reject()));
+ layout()->addWidget(m_buttons);
+}
+
+FileDialog::~FileDialog()
+{
+}
+
FileChooserPortal::FileChooserPortal(QObject *parent)
: QDBusAbstractAdaptor(parent)
{
qDBusRegisterMetaType();
qDBusRegisterMetaType();
qDBusRegisterMetaType();
qDBusRegisterMetaType();
}
FileChooserPortal::~FileChooserPortal()
{
}
uint FileChooserPortal::OpenFile(const QDBusObjectPath &handle,
const QString &app_id,
const QString &parent_window,
const QString &title,
const QVariantMap &options,
QVariantMap &results)
{
Q_UNUSED(app_id);
qCDebug(XdgDesktopPortalKdeFileChooser) << "OpenFile called with parameters:";
qCDebug(XdgDesktopPortalKdeFileChooser) << " handle: " << handle.path();
qCDebug(XdgDesktopPortalKdeFileChooser) << " parent_window: " << parent_window;
qCDebug(XdgDesktopPortalKdeFileChooser) << " title: " << title;
qCDebug(XdgDesktopPortalKdeFileChooser) << " options: " << options;
bool modalDialog = true;
bool multipleFiles = false;
QString acceptLabel;
QStringList nameFilters;
QStringList mimeTypeFilters;
/* TODO
* choices a(ssa(ss)s)
* List of serialized combo boxes to add to the file chooser.
*
* For each element, the first string is an ID that will be returned with the response, te second string is a user-visible label.
* The a(ss) is the list of choices, each being a is an ID and a user-visible label. The final string is the initial selection,
* or "", to let the portal decide which choice will be initially selected. None of the strings, except for the initial selection, should be empty.
*
* As a special case, passing an empty array for the list of choices indicates a boolean choice that is typically displayed as a check button, using "true" and "false" as the choices.
* Example: [('encoding', 'Encoding', [('utf8', 'Unicode (UTF-8)'), ('latin15', 'Western')], 'latin15'), ('reencode', 'Reencode', [], 'false')]
*/
if (options.contains(QLatin1String("accept_label"))) {
acceptLabel = options.value(QLatin1String("accept_label")).toString();
}
if (options.contains(QLatin1String("modal"))) {
modalDialog = options.value(QLatin1String("modal")).toBool();
}
if (options.contains(QLatin1String("multiple"))) {
multipleFiles = options.value(QLatin1String("multiple")).toBool();
}
if (options.contains(QLatin1String("filters"))) {
FilterListList filterListList = qdbus_cast(options.value(QLatin1String("filters")));
for (const FilterList &filterList : filterListList) {
QStringList filterStrings;
for (const Filter &filterStruct : filterList.filters) {
if (filterStruct.type == 0) {
filterStrings << filterStruct.filterString;
} else {
mimeTypeFilters << filterStruct.filterString;
}
}
if (!filterStrings.isEmpty()) {
- nameFilters << QStringLiteral("%1 (%2)").arg(filterList.userVisibleName).arg(filterStrings.join(QLatin1String(" ")));
+ nameFilters << QStringLiteral("%1|%2").arg(filterStrings.join(QLatin1Char(' '))).arg(filterList.userVisibleName);
}
}
}
- QFileDialog *fileDialog = new QFileDialog();
+ QScopedPointer fileDialog(new FileDialog());
fileDialog->setWindowTitle(title);
fileDialog->setModal(modalDialog);
- fileDialog->setFileMode(multipleFiles ? QFileDialog::ExistingFiles : QFileDialog::ExistingFile);
- fileDialog->setLabelText(QFileDialog::Accept, !acceptLabel.isEmpty() ? acceptLabel : i18n("Open"));
+ fileDialog->m_fileWidget->setMode(multipleFiles ? KFile::Mode::File | KFile::Mode::ExistingOnly : KFile::Mode::Files | KFile::Mode::ExistingOnly);
+ fileDialog->m_fileWidget->okButton()->setText(!acceptLabel.isEmpty() ? acceptLabel : i18n("Open"));
if (!nameFilters.isEmpty()) {
- fileDialog->setNameFilters(nameFilters);
+ fileDialog->m_fileWidget->setFilter(nameFilters.join(QLatin1Char('\n')));
}
if (!mimeTypeFilters.isEmpty()) {
- fileDialog->setMimeTypeFilters(mimeTypeFilters);
+ fileDialog->m_fileWidget->setMimeFilter(mimeTypeFilters);
}
if (fileDialog->exec() == QDialog::Accepted) {
QStringList files;
- for (const QString &filename : fileDialog->selectedFiles()) {
+ for (const QString &filename : fileDialog->m_fileWidget->selectedFiles()) {
QUrl url = QUrl::fromLocalFile(filename);
files << url.toDisplayString();
}
results.insert(QLatin1String("uris"), files);
- fileDialog->deleteLater();
return 0;
}
- fileDialog->deleteLater();
return 1;
}
uint FileChooserPortal::SaveFile(const QDBusObjectPath &handle,
const QString &app_id,
const QString &parent_window,
const QString &title,
const QVariantMap &options,
QVariantMap &results)
{
Q_UNUSED(app_id);
qCDebug(XdgDesktopPortalKdeFileChooser) << "SaveFile called with parameters:";
qCDebug(XdgDesktopPortalKdeFileChooser) << " handle: " << handle.path();
qCDebug(XdgDesktopPortalKdeFileChooser) << " parent_window: " << parent_window;
qCDebug(XdgDesktopPortalKdeFileChooser) << " title: " << title;
qCDebug(XdgDesktopPortalKdeFileChooser) << " options: " << options;
bool modalDialog = true;
QString acceptLabel;
QString currentName;
QString currentFolder;
QString currentFile;
QStringList nameFilters;
QStringList mimeTypeFilters;
// TODO parse options - choices
if (options.contains(QLatin1String("modal"))) {
modalDialog = options.value(QLatin1String("modal")).toBool();
}
if (options.contains(QLatin1String("accept_label"))) {
acceptLabel = options.value(QLatin1String("accept_label")).toString();
}
if (options.contains(QLatin1String("current_name"))) {
currentName = options.value(QLatin1String("current_name")).toString();
}
if (options.contains(QLatin1String("current_folder"))) {
currentFolder = QString::fromUtf8(options.value(QLatin1String("current_folder")).toByteArray());
}
if (options.contains(QLatin1String("current_file"))) {
currentFile = QString::fromUtf8(options.value(QLatin1String("current_file")).toByteArray());
}
if (options.contains(QLatin1String("filters"))) {
FilterListList filterListList = qdbus_cast(options.value(QLatin1String("filters")));
for (const FilterList &filterList : filterListList) {
QStringList filterStrings;
for (const Filter &filterStruct : filterList.filters) {
if (filterStruct.type == 0) {
filterStrings << filterStruct.filterString;
} else {
mimeTypeFilters << filterStruct.filterString;
}
}
if (!filterStrings.isEmpty()) {
- nameFilters << QStringLiteral("%1 (%2)").arg(filterList.userVisibleName).arg(filterStrings.join(QLatin1String(" ")));
+ nameFilters << QStringLiteral("%1|%2").arg(filterStrings.join(QLatin1Char(' '))).arg(filterList.userVisibleName);
}
}
}
- QFileDialog *fileDialog = new QFileDialog();
+ QScopedPointer fileDialog(new FileDialog());
fileDialog->setWindowTitle(title);
fileDialog->setModal(modalDialog);
- fileDialog->setAcceptMode(QFileDialog::AcceptSave);
+ fileDialog->m_fileWidget->setOperationMode(KFileWidget::Saving);
if (!currentFolder.isEmpty()) {
- fileDialog->setDirectoryUrl(QUrl(currentFolder));
+ fileDialog->m_fileWidget->setUrl(QUrl::fromLocalFile(currentFolder));
}
if (!currentFile.isEmpty()) {
- fileDialog->selectFile(currentFile);
+ fileDialog->m_fileWidget->setSelectedUrl(QUrl::fromLocalFile(currentFile));
}
if (!currentName.isEmpty()) {
- fileDialog->selectFile(currentName);
+ const QUrl url = fileDialog->m_fileWidget->baseUrl();
+ fileDialog->m_fileWidget->setSelectedUrl(QUrl::fromLocalFile(QStringLiteral("%1/%2").arg(url.toDisplayString(QUrl::StripTrailingSlash), currentName)));
}
if (!acceptLabel.isEmpty()) {
- fileDialog->setLabelText(QFileDialog::Accept, acceptLabel);
+ fileDialog->m_fileWidget->okButton()->setText(acceptLabel);
}
if (!nameFilters.isEmpty()) {
- fileDialog->setNameFilters(nameFilters);
+ fileDialog->m_fileWidget->setFilter(nameFilters.join(QLatin1Char('\n')));
}
if (!mimeTypeFilters.isEmpty()) {
- fileDialog->setMimeTypeFilters(mimeTypeFilters);
+ fileDialog->m_fileWidget->setMimeFilter(mimeTypeFilters);
}
if (fileDialog->exec() == QDialog::Accepted) {
QStringList files;
- for (const QString &filename : fileDialog->selectedFiles()) {
- QUrl url = QUrl::fromLocalFile(filename);
- files << url.toDisplayString();
- }
+ QUrl url = QUrl::fromLocalFile(fileDialog->m_fileWidget->selectedFile());
+ files << url.toDisplayString();
results.insert(QLatin1String("uris"), files);
- fileDialog->deleteLater();
return 0;
}
- fileDialog->deleteLater();
return 1;
}
diff --git a/src/filechooser.h b/src/filechooser.h
index 06260e7..b1b13da 100644
--- a/src/filechooser.h
+++ b/src/filechooser.h
@@ -1,65 +1,84 @@
/*
- * Copyright © 2016 Red Hat, Inc
+ * Copyright © 2016-2018 Red Hat, Inc
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors:
* Jan Grulich
*/
#ifndef XDG_DESKTOP_PORTAL_KDE_FILECHOOSER_H
#define XDG_DESKTOP_PORTAL_KDE_FILECHOOSER_H
#include
#include
#include
+#include
+
+class KFileWidget;
+class QDialogButtonBox;
+
+class FileDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ friend class FileChooserPortal;
+
+ FileDialog(QDialog *parent = nullptr, Qt::WindowFlags flags = {});
+ ~FileDialog();
+
+private:
+ QDialogButtonBox *m_buttons;
+protected:
+ KFileWidget *m_fileWidget;
+};
class FileChooserPortal : public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.freedesktop.impl.portal.FileChooser")
public:
// Keep in sync with qflatpakfiledialog from flatpak-platform-plugin
typedef struct {
uint type;
QString filterString;
} Filter;
typedef QList Filters;
typedef struct {
QString userVisibleName;
Filters filters;
} FilterList;
typedef QList FilterListList;
explicit FileChooserPortal(QObject *parent);
~FileChooserPortal();
public Q_SLOTS:
uint OpenFile(const QDBusObjectPath &handle,
const QString &app_id,
const QString &parent_window,
const QString &title,
const QVariantMap &options,
QVariantMap &results);
uint SaveFile(const QDBusObjectPath &handle,
const QString &app_id,
const QString &parent_window,
const QString &title,
const QVariantMap &options,
QVariantMap &results);
};
#endif // XDG_DESKTOP_PORTAL_KDE_FILECHOOSER_H