How to set FileDialog's folder from a UNC path in QML?

2.2k Views Asked by At

I want to store the last used folder in a file dialog in qml (using Qt version 5.6). The way I do it is through QSettings that has a url property lastUsedFolder as such:

/////////////
/// myApp.qml
/////////////

import QtQuick 2.3
import QtQuick.Dialogs 1.1
import Qt.labs.settings 1.0

Settings {
    id: settings
    property url lastUsedFolder;
}

FileDialog {
    id: openDialog
    onVisibleChanged:
    {
        if(visible && myApp.doesFolderStillExist(settings.lastUsedFolder))
        {
            console.log("setting folder of dialog")
            folder = settings.lastUsedFolder
            console.log(folder)
        }
    }
    onAccepted:
    {
        console.log("saving folder: " + folder)
        settings.lastUsedFolder = folder;
    }
}

/////////////
/// myApp.cpp
/////////////
bool myApp::doesFolderStillExist(QUrl folderUrl)
{
    QFileInfo folder(folderUrl.toLocalFile());
    if (folder.exists())
        return true;
    return false;
}

This works well enough when working with local files, but does not when using files on remote computers addressed by a UNC-format path such as \\myRemotePC.somewhere.com\myData\.

If I navigate to this address and accept the dialog, the folder is stored thanks to the onAccepted method and the console prints saving folder: file://myRemotePC.somewhere.com/myData. Then when I open the dialog again, the onVisibleChanged triggers. The doesFolderStillExists method sees the folder - the QUrl.toLocalFile seems to work - and also the stored path in settings.lastUsedFolder is still the same that was stored. But then the app crashes on the line that assigns to the folder property with the following error (Windows 7; the last console print is just the "setting folder of dialog"):

QWindowsNativeFileDialogBase::shellItem: SHCreateItemFromParsingName(file:///myRemotePC.somewhere.com/myData) failed ()

In other words, it crashes when I try to set the folder property of the dialog using the exact same value I read from it before...and that confuses me.

Not sure if it matters, but one strange thing I noticed is that the error message has three forward slashes after the file:, while the path that I am setting as the folder has only two. I tried to modify the path in various ways:

  • if the file: is omitted entirely, the dialog opens in the default location, probably failing to parse the address in a meaningful way - which is kind of expected
  • no matter how many forward slashes I add or remove after the file:, the same error message appears, always with three slashes in the shown path

I would appreciate any advice that would lead me to being able to store and re-use the last used folder in a FileDialog in a way that is usable for both "local" and UNC paths, even if it was done in a different way than we are currently using.

1

There are 1 best solutions below

3
Bastien Thonnat On

It seem to be an error from Qt. QFileDialog try to "correct" your URI in a bad way, cause if you convert an UNC path like "\myRemotePC.somewhere.com\myData\" into an URI it will give you "file://myRemotePC.somewhere.com/myData", this part is correct, but from QFileDialog point of view, you try to get a local folder.

I try to feed the QFileDialog with raw string or url but QFileDialog persist to convert the path.

If you need one workaround, call QFileDialog from C++, it work with string path like UNC path.

Another workaround, connect your external folder as network drive.

Sorry for my poor English ^^

If someone want a fast try.

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import Qt.labs.settings 1.0

Window {
Component.onCompleted: {
    openDialog.open();
}

FileDialog {
    id: openDialog
    selectFolder: true
    Component.onCompleted:  folder = settings.lastFolderURL;
    onVisibleChanged:
    {
        console.log("lastFolder as string " + settings.lastFolderString);
        console.log("lastFolder as URL " + settings.lastFolderURL);
    }
    onAccepted:
    {
        console.log("Selected folder : " + folder)
        settings.lastFolderString = folder;
        settings.lastFolderURL = folder;
    }
}

Settings {
    id: settings
    property string lastFolderString ;
    property url lastFolderURL;
}
}