Add tilde (both ~ and ~<user>) expansion to QFileDialog on UNIX.
Task-number: QTBUG-3265 Change-Id: Id8062afe69e798e1f9cf3f4e967ae0d30c362b72 Reviewed-on: http://codereview.qt.nokia.com/411 Reviewed-by: Pierre Rossi <pierre.rossi@gmail.com>bb10
parent
15d6f1f031
commit
94c173de05
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,36 @@ 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);
|
||||
#else
|
||||
QFETCH(QString, tildePath);
|
||||
QFETCH(QString, expandedPath);
|
||||
|
||||
QCOMPARE(qt_tildeExpansion(tildePath), expandedPath);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
QTEST_MAIN(tst_QFiledialog)
|
||||
#include "tst_qfiledialog.moc"
|
||||
|
|
|
|||
Loading…
Reference in New Issue