| 168 | } |
| 169 | |
| 170 | QString Path::relativePath(const Path& path) const |
| 171 | { |
| 172 | if (!path.isValid()) { |
| 173 | return QString(); |
| 174 | } |
| 175 | if (!isValid() || remotePrefix() != path.remotePrefix()) { |
| 176 | // different remote destinations or we are invalid, return input as-is |
| 177 | return path.pathOrUrl(); |
| 178 | } |
| 179 | // while I'd love to use QUrl::relativePath here, it seems to behave pretty |
| 180 | // strangely, and adds unexpected "./" at the start for example |
| 181 | // so instead, do it on our own based on _relativePath in kurl.cpp |
| 182 | // this should also be more performant I think |
| 183 | |
| 184 | // Find where they meet |
| 185 | int level = isRemote() ? 1 : 0; |
| 186 | const int maxLevel = qMin(m_data.count(), path.m_data.count()); |
| 187 | while (level < maxLevel && m_data.at(level) == path.m_data.at(level)) { |
| 188 | ++level; |
| 189 | } |
| 190 | |
| 191 | // Need to go down out of our path to the common branch. |
| 192 | // but keep in mind that e.g. '/' paths have an empty name |
| 193 | int backwardSegments = m_data.count() - level; |
| 194 | if (backwardSegments && level < maxLevel && m_data.at(level).isEmpty()) { |
| 195 | --backwardSegments; |
| 196 | } |
| 197 | |
| 198 | // Now up from the common branch to the second path. |
| 199 | int forwardSegmentsLength = 0; |
| 200 | for (int i = level; i < path.m_data.count(); ++i) { |
| 201 | forwardSegmentsLength += path.m_data.at(i).length(); |
| 202 | // slashes |
| 203 | if (i + 1 != path.m_data.count()) { |
| 204 | forwardSegmentsLength += 1; |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | QString relativePath; |
| 209 | relativePath.reserve((backwardSegments * 3) + forwardSegmentsLength); |
| 210 | for (int i = 0; i < backwardSegments; ++i) { |
| 211 | relativePath.append(QLatin1String("../")); |
| 212 | } |
| 213 | |
| 214 | for (int i = level; i < path.m_data.count(); ++i) { |
| 215 | relativePath.append(path.m_data.at(i)); |
| 216 | if (i + 1 != path.m_data.count()) { |
| 217 | relativePath.append(QLatin1Char('/')); |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | Q_ASSERT(relativePath.length() == ((backwardSegments * 3) + forwardSegmentsLength)); |
| 222 | |
| 223 | return relativePath; |
| 224 | } |
| 225 | |
| 226 | static bool isParentPath(const QVector<QString>& parent, const QVector<QString>& child, bool direct) |
| 227 | { |