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("ftp"), QStringLiteral("http"),
46 QStringLiteral("https"), QStringLiteral("webdav"), QStringLiteral("webdavs"),
47 QStringLiteral("smb"),
48 QStringLiteral(""), // this makes removable devices shown
51 setMultiSelectionMode(false);
53 connect(_dialog
, &QFileDialog::filterSelected
, this, &KDE5FilePicker::filterChanged
);
54 connect(_dialog
, &QFileDialog::fileSelected
, this, &KDE5FilePicker::selectionChanged
);
59 void KDE5FilePicker::enableFolderMode()
61 _dialog
->setOption(QFileDialog::ShowDirsOnly
, true);
62 // Workaround for https://bugs.kde.org/show_bug.cgi?id=406464 :
63 // Don't set file mode to QFileDialog::Directory when native KDE Plasma 5
64 // file dialog is used, since clicking on directory "bar" inside directory "foo"
65 // and then confirming would return "foo" rather than "foo/bar";
66 // on the other hand, non-native file dialog needs 'QFileDialog::Directory'
67 // and doesn't allow folder selection otherwise
68 if (Application::GetDesktopEnvironment() != "PLASMA5")
70 _dialog
->setFileMode(QFileDialog::Directory
);
74 KDE5FilePicker::~KDE5FilePicker()
76 delete _extraControls
;
80 void KDE5FilePicker::setTitle(const QString
& title
) { _dialog
->setWindowTitle(title
); }
82 bool KDE5FilePicker::execute()
84 if (!_filters
.isEmpty())
85 _dialog
->setNameFilters(_filters
);
86 if (!_currentFilter
.isEmpty())
87 _dialog
->selectNameFilter(_currentFilter
);
90 //block and wait for user input
91 return _dialog
->exec() == QFileDialog::Accepted
;
94 void KDE5FilePicker::setMultiSelectionMode(bool multiSelect
)
96 if (_dialog
->acceptMode() == QFileDialog::AcceptSave
)
99 _dialog
->setFileMode(multiSelect
? QFileDialog::ExistingFiles
: QFileDialog::ExistingFile
);
102 void KDE5FilePicker::setDefaultName(const QString
& name
) { _dialog
->selectFile(name
); }
104 void KDE5FilePicker::setDisplayDirectory(const QString
& dir
)
106 _dialog
->setDirectoryUrl(QUrl(dir
));
109 QString
KDE5FilePicker::getDisplayDirectory() const { return _dialog
->directoryUrl().url(); }
111 QList
<QUrl
> KDE5FilePicker::getSelectedFiles() const { return _dialog
->selectedUrls(); }
113 void KDE5FilePicker::appendFilter(const QString
& title
, const QString
& filter
)
117 // '/' need to be escaped else they are assumed to be mime types by kfiledialog
119 t
.replace("/", "\\/");
121 // openoffice gives us filters separated by ';' qt dialogs just want space separated
124 // make sure "*.*" is not used as "all files"
125 f
.replace("*.*", "*");
127 _filters
<< QStringLiteral("%1 (%2)").arg(t
, f
);
128 _titleToFilters
[t
] = _filters
.constLast();
131 void KDE5FilePicker::setCurrentFilter(const QString
& title
)
133 _currentFilter
= _titleToFilters
.value(title
);
136 QString
KDE5FilePicker::getCurrentFilter() const
138 QString filter
= _titleToFilters
.key(_dialog
->selectedNameFilter());
140 //default if not found
141 if (filter
.isEmpty())
142 filter
= "ODF Text Document (.odt)";
147 void KDE5FilePicker::setValue(sal_Int16 controlId
, sal_Int16
/*nControlAction*/, bool value
)
149 if (_customWidgets
.contains(controlId
))
151 QCheckBox
* cb
= dynamic_cast<QCheckBox
*>(_customWidgets
.value(controlId
));
153 cb
->setChecked(value
);
156 qWarning() << "set value on unknown control" << controlId
;
159 bool KDE5FilePicker::getValue(sal_Int16 controlId
, sal_Int16
/*nControlAction*/) const
162 if (_customWidgets
.contains(controlId
))
164 QCheckBox
* cb
= dynamic_cast<QCheckBox
*>(_customWidgets
.value(controlId
));
166 ret
= cb
->isChecked();
169 qWarning() << "get value on unknown control" << controlId
;
174 void KDE5FilePicker::enableControl(sal_Int16 controlId
, bool enable
)
176 if (_customWidgets
.contains(controlId
))
177 _customWidgets
.value(controlId
)->setEnabled(enable
);
179 qWarning() << "enable on unknown control" << controlId
;
182 void KDE5FilePicker::setLabel(sal_Int16 controlId
, const QString
& label
)
184 if (_customWidgets
.contains(controlId
))
186 QCheckBox
* cb
= dynamic_cast<QCheckBox
*>(_customWidgets
.value(controlId
));
191 qWarning() << "set label on unknown control" << controlId
;
194 QString
KDE5FilePicker::getLabel(sal_Int16 controlId
) const
197 if (_customWidgets
.contains(controlId
))
199 QCheckBox
* cb
= dynamic_cast<QCheckBox
*>(_customWidgets
.value(controlId
));
204 qWarning() << "get label on unknown control" << controlId
;
209 void KDE5FilePicker::addCheckBox(sal_Int16 controlId
, const QString
& label
, bool hidden
)
211 auto resString
= label
;
212 resString
.replace('~', '&');
214 auto widget
= new QCheckBox(resString
, _extraControls
);
215 widget
->setHidden(hidden
);
218 _layout
->addWidget(widget
);
220 _customWidgets
.insert(controlId
, widget
);
223 void KDE5FilePicker::initialize(bool saveDialog
)
226 QFileDialog::AcceptMode operationMode
227 = saveDialog
? QFileDialog::AcceptSave
: QFileDialog::AcceptOpen
;
229 _dialog
->setAcceptMode(operationMode
);
232 _dialog
->setFileMode(QFileDialog::AnyFile
);
235 void KDE5FilePicker::setWinId(sal_uInt64 winId
) { _winId
= winId
; }
237 void KDE5FilePicker::setupCustomWidgets()
239 // When using the platform-native Plasma/KDE5 file picker, we currently rely on KFileWidget
240 // being present to add the custom controls visible (s. 'eventFilter' method).
241 // Since this doesn't work for other desktop environments, use a non-native
242 // dialog there in order not to lose the custom controls and insert the custom
243 // widget in the layout returned by QFileDialog::layout()
244 // (which returns nullptr for native file dialogs)
245 if (Application::GetDesktopEnvironment() == "PLASMA5")
247 qApp
->installEventFilter(this);
251 _dialog
->setOption(QFileDialog::DontUseNativeDialog
);
252 QGridLayout
* pLayout
= static_cast<QGridLayout
*>(_dialog
->layout());
254 const int row
= pLayout
->rowCount();
255 pLayout
->addWidget(_extraControls
, row
, 1);
259 bool KDE5FilePicker::eventFilter(QObject
* o
, QEvent
* e
)
261 if (e
->type() == QEvent::Show
&& o
->isWidgetType())
263 auto* w
= static_cast<QWidget
*>(o
);
264 if (!w
->parentWidget() && w
->isModal())
267 To replace when baseline will include kwindowsystem >= 5.62 with:
268 w->setAttribute(Qt::WA_NativeWindow, true);
269 KWindowSystem::setMainWindow(w->windowHandle(), _winId);
271 SAL_WNODEPRECATED_DECLARATIONS_PUSH
272 KWindowSystem::setMainWindow(w
, _winId
);
273 SAL_WNODEPRECATED_DECLARATIONS_POP
274 if (auto* fileWidget
= w
->findChild
<KFileWidget
*>({}, Qt::FindDirectChildrenOnly
))
276 fileWidget
->setCustomWidget(_extraControls
);
277 // remove event filter again; the only purpose was to set the custom widget here
278 qApp
->removeEventFilter(this);
282 return QObject::eventFilter(o
, e
);
285 #include <kde5_filepicker.moc>
287 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */