8

I want the user to be able to enter a name for a file that will be saved as an xml file. Currently on Windows and Mac if you enter "test" as the file name it will automatically add ".xml" which is what I want. Unfortunately when testing a Linux build I found that entering a file name without an extension would save as an ordinary file. The user has to specify the extension in the file string (i.e "test.xml") in order for it to save in the correct format.

The code I'm using is below. Is this a Qt bug or is there a way to specify in Qt that it should add an extension if one wasn't found?

// Get value for "dir". If the setting doesn't exist then use
// the the path in "defaultsave.directory"
QString prevPath = prevValues.value("dir", QString::fromStdString(
  ConfigService::Instance().getString("defaultsave.directory"))).toString();

QString filter;
filter.append("Files (*.xml)");
filter += ";;AllFiles (*.*)";
QString groupingFile = QFileDialog::getSaveFileName(this, "Save Grouping file as", prevPath, filter);
Robert Whitley
  • 981
  • 3
  • 13
  • 28
  • have you considered the documentation on platform specifics already? – Sebastian Mach Mar 22 '12 at 12:43
  • I've added a comment to the bug report that originally requested this feature (and is claimed to be fixed): https://bugreports.qt-project.org/browse/QTBUG-27186#comment-248985 – Bernhard Reiter Jun 30 '14 at 09:20
  • possible duplicate of [QFileDialog: adding extension automatically when saving file?](http://stackoverflow.com/questions/1953631/qfiledialog-adding-extension-automatically-when-saving-file) – vsz Aug 03 '15 at 06:06
  • @vsz, have you checked that the proposed solution works for the static call being used here, `getSaveFileName`? I know it works for actual `QFileDialog` objects, I'm just not certain re the static functions, since they apparently don't always use `QFileDialog`. – paxdiablo Aug 03 '15 at 06:30

3 Answers3

11

Since you get the string from the dialog with getSaveFileName, you can just do something like:

if (!groupingFile.endsWith(".xml"))
    groupingFile += ".xml";

It's probably different on Linux because of this little snippet buried in the documentation for getSaveFileName:

On Windows, Mac OS X and Symbian^3, this static function will use the native file dialog and not a QFileDialog.

In other words, it's the adding of the prefix (done by the native dialogs) that is aberrant, at least in terms of Qt.


As pointed out in the comments, you may find an issue with this solution in that the dialog box itself won't notify you if you type in xyzzy manually and the file xyzzy.xml already exists (assuming the native dialogs do this - I haven't actually checked). If you want that behaviour, you'll need to implement it as well.

paxdiablo
  • 772,407
  • 210
  • 1,477
  • 1,841
  • I was so caught up with trying to get QFileDialog to work I forgot to look at the obvious solution. Thanks. I'd still like to know why the functionality of QFileDialog is different for Linux builds. – Robert Whitley Mar 22 '12 at 13:29
  • 1
    @RobertWhitley, see my update, there's a bit of doco stating that these static functions don't actually use `QFileDialog`. – paxdiablo Mar 22 '12 at 13:41
  • 2
    There is one downside to this approach: If you use `QFileDialog::confirmOverwrite` (default), QFileDialog tests for a different filename than the one you're actually writing to. The solution is to either pass `QFileDialog::DontConfirmOverwrite` and do your own confirmation dialog, or to use `QFileDialog::defaultSuffix`, which is not available through `QFileDialog::getSaveFileName`. Either way, you need more code than just the static function call. :-( – hans_meine Mar 24 '14 at 13:54
  • -1: The original of this duplicate question provides the correct answer. This answer has the issues of not checking the correct file for overwriting – vsz Aug 03 '15 at 06:05
  • @vsz, I see no requirement in the question for checking overwrites, only a request for being able to add the extension (and I have to assume it was satisfactory since the OP accepted the answer). In any case, I don't believe this is necessarily a dupe. The linked question is actually using a `QFileDialog` object directly, this question instead calls the static function `getSaveFileName`, which doesn't use `QFileDialog` objects on all platforms. – paxdiablo Aug 03 '15 at 06:46
  • @paxdiablo : If I posted an answer which caused a memory leak, and after you pointed it out, I answered that *"I see no requirement for not causing a memory leak"*, what would you think? This site should not be about our egos, but about providing useful answers both for the OP and future visitors. If the user selects an existing file in the dialog, a warning about overwriting will appear. If the user instead types the name of the same file, the warning does not appear and the file is silently overwritten. I would classify this as a serious bug. – vsz Aug 03 '15 at 16:54
  • The answer should be edited to point it out. I didn't edit it yet, because I think it's more polite to let the original answerer do it. Just because the OP accepted it does not mean it's not a problem, maybe the OP also didn't notice it. – vsz Aug 03 '15 at 16:54
  • 1
    @vsz, What would I think? I would think that a memory leak was a bug in a long running program but irrelevant in a short running one. As in "context matters". However, I've made a note in the answer that it's something people may want to consider. If you think it can be improved, I'm happy (and ego-less enough) to accept any suggestions :-) Thanks for your input to date, I do appreciate it. – paxdiablo Aug 04 '15 at 01:52
4

We created our own save dialog method to get around this. The solution is essentially the same as @paxdiablo's answer (just add the extension), but this is more general:

QString ShowSaveFileDialog(QWidget *parent,
                           const QString &title,
                           const QString &directory,
                           const QString &filter) {
#if defined(Q_WS_WIN) || defined(Q_WS_MAC)
  return QFileDialog::getSaveFileName(parent,
                                      title,
                                      directory,
                                      filter);
#else
  QFileDialog dialog(parent, title, directory, filter);
  if (parent) {
    dialog.setWindowModality(Qt::WindowModal);
  }
  QRegExp filter_regex(QLatin1String("(?:^\\*\\.(?!.*\\()|\\(\\*\\.)(\\w+)"));
  QStringList filters = filter.split(QLatin1String(";;"));
  if (!filters.isEmpty()) {
    dialog.setNameFilter(filters.first());
    if (filter_regex.indexIn(filters.first()) != -1) {
      dialog.setDefaultSuffix(filter_regex.cap(1));
    }
  }
  dialog.setAcceptMode(QFileDialog::AcceptSave);
  if (dialog.exec() == QDialog::Accepted) {
    QString file_name = dialog.selectedFiles().first();
    QFileInfo info(file_name);
    if (info.suffix().isEmpty() && !dialog.selectedNameFilter().isEmpty()) {
      if (filter_regex.indexIn(dialog.selectedNameFilter()) != -1) {
        QString extension = filter_regex.cap(1);
        file_name += QLatin1String(".") + extension;
      }
    }
    return file_name;
  } else {
    return QString();
  }
#endif  // Q_WS_MAC || Q_WS_WIN
}
Dave Mateer
  • 16,802
  • 15
  • 90
  • 142
0

Did you look at QFileDialog::setDefaultSuffix?

olegst
  • 1,069
  • 9
  • 31