-
Bug
-
Resolution: Unresolved
-
P3: Somewhat important
-
None
-
6.11
-
None
QFileDialog has the option to return the selected file(s) as either QString or QUrl. On the implementation side the platform file dialog always returns QUrl.
In some cases our file dialogs want to report custom file paths in some form, so that it can be picked up QAbstractFileEngine. Examples are photo library assets on iOS, Cloud documents on macOS/iOS, or APK/Asset/Content file engines on Android.
The current approach for this is to use a custom scheme, e.g. assets-library://, however that brings some awkward situations for QUrl.
- A QUrl will only report isLocalFile() for file:// scheme, so clients that play it safe and check isLocalFile() before passing things down to QFile will have issues.
- ⚠️ Surprisingly, we also treat webdav:// as a local file scheme on Windows!
- Calling toLocalFile() on non-isLocalFile() URLs will return an empty string.
So the only way that these special URLs into something that can be passed to QFile (which doesn’t take QUrls), is to use url.toString(), which is unintuitive. However this is exactly what QFileDialog does to turn the QUrls from the platform file dialog into QStrings, via url.toString(QUrl::PreferLocalFile).
⚠️ The QUrl::PreferLocalFile argument is important here, as without it we get a string including the file:// sceme for file URLs, and we do not have a QAbstractFileEngine or logic anywhere that resolves that into a plain file path.
A related issue is that if a file URL contains a query or fragment, isLocalFile will still return true, but toLocalFile will strip the query and hash, removing important information that may be needed by the QAbstractFileEngine.
QUrl::toString() will detect the situation and return the URL without stripping, ie file:///foo/bar/baz.txt?id=123, but that includes the file:// scheme (even with QUrl::PreferLocalFile), which we don’t have logic to handle in QFile and friends.
Given all of this:
- A QAbstractFileEngine can pick arbitrary path to serve. It’s not limited by the path string having a “scheme”-like prefix.
- A QFile takes an opaque path string, which may or may not be served by an QAbstractFileEngine
- When QFileDialog (and its backends) serves URLs, it’s probably correct to never report any of the magic paths as file://
- Seeing as the query and fragment is stripped in toLocalFile, and toString passes on the file scheme
- Even if we baked the magic bits into the path itself, which would be preserved by toLocalFile, the url reporting as isLocalFile may lead people to believe they can pass the path to non-QFile file system operations, which is not the case.
- Seeing as the query and fragment is stripped in toLocalFile, and toString passes on the file scheme
- Which means we need custom URL schemes, and should document that QFileDialog may return URLs that can still be passed down to QFile, even though they are not isLocalFile, and if doing so, to always use toString( QUrl::PreferLocalFile).
Thoughts?
QUrl("file:///foo/bar/baz.txt") isLocalFile: true toLocalFile: "/foo/bar/baz.txt" toString: "/foo/bar/baz.txt" QUrl("asset-library:///foo/bar/baz.txt") isLocalFile: false toLocalFile: "" toString: "asset-library:///foo/bar/baz.txt" QUrl("file:///foo/bar/baz.txt?id=123") isLocalFile: true toLocalFile: "/foo/bar/baz.txt" toString: "file:///foo/bar/baz.txt?id=123" QUrl("asset-library:///foo/bar/baz.txt?id=123") isLocalFile: false toLocalFile: "" toString: "asset-library:///foo/bar/baz.txt?id=123" QUrl("file:///foo/bar/baz.txt#myfragment") isLocalFile: true toLocalFile: "/foo/bar/baz.txt" toString: "file:///foo/bar/baz.txt#myfragment" QUrl("asset-library:///foo/bar/baz.txt#myfragment") isLocalFile: false toLocalFile: "" toString: "asset-library:///foo/bar/baz.txt#myfragment" # Only on Windows QUrl("webdavs:///foo/bar/baz.txt") isLocalFile: true toLocalFile: "/foo/bar/baz.txt" toString: "/foo/bar/baz.txt" QUrl("webdavs:///foo/bar/baz.txt?id=123") isLocalFile: true toLocalFile: "/foo/bar/baz.txt" toString: "webdavs:///foo/bar/baz.txt?id=123" QUrl("webdavs:///foo/bar/baz.txt#myfragment") isLocalFile: true toLocalFile: "/foo/bar/baz.txt" toString: "webdavs:///foo/bar/baz.txt#myfragment" # Otherwise QUrl("webdavs:///foo/bar/baz.txt") isLocalFile: false toLocalFile: "" toString: "webdavs:///foo/bar/baz.txt" QUrl("webdavs:///foo/bar/baz.txt?id=123") isLocalFile: false toLocalFile: "" toString: "webdavs:///foo/bar/baz.txt?id=123" QUrl("webdavs:///foo/bar/baz.txt#myfragment") isLocalFile: false toLocalFile: "" toString: "webdavs:///foo/bar/baz.txt#myfragment"
- relates to
-
QTBUG-103246 Qt should have a QIo like what KIO is. But much much better
-
- Open
-