tdf#125971: map file URLs from QFileDialog to LO internal format
jmux' suggestion at
<https://bugs.documentfoundation.org/show_bug.cgi?id=125971#c7> turns out to be
the correct fix after all; explained in a lengthy comment why that seemingly
wrong call of translateToInternal happens to do the right thing.
(Much of this patch is about passing the XComponentContext down to where it is
now needed in Qt5FilePicker::getSelectedFiles.)
Change-Id: I235554f8494cd3094a011d5a903059326db499fc
Reviewed-on: https://gerrit.libreoffice.org/74359
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
diff --git a/vcl/inc/qt5/Qt5FilePicker.hxx b/vcl/inc/qt5/Qt5FilePicker.hxx
index 74d082a..d4e74b9 100644
--- a/vcl/inc/qt5/Qt5FilePicker.hxx
+++ b/vcl/inc/qt5/Qt5FilePicker.hxx
@@ -58,6 +58,8 @@
Q_OBJECT
private:
css::uno::Reference<css::uno::XComponentContext> m_context;
// whether to show (i.e. not remove) the file extension in the filter title,
// e.g. whether to use "ODF Text Document (*.odt)" or just
// "ODF Text Document" as filter title
@@ -88,7 +90,8 @@
public:
// use non-native file dialog by default; there's no easy way to add custom widgets
// in a generic way in the native one
explicit Qt5FilePicker(QFileDialog::FileMode, bool bShowFileExtensionInFilterTitle = false,
explicit Qt5FilePicker(css::uno::Reference<css::uno::XComponentContext> const& context,
QFileDialog::FileMode, bool bShowFileExtensionInFilterTitle = false,
bool bUseNativeDialog = false);
virtual ~Qt5FilePicker() override;
diff --git a/vcl/inc/qt5/Qt5Instance.hxx b/vcl/inc/qt5/Qt5Instance.hxx
index 2411cdb..881ac17 100644
--- a/vcl/inc/qt5/Qt5Instance.hxx
+++ b/vcl/inc/qt5/Qt5Instance.hxx
@@ -78,7 +78,9 @@
void deleteObjectLaterSignal(QObject* pObject);
protected:
virtual Qt5FilePicker* createPicker(QFileDialog::FileMode);
virtual Qt5FilePicker*
createPicker(css::uno::Reference<css::uno::XComponentContext> const& context,
QFileDialog::FileMode);
public:
explicit Qt5Instance(std::unique_ptr<QApplication>& pQApp, bool bUseCairo = false);
diff --git a/vcl/qt5/Qt5FilePicker.cxx b/vcl/qt5/Qt5FilePicker.cxx
index 084aa76..63b3ff7 100644
--- a/vcl/qt5/Qt5FilePicker.cxx
+++ b/vcl/qt5/Qt5FilePicker.cxx
@@ -33,6 +33,7 @@
#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
#include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
#include <cppuhelper/interfacecontainer.h>
#include <cppuhelper/supportsservice.hxx>
#include <sal/log.hxx>
@@ -77,9 +78,11 @@
}
}
Qt5FilePicker::Qt5FilePicker(QFileDialog::FileMode eMode, bool bShowFileExtensionInFilterTitle,
Qt5FilePicker::Qt5FilePicker(css::uno::Reference<css::uno::XComponentContext> const& context,
QFileDialog::FileMode eMode, bool bShowFileExtensionInFilterTitle,
bool bUseNativeDialog)
: Qt5FilePicker_Base(m_aHelperMutex)
, m_context(context)
, m_bShowFileExtensionInFilterTitle(bShowFileExtensionInFilterTitle)
, m_pFileDialog(new QFileDialog(nullptr, {}, QDir::homePath()))
, m_bIsFolderPicker(eMode == QFileDialog::Directory)
@@ -254,9 +257,29 @@
uno::Sequence<OUString> seq(urls.size());
auto const trans = css::uri::ExternalUriReferenceTranslator::create(m_context);
size_t i = 0;
for (const QUrl& aURL : urls)
seq[i++] = toOUString(aURL.toString());
{
// Unlike LO, QFileDialog (<https://doc.qt.io/qt-5/qfiledialog.html>) apparently always
// treats file-system pathnames as UTF-8--encoded, regardless of LANG/LC_CTYPE locale
// setting. And pathnames containing byte sequences that are not valid UTF-8 are apparently
// filtered out and not even displayed by QFileDialog, so aURL will always have a "payload"
// that matches the pathname's byte sequence. So the pathname's byte sequence (which
// happens to also be aURL's payload) in the LANG/LC_CTYPE encoding needs to be converted
// into LO's internal UTF-8 file URL encoding via
// XExternalUriReferenceTranslator::translateToInternal (which looks somewhat paradoxical as
// aURL.toEncoded() nominally already has a UTF-8 payload):
auto const extUrl = toOUString(aURL.toEncoded());
auto intUrl = trans->translateToInternal(extUrl);
if (intUrl.isEmpty())
{
// If translation failed, fall back to original URL:
SAL_WARN("vcl.qt5", "cannot convert <" << extUrl << "> from locale encoding to UTF-8");
intUrl = extUrl;
}
seq[i++] = intUrl;
}
return seq;
}
diff --git a/vcl/qt5/Qt5Instance.cxx b/vcl/qt5/Qt5Instance.cxx
index dc3df64..d657ab7 100644
--- a/vcl/qt5/Qt5Instance.cxx
+++ b/vcl/qt5/Qt5Instance.cxx
@@ -403,32 +403,34 @@
aEvent.m_pFrame->CallCallback(aEvent.m_nEvent, aEvent.m_pData);
}
Qt5FilePicker* Qt5Instance::createPicker(QFileDialog::FileMode eMode)
Qt5FilePicker*
Qt5Instance::createPicker(css::uno::Reference<css::uno::XComponentContext> const& context,
QFileDialog::FileMode eMode)
{
if (!IsMainThread())
{
SolarMutexGuard g;
Qt5FilePicker* pPicker;
RunInMainThread(std::function([&, this]() { pPicker = createPicker(eMode); }));
RunInMainThread(std::function([&, this]() { pPicker = createPicker(context, eMode); }));
assert(pPicker);
return pPicker;
}
return new Qt5FilePicker(eMode);
return new Qt5FilePicker(context, eMode);
}
css::uno::Reference<css::ui::dialogs::XFilePicker2>
Qt5Instance::createFilePicker(const css::uno::Reference<css::uno::XComponentContext>&)
Qt5Instance::createFilePicker(const css::uno::Reference<css::uno::XComponentContext>& context)
{
return css::uno::Reference<css::ui::dialogs::XFilePicker2>(
createPicker(QFileDialog::ExistingFile));
createPicker(context, QFileDialog::ExistingFile));
}
css::uno::Reference<css::ui::dialogs::XFolderPicker2>
Qt5Instance::createFolderPicker(const css::uno::Reference<css::uno::XComponentContext>&)
Qt5Instance::createFolderPicker(const css::uno::Reference<css::uno::XComponentContext>& context)
{
return css::uno::Reference<css::ui::dialogs::XFolderPicker2>(
createPicker(QFileDialog::Directory));
createPicker(context, QFileDialog::Directory));
}
css::uno::Reference<css::uno::XInterface>
diff --git a/vcl/unx/kde5/KDE5FilePicker.hxx b/vcl/unx/kde5/KDE5FilePicker.hxx
index 32cbd4c..786a99b 100644
--- a/vcl/unx/kde5/KDE5FilePicker.hxx
+++ b/vcl/unx/kde5/KDE5FilePicker.hxx
@@ -34,7 +34,8 @@
bool allowRemoteUrls;
public:
explicit KDE5FilePicker(QFileDialog::FileMode);
explicit KDE5FilePicker(css::uno::Reference<css::uno::XComponentContext> const& context,
QFileDialog::FileMode);
// XExecutableDialog functions
virtual sal_Int16 SAL_CALL execute() override;
diff --git a/vcl/unx/kde5/KDE5FilePicker2.cxx b/vcl/unx/kde5/KDE5FilePicker2.cxx
index ac99b5d..cb778e2 100644
--- a/vcl/unx/kde5/KDE5FilePicker2.cxx
+++ b/vcl/unx/kde5/KDE5FilePicker2.cxx
@@ -49,9 +49,10 @@
// KDE5FilePicker
KDE5FilePicker::KDE5FilePicker(QFileDialog::FileMode eMode)
KDE5FilePicker::KDE5FilePicker(css::uno::Reference<css::uno::XComponentContext> const& context,
QFileDialog::FileMode eMode)
// Native kde5 filepicker does not add file extension automatically
: Qt5FilePicker(eMode, true, true)
: Qt5FilePicker(context, eMode, true, true)
, _layout(new QGridLayout(m_pExtraControls))
, allowRemoteUrls(false)
{
diff --git a/vcl/unx/kde5/KDE5SalInstance.cxx b/vcl/unx/kde5/KDE5SalInstance.cxx
index 3a227fc..01432122 100644
--- a/vcl/unx/kde5/KDE5SalInstance.cxx
+++ b/vcl/unx/kde5/KDE5SalInstance.cxx
@@ -50,13 +50,15 @@
return pRet;
}
Qt5FilePicker* KDE5SalInstance::createPicker(QFileDialog::FileMode eMode)
Qt5FilePicker*
KDE5SalInstance::createPicker(css::uno::Reference<css::uno::XComponentContext> const& context,
QFileDialog::FileMode eMode)
{
if (!IsMainThread())
{
SolarMutexGuard g;
Qt5FilePicker* pPicker;
RunInMainThread(std::function([&, this]() { pPicker = createPicker(eMode); }));
RunInMainThread(std::function([&, this]() { pPicker = createPicker(context, eMode); }));
assert(pPicker);
return pPicker;
}
@@ -65,8 +67,8 @@
// being used in the native file picker, which is only the case for KDE Plasma.
// Therefore, return the plain qt5 one in order to not lose custom controls.
if (Application::GetDesktopEnvironment() == "KDE5")
return new KDE5FilePicker(eMode);
return Qt5Instance::createPicker(eMode);
return new KDE5FilePicker(context, eMode);
return Qt5Instance::createPicker(context, eMode);
}
extern "C" {
diff --git a/vcl/unx/kde5/KDE5SalInstance.hxx b/vcl/unx/kde5/KDE5SalInstance.hxx
index 53993a5..a7c633f 100644
--- a/vcl/unx/kde5/KDE5SalInstance.hxx
+++ b/vcl/unx/kde5/KDE5SalInstance.hxx
@@ -23,7 +23,8 @@
class KDE5SalInstance final : public Qt5Instance
{
Qt5FilePicker* createPicker(QFileDialog::FileMode) override;
Qt5FilePicker* createPicker(css::uno::Reference<css::uno::XComponentContext> const& context,
QFileDialog::FileMode) override;
SalFrame* CreateFrame(SalFrame* pParent, SalFrameStyleFlags nStyle) override;
bool hasNativeFileSelection() const override { return true; }