tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / vcl / unx / gtk3_kde5 / kde5_filepicker.cxx
blob28aee235a3bd2369a4c608228f3e081d7a4baffb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/svapp.hxx>
22 #include "kde5_filepicker.hxx"
24 #include <KWindowSystem>
25 #include <KFileWidget>
27 #include <QtCore/QDebug>
28 #include <QtCore/QUrl>
29 #include <QtWidgets/QCheckBox>
30 #include <QtWidgets/QFileDialog>
31 #include <QtWidgets/QGridLayout>
32 #include <QtWidgets/QWidget>
33 #include <QtWidgets/QApplication>
35 // KDE5FilePicker
37 KDE5FilePicker::KDE5FilePicker(QObject* parent)
38 : QObject(parent)
39 , _dialog(new QFileDialog(nullptr, {}, QDir::homePath()))
40 , _extraControls(new QWidget)
41 , _layout(new QGridLayout(_extraControls))
42 , _winId(0)
44 _dialog->setSupportedSchemes({
45 QStringLiteral("file"), QStringLiteral("http"), QStringLiteral("https"),
46 QStringLiteral("webdav"), QStringLiteral("webdavs"), QStringLiteral("smb"),
47 QStringLiteral(""), // this makes removable devices shown
48 });
50 setMultiSelectionMode(false);
52 connect(_dialog, &QFileDialog::filterSelected, this, &KDE5FilePicker::filterChanged);
53 connect(_dialog, &QFileDialog::fileSelected, this, &KDE5FilePicker::selectionChanged);
55 setupCustomWidgets();
58 void KDE5FilePicker::enableFolderMode()
60 _dialog->setOption(QFileDialog::ShowDirsOnly, true);
61 // Workaround for https://bugs.kde.org/show_bug.cgi?id=406464 :
62 // Don't set file mode to QFileDialog::Directory when native KDE Plasma 5
63 // file dialog is used, since clicking on directory "bar" inside directory "foo"
64 // and then confirming would return "foo" rather than "foo/bar";
65 // on the other hand, non-native file dialog needs 'QFileDialog::Directory'
66 // and doesn't allow folder selection otherwise
67 if (Application::GetDesktopEnvironment() != "PLASMA5")
69 _dialog->setFileMode(QFileDialog::Directory);
73 KDE5FilePicker::~KDE5FilePicker()
75 delete _extraControls;
76 delete _dialog;
79 void KDE5FilePicker::setTitle(const QString& title) { _dialog->setWindowTitle(title); }
81 bool KDE5FilePicker::execute()
83 if (!_filters.isEmpty())
84 _dialog->setNameFilters(_filters);
85 if (!_currentFilter.isEmpty())
86 _dialog->selectNameFilter(_currentFilter);
88 _dialog->show();
89 //block and wait for user input
90 return _dialog->exec() == QFileDialog::Accepted;
93 void KDE5FilePicker::setMultiSelectionMode(bool multiSelect)
95 if (_dialog->acceptMode() == QFileDialog::AcceptSave)
96 return;
98 _dialog->setFileMode(multiSelect ? QFileDialog::ExistingFiles : QFileDialog::ExistingFile);
101 void KDE5FilePicker::setDefaultName(const QString& name) { _dialog->selectFile(name); }
103 void KDE5FilePicker::setDisplayDirectory(const QString& dir)
105 _dialog->setDirectoryUrl(QUrl(dir));
108 QString KDE5FilePicker::getDisplayDirectory() const { return _dialog->directoryUrl().url(); }
110 QList<QUrl> KDE5FilePicker::getSelectedFiles() const { return _dialog->selectedUrls(); }
112 void KDE5FilePicker::appendFilter(const QString& title, const QString& filter)
114 QString t = title;
115 QString f = filter;
116 // '/' need to be escaped else they are assumed to be mime types by kfiledialog
117 //see the docs
118 t.replace("/", "\\/");
120 // openoffice gives us filters separated by ';' qt dialogs just want space separated
121 f.replace(";", " ");
123 // make sure "*.*" is not used as "all files"
124 f.replace("*.*", "*");
126 _filters << QStringLiteral("%1 (%2)").arg(t, f);
127 _titleToFilters[t] = _filters.constLast();
130 void KDE5FilePicker::setCurrentFilter(const QString& title)
132 _currentFilter = _titleToFilters.value(title);
135 QString KDE5FilePicker::getCurrentFilter() const
137 QString filter = _titleToFilters.key(_dialog->selectedNameFilter());
139 //default if not found
140 if (filter.isEmpty())
141 filter = "ODF Text Document (.odt)";
143 return filter;
146 void KDE5FilePicker::setValue(sal_Int16 controlId, sal_Int16 /*nControlAction*/, bool value)
148 if (_customWidgets.contains(controlId))
150 QCheckBox* cb = dynamic_cast<QCheckBox*>(_customWidgets.value(controlId));
151 if (cb)
152 cb->setChecked(value);
154 else
155 qWarning() << "set value on unknown control" << controlId;
158 bool KDE5FilePicker::getValue(sal_Int16 controlId, sal_Int16 /*nControlAction*/) const
160 bool ret = false;
161 if (_customWidgets.contains(controlId))
163 QCheckBox* cb = dynamic_cast<QCheckBox*>(_customWidgets.value(controlId));
164 if (cb)
165 ret = cb->isChecked();
167 else
168 qWarning() << "get value on unknown control" << controlId;
170 return ret;
173 void KDE5FilePicker::enableControl(sal_Int16 controlId, bool enable)
175 if (_customWidgets.contains(controlId))
176 _customWidgets.value(controlId)->setEnabled(enable);
177 else
178 qWarning() << "enable on unknown control" << controlId;
181 void KDE5FilePicker::setLabel(sal_Int16 controlId, const QString& label)
183 if (_customWidgets.contains(controlId))
185 QCheckBox* cb = dynamic_cast<QCheckBox*>(_customWidgets.value(controlId));
186 if (cb)
187 cb->setText(label);
189 else
190 qWarning() << "set label on unknown control" << controlId;
193 QString KDE5FilePicker::getLabel(sal_Int16 controlId) const
195 QString label;
196 if (_customWidgets.contains(controlId))
198 QCheckBox* cb = dynamic_cast<QCheckBox*>(_customWidgets.value(controlId));
199 if (cb)
200 label = cb->text();
202 else
203 qWarning() << "get label on unknown control" << controlId;
205 return label;
208 void KDE5FilePicker::addCheckBox(sal_Int16 controlId, const QString& label, bool hidden)
210 auto resString = label;
211 resString.replace('~', '&');
213 auto widget = new QCheckBox(resString, _extraControls);
214 widget->setHidden(hidden);
215 if (!hidden)
217 _layout->addWidget(widget);
219 _customWidgets.insert(controlId, widget);
222 void KDE5FilePicker::initialize(bool saveDialog)
224 //default is opening
225 QFileDialog::AcceptMode operationMode
226 = saveDialog ? QFileDialog::AcceptSave : QFileDialog::AcceptOpen;
228 _dialog->setAcceptMode(operationMode);
230 if (saveDialog)
231 _dialog->setFileMode(QFileDialog::AnyFile);
234 void KDE5FilePicker::setWinId(sal_uInt64 winId) { _winId = winId; }
236 void KDE5FilePicker::setupCustomWidgets()
238 // When using the platform-native Plasma/KDE5 file picker, we currently rely on KFileWidget
239 // being present to add the custom controls visible (s. 'eventFilter' method).
240 // Since this doesn't work for other desktop environments, use a non-native
241 // dialog there in order not to lose the custom controls and insert the custom
242 // widget in the layout returned by QFileDialog::layout()
243 // (which returns nullptr for native file dialogs)
244 if (Application::GetDesktopEnvironment() == "PLASMA5")
246 qApp->installEventFilter(this);
248 else
250 _dialog->setOption(QFileDialog::DontUseNativeDialog);
251 QGridLayout* pLayout = static_cast<QGridLayout*>(_dialog->layout());
252 assert(pLayout);
253 const int row = pLayout->rowCount();
254 pLayout->addWidget(_extraControls, row, 1);
258 bool KDE5FilePicker::eventFilter(QObject* o, QEvent* e)
260 if (e->type() == QEvent::Show && o->isWidgetType())
262 auto* w = static_cast<QWidget*>(o);
263 if (!w->parentWidget() && w->isModal())
266 To replace when baseline will include kwindowsystem >= 5.62 with:
267 w->setAttribute(Qt::WA_NativeWindow, true);
268 KWindowSystem::setMainWindow(w->windowHandle(), _winId);
270 SAL_WNODEPRECATED_DECLARATIONS_PUSH
271 KWindowSystem::setMainWindow(w, _winId);
272 SAL_WNODEPRECATED_DECLARATIONS_POP
273 if (auto* fileWidget = w->findChild<KFileWidget*>({}, Qt::FindDirectChildrenOnly))
275 fileWidget->setCustomWidget(_extraControls);
276 // remove event filter again; the only purpose was to set the custom widget here
277 qApp->removeEventFilter(this);
281 return QObject::eventFilter(o, e);
284 #include <kde5_filepicker.moc>
286 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */