diff options
author | Pierre Rossi <pierre.rossi@nokia.com> | 2011-05-20 12:16:33 (GMT) |
---|---|---|
committer | Pierre Rossi <pierre.rossi@nokia.com> | 2011-06-08 16:15:05 (GMT) |
commit | df6713b8f55fc007796f404a3615bf348d1d0782 (patch) | |
tree | 96cf40cf2448603da00f3c5e7993b40541ace9d3 | |
parent | 32079bb0b348ef5f7126e69be9bcfb249c1a6412 (diff) | |
download | Qt-df6713b8f55fc007796f404a3615bf348d1d0782.zip Qt-df6713b8f55fc007796f404a3615bf348d1d0782.tar.gz Qt-df6713b8f55fc007796f404a3615bf348d1d0782.tar.bz2 |
Add tilde (both ~ and ~<userName>) expansion to QFileDialog on UNIX.
Task-number: QTBUG-3265
Reviewed-by: Thiago
-rw-r--r-- | src/gui/dialogs/qfiledialog.cpp | 77 | ||||
-rw-r--r-- | tests/auto/qfiledialog/tst_qfiledialog.cpp | 38 |
2 files changed, 111 insertions, 4 deletions
diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index 897a916..8da60e6 100644 --- a/src/gui/dialogs/qfiledialog.cpp +++ b/src/gui/dialogs/qfiledialog.cpp @@ -66,6 +66,9 @@ #if defined(Q_OS_WINCE) extern bool qt_priv_ptr_valid; #endif +#if defined(Q_OS_UNIX) +#include <pwd.h> +#endif #endif QT_BEGIN_NAMESPACE @@ -858,23 +861,78 @@ void QFileDialog::selectFile(const QString &filename) d->lineEdit()->setText(file); } +#ifdef Q_OS_UNIX +Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0) +{ + if (expanded != 0) + *expanded = false; + if (!path.startsWith(QLatin1Char('~'))) + return path; + QString ret = path; + QStringList tokens = ret.split(QDir::separator()); + if (tokens.first() == QLatin1String("~")) { + ret.replace(0, 1, QDir::homeDirPath()); + } else { + QString userName = tokens.first(); + userName.remove(0, 1); +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) + passwd pw; + passwd *tmpPw; + char buf[200]; + const int bufSize = sizeof(buf); + int err = getpwnam_r(userName.toLocal8Bit().constData(), &pw, buf, bufSize, &tmpPw); + if (err || !tmpPw) + return ret; + const QString homePath = QString::fromLocal8Bit(pw.pw_dir); +#else + passwd *pw = getpwnam(userName.toLocal8Bit().constData()); + if (!pw) + return ret; + const QString homePath = QString::fromLocal8Bit(pw->pw_dir); +#endif + ret.replace(0, tokens.first().length(), homePath); + } + if (expanded != 0) + *expanded = true; + return ret; +} +#endif + /** Returns the text in the line edit which can be one or more file names */ QStringList QFileDialogPrivate::typedFiles() const { + Q_Q(const QFileDialog); QStringList files; QString editText = lineEdit()->text(); - if (!editText.contains(QLatin1Char('"'))) + if (!editText.contains(QLatin1Char('"'))) { +#ifdef Q_OS_UNIX + const QString prefix = q->directory().absolutePath() + QDir::separator(); + if (QFile::exists(prefix + editText)) + files << editText; + else + files << qt_tildeExpansion(editText); +#else files << editText; - else { +#endif + } else { // " is used to separate files like so: "file1" "file2" "file3" ... // ### need escape character for filenames with quotes (") QStringList tokens = editText.split(QLatin1Char('\"')); for (int i=0; i<tokens.size(); ++i) { if ((i % 2) == 0) continue; // Every even token is a separator +#ifdef Q_OS_UNIX + const QString token = tokens.at(i); + const QString prefix = q->directory().absolutePath() + QDir::separator(); + if (QFile::exists(prefix + token)) + files << token; + else + files << qt_tildeExpansion(token); +#else files << toInternal(tokens.at(i)); +#endif } } return addDefaultSuffixToFiles(files); @@ -3338,6 +3396,17 @@ QStringList QFSCompleter::splitPath(const QString &path) const pathCopy = pathCopy.mid(2); else doubleSlash.clear(); +#elif defined(Q_OS_UNIX) + bool expanded; + pathCopy = qt_tildeExpansion(pathCopy, &expanded); + if (expanded) { + QFileSystemModel *dirModel; + if (proxyModel) + dirModel = qobject_cast<QFileSystemModel *>(proxyModel->sourceModel()); + else + dirModel = sourceModel; + dirModel->fetchMore(dirModel->index(pathCopy)); + } #endif QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']')); @@ -3354,14 +3423,14 @@ QStringList QFSCompleter::splitPath(const QString &path) const parts.append(QString()); #else QStringList parts = pathCopy.split(re); - if (path[0] == sep[0]) // read the "/" at the beginning as the split removed it + if (pathCopy[0] == sep[0]) // read the "/" at the beginning as the split removed it parts[0] = sep[0]; #endif #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) bool startsFromRoot = !parts.isEmpty() && parts[0].endsWith(QLatin1Char(':')); #else - bool startsFromRoot = path[0] == sep[0]; + bool startsFromRoot = pathCopy[0] == sep[0]; #endif if (parts.count() == 1 || (parts.count() > 1 && !startsFromRoot)) { const QFileSystemModel *dirModel; diff --git a/tests/auto/qfiledialog/tst_qfiledialog.cpp b/tests/auto/qfiledialog/tst_qfiledialog.cpp index 42e82a9..24ac9f7 100644 --- a/tests/auto/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/qfiledialog/tst_qfiledialog.cpp @@ -78,6 +78,10 @@ # define STRINGIFY(x) #x # define TOSTRING(x) STRINGIFY(x) # define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID) "/" +#elif defined(Q_OS_UNIX) +#ifdef QT_BUILD_INTERNAL +extern Q_GUI_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0); +#endif #endif class QNonNativeFileDialog : public QFileDialog @@ -144,6 +148,10 @@ private slots: void clearLineEdit(); void enableChooseButton(); void hooks(); +#ifdef Q_OS_UNIX + void tildeExpansion_data(); + void tildeExpansion(); +#endif private: QByteArray userSettings; @@ -1323,5 +1331,35 @@ void tst_QFiledialog::hooks() QCOMPARE(QFileDialog::getSaveFileName(), QString("saveName")); } +#ifdef Q_OS_UNIX +void tst_QFiledialog::tildeExpansion_data() +{ + QTest::addColumn<QString>("tildePath"); + QTest::addColumn<QString>("expandedPath"); + + QTest::newRow("empty path") << QString() << QString(); + QTest::newRow("~") << QString::fromLatin1("~") << QDir::homePath(); + QTest::newRow("~/some/sub/dir/") << QString::fromLatin1("~/some/sub/dir") << QDir::homePath() + + QString::fromLatin1("/some/sub/dir"); + QString userHome = QString(qgetenv("USER")); + userHome.prepend('~'); + QTest::newRow("current user (~<user> syntax)") << userHome << QDir::homePath(); + QString invalid = QString::fromLatin1("~thisIsNotAValidUserName"); + QTest::newRow("invalid user name") << invalid << invalid; +} + + +void tst_QFiledialog::tildeExpansion() +{ +#ifndef QT_BUILD_INTERNAL + QSKIP("Test case relies on developer build (AUTOTEST_EXPORT)", SkipAll); +#endif + QFETCH(QString, tildePath); + QFETCH(QString, expandedPath); + + QCOMPARE(qt_tildeExpansion(tildePath), expandedPath); +} +#endif + QTEST_MAIN(tst_QFiledialog) #include "tst_qfiledialog.moc" |