|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; see the file COPYING. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "konq_historymgr.h"
|
|
|
|
|
|
|
|
#include <dcopclient.h>
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <ksavefile.h>
|
|
|
|
#include <ksimpleconfig.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
|
|
|
|
#include <zlib.h>
|
|
|
|
|
|
|
|
#include "konqbookmarkmanager.h"
|
|
|
|
|
|
|
|
const TQ_UINT32 KonqHistoryManager::s_historyVersion = 3;
|
|
|
|
|
|
|
|
KonqHistoryManager::KonqHistoryManager( TQObject *parent, const char *name )
|
|
|
|
: KParts::HistoryProvider( parent, name ),
|
|
|
|
KonqHistoryComm( "KonqHistoryManager" )
|
|
|
|
{
|
|
|
|
m_updateTimer = new TQTimer( this );
|
|
|
|
|
|
|
|
// defaults
|
|
|
|
KConfig *config = KGlobal::config();
|
|
|
|
KConfigGroupSaver cs( config, "HistorySettings" );
|
|
|
|
m_maxCount = config->readNumEntry( "Maximum of History entries", 500 );
|
|
|
|
m_maxCount = TQMAX( 1, m_maxCount );
|
|
|
|
m_maxAgeDays = config->readNumEntry( "Maximum age of History entries", 90);
|
|
|
|
|
|
|
|
m_history.setAutoDelete( true );
|
|
|
|
m_filename = locateLocal( "data",
|
|
|
|
TQString::tqfromLatin1("konqueror/konq_history" ));
|
|
|
|
|
|
|
|
if ( !kapp->dcopClient()->isAttached() )
|
|
|
|
kapp->dcopClient()->attach();
|
|
|
|
|
|
|
|
|
|
|
|
// take care of the completion object
|
|
|
|
m_pCompletion = new KCompletion;
|
|
|
|
m_pCompletion->setOrder( KCompletion::Weighted );
|
|
|
|
|
|
|
|
// and load the history
|
|
|
|
loadHistory();
|
|
|
|
|
|
|
|
connect( m_updateTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotEmitUpdated() ));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KonqHistoryManager::~KonqHistoryManager()
|
|
|
|
{
|
|
|
|
delete m_pCompletion;
|
|
|
|
clearPending();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqHistoryManager::isSenderOfBroadcast()
|
|
|
|
{
|
|
|
|
DCOPClient *dc = callingDcopClient();
|
|
|
|
return !dc || (dc->senderId() == dc->appId());
|
|
|
|
}
|
|
|
|
|
|
|
|
// loads the entire history
|
|
|
|
bool KonqHistoryManager::loadHistory()
|
|
|
|
{
|
|
|
|
clearPending();
|
|
|
|
m_history.clear();
|
|
|
|
m_pCompletion->clear();
|
|
|
|
|
|
|
|
TQFile file( m_filename );
|
|
|
|
if ( !file.open( IO_ReadOnly ) ) {
|
|
|
|
if ( file.exists() )
|
|
|
|
kdWarning() << "Can't open " << file.name() << endl;
|
|
|
|
|
|
|
|
// try to load the old completion history
|
|
|
|
bool ret = loadFallback();
|
|
|
|
emit loadingFinished();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDataStream fileStream( &file );
|
|
|
|
TQByteArray data; // only used for version == 2
|
|
|
|
// we construct the stream object now but fill in the data later.
|
|
|
|
// thanks to QBA's explicit sharing this works :)
|
|
|
|
TQDataStream crcStream( data, IO_ReadOnly );
|
|
|
|
|
|
|
|
if ( !fileStream.atEnd() ) {
|
|
|
|
TQ_UINT32 version;
|
|
|
|
fileStream >> version;
|
|
|
|
|
|
|
|
TQDataStream *stream = &fileStream;
|
|
|
|
|
|
|
|
bool crcChecked = false;
|
|
|
|
bool crcOk = false;
|
|
|
|
|
|
|
|
if ( version == 2 || version == 3) {
|
|
|
|
TQ_UINT32 crc;
|
|
|
|
crcChecked = true;
|
|
|
|
fileStream >> crc >> data;
|
|
|
|
crcOk = crc32( 0, reinterpret_cast<unsigned char *>( data.data() ), data.size() ) == crc;
|
|
|
|
stream = &crcStream; // pick up the right stream
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( version == 3 )
|
|
|
|
{
|
|
|
|
//Use KURL marshalling for V3 format.
|
|
|
|
KonqHistoryEntry::marshalURLAsStrings = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( version != 0 && version < 3 ) //Versions 1,2 (but not 0) are also valid
|
|
|
|
{
|
|
|
|
//Turn on backwards compatibility mode..
|
|
|
|
KonqHistoryEntry::marshalURLAsStrings = true;
|
|
|
|
// it doesn't make sense to save to save maxAge and maxCount in the
|
|
|
|
// binary file, this would make backups impossible (they would clear
|
|
|
|
// themselves on startup, because all entries expire).
|
|
|
|
// [But V1 and V2 formats did it, so we do a dummy read]
|
|
|
|
TQ_UINT32 dummy;
|
|
|
|
*stream >> dummy;
|
|
|
|
*stream >> dummy;
|
|
|
|
|
|
|
|
//OK.
|
|
|
|
version = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( s_historyVersion != version || ( crcChecked && !crcOk ) ) {
|
|
|
|
kdWarning() << "The history version doesn't match, aborting loading" << endl;
|
|
|
|
file.close();
|
|
|
|
emit loadingFinished();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
while ( !stream->atEnd() ) {
|
|
|
|
KonqHistoryEntry *entry = new KonqHistoryEntry;
|
|
|
|
Q_CHECK_PTR( entry );
|
|
|
|
*stream >> *entry;
|
|
|
|
// kdDebug(1203) << "## loaded entry: " << entry->url << ", Title: " << entry->title << endl;
|
|
|
|
m_history.append( entry );
|
|
|
|
TQString urlString2 = entry->url.prettyURL();
|
|
|
|
|
|
|
|
addToCompletion( urlString2, entry->typedURL, entry->numberOfTimesVisited );
|
|
|
|
|
|
|
|
// and fill our baseclass.
|
|
|
|
TQString urlString = entry->url.url();
|
|
|
|
KParts::HistoryProvider::insert( urlString );
|
|
|
|
// DF: also insert the "pretty" version if different
|
|
|
|
// This helps getting 'visited' links on websites which don't use fully-escaped urls.
|
|
|
|
|
|
|
|
if ( urlString != urlString2 )
|
|
|
|
KParts::HistoryProvider::insert( urlString2 );
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug(1203) << "## loaded: " << m_history.count() << " entries." << endl;
|
|
|
|
|
|
|
|
m_history.sort();
|
|
|
|
adjustSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//This is important - we need to switch to a consistent marshalling format for
|
|
|
|
//communicating between different konqueror instances. Since during an upgrade
|
|
|
|
//some "old" copies may still running, we use the old format for the DCOP transfers.
|
|
|
|
//This doesn't make that much difference performance-wise for single entries anyway.
|
|
|
|
KonqHistoryEntry::marshalURLAsStrings = true;
|
|
|
|
|
|
|
|
|
|
|
|
// Theoretically, we should emit update() here, but as we only ever
|
|
|
|
// load items on startup up to now, this doesn't make much sense. Same
|
|
|
|
// thing for the above loadFallback().
|
|
|
|
// emit KParts::HistoryProvider::update( some list );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
emit loadingFinished();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// saves the entire history
|
|
|
|
bool KonqHistoryManager::saveHistory()
|
|
|
|
{
|
|
|
|
KSaveFile file( m_filename );
|
|
|
|
if ( file.status() != 0 ) {
|
|
|
|
kdWarning() << "Can't open " << file.name() << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDataStream *fileStream = file.dataStream();
|
|
|
|
*fileStream << s_historyVersion;
|
|
|
|
|
|
|
|
TQByteArray data;
|
|
|
|
TQDataStream stream( data, IO_WriteOnly );
|
|
|
|
|
|
|
|
//We use KURL for marshalling URLs in entries in the V3
|
|
|
|
//file format
|
|
|
|
KonqHistoryEntry::marshalURLAsStrings = false;
|
|
|
|
TQPtrListIterator<KonqHistoryEntry> it( m_history );
|
|
|
|
KonqHistoryEntry *entry;
|
|
|
|
while ( (entry = it.current()) ) {
|
|
|
|
stream << *entry;
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
//For DCOP, transfer strings instead - wire compat.
|
|
|
|
KonqHistoryEntry::marshalURLAsStrings = true;
|
|
|
|
|
|
|
|
TQ_UINT32 crc = crc32( 0, reinterpret_cast<unsigned char *>( data.data() ), data.size() );
|
|
|
|
*fileStream << crc << data;
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KonqHistoryManager::adjustSize()
|
|
|
|
{
|
|
|
|
KonqHistoryEntry *entry = m_history.getFirst();
|
|
|
|
|
|
|
|
while ( m_history.count() > m_maxCount || isExpired( entry ) ) {
|
|
|
|
removeFromCompletion( entry->url.prettyURL(), entry->typedURL );
|
|
|
|
|
|
|
|
TQString urlString = entry->url.url();
|
|
|
|
KParts::HistoryProvider::remove( urlString );
|
|
|
|
|
|
|
|
addToUpdateList( urlString );
|
|
|
|
|
|
|
|
emit entryRemoved( m_history.getFirst() );
|
|
|
|
m_history.removeFirst(); // deletes the entry
|
|
|
|
|
|
|
|
entry = m_history.getFirst();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KonqHistoryManager::addPending( const KURL& url, const TQString& typedURL,
|
|
|
|
const TQString& title )
|
|
|
|
{
|
|
|
|
addToHistory( true, url, typedURL, title );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::confirmPending( const KURL& url,
|
|
|
|
const TQString& typedURL,
|
|
|
|
const TQString& title )
|
|
|
|
{
|
|
|
|
addToHistory( false, url, typedURL, title );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KonqHistoryManager::addToHistory( bool pending, const KURL& _url,
|
|
|
|
const TQString& typedURL,
|
|
|
|
const TQString& title )
|
|
|
|
{
|
|
|
|
kdDebug(1203) << "## addToHistory: " << _url.prettyURL() << " Typed URL: " << typedURL << ", Title: " << title << endl;
|
|
|
|
|
|
|
|
if ( filterOut( _url ) ) // we only want remote URLs
|
|
|
|
return;
|
|
|
|
|
|
|
|
// http URLs without a path will get redirected immediately to url + '/'
|
|
|
|
if ( _url.path().isEmpty() && _url.protocol().startsWith("http") )
|
|
|
|
return;
|
|
|
|
|
|
|
|
KURL url( _url );
|
|
|
|
bool hasPass = url.hasPass();
|
|
|
|
url.setPass( TQString::null ); // No password in the history, especially not in the completion!
|
|
|
|
url.setHost( url.host().lower() ); // All host parts lower case
|
|
|
|
KonqHistoryEntry entry;
|
|
|
|
TQString u = url.prettyURL();
|
|
|
|
entry.url = url;
|
|
|
|
if ( (u != typedURL) && !hasPass )
|
|
|
|
entry.typedURL = typedURL;
|
|
|
|
|
|
|
|
// we only keep the title if we are confirming an entry. Otherwise,
|
|
|
|
// we might get bogus titles from the previous url (actually it's just
|
|
|
|
// konqueror's window caption).
|
|
|
|
if ( !pending && u != title )
|
|
|
|
entry.title = title;
|
|
|
|
entry.firstVisited = TQDateTime::tqcurrentDateTime();
|
|
|
|
entry.lastVisited = entry.firstVisited;
|
|
|
|
|
|
|
|
// always remove from pending if available, otherwise the else branch leaks
|
|
|
|
// if the map already contains an entry for this key.
|
|
|
|
TQMapIterator<TQString,KonqHistoryEntry*> it = m_pending.find( u );
|
|
|
|
if ( it != m_pending.end() ) {
|
|
|
|
delete it.data();
|
|
|
|
m_pending.remove( it );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !pending ) {
|
|
|
|
if ( it != m_pending.end() ) {
|
|
|
|
// we make a pending entry official, so we just have to update
|
|
|
|
// and not increment the counter. No need to care about
|
|
|
|
// firstVisited, as this is not taken into account on update.
|
|
|
|
entry.numberOfTimesVisited = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
// We add a copy of the current history entry of the url to the
|
|
|
|
// pending list, so that we can restore it if the user canceled.
|
|
|
|
// If there is no entry for the url yet, we just store the url.
|
|
|
|
KonqHistoryEntry *oldEntry = findEntry( url );
|
|
|
|
m_pending.insert( u, oldEntry ?
|
|
|
|
new KonqHistoryEntry( *oldEntry ) : 0L );
|
|
|
|
}
|
|
|
|
|
|
|
|
// notify all konqueror instances about the entry
|
|
|
|
emitAddToHistory( entry );
|
|
|
|
}
|
|
|
|
|
|
|
|
// interface of KParts::HistoryManager
|
|
|
|
// Usually, we only record the history for non-local URLs (i.e. filterOut()
|
|
|
|
// returns false). But when using the HistoryProvider interface, we record
|
|
|
|
// exactly those filtered-out urls.
|
|
|
|
// Moreover, we don't get any pending/confirming entries, just one insert()
|
|
|
|
void KonqHistoryManager::insert( const TQString& url )
|
|
|
|
{
|
|
|
|
KURL u ( url );
|
|
|
|
if ( !filterOut( u ) || u.protocol() == "about" ) { // remote URL
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Local URL -> add to history
|
|
|
|
KonqHistoryEntry entry;
|
|
|
|
entry.url = u;
|
|
|
|
entry.firstVisited = TQDateTime::tqcurrentDateTime();
|
|
|
|
entry.lastVisited = entry.firstVisited;
|
|
|
|
emitAddToHistory( entry );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::emitAddToHistory( const KonqHistoryEntry& entry )
|
|
|
|
{
|
|
|
|
TQByteArray data;
|
|
|
|
TQDataStream stream( data, IO_WriteOnly );
|
|
|
|
stream << entry << objId();
|
|
|
|
// Protection against very long urls (like data:)
|
|
|
|
if ( data.size() > 4096 )
|
|
|
|
return;
|
|
|
|
kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
|
|
|
|
"notifyHistoryEntry(KonqHistoryEntry, TQCString)",
|
|
|
|
data );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KonqHistoryManager::removePending( const KURL& url )
|
|
|
|
{
|
|
|
|
// kdDebug(1203) << "## Removing pending... " << url.prettyURL() << endl;
|
|
|
|
|
|
|
|
if ( url.isLocalFile() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQMapIterator<TQString,KonqHistoryEntry*> it = m_pending.find( url.prettyURL() );
|
|
|
|
if ( it != m_pending.end() ) {
|
|
|
|
KonqHistoryEntry *oldEntry = it.data(); // the old entry, may be 0L
|
|
|
|
emitRemoveFromHistory( url ); // remove the current pending entry
|
|
|
|
|
|
|
|
if ( oldEntry ) // we had an entry before, now use that instead
|
|
|
|
emitAddToHistory( *oldEntry );
|
|
|
|
|
|
|
|
delete oldEntry;
|
|
|
|
m_pending.remove( it );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// clears the pending list and makes sure the entries get deleted.
|
|
|
|
void KonqHistoryManager::clearPending()
|
|
|
|
{
|
|
|
|
TQMapIterator<TQString,KonqHistoryEntry*> it = m_pending.begin();
|
|
|
|
while ( it != m_pending.end() ) {
|
|
|
|
delete it.data();
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
m_pending.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::emitRemoveFromHistory( const KURL& url )
|
|
|
|
{
|
|
|
|
TQByteArray data;
|
|
|
|
TQDataStream stream( data, IO_WriteOnly );
|
|
|
|
stream << url << objId();
|
|
|
|
kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
|
|
|
|
"notifyRemove(KURL, TQCString)", data );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::emitRemoveFromHistory( const KURL::List& urls )
|
|
|
|
{
|
|
|
|
TQByteArray data;
|
|
|
|
TQDataStream stream( data, IO_WriteOnly );
|
|
|
|
stream << urls << objId();
|
|
|
|
kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
|
|
|
|
"notifyRemove(KURL::List, TQCString)", data );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::emitClear()
|
|
|
|
{
|
|
|
|
TQByteArray data;
|
|
|
|
TQDataStream stream( data, IO_WriteOnly );
|
|
|
|
stream << objId();
|
|
|
|
kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
|
|
|
|
"notifyClear(TQCString)", data );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::emitSetMaxCount( TQ_UINT32 count )
|
|
|
|
{
|
|
|
|
TQByteArray data;
|
|
|
|
TQDataStream stream( data, IO_WriteOnly );
|
|
|
|
stream << count << objId();
|
|
|
|
kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
|
|
|
|
"notifyMaxCount(TQ_UINT32, TQCString)", data );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::emitSetMaxAge( TQ_UINT32 days )
|
|
|
|
{
|
|
|
|
TQByteArray data;
|
|
|
|
TQDataStream stream( data, IO_WriteOnly );
|
|
|
|
stream << days << objId();
|
|
|
|
kapp->dcopClient()->send( "konqueror*", "KonqHistoryManager",
|
|
|
|
"notifyMaxAge(TQ_UINT32, TQCString)", data );
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
// DCOP called methods
|
|
|
|
|
|
|
|
void KonqHistoryManager::notifyHistoryEntry( KonqHistoryEntry e,
|
|
|
|
TQCString )
|
|
|
|
{
|
|
|
|
//kdDebug(1203) << "Got new entry from Broadcast: " << e.url.prettyURL() << endl;
|
|
|
|
|
|
|
|
KonqHistoryEntry *entry = findEntry( e.url );
|
|
|
|
TQString urlString = e.url.url();
|
|
|
|
|
|
|
|
if ( !entry ) { // create a new history entry
|
|
|
|
entry = new KonqHistoryEntry;
|
|
|
|
entry->url = e.url;
|
|
|
|
entry->firstVisited = e.firstVisited;
|
|
|
|
entry->numberOfTimesVisited = 0; // will get set to 1 below
|
|
|
|
m_history.append( entry );
|
|
|
|
KParts::HistoryProvider::insert( urlString );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !e.typedURL.isEmpty() )
|
|
|
|
entry->typedURL = e.typedURL;
|
|
|
|
if ( !e.title.isEmpty() )
|
|
|
|
entry->title = e.title;
|
|
|
|
entry->numberOfTimesVisited += e.numberOfTimesVisited;
|
|
|
|
entry->lastVisited = e.lastVisited;
|
|
|
|
|
|
|
|
addToCompletion( entry->url.prettyURL(), entry->typedURL );
|
|
|
|
|
|
|
|
// bool pending = (e.numberOfTimesVisited != 0);
|
|
|
|
|
|
|
|
adjustSize();
|
|
|
|
|
|
|
|
// note, no need to do the updateBookmarkMetadata for every
|
|
|
|
// history object, only need to for the broadcast sender as
|
|
|
|
// the history object itself keeps the data consistant.
|
|
|
|
bool updated = KonqBookmarkManager::self()->updateAccessMetadata( urlString );
|
|
|
|
|
|
|
|
if ( isSenderOfBroadcast() ) {
|
|
|
|
// we are the sender of the broadcast, so we save
|
|
|
|
saveHistory();
|
|
|
|
// note, bk save does not notify, and we don't want to!
|
|
|
|
if (updated)
|
|
|
|
KonqBookmarkManager::self()->save();
|
|
|
|
}
|
|
|
|
|
|
|
|
addToUpdateList( urlString );
|
|
|
|
emit entryAdded( entry );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::notifyMaxCount( TQ_UINT32 count, TQCString )
|
|
|
|
{
|
|
|
|
m_maxCount = count;
|
|
|
|
clearPending();
|
|
|
|
adjustSize();
|
|
|
|
|
|
|
|
KConfig *config = KGlobal::config();
|
|
|
|
KConfigGroupSaver cs( config, "HistorySettings" );
|
|
|
|
config->writeEntry( "Maximum of History entries", m_maxCount );
|
|
|
|
|
|
|
|
if ( isSenderOfBroadcast() ) {
|
|
|
|
saveHistory();
|
|
|
|
config->sync();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::notifyMaxAge( TQ_UINT32 days, TQCString )
|
|
|
|
{
|
|
|
|
m_maxAgeDays = days;
|
|
|
|
clearPending();
|
|
|
|
adjustSize();
|
|
|
|
|
|
|
|
KConfig *config = KGlobal::config();
|
|
|
|
KConfigGroupSaver cs( config, "HistorySettings" );
|
|
|
|
config->writeEntry( "Maximum age of History entries", m_maxAgeDays );
|
|
|
|
|
|
|
|
if ( isSenderOfBroadcast() ) {
|
|
|
|
saveHistory();
|
|
|
|
config->sync();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::notifyClear( TQCString )
|
|
|
|
{
|
|
|
|
clearPending();
|
|
|
|
m_history.clear();
|
|
|
|
m_pCompletion->clear();
|
|
|
|
|
|
|
|
if ( isSenderOfBroadcast() )
|
|
|
|
saveHistory();
|
|
|
|
|
|
|
|
KParts::HistoryProvider::clear(); // also emits the cleared() signal
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::notifyRemove( KURL url, TQCString )
|
|
|
|
{
|
|
|
|
kdDebug(1203) << "#### Broadcast: remove entry:: " << url.prettyURL() << endl;
|
|
|
|
|
|
|
|
|
|
|
|
KonqHistoryEntry *entry = m_history.findEntry( url );
|
|
|
|
|
|
|
|
if ( entry ) { // entry is now the current item
|
|
|
|
removeFromCompletion( entry->url.prettyURL(), entry->typedURL );
|
|
|
|
|
|
|
|
TQString urlString = entry->url.url();
|
|
|
|
KParts::HistoryProvider::remove( urlString );
|
|
|
|
|
|
|
|
addToUpdateList( urlString );
|
|
|
|
|
|
|
|
m_history.take(); // does not delete
|
|
|
|
emit entryRemoved( entry );
|
|
|
|
delete entry;
|
|
|
|
|
|
|
|
if ( isSenderOfBroadcast() )
|
|
|
|
saveHistory();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::notifyRemove( KURL::List urls, TQCString )
|
|
|
|
{
|
|
|
|
kdDebug(1203) << "#### Broadcast: removing list!" << endl;
|
|
|
|
|
|
|
|
bool doSave = false;
|
|
|
|
KURL::List::Iterator it = urls.begin();
|
|
|
|
while ( it != urls.end() ) {
|
|
|
|
KonqHistoryEntry *entry = m_history.findEntry( *it );
|
|
|
|
|
|
|
|
if ( entry ) { // entry is now the current item
|
|
|
|
removeFromCompletion( entry->url.prettyURL(), entry->typedURL );
|
|
|
|
|
|
|
|
TQString urlString = entry->url.url();
|
|
|
|
KParts::HistoryProvider::remove( urlString );
|
|
|
|
|
|
|
|
addToUpdateList( urlString );
|
|
|
|
|
|
|
|
m_history.take(); // does not delete
|
|
|
|
emit entryRemoved( entry );
|
|
|
|
delete entry;
|
|
|
|
doSave = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doSave && isSenderOfBroadcast())
|
|
|
|
saveHistory();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// compatibility fallback, try to load the old completion history
|
|
|
|
bool KonqHistoryManager::loadFallback()
|
|
|
|
{
|
|
|
|
TQString file = locateLocal( "config", TQString::tqfromLatin1("konq_history"));
|
|
|
|
if ( file.isEmpty() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
KonqHistoryEntry *entry;
|
|
|
|
KSimpleConfig config( file );
|
|
|
|
config.setGroup("History");
|
|
|
|
TQStringList items = config.readListEntry( "CompletionItems" );
|
|
|
|
TQStringList::Iterator it = items.begin();
|
|
|
|
|
|
|
|
while ( it != items.end() ) {
|
|
|
|
entry = createFallbackEntry( *it );
|
|
|
|
if ( entry ) {
|
|
|
|
m_history.append( entry );
|
|
|
|
addToCompletion( entry->url.prettyURL(), TQString::null, entry->numberOfTimesVisited );
|
|
|
|
|
|
|
|
KParts::HistoryProvider::insert( entry->url.url() );
|
|
|
|
}
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_history.sort();
|
|
|
|
adjustSize();
|
|
|
|
saveHistory();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// tries to create a small KonqHistoryEntry out of a string, where the string
|
|
|
|
// looks like "http://www.bla.com/bla.html:23"
|
|
|
|
// the attached :23 is the weighting from KCompletion
|
|
|
|
KonqHistoryEntry * KonqHistoryManager::createFallbackEntry(const TQString& item) const
|
|
|
|
{
|
|
|
|
// code taken from KCompletion::addItem(), adjusted to use weight = 1
|
|
|
|
uint len = item.length();
|
|
|
|
uint weight = 1;
|
|
|
|
|
|
|
|
// find out the weighting of this item (appended to the string as ":num")
|
|
|
|
int index = item.findRev(':');
|
|
|
|
if ( index > 0 ) {
|
|
|
|
bool ok;
|
|
|
|
weight = item.mid( index + 1 ).toUInt( &ok );
|
|
|
|
if ( !ok )
|
|
|
|
weight = 1;
|
|
|
|
|
|
|
|
len = index; // only insert until the ':'
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KonqHistoryEntry *entry = 0L;
|
|
|
|
KURL u( item.left( len ));
|
|
|
|
if ( u.isValid() ) {
|
|
|
|
entry = new KonqHistoryEntry;
|
|
|
|
// that's the only entries we know about...
|
|
|
|
entry->url = u;
|
|
|
|
entry->numberOfTimesVisited = weight;
|
|
|
|
// to make it not expire immediately...
|
|
|
|
entry->lastVisited = TQDateTime::tqcurrentDateTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
KonqHistoryEntry * KonqHistoryManager::findEntry( const KURL& url )
|
|
|
|
{
|
|
|
|
// small optimization (dict lookup) for items _not_ in our history
|
|
|
|
if ( !KParts::HistoryProvider::contains( url.url() ) )
|
|
|
|
return 0L;
|
|
|
|
|
|
|
|
return m_history.findEntry( url );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqHistoryManager::filterOut( const KURL& url )
|
|
|
|
{
|
|
|
|
return ( url.isLocalFile() || url.host().isEmpty() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::slotEmitUpdated()
|
|
|
|
{
|
|
|
|
emit KParts::HistoryProvider::updated( m_updateURLs );
|
|
|
|
m_updateURLs.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList KonqHistoryManager::allURLs() const
|
|
|
|
{
|
|
|
|
TQStringList list;
|
|
|
|
KonqHistoryIterator it ( m_history );
|
|
|
|
for ( ; it.current(); ++it )
|
|
|
|
list.append( it.current()->url.url() );
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::addToCompletion( const TQString& url, const TQString& typedURL,
|
|
|
|
int numberOfTimesVisited )
|
|
|
|
{
|
|
|
|
m_pCompletion->addItem( url, numberOfTimesVisited );
|
|
|
|
// typed urls have a higher priority
|
|
|
|
m_pCompletion->addItem( typedURL, numberOfTimesVisited +10 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqHistoryManager::removeFromCompletion( const TQString& url, const TQString& typedURL )
|
|
|
|
{
|
|
|
|
m_pCompletion->removeItem( url );
|
|
|
|
m_pCompletion->removeItem( typedURL );
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
KonqHistoryEntry * KonqHistoryList::findEntry( const KURL& url )
|
|
|
|
{
|
|
|
|
// we search backwards, probably faster to find an entry
|
|
|
|
KonqHistoryEntry *entry = last();
|
|
|
|
while ( entry ) {
|
|
|
|
if ( entry->url == url )
|
|
|
|
return entry;
|
|
|
|
|
|
|
|
entry = prev();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
// sort by lastVisited date (oldest go first)
|
|
|
|
int KonqHistoryList::compareItems( TQPtrCollection::Item item1,
|
|
|
|
TQPtrCollection::Item item2 )
|
|
|
|
{
|
|
|
|
KonqHistoryEntry *entry1 = static_cast<KonqHistoryEntry *>( item1 );
|
|
|
|
KonqHistoryEntry *entry2 = static_cast<KonqHistoryEntry *>( item2 );
|
|
|
|
|
|
|
|
if ( entry1->lastVisited > entry2->lastVisited )
|
|
|
|
return 1;
|
|
|
|
else if ( entry1->lastVisited < entry2->lastVisited )
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
using namespace KParts; // for IRIX
|
|
|
|
|
|
|
|
#include "konq_historymgr.moc"
|