1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
37 KDE5FilePicker::KDE5FilePicker(QObject
* parent
)
39 , _dialog(new QFileDialog(nullptr, {}, QDir::homePath()))
40 , _extraControls(new QWidget
)
41 , _layout(new QGridLayout(_extraControls
))
44 _dialog
->setSupportedSchemes({
45 QStringLiteral("file"), QStringLiteral("http"), QStringLiteral("https"),
46 QStringLiteral("webdav"), QStringLiteral("webdavs"), QStringLiteral("smb"),
47 QStringLiteral(""), // this makes removable devices shown
50 setMultiSelectionMode(false);
52 connect(_dialog
, &QFileDialog::filterSelected
, this, &KDE5FilePicker::filterChanged
);
53 connect(_dialog
, &QFileDialog::fileSelected
, this, &KDE5FilePicker::selectionChanged
);
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
;
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
);
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
)
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
)
116 // '/' need to be escaped else they are assumed to be mime types by kfiledialog
118 t
.replace("/", "\\/");
120 // openoffice gives us filters separated by ';' qt dialogs just want space separated
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)";
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
));
152 cb
->setChecked(value
);
155 qWarning() << "set value on unknown control" << controlId
;
158 bool KDE5FilePicker::getValue(sal_Int16 controlId
, sal_Int16
/*nControlAction*/) const
161 if (_customWidgets
.contains(controlId
))
163 QCheckBox
* cb
= dynamic_cast<QCheckBox
*>(_customWidgets
.value(controlId
));
165 ret
= cb
->isChecked();
168 qWarning() << "get value on unknown control" << controlId
;
173 void KDE5FilePicker::enableControl(sal_Int16 controlId
, bool enable
)
175 if (_customWidgets
.contains(controlId
))
176 _customWidgets
.value(controlId
)->setEnabled(enable
);
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
));
190 qWarning() << "set label on unknown control" << controlId
;
193 QString
KDE5FilePicker::getLabel(sal_Int16 controlId
) const
196 if (_customWidgets
.contains(controlId
))
198 QCheckBox
* cb
= dynamic_cast<QCheckBox
*>(_customWidgets
.value(controlId
));
203 qWarning() << "get label on unknown control" << controlId
;
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
);
217 _layout
->addWidget(widget
);
219 _customWidgets
.insert(controlId
, widget
);
222 void KDE5FilePicker::initialize(bool saveDialog
)
225 QFileDialog::AcceptMode operationMode
226 = saveDialog
? QFileDialog::AcceptSave
: QFileDialog::AcceptOpen
;
228 _dialog
->setAcceptMode(operationMode
);
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);
250 _dialog
->setOption(QFileDialog::DontUseNativeDialog
);
251 QGridLayout
* pLayout
= static_cast<QGridLayout
*>(_dialog
->layout());
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: */