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>
This commit is contained in:
parent
386292837b
commit
9f6a0300a5
@ -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));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user