From e9c079a648721ea53d58e63bc61b61f9a5da867f Mon Sep 17 00:00:00 2001
From: Daniel Teske <daniel.teske@nokia.com>
Date: Fri, 25 Nov 2011 13:17:52 +0100
Subject: [PATCH] Add FileName isChildOf/relativePath and endsWith and
 appendPath

Needed by qtversionmanager

Change-Id: I4d455298e809b744ae3663493914db6e31f372a6
Reviewed-by: Tobias Hunger <tobias.hunger@nokia.com>
Reviewed-by: Daniel Teske <daniel.teske@nokia.com>
---
 src/libs/utils/fileutils.cpp               | 70 ++++++++++++++++++----
 src/libs/utils/fileutils.h                 | 19 ++++--
 src/plugins/qt4projectmanager/qt4nodes.cpp | 11 ++--
 3 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp
index 65e3fbbad67..4a306ef79b5 100644
--- a/src/libs/utils/fileutils.cpp
+++ b/src/libs/utils/fileutils.cpp
@@ -407,6 +407,14 @@ TempFileSaver::~TempFileSaver()
         QFile::remove(m_fileName);
 }
 
+/*! \class Utils::FileName
+
+    \brief A light-weight convenience class for filenames
+
+    On windows filenames are compared case insensitively.
+*/
+
+
 #ifdef Q_OS_WIN
 Qt::CaseSensitivity FileName::cs = Qt::CaseInsensitive;
 #else
@@ -419,31 +427,62 @@ FileName::FileName()
 
 }
 
+/// Constructs a FileName from \a info
 FileName::FileName(const QFileInfo &info)
     : QString(info.absoluteFilePath())
 {
 }
 
+/// \returns a QFileInfo
+QFileInfo FileName::toFileInfo() const
+{
+    return QFileInfo(*this);
+}
+
+/// \returns a QString for passing on to QString based APIs
 QString FileName::toString() const
 {
     return QString(*this);
 }
 
+/// \returns a QString to display to the user
+/// Converts the separators to the native format
+QString FileName::toUserOutput() const
+{
+    return QDir::toNativeSeparators(toString());
+}
+
+/// Constructs a FileName from \a fileName
+/// \a fileName is not checked for validity.
 FileName FileName::fromString(const QString &filename)
 {
     return FileName(filename);
 }
 
+/// Constructs a FileName from \a fileName
+/// \a fileName is only passed through QDir::cleanPath
+/// and QDir::fromNativeSeparators
+FileName FileName::fromUserInput(const QString &filename)
+{
+    return FileName(QDir::cleanPath(QDir::fromNativeSeparators(filename)));
+}
+
 FileName::FileName(const QString &string)
     : QString(string)
 {
 
 }
+
 bool FileName::operator==(const FileName &other) const
 {
     return QString::compare(*this, other, cs) == 0;
 }
 
+bool FileName::operator!=(const FileName &other) const
+{
+    return !(*this == other);
+}
+
 bool FileName::operator<(const FileName &other) const
 {
     return QString::compare(*this, other, cs) < 0;
@@ -464,29 +503,38 @@ bool FileName::operator>=(const FileName &other) const
     return other <= *this;
 }
 
-bool FileName::startsWith(const QString &s) const
+/// \returns whether FileName is a child of \a s
+bool FileName::isChildOf(const FileName &s) const
 {
-    return QString::startsWith(s, cs);
+    if (!QString::startsWith(s, cs))
+        return false;
+    if (size() <= s.size())
+        return false;
+    return at(s.size()) == '/';
 }
 
+/// \returns whether FileName endsWith \a s
 bool FileName::endsWith(const QString &s) const
 {
     return QString::endsWith(s, cs);
 }
 
-FileName FileName::left(int n) const
-{
-    return FileName(QString::left(n));
-}
-
-FileName FileName::mid(int position, int n) const
+/// \returns the relativeChildPath of FileName to parent if FileName is a child of parent
+/// \note returns a empty FileName if FileName is not a child of parent
+/// That is, this never returns a path starting with "../"
+FileName FileName::relativeChildPath(const FileName &parent) const
 {
-    return FileName(QString::mid(position, n));
+    if (!isChildOf(parent))
+        return Utils::FileName();
+    return FileName(QString::mid(parent.size() + 1, -1));
 }
 
-FileName FileName::right(int n) const
+/// Appends \a s, ensuring a / between the parts
+void FileName::appendPath(const QString &s)
 {
-    return FileName(QString::right(n));
+    if (QString::endsWith(QLatin1Char('/')))
+        append(QLatin1Char('/'));
+    append(s);
 }
 
 } // namespace Utils
diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h
index 90c8f47dfa9..308d9199cc2 100644
--- a/src/libs/utils/fileutils.h
+++ b/src/libs/utils/fileutils.h
@@ -39,6 +39,7 @@
 #include <QtCore/QIODevice>
 #include <QtCore/QXmlStreamWriter> // Mac.
 #include <QtCore/QFileInfo>
+#include <QtCore/QMetaType>
 
 QT_BEGIN_NAMESPACE
 class QFile;
@@ -145,26 +146,32 @@ class QTCREATOR_UTILS_EXPORT FileName : private QString
 public:
     FileName();
     explicit FileName(const QFileInfo &info);
-    QString toString() const;
+    QFileInfo toFileInfo() const;
     static FileName fromString(const QString &filename);
+    static FileName fromUserInput(const QString &filename);
+    QString toString() const;
+    QString toUserOutput() const;
 
     bool operator==(const FileName &other) const;
+    bool operator!=(const FileName &other) const;
     bool operator<(const FileName &other) const;
     bool operator<=(const FileName &other) const;
     bool operator>(const FileName &other) const;
     bool operator>=(const FileName &other) const;
 
-    bool startsWith(const QString &s) const;
+    bool isChildOf(const FileName &s) const;
     bool endsWith(const QString &s) const;
 
-    FileName left(int n) const Q_REQUIRED_RESULT;
-    FileName mid(int position, int n = -1) const Q_REQUIRED_RESULT;
-    FileName right(int n) const Q_REQUIRED_RESULT;
+    Utils::FileName relativeChildPath(const FileName &parent) const;
+    void appendPath(const QString &s);
 
     using QString::size;
     using QString::count;
     using QString::length;
     using QString::isEmpty;
+    using QString::isNull;
+    using QString::clear;
+    using QString::append;
 private:
     static Qt::CaseSensitivity cs;
     FileName(const QString &string);
@@ -176,4 +183,6 @@ QT_BEGIN_NAMESPACE
 QTCREATOR_UTILS_EXPORT uint qHash(const Utils::FileName &a);
 QT_END_NAMESPACE
 
+Q_DECLARE_METATYPE(Utils::FileName)
+
 #endif // FILEUTILS_H
diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp
index fe0c3b8207d..1819417d907 100644
--- a/src/plugins/qt4projectmanager/qt4nodes.cpp
+++ b/src/plugins/qt4projectmanager/qt4nodes.cpp
@@ -309,14 +309,13 @@ struct InternalNode
     void create(const QString &projectDir, const QSet<Utils::FileName> &newFilePaths, ProjectExplorer::FileType type)
     {
         static const QChar separator = QChar('/');
-        const QString projectDirWithSeparator = projectDir + separator;
-        int projectDirWithSeparatorLength = projectDirWithSeparator.length();
+        const Utils::FileName projectDirFileName = Utils::FileName::fromString(projectDir);
         foreach (const Utils::FileName &file, newFilePaths) {
             Utils::FileName fileWithoutPrefix;
             bool isRelative;
-            if (file.startsWith(projectDirWithSeparator)) {
+            if (file.isChildOf(projectDirFileName)) {
                 isRelative = true;
-                fileWithoutPrefix = file.mid(projectDirWithSeparatorLength);
+                fileWithoutPrefix = file.relativeChildPath(projectDirFileName);
             } else {
                 isRelative = false;
                 fileWithoutPrefix = file;
@@ -328,7 +327,7 @@ struct InternalNode
 #endif
             QStringListIterator it(parts);
             InternalNode *currentNode = this;
-            QString path = (isRelative ? projectDirWithSeparator : "");
+            QString path = (isRelative ? (projectDirFileName.toString() + '/') : QString(""));
             while (it.hasNext()) {
                 const QString &key = it.next();
                 if (it.hasNext()) { // key is directory
@@ -683,7 +682,7 @@ void Qt4PriFileNode::folderChanged(const QString &folder)
     newFiles += recursiveEnumerate(changedFolder);
 
     foreach (const Utils::FileName &file, m_recursiveEnumerateFiles) {
-        if (!file.startsWith(changedFolder))
+        if (!file.isChildOf(Utils::FileName::fromString(changedFolder)))
             newFiles.insert(file);
     }
 
-- 
GitLab