konq_historymgr.cc
00001 /* This file is part of the KDE project 00002 Copyright (C) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org> 00003 00004 This program is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; see the file COPYING. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "konq_historymgr.h" 00021 00022 #include <dcopclient.h> 00023 00024 #include <kapplication.h> 00025 #include <kdebug.h> 00026 #include <ksavefile.h> 00027 #include <ksimpleconfig.h> 00028 #include <kstandarddirs.h> 00029 00030 #include <zlib.h> 00031 00032 #include "konqbookmarkmanager.h" 00033 00034 const Q_UINT32 KonqHistoryManager::s_historyVersion = 3; 00035 00036 KonqHistoryManager::KonqHistoryManager( QObject *parent, const char *name ) 00037 : KParts::HistoryProvider( parent, name ), 00038 KonqHistoryComm( "KonqHistoryManager" ) 00039 { 00040 m_updateTimer = new QTimer( this ); 00041 00042 // defaults 00043 KConfig *config = KGlobal::config(); 00044 KConfigGroupSaver cs( config, "HistorySettings" ); 00045 m_maxCount = config->readNumEntry( "Maximum of History entries", 500 ); 00046 m_maxCount = QMAX( 1, m_maxCount ); 00047 m_maxAgeDays = config->readNumEntry( "Maximum age of History entries", 90); 00048 00049 m_history.setAutoDelete( true ); 00050 m_filename = locateLocal( "data", 00051 QString::fromLatin1("konqueror/konq_history" )); 00052 00053 if ( !kapp->dcopClient()->isAttached() ) 00054 kapp->dcopClient()->attach(); 00055 00056 00057 // take care of the completion object 00058 m_pCompletion = new KCompletion; 00059 m_pCompletion->setOrder( KCompletion::Weighted ); 00060 00061 // and load the history 00062 loadHistory(); 00063 00064 connect( m_updateTimer, SIGNAL( timeout() ), SLOT( slotEmitUpdated() )); 00065 } 00066 00067 00068 KonqHistoryManager::~KonqHistoryManager() 00069 { 00070 delete m_pCompletion; 00071 clearPending(); 00072 } 00073 00074 bool KonqHistoryManager::isSenderOfBroadcast() 00075 { 00076 DCOPClient *dc = callingDcopClient(); 00077 return !dc || (dc->senderId() == dc->appId()); 00078 } 00079 00080 // loads the entire history 00081 bool KonqHistoryManager::loadHistory() 00082 { 00083 clearPending(); 00084 m_history.clear(); 00085 m_pCompletion->clear(); 00086 00087 QFile file( m_filename ); 00088 if ( !file.open( IO_ReadOnly ) ) { 00089 if ( file.exists() ) 00090 kdWarning() << "Can't open " << file.name() << endl; 00091 00092 // try to load the old completion history 00093 bool ret = loadFallback(); 00094 emit loadingFinished(); 00095 return ret; 00096 } 00097 00098 QDataStream fileStream( &file ); 00099 QByteArray data; // only used for version == 2 00100 // we construct the stream object now but fill in the data later. 00101 // thanks to QBA's explicit sharing this works :) 00102 QDataStream crcStream( data, IO_ReadOnly ); 00103 00104 if ( !fileStream.atEnd() ) { 00105 Q_UINT32 version; 00106 fileStream >> version; 00107 00108 QDataStream *stream = &fileStream; 00109 00110 bool crcChecked = false; 00111 bool crcOk = false; 00112 00113 if ( version == 2 || version == 3) { 00114 Q_UINT32 crc; 00115 crcChecked = true; 00116 fileStream >> crc >> data; 00117 crcOk = crc32( 0, reinterpret_cast<unsigned char *>( data.data() ), data.size() ) == crc; 00118 stream = &crcStream; // pick up the right stream 00119 } 00120 00121 if ( version == 3 ) 00122 { 00123 //Use KURL marshalling for V3 format. 00124 KonqHistoryEntry::marshalURLAsStrings = false; 00125 } 00126 00127 if ( version != 0 && version < 3 ) //Versions 1,2 (but not 0) are also valid 00128 { 00129 //Turn on backwards compatibility mode.. 00130 KonqHistoryEntry::marshalURLAsStrings = true; 00131 // it doesn't make sense to save to save maxAge and maxCount in the 00132 // binary file, this would make backups impossible (they would clear 00133 // themselves on startup, because all entries expire). 00134 // [But V1 and V2 formats did it, so we do a dummy read] 00135 Q_UINT32 dummy; 00136 *stream >> dummy; 00137 *stream >> dummy; 00138 00139 //OK. 00140 version = 3; 00141 } 00142 00143 if ( s_historyVersion != version || ( crcChecked && !crcOk ) ) { 00144 kdWarning() << "The history version doesn't match, aborting loading" << endl; 00145 file.close(); 00146 emit loadingFinished(); 00147 return false; 00148 } 00149 00150 00151 while ( !stream->atEnd() ) { 00152 KonqHistoryEntry *entry = new KonqHistoryEntry; 00153 Q_CHECK_PTR( entry ); 00154 *stream >> *entry; 00155 // kdDebug(1203) << "## loaded entry: " << entry->url << ", Title: " << entry->title << endl; 00156 m_history.append( entry ); 00157 QString urlString2 = entry->url.prettyURL(); 00158 00159 addToCompletion( urlString2, entry->typedURL, entry->numberOfTimesVisited ); 00160 00161 // and fill our baseclass. 00162 QString urlString = entry->url.url(); 00163 KParts::HistoryProvider::insert( urlString ); 00164 // DF: also insert the "pretty" version if different 00165 // This helps getting 'visited' links on websites which don't use fully-escaped urls. 00166 00167 if ( urlString != urlString2 ) 00168 KParts::HistoryProvider::insert( urlString2 ); 00169 } 00170 00171 kdDebug(1203) << "## loaded: " << m_history.count() << " entries." << endl; 00172 00173 m_history.sort(); 00174 adjustSize(); 00175 } 00176 00177 00178 //This is important - we need to switch to a consistent marshalling format for 00179 //communicating between different konqueror instances. Since during an upgrade 00180 //some "old" copies may still running, we use the old format for the DCOP transfers. 00181 //This doesn't make that much difference performance-wise for single entries anyway. 00182 KonqHistoryEntry::marshalURLAsStrings = true; 00183 00184 00185 // Theoretically, we should emit update() here, but as we only ever 00186 // load items on startup up to now, this doesn't make much sense. Same 00187 // thing for the above loadFallback(). 00188 // emit KParts::HistoryProvider::update( some list ); 00189 00190 00191 00192 file.close(); 00193 emit loadingFinished(); 00194 00195 return true; 00196 } 00197 00198 00199 // saves the entire history 00200 bool KonqHistoryManager::saveHistory() 00201 { 00202 KSaveFile file( m_filename ); 00203 if ( file.status() != 0 ) { 00204 kdWarning() << "Can't open " << file.name() << endl; 00205 return false; 00206 } 00207 00208 QDataStream *fileStream = file.dataStream(); 00209 *fileStream << s_historyVersion; 00210 00211 QByteArray data; 00212 QDataStream stream( data, IO_WriteOnly ); 00213 00214 //We use KURL for marshalling URLs in entries in the V3 00215 //file format 00216 KonqHistoryEntry::marshalURLAsStrings = false; 00217 QPtrListIterator<KonqHistoryEntry> it( m_history ); 00218 KonqHistoryEntry *entry; 00219 while ( (entry = it.current()) ) { 00220 stream << *entry; 00221 ++it; 00222 } 00223 00224 //For DCOP, transfer strings instead - wire compat. 00225 KonqHistoryEntry::marshalURLAsStrings = true; 00226 00227 Q_UINT32 crc = crc32( 0, reinterpret_cast<unsigned char *>( data.data() ), data.size() ); 00228 *fileStream << crc << data; 00229 00230 file.close(); 00231 00232 return true; 00233 } 00234 00235 00236 void KonqHistoryManager::adjustSize() 00237 { 00238 KonqHistoryEntry *entry = m_history.getFirst(); 00239 00240 while ( m_history.count() > m_maxCount || isExpired( entry ) ) { 00241 removeFromCompletion( entry->url.prettyURL(), entry->typedURL ); 00242 00243 QString urlString = entry->url.url(); 00244 KParts::HistoryProvider::remove( urlString ); 00245 00246 addToUpdateList( urlString ); 00247 00248 emit entryRemoved( m_history.getFirst() ); 00249 m_history.removeFirst(); // deletes the entry 00250 00251 entry = m_history.getFirst(); 00252 } 00253 } 00254 00255 00256 void KonqHistoryManager::addPending( const KURL& url, const QString& typedURL, 00257 const QString& title ) 00258 { 00259 addToHistory( true, url, typedURL, title ); 00260 } 00261 00262 void KonqHistoryManager::confirmPending( const KURL& url, 00263 const QString& typedURL, 00264 const QString& title ) 00265 { 00266 addToHistory( false, url, typedURL, title ); 00267 } 00268 00269 00270 void KonqHistoryManager::addToHistory( bool pending, const KURL& _url, 00271 const QString& typedURL, 00272 const QString& title ) 00273 { 00274 kdDebug(1203) << "## addToHistory: " << _url.prettyURL() << " Typed URL: " << typedURL << ", Title: " << title << endl; 00275 00276 if ( filterOut( _url ) ) // we only want remote URLs 00277 return; 00278 00279 // http URLs without a path will get redirected immediately to url + '/' 00280 if ( _url.path().isEmpty() && _url.protocol().startsWith("http") ) 00281 return; 00282 00283 KURL url( _url ); 00284 bool hasPass = url.hasPass(); 00285 url.setPass( QString::null ); // No password in the history, especially not in the completion! 00286 url.setHost( url.host().lower() ); // All host parts lower case 00287 KonqHistoryEntry entry; 00288 QString u = url.prettyURL(); 00289 entry.url = url; 00290 if ( (u != typedURL) && !hasPass ) 00291 entry.typedURL = typedURL; 00292 00293 // we only keep the title if we are confirming an entry. Otherwise, 00294 // we might get bogus titles from the previous url (actually it's just 00295 // konqueror's window caption). 00296 if ( !pending && u != title ) 00297 entry.title = title; 00298 entry.firstVisited = QDateTime::currentDateTime(); 00299 entry.lastVisited = entry.firstVisited; 00300 00301 // always remove from pending if available, otherwise the else branch leaks 00302 // if the map already contains an entry for this key. 00303 QMapIterator<QString,KonqHistoryEntry*> it = m_pending.find( u ); 00304 if ( it != m_pending.end() ) { 00305 delete it.data(); 00306 m_pending.remove( it ); 00307 } 00308 00309 if ( !pending ) { 00310 if ( it != m_pending.end() ) { 00311 // we make a pending entry official, so we just have to update 00312 // and not increment the counter. No need to care about 00313 // firstVisited, as this is not taken into account on addToHistory( true, url, typedURL, title ); 00260 } 00261 00262 void KonqHistoryManager::confirmPending( const KURL& url, 00263 const QString& typedURL, 00264 const QString& title ) 00265 { 00266 addToHistory( false, url, typedURL, title ); 00267 } 00268 00269 00270 void KonqHistoryManager::addToHistory( bool pending, const KURL& _url, 00271 const QString& typedURL, 00272 const QString& title ) 00273 { 00274 kdDebug(1203) << "## addToHistory: " << _url.prettyURL() << " Typed URL: " << typedURL << ", Title: " << title << endl; 00275 00276 if ( filterOut( _url ) ) // we only want remote URLs 00277 return; 00278 00279 // http URLs without a path will get redirected immediately to url + '/' 00280 if ( _url.path().isEmpty() && _url.protocol().startsWith("http") ) 00281 return; 00282 00283 KURL url( _url ); 00284 bool hasPass = url.hasPass(); 00285 url.setPass( QString::null ); // No password in the history, especially not in the completion! 00286 url.setHost( url.host().lower() ); // All host parts lower case 00287 KonqHistoryEntry entry; 00288 QString u = url.prettyURL(); 00289 entry.url = url; 00290 if ( (u != typedURL) && !hasPass ) 00291 entry.typedURL = typedURL; 00292 00293 // we only keep the title if we are confirming an entry. Otherwise, 00294 // we might get bogus titles from the previous url (actually it's just 00295 // konqueror's window caption). 00296 if ( !pending && u != title ) 00297 entry.title = title; 00298 entry.firstVisited = QDateTime::currentDateTime(); 00299 entry.lastVisited = entry.firstVisited; 00300 00301 // always remove from pending if available, otherwise the else branch leaks 00302 // if the map already contains an entry for this key. 00303 QMapIterator<QString,KonqHistoryEntry*> it = m_pending.find( u ); 00304 if ( it != m_pending.end() ) { 00305 delete it.data(); 00306 m_pending.remove( it ); 00307 } 00308 00309 if ( !pending ) { 00310 if ( it != m_pending.end() ) { 00311 // we make a pending entry official, so we just have to update 00312 // and not increment the counter. No need to care about 00313 // firstVisited, as this is not taken into account on addToHistory( true, url, typedURL, title ); 00260 } 00261 00262 void KonqHistoryManager::confirmPending( const KURL& url, 00263 const QString& typedURL, 00264 const QString& title ) 00265 { 00266 addToHistory( false, url, typedURL, title ); 00267 } 00268 00269 00270 void KonqHistoryManager::addToHistory( bool pending, const KURL& _url, 00271 const QString& typedURL, 00272 const QString& title ) 00273 { 00274 kdDebug(1203) << "## addToHistory: " << _url.prettyURL() << " Typed URL: " << typedURL << ", Title: " << title << endl; 00275 00276 if ( filterOut( _url ) ) // we only want remote URLs 00277 return; 00278 00279 // http URLs without a path will get redirected immediately to url + '/' 00280 if ( _url.path().isEmpty() && _url.protocol().startsWith("http") ) 00281 return; 00282 00283 KURL url( _url ); 00284 bool hasPass = url.hasPass(); 00285 url.setPass( QString::null ); // No password in the history, especially not in the completion! 00286 url.setHost( url.host().lower() ); // All host parts lower case 00287 KonqHistoryEntry entry; 00288 QString u = url.prettyURL(); 00289 entry.url = url; 00290 if ( (u != typedURL) && !hasPass ) 00291 entry.typedURL = typedURL; 00292 00293 // we only keep the title if we are confirming an entry. Otherwise, 00294 // we might get bogus titles from the previous url (actually it's just 00295 // konqueror's window caption). 00296 if ( !pending && u != title ) 00297 entry.title = title; 00298 entry.firstVisited = QDateTime::currentDateTime(); 00299 entry.lastVisited = entry.firstVisited; 00300 00301 // always remove from pending if available, otherwise the else branch leaks 00302 // if the map already contains an entry for this key. 00303 QMapIterator<QString,KonqHistoryEntry*> it = m_pending.find( u ); 00304 if ( it != m_pending.end() ) { 00305 delete it.data(); 00306 m_pending.remove( it ); 00307 } 00308 00309 if ( !pending ) { 00310 if ( it != m_pending.end() ) { 00311 // we make a pending entry official, so we just have to update 00312 // and not increment the counter. No need to care about 00313 // firstVisited, as this is not taken into account on addToHistory( true, url, typedURL, title ); 00260 } 00261 00262 void KonqHistoryManager::confirmPending( const KURL& url, 00263 const QString& typedURL, 00264 const QString& title ) 00265 { 00266 addToHistory( false, url, typedURL, title ); 00267 } 00268 00269 00270 void KonqHistoryManager::addToHistory( bool pending, const KURL& _url, 00271 const QString& typedURL, 00272 const QString& title ) 00273 { 00274 kdDebug(1203) << "## addToHistory: " << _url.prettyURL() << " Typed URL: " << typedURL << ", Title: " << title << endl; 00275 00276 if ( filterOut( _url ) ) // we only want remote URLs 00277 return; 00278 00279 // http URLs without a path will get redirected immediately to url + '/' 00280 if ( _url.path().isEmpty() && _url.protocol().startsWith("http") ) 00281 return; 00282 00283 KURL url( _url ); 00284 bool hasPass = url.hasPass(); 00285 url.setPass( QString::null ); // No password in the history, especially not in the completion! 00286 url.setHost( url.host().lower() ); // All host parts lower case 00287 KonqHistoryEntry entry; 00288 QString u = url.prettyURL(); 00289 entry.url = url; 00290 if ( (u != typedURL) && !hasPass ) 00291 entry.typedURL = typedURL; 00292 00293 // we only keep the title if we are confirming an entry. Otherwise, 00294 // we might get bogus titles from the previous url (actually it's just 00295 // konqueror's window caption). 00296 if ( !pending && u != title ) 00297 entry.title = title; 00298 entry.firstVisited = QDateTime::currentDateTime(); 00299 entry.lastVisited = entry.firstVisited; 00300 00301 // always remove from pending if available, otherwise the else branch leaks 00302 // if the map already contains an entry for this key. 00303 QMapIterator<QString,KonqHistoryEntry*> it = m_pending.find( u ); 00304 if ( it != m_pending.end() ) { 00305 delete it.data(); 00306 m_pending.remove( it ); 00307 } 00308 00309 if ( !pending ) { 00310 if ( it != m_pending.end() ) { 00311 // we make a pending entry official, so we just have to update 00312 // and not increment the counter. No need to care about 00313 // firstVisited, as this is not taken into account on addToHistory( true, url, typedURL, title ); 00260 } 00261 00262 void KonqHistoryManager::confirmPending( const KURL& url, 00263 const QString& typedURL, 00264 const QString& title ) 00265 { 00266 addToHistory( false, url, typedURL, title ); 00267 } 00268 00269 00270 void KonqHistoryManager::addToHistory( bool pending, const KURL& _url, 00271 const QString& typedURL, 00272 const QString& title ) 00273 { 00274 kdDebug(1203) << "## addToHistory: " << _url.prettyURL() << " Typed URL: " << typedURL << ", Title: " << title << endl; 00275 00276 if ( filterOut( _url ) ) // we only want remote URLs 00277 return; 00278 00279 // http URLs without a path will get redirected immediately to url + '/' 00280 if ( _url.path().isEmpty() && _url.protocol().startsWith("http") ) 00281 return; 00282 00283 KURL url( _url ); 00284 bool hasPass = url.hasPass(); 00285 url.setPass( QString::null ); // No password in the history, especially not in the completion! 00286 url.setHost( url.host().lower() ); // All host parts lower case 00287 KonqHistoryEntry entry; 00288 QString u = url.prettyURL(); 00289 entry.url = url; 00290 if ( (u != typedURL) && !hasPass ) 00291 entry.typedURL = typedURL; 00292 00293 // we only keep the title if we are confirming an entry. Otherwise, 00294 // we might get bogus titles from the previous url (actually it's just 00295 // konqueror's window caption). 00296 if ( !pending && u != title ) 00297 entry.title = title; 00298 entry.firstVisited = QDateTime::currentDateTime(); 00299 entry.lastVisited = entry.firstVisited; 00300 00301 // always remove from pending if available, otherwise the else branch leaks 00302 // if the map already contains an entry for this key. 00303 QMapIterator<QString,KonqHistoryEntry*> it = m_pending.find( u ); 00304 if ( it != m_pending.end() ) { 00305 delete it.data(); 00306 m_pending.remove( it ); 00307 } 00308 00309 if ( !pending ) { 00310 if ( it != m_pending.end() ) { 00311 // we make a pending entry official, so we just have to update 00312 // and not increment the counter. No need to care about 00313 // firstVisited, as this is not taken into account on addToHistory( true, url, typedURL, title ); 00260 } 00261 00262 void KonqHistoryManager::confirmPending( const KURL& url, 00263 const QString& typedURL, 00264 const QString& title ) 00265 { 00266 addToHistory( false, url, typedURL, title ); 00267 } 00268 00269 00270 void KonqHistoryManager::addToHistory( bool pending, const KURL& _url, 00271 const QString& typedURL, 00272 const QString& title ) 00273 { 00274 kdDebug(1203) << "## addToHistory: " << _url.prettyURL() << " Typed URL: " << typedURL << ", Title: " << title << endl; 00275 00276 if ( filterOut( _url ) ) // we only want remote URLs 00277 return; 00278 00279 // http URLs without a path will get redirected immediately to url + '/' 00280 if ( _url.path().isEmpty() && _url.protocol().startsWith("http") ) 00281 return; 00282 00283 KURL url( _url ); 00284 bool hasPass = url.hasPass(); 00285 url.setPass( QString::null ); // No password in the history, especially not in the completion! 00286 url.setHost( url.host().lower() ); // All host parts lower case 00287 KonqHistoryEntry entry; 00288 QString u = url.prettyURL(); 00289 entry.url = url; 00290 if ( (u != typedURL) && !hasPass ) 00291 entry.typedURL = typedURL; 00292 00293 // we only keep the title if we are confirming an entry. Otherwise, 00294 // we might get bogus titles from the previous url (actually it's just 00295 // konqueror's window caption). 00296 if ( !pending && u != title ) 00297 entry.title = title; 00298 entry.firstVisited = QDateTime::currentDateTime(); 00299 entry.lastVisited = entry.firstVisited; 00300 00301 // always remove from pending if available, otherwise the else branch leaks 00302 // if the map already contains an entry for this key. 00303 QMapIterator<QString,KonqHistoryEntry*> it = m_pending.find( u ); 00304 if ( it != m_pending.end() ) { 00305 delete it.data(); 00306 m_pending.remove( it ); 00307 } 00308 00309 if ( !pending ) { 00310 if ( it != m_pending.end() ) { 00311 // we make a pending entry official, so we just have to update 00312 // and not increment the counter. No need to care about 00313 // firstVisited, as this is not taken into account on addToHistory( true, url, typedURL, title ); 00260 } 00261 00262 void KonqHistoryManager::confirmPending( const KURL& url, 00263 const QString& typedURL, 00264 const QString& title ) 00265 { 00266 addToHistory( false, url, typedURL, title ); 00267 } 00268 00269 00270 void KonqHistoryManager::addToHistory( bool pending, const KURL& _url, 00271 const QString& typedURL, 00272 const QString& title ) 00273 { 00274 kdDebug(1203) << "## addToHistory: " << _url.prettyURL() << " Typed URL: " << typedURL << ", Title: " << title << endl; 00275 00276 if ( filterOut( _url ) ) // we only want remote URLs 00277 return; 00278 00279 // http URLs without a path will get redirected immediately to url + '/' 00280 if ( _url.path().isEmpty() && _url.protocol().startsWith("http") ) 00281 return; 00282 00283 KURL url( _url ); 00284 bool hasPass = url.hasPass(); 00285 url.setPass( QString::null ); // No password in the history, especially not in the completion! 00286 url.setHost( url.host().lower() ); // All host parts lower case 00287 KonqHistoryEntry entry; 00288 QString u = url.prettyURL(); 00289 entry.url = url; 00290 if ( (u != typedURL) && !hasPass ) 00291 entry.typedURL = typedURL; 00292 00293 // we only keep the title if we are confirming an entry. Otherwise, 00294 // we might get bogus titles from the previous url (actually it's just 00295 // konqueror's window caption). 00296 if ( !pending && u != title ) 00297 entry.title = title; 00298 entry.firstVisited = QDateTime::currentDateTime(); 00299 entry.lastVisited = entry.firstVisited; 00300 00301 // always remove from pending if available, otherwise the else branch leaks 00302 // if the map already contains an entry for this key. 00303 QMapIterator<QString,KonqHistoryEntry*> it = m_pending.find( u ); 00304 if ( it != m_pending.end() ) { 00305 delete it.data(); 00306 m_pending.remove( it ); 00307 } 00308 00309 if ( !pending ) { 00310 if ( it != m_pending.end() ) { 00311 // we make a pending entry official, so we just have to update 00312 // and not increment the counter. No need to care about 00313 // firstVisited, as this is not taken into account on addToHistory( true, url, typedURL, title ); 00260 } 00261 00262 void KonqHistoryManager::confirmPending( const KURL& url, 00263 const QString& typedURL, 00264 const QString& title ) 00265 { 00266 addToHistory( false, url, typedURL, title ); 00267 } 00268 00269 00270 void KonqHistoryManager::addToHistory( bool pending, const KURL& _url, 00271 const QString& typedURL, 00272 const QString& title ) 00273 { 00274 kdDebug(1203) << "## addToHistory: " << _url.prettyURL() << " Typed URL: " << typedURL << ", Title: " << title <<
