diff options
Diffstat (limited to 'vcl/unx/gtk3_kde5/kde5_filepicker.cxx')
-rw-r--r-- | vcl/unx/gtk3_kde5/kde5_filepicker.cxx | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/vcl/unx/gtk3_kde5/kde5_filepicker.cxx b/vcl/unx/gtk3_kde5/kde5_filepicker.cxx new file mode 100644 index 000000000..b3382b33d --- /dev/null +++ b/vcl/unx/gtk3_kde5/kde5_filepicker.cxx @@ -0,0 +1,287 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <vcl/svapp.hxx> + +#include "kde5_filepicker.hxx" + +#include <KWindowSystem> +#include <KFileWidget> + +#include <QtCore/QDebug> +#include <QtCore/QUrl> +#include <QtWidgets/QCheckBox> +#include <QtWidgets/QFileDialog> +#include <QtWidgets/QGridLayout> +#include <QtWidgets/QWidget> +#include <QtWidgets/QApplication> + +// KDE5FilePicker + +KDE5FilePicker::KDE5FilePicker(QObject* parent) + : QObject(parent) + , _dialog(new QFileDialog(nullptr, {}, QDir::homePath())) + , _extraControls(new QWidget) + , _layout(new QGridLayout(_extraControls)) + , _winId(0) +{ + _dialog->setSupportedSchemes({ + QStringLiteral("file"), QStringLiteral("ftp"), QStringLiteral("http"), + QStringLiteral("https"), QStringLiteral("webdav"), QStringLiteral("webdavs"), + QStringLiteral("smb"), + QStringLiteral(""), // this makes removable devices shown + }); + + setMultiSelectionMode(false); + + connect(_dialog, &QFileDialog::filterSelected, this, &KDE5FilePicker::filterChanged); + connect(_dialog, &QFileDialog::fileSelected, this, &KDE5FilePicker::selectionChanged); + + setupCustomWidgets(); +} + +void KDE5FilePicker::enableFolderMode() +{ + _dialog->setOption(QFileDialog::ShowDirsOnly, true); + // Workaround for https://bugs.kde.org/show_bug.cgi?id=406464 : + // Don't set file mode to QFileDialog::Directory when native KDE Plasma 5 + // file dialog is used, since clicking on directory "bar" inside directory "foo" + // and then confirming would return "foo" rather than "foo/bar"; + // on the other hand, non-native file dialog needs 'QFileDialog::Directory' + // and doesn't allow folder selection otherwise + if (Application::GetDesktopEnvironment() != "PLASMA5") + { + _dialog->setFileMode(QFileDialog::Directory); + } +} + +KDE5FilePicker::~KDE5FilePicker() +{ + delete _extraControls; + delete _dialog; +} + +void KDE5FilePicker::setTitle(const QString& title) { _dialog->setWindowTitle(title); } + +bool KDE5FilePicker::execute() +{ + if (!_filters.isEmpty()) + _dialog->setNameFilters(_filters); + if (!_currentFilter.isEmpty()) + _dialog->selectNameFilter(_currentFilter); + + _dialog->show(); + //block and wait for user input + return _dialog->exec() == QFileDialog::Accepted; +} + +void KDE5FilePicker::setMultiSelectionMode(bool multiSelect) +{ + if (_dialog->acceptMode() == QFileDialog::AcceptSave) + return; + + _dialog->setFileMode(multiSelect ? QFileDialog::ExistingFiles : QFileDialog::ExistingFile); +} + +void KDE5FilePicker::setDefaultName(const QString& name) { _dialog->selectFile(name); } + +void KDE5FilePicker::setDisplayDirectory(const QString& dir) +{ + _dialog->setDirectoryUrl(QUrl(dir)); +} + +QString KDE5FilePicker::getDisplayDirectory() const { return _dialog->directoryUrl().url(); } + +QList<QUrl> KDE5FilePicker::getSelectedFiles() const { return _dialog->selectedUrls(); } + +void KDE5FilePicker::appendFilter(const QString& title, const QString& filter) +{ + QString t = title; + QString f = filter; + // '/' need to be escaped else they are assumed to be mime types by kfiledialog + //see the docs + t.replace("/", "\\/"); + + // openoffice gives us filters separated by ';' qt dialogs just want space separated + f.replace(";", " "); + + // make sure "*.*" is not used as "all files" + f.replace("*.*", "*"); + + _filters << QStringLiteral("%1 (%2)").arg(t, f); + _titleToFilters[t] = _filters.constLast(); +} + +void KDE5FilePicker::setCurrentFilter(const QString& title) +{ + _currentFilter = _titleToFilters.value(title); +} + +QString KDE5FilePicker::getCurrentFilter() const +{ + QString filter = _titleToFilters.key(_dialog->selectedNameFilter()); + + //default if not found + if (filter.isEmpty()) + filter = "ODF Text Document (.odt)"; + + return filter; +} + +void KDE5FilePicker::setValue(sal_Int16 controlId, sal_Int16 /*nControlAction*/, bool value) +{ + if (_customWidgets.contains(controlId)) + { + QCheckBox* cb = dynamic_cast<QCheckBox*>(_customWidgets.value(controlId)); + if (cb) + cb->setChecked(value); + } + else + qWarning() << "set value on unknown control" << controlId; +} + +bool KDE5FilePicker::getValue(sal_Int16 controlId, sal_Int16 /*nControlAction*/) const +{ + bool ret = false; + if (_customWidgets.contains(controlId)) + { + QCheckBox* cb = dynamic_cast<QCheckBox*>(_customWidgets.value(controlId)); + if (cb) + ret = cb->isChecked(); + } + else + qWarning() << "get value on unknown control" << controlId; + + return ret; +} + +void KDE5FilePicker::enableControl(sal_Int16 controlId, bool enable) +{ + if (_customWidgets.contains(controlId)) + _customWidgets.value(controlId)->setEnabled(enable); + else + qWarning() << "enable on unknown control" << controlId; +} + +void KDE5FilePicker::setLabel(sal_Int16 controlId, const QString& label) +{ + if (_customWidgets.contains(controlId)) + { + QCheckBox* cb = dynamic_cast<QCheckBox*>(_customWidgets.value(controlId)); + if (cb) + cb->setText(label); + } + else + qWarning() << "set label on unknown control" << controlId; +} + +QString KDE5FilePicker::getLabel(sal_Int16 controlId) const +{ + QString label; + if (_customWidgets.contains(controlId)) + { + QCheckBox* cb = dynamic_cast<QCheckBox*>(_customWidgets.value(controlId)); + if (cb) + label = cb->text(); + } + else + qWarning() << "get label on unknown control" << controlId; + + return label; +} + +void KDE5FilePicker::addCheckBox(sal_Int16 controlId, const QString& label, bool hidden) +{ + auto resString = label; + resString.replace('~', '&'); + + auto widget = new QCheckBox(resString, _extraControls); + widget->setHidden(hidden); + if (!hidden) + { + _layout->addWidget(widget); + } + _customWidgets.insert(controlId, widget); +} + +void KDE5FilePicker::initialize(bool saveDialog) +{ + //default is opening + QFileDialog::AcceptMode operationMode + = saveDialog ? QFileDialog::AcceptSave : QFileDialog::AcceptOpen; + + _dialog->setAcceptMode(operationMode); + + if (saveDialog) + _dialog->setFileMode(QFileDialog::AnyFile); +} + +void KDE5FilePicker::setWinId(sal_uInt64 winId) { _winId = winId; } + +void KDE5FilePicker::setupCustomWidgets() +{ + // When using the platform-native Plasma/KDE5 file picker, we currently rely on KFileWidget + // being present to add the custom controls visible (s. 'eventFilter' method). + // Since this doesn't work for other desktop environments, use a non-native + // dialog there in order not to lose the custom controls and insert the custom + // widget in the layout returned by QFileDialog::layout() + // (which returns nullptr for native file dialogs) + if (Application::GetDesktopEnvironment() == "PLASMA5") + { + qApp->installEventFilter(this); + } + else + { + _dialog->setOption(QFileDialog::DontUseNativeDialog); + QGridLayout* pLayout = static_cast<QGridLayout*>(_dialog->layout()); + assert(pLayout); + const int row = pLayout->rowCount(); + pLayout->addWidget(_extraControls, row, 1); + } +} + +bool KDE5FilePicker::eventFilter(QObject* o, QEvent* e) +{ + if (e->type() == QEvent::Show && o->isWidgetType()) + { + auto* w = static_cast<QWidget*>(o); + if (!w->parentWidget() && w->isModal()) + { + /* + To replace when baseline will include kwindowsystem >= 5.62 with: + w->setAttribute(Qt::WA_NativeWindow, true); + KWindowSystem::setMainWindow(w->windowHandle(), _winId); + */ + SAL_WNODEPRECATED_DECLARATIONS_PUSH + KWindowSystem::setMainWindow(w, _winId); + SAL_WNODEPRECATED_DECLARATIONS_POP + if (auto* fileWidget = w->findChild<KFileWidget*>({}, Qt::FindDirectChildrenOnly)) + { + fileWidget->setCustomWidget(_extraControls); + // remove event filter again; the only purpose was to set the custom widget here + qApp->removeEventFilter(this); + } + } + } + return QObject::eventFilter(o, e); +} + +#include <kde5_filepicker.moc> + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |