Native file dialog on Linux Ubuntu "swallows" file extensions
-
wrote on 19 Sept 2019, 13:04 last edited by
In the past, when I call the static
QFileDialog::getOpenFileName()
andQFileDialog::getSaveFileName()
functions, the window manager in Ubuntu appears to hide the file extension from the user, although it filters the files correctly. I.e. if I pass a filter likeCSV files (*.csv)
, on Ubuntu Nautilus the drop-down list at the bottom will only show"CSV files"
. So to get the"(*.csv)"
part to show, I have been setting the filters like this:"CSV files [*.csv] (*.csv)"
and the user will see"CSV files [*.csv]"
which is OK.Now I discovered that I am getting a lot of Gtk warnings about
GtkDialog mapped without a transient parent
and have read somewhere that if you pass the optionQFileDialog::DontUseNativeDialog
, you can make the warnings go away. However, when I do that, the filter shows both the[*.csv]
AND the(*.csv)
part, which is obviously very strange for the user to see.Also, I would rather use the native dialog if possible because the user then has access to the bookmarks, etc. which are not shown in the non-native dialog.
It is very strange because all other applications seem to get the file extension to show up in the selection list with no problem ... only in Qt. Is this a known bug?
-
wrote on 19 Sept 2019, 14:35 last edited by
I think this is a bug. Have a look at this function in the file
qgtk3dialoghelpers.cpp
(beginning at line 473 using Qt 5.11.1 sources):void QGtk3FileDialogHelper::setNameFilters(const QStringList &filters) { GtkDialog *gtkDialog = d->gtkDialog(); foreach (GtkFileFilter *filter, _filters) gtk_file_chooser_remove_filter(GTK_FILE_CHOOSER(gtkDialog), filter); _filters.clear(); _filterNames.clear(); foreach (const QString &filter, filters) { GtkFileFilter *gtkFilter = gtk_file_filter_new(); const QString name = filter.left(filter.indexOf(QLatin1Char('('))); const QStringList extensions = cleanFilterList(filter); gtk_file_filter_set_name(gtkFilter, qUtf8Printable(name.isEmpty() ? extensions.join(QLatin1String(", ")) : name)); foreach (const QString &ext, extensions) gtk_file_filter_add_pattern(gtkFilter, qUtf8Printable(ext)); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(gtkDialog), gtkFilter); _filters.insert(filter, gtkFilter); _filterNames.insert(gtkFilter, filter); } }
According to the Gtk docs, the function
gtk_file_filter_set_name()
is supposed to set the "human-readable" part of the file filter. But the code immediately above it has stripped the variablename
of the extension, so it seems obvious that it won't be shown.I seem to remember that on Windows, one could add the extension twice in round parentheses; however, it will get cut off at the first round left parenthesis here in this function.
Should I file a bug report? Or has this been fixed in later versions of Qt?
-
I think this is a bug. Have a look at this function in the file
qgtk3dialoghelpers.cpp
(beginning at line 473 using Qt 5.11.1 sources):void QGtk3FileDialogHelper::setNameFilters(const QStringList &filters) { GtkDialog *gtkDialog = d->gtkDialog(); foreach (GtkFileFilter *filter, _filters) gtk_file_chooser_remove_filter(GTK_FILE_CHOOSER(gtkDialog), filter); _filters.clear(); _filterNames.clear(); foreach (const QString &filter, filters) { GtkFileFilter *gtkFilter = gtk_file_filter_new(); const QString name = filter.left(filter.indexOf(QLatin1Char('('))); const QStringList extensions = cleanFilterList(filter); gtk_file_filter_set_name(gtkFilter, qUtf8Printable(name.isEmpty() ? extensions.join(QLatin1String(", ")) : name)); foreach (const QString &ext, extensions) gtk_file_filter_add_pattern(gtkFilter, qUtf8Printable(ext)); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(gtkDialog), gtkFilter); _filters.insert(filter, gtkFilter); _filterNames.insert(gtkFilter, filter); } }
According to the Gtk docs, the function
gtk_file_filter_set_name()
is supposed to set the "human-readable" part of the file filter. But the code immediately above it has stripped the variablename
of the extension, so it seems obvious that it won't be shown.I seem to remember that on Windows, one could add the extension twice in round parentheses; however, it will get cut off at the first round left parenthesis here in this function.
Should I file a bug report? Or has this been fixed in later versions of Qt?
@robert-hairgrove said in Native file dialog on Linux Ubuntu "swallows" file extensions:
Or has this been fixed in later versions of Qt?
I don't know, but you can test with the recent Qt version.
-
wrote on 19 Sept 2019, 15:09 last edited by Robert Hairgrove
Test case using the filter string from the Qt docs. Please note that the behavior probably is only shown on Linux with Gtk window manager.
#include <QMainWindow> #include <QApplication> #include <QPushButton> #include <QtCore> #include <QFileDialog> #include <QMessageBox> int main(int argc, char *argv[]) { QApplication a(argc, argv); QMainWindow w; QPushButton b; b.setText("Bye!"); w.setCentralWidget(&b); w.connect(&b, &QPushButton::clicked, &w, &QMainWindow::close); QString fn = QFileDialog::getOpenFileName( &w, "Testing the native dialog", QString(), "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"); if (!fn.isEmpty()) { QString msg = "You chose the file:\n"; QMessageBox::information(&w,"File Selected",msg.append(fn)); } fn = QFileDialog::getOpenFileName( &w, "Testing the Qt (non-native) dialog", QString(), "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)", nullptr, QFileDialog::DontUseNativeDialog); if (!fn.isEmpty()) { QString msg = "You chose the file:\n"; QMessageBox::information(&w,"File Selected",msg.append(fn)); } w.show(); return a.exec(); }
-
wrote on 19 Sept 2019, 15:36 last edited by
I just filed a bug report here.
-
wrote on 21 Sept 2019, 07:54 last edited by
I'm trying to create a workaround until this is fixed. Is there any way to determine which platform theme is used at compile time, or lacking that at runtime? I can use
#ifdef __linux__
etc., but there are certainly other window managers which might be used and not just Gtk. And I couldn't find any Gtk-specific macros to use.And since the platform dialog helpers (QPA) are plugins, maybe a runtime decision as to how to format the filter string would be most appropriate. How can I do this?
-
Hi,
You can use QSysInfo for runtime checks.
You have the Q_OS_XXX macros for build time separation.
-
Hi,
You can use QSysInfo for runtime checks.
You have the Q_OS_XXX macros for build time separation.
wrote on 23 Sept 2019, 05:57 last edited by@SGaist Thanks ... these are great suggestions, but I couldn't find any way of querying QSysInfo for the window manager currently being used. I would need something Gnome or Gtk-specific, I suppose.
-
This thread might give you some clues:
-
wrote on 23 Sept 2019, 20:19 last edited by
@SGaist Fantastic ... this will certainly help ... thank you!
-
I'm trying to create a workaround until this is fixed. Is there any way to determine which platform theme is used at compile time, or lacking that at runtime? I can use
#ifdef __linux__
etc., but there are certainly other window managers which might be used and not just Gtk. And I couldn't find any Gtk-specific macros to use.And since the platform dialog helpers (QPA) are plugins, maybe a runtime decision as to how to format the filter string would be most appropriate. How can I do this?
wrote on 14 Nov 2020, 11:05 last edited by@Robert-Hairgrove In the meantime, I have resorted to iterating over the environment variables which are available in the
main()
function if you declare it like this:int main(int argc, char*argv[], char*envp[]) { /*...*/ }
If any of the strings contain
"GNOME"
or"GTK_"
, I can set a global flag which allows me to mogrify the filter string so that it isn't swallowed. So if my filter string looks like this:"Text files (*.txt)"
then I insert two Unicode look-alike characters (
u8'FF08'
andu8'FF09'
, full-width parentheses) and duplicate the extension, i.e.:"Text files(*.txt) (*.txt)"
The user will see:
"Text files(*.txt)"
which is good enough for my purposes.