Native file dialog on Linux Ubuntu "swallows" file extensions
-
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?
-
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.
-
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(); }
-
I just filed a bug report here.
-
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.
@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.
-
@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?
@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.