summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@digia.com>2014-04-28 16:16:34 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-04-29 03:27:26 +0200
commit9f6a0300a5ab5996a97b27bc8ada55f41e3ca517 (patch)
tree17f14408a71d82b3f0baf012f44a4a6533aa8ac3
parent386292837bf5f6bcb502bd3fa68cb2a4e9498b1b (diff)
Observe case insensitive file systems in QFileDialog::selectFile().
When stripping the root path from a file name that cannot be found in the model, use case sensitive comparison depending on file system. Task-number: QTBUG-38162 Change-Id: I28e28973fca2da35a5768fdd00cc258b9669a15a Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp60
-rw-r--r--tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp37
2 files changed, 77 insertions, 20 deletions
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index ecbd9480ff..bb8cdec896 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -71,6 +71,7 @@ extern bool qt_priv_ptr_valid;
#endif
#if defined(Q_OS_UNIX)
#include <pwd.h>
+#include <unistd.h> // for pathconf() on OS X
#elif defined(Q_OS_WIN)
# include <QtCore/qt_windows.h>
#endif
@@ -1018,6 +1019,44 @@ QUrl QFileDialog::directoryUrl() const
return QUrl::fromLocalFile(directory().absolutePath());
}
+// FIXME Qt 5.4: Use upcoming QVolumeInfo class to determine this information?
+static inline bool isCaseSensitiveFileSystem(const QString &path)
+{
+ Q_UNUSED(path)
+#if defined(Q_OS_WIN)
+ // Return case insensitive unconditionally, even if someone has a case sensitive
+ // file system mounted, wrongly capitalized drive letters will cause mismatches.
+ return false;
+#elif defined(Q_OS_OSX)
+ return pathconf(QFile::encodeName(path).constData(), _PC_CASE_SENSITIVE);
+#else
+ return true;
+#endif
+}
+
+// Determine the file name to be set on the line edit from the path
+// passed to selectFile() in mode QFileDialog::AcceptSave.
+static inline QString fileFromPath(const QString &rootPath, QString path)
+{
+ if (!QFileInfo(path).isAbsolute())
+ return path;
+ if (path.startsWith(rootPath, isCaseSensitiveFileSystem(rootPath) ? Qt::CaseSensitive : Qt::CaseInsensitive))
+ path.remove(0, rootPath.size());
+
+ if (path.isEmpty())
+ return path;
+
+ if (path.at(0) == QDir::separator()
+#ifdef Q_OS_WIN
+ //On Windows both cases can happen
+ || path.at(0) == QLatin1Char('/')
+#endif
+ ) {
+ path.remove(0, 1);
+ }
+ return path;
+}
+
/*!
Selects the given \a filename in the file dialog.
@@ -1049,28 +1088,9 @@ void QFileDialog::selectFile(const QString &filename)
}
QModelIndex index = d->model->index(filename);
- QString file;
- if (!index.isValid()) {
- // save as dialog where we want to input a default value
- QString text = filename;
- if (QFileInfo(filename).isAbsolute()) {
- QString current = d->rootPath();
- text.remove(current);
- if (text.at(0) == QDir::separator()
-#ifdef Q_OS_WIN
- //On Windows both cases can happen
- || text.at(0) == QLatin1Char('/')
-#endif
- )
- text = text.remove(0,1);
- }
- file = text;
- } else {
- file = index.data().toString();
- }
d->qFileDialogUi->listView->selectionModel()->clear();
if (!isVisible() || !d->lineEdit()->hasFocus())
- d->lineEdit()->setText(file);
+ d->lineEdit()->setText(index.isValid() ? index.data().toString() : fileFromPath(d->rootPath(), filename));
}
/*!
diff --git a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp
index e856c2efc5..047df0d3f2 100644
--- a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp
+++ b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp
@@ -43,6 +43,7 @@
#include <QtTest/QtTest>
#include <qcoreapplication.h>
+#include <qfile.h>
#include <qdebug.h>
#include <qsharedpointer.h>
#include <qfiledialog.h>
@@ -72,6 +73,7 @@
#include <QFileSystemModel>
#if defined(Q_OS_UNIX)
+#include <unistd.h> // for pathconf() on OS X
#ifdef QT_BUILD_INTERNAL
QT_BEGIN_NAMESPACE
extern Q_GUI_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0);
@@ -79,6 +81,19 @@ QT_END_NAMESPACE
#endif
#endif
+static inline bool isCaseSensitiveFileSystem(const QString &path)
+{
+ Q_UNUSED(path)
+#if defined(Q_OS_MAC)
+ return pathconf(QFile::encodeName(path).constData(), _PC_CASE_SENSITIVE);
+#elif defined(Q_OS_WIN)
+ return false;
+#else
+ return true;
+#endif
+}
+
+
class QNonNativeFileDialog : public QFileDialog
{
Q_OBJECT
@@ -130,6 +145,7 @@ private slots:
void selectFile_data();
void selectFile();
void selectFiles();
+ void selectFileWrongCaseSaveAs();
void selectFilter();
void viewMode();
void proxymodel();
@@ -882,6 +898,27 @@ void tst_QFiledialog::selectFile()
fd.reset(); // Ensure the file dialog let's go of the temporary file for "temp".
}
+void tst_QFiledialog::selectFileWrongCaseSaveAs()
+{
+ const QString home = QDir::homePath();
+ if (isCaseSensitiveFileSystem(home))
+ QSKIP("This test is intended for case-insensitive file systems only.");
+ // QTBUG-38162: when passing a wrongly capitalized path to selectFile()
+ // on a case-insensitive file system, the line edit should only
+ // contain the file name ("c:\PRogram files\foo.txt" -> "foo.txt").
+ const QString fileName = QStringLiteral("foo.txt");
+ const QString path = home + QLatin1Char('/') + fileName;
+ QString wrongCasePath = path;
+ for (int c = 0; c < wrongCasePath.size(); c += 2)
+ wrongCasePath[c] = wrongCasePath.at(c).isLower() ? wrongCasePath.at(c).toUpper() : wrongCasePath.at(c).toLower();
+ QNonNativeFileDialog fd(0, "QTBUG-38162", wrongCasePath);
+ fd.setAcceptMode(QFileDialog::AcceptSave);
+ fd.selectFile(wrongCasePath);
+ const QLineEdit *lineEdit = fd.findChild<QLineEdit*>("fileNameEdit");
+ QVERIFY(lineEdit);
+ QCOMPARE(lineEdit->text().compare(fileName, Qt::CaseInsensitive), 0);
+}
+
void tst_QFiledialog::selectFiles()
{
QTemporaryDir tempDir;