File indexing completed on 2024-03-24 05:01:14
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2000, 2001 Carsten Pfeiffer <pfeiffer@kde.org> 0003 SPDX-FileCopyrightText: 2007 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "konqhistorymanager.h" 0009 #include <kbookmarkmanager.h> 0010 #include "konqurl.h" 0011 0012 #include <QTimer> 0013 #include "konqdebug.h" 0014 #include <kconfig.h> 0015 #include <kcompletion.h> 0016 0017 #include <kconfiggroup.h> 0018 0019 KonqHistoryManager::KonqHistoryManager(KBookmarkManager *bookmarkManager, QObject *parent) 0020 : KonqHistoryProvider(parent), 0021 m_bookmarkManager(bookmarkManager) 0022 { 0023 m_updateTimer = new QTimer(this); 0024 0025 // take care of the completion object 0026 m_pCompletion = new KCompletion; 0027 m_pCompletion->setOrder(KCompletion::Weighted); 0028 0029 // and load the history 0030 loadHistory(); 0031 0032 connect(m_updateTimer, &QTimer::timeout, this, &KonqHistoryManager::slotEmitUpdated); 0033 connect(this, &KonqHistoryManager::cleared, this, &KonqHistoryManager::slotCleared); 0034 connect(this, &KonqHistoryManager::entryRemoved, this, &KonqHistoryManager::slotEntryRemoved); 0035 } 0036 0037 KonqHistoryManager::~KonqHistoryManager() 0038 { 0039 delete m_pCompletion; 0040 clearPending(); 0041 } 0042 0043 bool KonqHistoryManager::loadHistory() 0044 { 0045 clearPending(); 0046 m_pCompletion->clear(); 0047 0048 if (!KonqHistoryProvider::loadHistory()) { 0049 return false; 0050 } 0051 0052 QListIterator<KonqHistoryEntry> it(entries()); 0053 while (it.hasNext()) { 0054 const KonqHistoryEntry &entry = it.next(); 0055 const QString prettyUrlString = entry.url.toDisplayString(); 0056 addToCompletion(prettyUrlString, entry.typedUrl, entry.numberOfTimesVisited); 0057 } 0058 0059 return true; 0060 } 0061 0062 void KonqHistoryManager::addPending(const QUrl &url, const QString &typedUrl, 0063 const QString &title) 0064 { 0065 addToHistory(true, url, typedUrl, title); 0066 } 0067 0068 void KonqHistoryManager::confirmPending(const QUrl &url, 0069 const QString &typedUrl, 0070 const QString &title) 0071 { 0072 addToHistory(false, url, typedUrl, title); 0073 } 0074 0075 void KonqHistoryManager::addToHistory(bool pending, const QUrl &_url, 0076 const QString &typedUrl, 0077 const QString &title) 0078 { 0079 //qCDebug(KONQUEROR_LOG) << _url << "Typed URL:" << typedUrl << ", Title:" << title; 0080 0081 if (filterOut(_url)) { // we only want remote URLs 0082 return; 0083 } 0084 0085 // http URLs without a path will get redirected immediately to url + '/' 0086 if (_url.path().isEmpty() && _url.scheme().startsWith(QLatin1String("http"))) { 0087 return; 0088 } 0089 0090 QUrl url(_url); 0091 bool hasPass = !url.password().isEmpty(); 0092 url.setPassword(QString()); // No password in the history, especially not in the completion! 0093 url.setHost(url.host().toLower()); // All host parts lower case 0094 KonqHistoryEntry entry; 0095 QString u = url.toDisplayString(); 0096 entry.url = url; 0097 if ((u != typedUrl) && !hasPass) { 0098 entry.typedUrl = typedUrl; 0099 } 0100 0101 // we only keep the title if we are confirming an entry. Otherwise, 0102 // we might get bogus titles from the previous url (actually it's just 0103 // konqueror's window caption). 0104 if (!pending && u != title) { 0105 entry.title = title; 0106 } 0107 entry.firstVisited = QDateTime::currentDateTime(); 0108 entry.lastVisited = entry.firstVisited; 0109 0110 // always remove from pending if available, otherwise the else branch leaks 0111 // if the map already contains an entry for this key. 0112 QMap<QString, KonqHistoryEntry *>::iterator it = m_pending.find(u); 0113 if (it != m_pending.end()) { 0114 delete it.value(); 0115 m_pending.erase(it); 0116 } 0117 0118 if (!pending) { 0119 if (it != m_pending.end()) { 0120 // we make a pending entry official, so we just have to update 0121 // and not increment the counter. No need to care about 0122 // firstVisited, as this is not taken into account on update. 0123 entry.numberOfTimesVisited = 0; 0124 } 0125 } else { 0126 // We add a copy of the current history entry of the url to the 0127 // pending list, so that we can restore it if the user canceled. 0128 // If there is no entry for the url yet, we just store the url. 0129 KonqHistoryList::const_iterator oldEntry = constFindEntry(url); 0130 m_pending.insert(u, (oldEntry != entries().constEnd()) ? 0131 new KonqHistoryEntry(*oldEntry) : nullptr); 0132 } 0133 0134 // notify all konqueror instances about the entry 0135 emitAddToHistory(entry); 0136 } 0137 0138 // interface of KParts::HistoryManager 0139 // Usually, we only record the history for non-local URLs (i.e. filterOut() 0140 // returns false). But when using the HistoryProvider interface, we record 0141 // exactly those filtered-out urls. 0142 // Moreover, we don't get any pending/confirming entries, just one insert() 0143 void KonqHistoryManager::insert(const QString &url) 0144 { 0145 QUrl u(url); 0146 if (!filterOut(u) || KonqUrl::hasKonqScheme(u)) { // remote URL 0147 return; 0148 } 0149 // Local URL -> add to history 0150 KonqHistoryEntry entry; 0151 entry.url = u; 0152 entry.firstVisited = QDateTime::currentDateTime(); 0153 entry.lastVisited = entry.firstVisited; 0154 emitAddToHistory(entry); 0155 } 0156 0157 void KonqHistoryManager::removePending(const QUrl &url) 0158 { 0159 // qCDebug(KONQUEROR_LOG) << "Removing pending..." << url; 0160 0161 if (url.isLocalFile()) { 0162 return; 0163 } 0164 0165 QMap<QString, KonqHistoryEntry *>::iterator it = m_pending.find(url.toDisplayString()); 0166 if (it != m_pending.end()) { 0167 KonqHistoryEntry *oldEntry = it.value(); // the old entry, may be 0 0168 emitRemoveFromHistory(url); // remove the current pending entry 0169 0170 if (oldEntry) { // we had an entry before, now use that instead 0171 emitAddToHistory(*oldEntry); 0172 } 0173 0174 delete oldEntry; 0175 m_pending.erase(it); 0176 } 0177 } 0178 0179 // clears the pending list and makes sure the entries get deleted. 0180 void KonqHistoryManager::clearPending() 0181 { 0182 QMap<QString, KonqHistoryEntry *>::iterator it = m_pending.begin(); 0183 while (it != m_pending.end()) { 0184 delete it.value(); 0185 ++it; 0186 } 0187 m_pending.clear(); 0188 } 0189 0190 /////////////////////////////////////////////////////////////////// 0191 // DBUS called methods 0192 0193 bool KonqHistoryManager::filterOut(const QUrl &url) 0194 { 0195 return (url.isLocalFile() || url.host().isEmpty()); 0196 } 0197 0198 void KonqHistoryManager::slotEmitUpdated() 0199 { 0200 emit HistoryProvider::updated(m_updateURLs); 0201 m_updateURLs.clear(); 0202 } 0203 0204 #if 0 // unused 0205 QStringList KonqHistoryManager::allURLs() const 0206 { 0207 QStringList list; 0208 QListIterator<KonqHistoryEntry> it(entries()); 0209 while (it.hasNext()) { 0210 list.append(it.next().url.url()); 0211 } 0212 return list; 0213 } 0214 #endif 0215 0216 void KonqHistoryManager::addToCompletion(const QString &url, const QString &typedUrl, 0217 int numberOfTimesVisited) 0218 { 0219 m_pCompletion->addItem(url, numberOfTimesVisited); 0220 // typed urls have a higher priority 0221 m_pCompletion->addItem(typedUrl, numberOfTimesVisited + 10); 0222 } 0223 0224 void KonqHistoryManager::removeFromCompletion(const QString &url, const QString &typedUrl) 0225 { 0226 m_pCompletion->removeItem(url); 0227 m_pCompletion->removeItem(typedUrl); 0228 } 0229 0230 void KonqHistoryManager::addToUpdateList(const QString &url) 0231 { 0232 m_updateURLs.append(url); 0233 m_updateTimer->setSingleShot(true); 0234 m_updateTimer->start(500); 0235 } 0236 0237 // Called by KonqHistoryProviderPrivate::slotNotifyClear() 0238 void KonqHistoryManager::slotCleared() 0239 { 0240 clearPending(); 0241 m_pCompletion->clear(); 0242 } 0243 0244 void KonqHistoryManager::finishAddingEntry(const KonqHistoryEntry &entry, bool isSender) 0245 { 0246 const QString urlString = entry.url.url(); 0247 addToCompletion(entry.url.toDisplayString(), entry.typedUrl); 0248 addToUpdateList(urlString); 0249 KonqHistoryProvider::finishAddingEntry(entry, isSender); 0250 0251 // note, no need to do the updateBookmarkMetadata for every 0252 // history object, only need to for the broadcast sender as 0253 // the history object itself keeps the data consistent. 0254 // ### why does the comment do exactly the opposite from the code? 0255 const bool updated = m_bookmarkManager ? m_bookmarkManager->updateAccessMetadata(urlString) : false; 0256 0257 if (isSender) { 0258 // note, bk save does not notify, and we don't want to! 0259 if (updated) { 0260 m_bookmarkManager->save(); 0261 } 0262 } 0263 } 0264 0265 void KonqHistoryManager::slotEntryRemoved(const KonqHistoryEntry &entry) 0266 { 0267 const QString urlString = entry.url.url(); 0268 removeFromCompletion(entry.url.toDisplayString(), entry.typedUrl); 0269 addToUpdateList(urlString); 0270 }