KIO

kcoreurlnavigator.cpp
1/*
2 SPDX-FileCopyrightText: 2006-2010 Peter Penz <peter.penz@gmx.at>
3 SPDX-FileCopyrightText: 2006 Aaron J. Seigo <aseigo@kde.org>
4 SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
5 SPDX-FileCopyrightText: 2007 Urs Wolfer <uwolfer @ kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "kcoreurlnavigator.h"
11
12#include "urlutil_p.h"
13
14#include <KIO/StatJob>
15#include <KLocalizedString>
16#include <kfileitem.h>
17#include <kprotocolinfo.h>
18
19#include <QDir>
20#include <QMimeData>
21#include <QMimeDatabase>
22
23#include <algorithm>
24#include <numeric>
25
26struct LocationData {
27 QUrl url;
28 QVariant state;
29};
30
31class KCoreUrlNavigatorPrivate
32{
33public:
34 KCoreUrlNavigatorPrivate(KCoreUrlNavigator *qq);
35
36 ~KCoreUrlNavigatorPrivate()
37 {
38 }
39
40 /**
41 * Returns true, if the MIME type of the path represents a
42 * compressed file like TAR or ZIP, as listed in @p archiveMimetypes
43 */
44 bool isCompressedPath(const QUrl &path, const QStringList &archiveMimetypes) const;
45
46 /**
47 * Returns the current history index, if \a historyIndex is
48 * smaller than 0. If \a historyIndex is greater or equal than
49 * the number of available history items, the largest possible
50 * history index is returned. For the other cases just \a historyIndex
51 * is returned.
52 */
53 int adjustedHistoryIndex(int historyIndex) const;
54
55 KCoreUrlNavigator *const q;
56
57 QList<LocationData> m_history;
58 int m_historyIndex = 0;
59};
60
61KCoreUrlNavigatorPrivate::KCoreUrlNavigatorPrivate(KCoreUrlNavigator *qq)
62 : q(qq)
63{
64}
65
66bool KCoreUrlNavigatorPrivate::isCompressedPath(const QUrl &url, const QStringList &archiveMimetypes) const
67{
70 return std::any_of(archiveMimetypes.begin(), archiveMimetypes.end(), [mime](const QString &archiveType) {
71 return mime.inherits(archiveType);
72 });
73}
74
75int KCoreUrlNavigatorPrivate::adjustedHistoryIndex(int historyIndex) const
76{
77 const int historySize = m_history.size();
78 if (historyIndex < 0) {
79 historyIndex = m_historyIndex;
80 } else if (historyIndex >= historySize) {
81 historyIndex = historySize - 1;
82 Q_ASSERT(historyIndex >= 0); // m_history.size() must always be > 0
83 }
84 return historyIndex;
85}
86
87// ------------------------------------------------------------------------------------------------
88
89KCoreUrlNavigator::KCoreUrlNavigator(const QUrl &url, QObject *parent)
90 : QObject(parent)
91 , d(new KCoreUrlNavigatorPrivate(this))
92{
93 d->m_history.prepend(LocationData{url.adjusted(QUrl::NormalizePathSegments), {}});
94}
95
96KCoreUrlNavigator::~KCoreUrlNavigator()
97{
98}
99
101{
102 historyIndex = d->adjustedHistoryIndex(historyIndex);
103 return d->m_history.at(historyIndex).url;
104}
105
107{
108 d->m_history[d->m_historyIndex].state = state;
109}
110
112{
113 historyIndex = d->adjustedHistoryIndex(historyIndex);
114 return d->m_history.at(historyIndex).state;
115}
116
118{
119 const int count = d->m_history.size();
120 if (d->m_historyIndex < count - 1) {
121 const QUrl newUrl = locationUrl(d->m_historyIndex + 1);
123
124 ++d->m_historyIndex;
125
126 Q_EMIT historyIndexChanged();
128 Q_EMIT currentLocationUrlChanged();
129 return true;
130 }
131
132 return false;
133}
134
136{
137 if (d->m_historyIndex > 0) {
138 const QUrl newUrl = locationUrl(d->m_historyIndex - 1);
140
141 --d->m_historyIndex;
142
143 Q_EMIT historyIndexChanged();
145 Q_EMIT currentLocationUrlChanged();
146 return true;
147 }
148
149 return false;
150}
151
153{
154 const QUrl currentUrl = locationUrl();
155 const QUrl upUrl = KIO::upUrl(currentUrl);
156 if (!currentUrl.matches(upUrl, QUrl::StripTrailingSlash)) {
157 setCurrentLocationUrl(upUrl);
158 return true;
159 }
160
161 return false;
162}
163
164QUrl KCoreUrlNavigator::currentLocationUrl() const
165{
166 return locationUrl();
167}
168
169void KCoreUrlNavigator::setCurrentLocationUrl(const QUrl &newUrl)
170{
171 if (newUrl == locationUrl()) {
172 return;
173 }
174
176
177 // This will be used below; we define it here because in the lower part of the
178 // code locationUrl() and url become the same URLs
179 QUrl firstChildUrl = KIO::UrlUtil::firstChildUrl(locationUrl(), url);
180
181 const QString scheme = url.scheme();
182 if (!scheme.isEmpty()) {
183 // Check if the URL represents a tar-, zip- or 7z-file, or an archive file supported by krarc.
184 const QStringList archiveMimetypes = KProtocolInfo::archiveMimetypes(scheme);
185
186 if (!archiveMimetypes.isEmpty()) {
187 // Check whether the URL is really part of the archive file, otherwise
188 // replace it by the local path again.
189 bool insideCompressedPath = d->isCompressedPath(url, archiveMimetypes);
190 if (!insideCompressedPath) {
191 QUrl prevUrl = url;
192 QUrl parentUrl = KIO::upUrl(url);
193 while (parentUrl != prevUrl) {
194 if (d->isCompressedPath(parentUrl, archiveMimetypes)) {
195 insideCompressedPath = true;
196 break;
197 }
198 prevUrl = parentUrl;
199 parentUrl = KIO::upUrl(parentUrl);
200 }
201 }
202 if (!insideCompressedPath) {
203 // drop the tar:, zip:, sevenz: or krarc: protocol since we are not
204 // inside the compressed path
205 url.setScheme(QStringLiteral("file"));
206 firstChildUrl.setScheme(QStringLiteral("file"));
207 }
208 }
209 }
210
211 // Check whether current history element has the same URL.
212 // If this is the case, just ignore setting the URL.
213 const LocationData &data = d->m_history.at(d->m_historyIndex);
214 const bool isUrlEqual = url.matches(locationUrl(), QUrl::StripTrailingSlash) || (!url.isValid() && url.matches(data.url, QUrl::StripTrailingSlash));
215 if (isUrlEqual) {
216 return;
217 }
218
220
221 if (d->m_historyIndex > 0) {
222 // If an URL is set when the history index is not at the end (= 0),
223 // then clear all previous history elements so that a new history
224 // tree is started from the current position.
225 auto begin = d->m_history.begin();
226 auto end = begin + d->m_historyIndex;
227 d->m_history.erase(begin, end);
228 d->m_historyIndex = 0;
229 }
230
231 Q_ASSERT(d->m_historyIndex == 0);
232 d->m_history.insert(0, LocationData{url, {}});
233
234 // Prevent an endless growing of the history: remembering
235 // the last 100 Urls should be enough...
236 const int historyMax = 100;
237 if (d->m_history.size() > historyMax) {
238 auto begin = d->m_history.begin() + historyMax;
239 auto end = d->m_history.end();
240 d->m_history.erase(begin, end);
241 }
242
243 Q_EMIT historyIndexChanged();
244 Q_EMIT historySizeChanged();
246 Q_EMIT currentLocationUrlChanged();
247 if (firstChildUrl.isValid()) {
248 Q_EMIT urlSelectionRequested(firstChildUrl);
249 }
250}
251
253{
254 return d->m_history.count();
255}
256
258{
259 return d->m_historyIndex;
260}
261
262#include "moc_kcoreurlnavigator.cpp"
Object that helps with keeping track of URLs in file-manager like interfaces.
Q_SIGNAL void urlSelectionRequested(const QUrl &url)
When the URL is changed and the new URL (e.g. /home/user1/) is a parent of the previous URL (e....
Q_SIGNAL void currentUrlAboutToChange(const QUrl &newUrl)
Is emitted, before the location URL is going to be changed to newUrl.
int historyIndex
The history index of the current location, where 0 <= history index < KCoreUrlNavigator::historySize(...
Q_INVOKABLE bool goBack()
Goes back one step in the URL history.
Q_INVOKABLE bool goForward()
Goes forward one step in the URL history.
Q_SIGNAL void historyChanged()
Is emitted, if the history has been changed.
Q_INVOKABLE bool goUp()
Goes up one step of the URL path and remembers the old path in the history.
Q_INVOKABLE QVariant locationState(int historyIndex=-1) const
Q_INVOKABLE QUrl locationUrl(int historyIndex=-1) const
int historySize
The amount of locations in the history.
Q_INVOKABLE void saveLocationState(const QVariant &state)
Saves the location state described by state for the current location.
static QStringList archiveMimetypes(const QString &protocol)
Returns the list of archive MIME types handled by the KIO worker implementing this protocol.
KIOCORE_EXPORT QUrl upUrl(const QUrl &url)
This function is useful to implement the "Up" button in a file manager for example.
Definition global.cpp:236
const QList< QKeySequence > & begin()
const QList< QKeySequence > & end()
iterator begin()
iterator end()
bool isEmpty() const const
qsizetype size() const const
QMimeType mimeTypeForUrl(const QUrl &url) const const
Q_EMITQ_EMIT
bool isEmpty() const const
StripTrailingSlash
QUrl adjusted(FormattingOptions options) const const
bool isValid() const const
bool matches(const QUrl &url, FormattingOptions options) const const
QString scheme() const const
void setScheme(const QString &scheme)
QString toString(FormattingOptions options) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:52 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.