logsui/logscntfinder/src/logscntfinder.cpp
changeset 0 4a5361db8937
child 2 7119b73b84d6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/logsui/logscntfinder/src/logscntfinder.cpp	Tue May 04 12:39:37 2010 +0300
@@ -0,0 +1,796 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+#include <QListIterator>
+
+#include <qcontactdetailfilter.h>
+#include <qcontactphonenumber.h>
+#include <qcontactname.h>
+#include <qcontactmanager.h>
+#include <qcontactavatar.h>
+#include <QVector>
+
+#include "logscntfinder.h"
+#include "logspredictivetranslator.h"
+#include "logslogger.h"
+
+const int MaxPredSearchPatternLen = 15;
+const QChar ZeroSepar('0');
+
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::richText()
+// -----------------------------------------------------------------------------
+//
+QString LogsCntText::richText( QString startTag, 
+                               QString endTag ) const
+{
+    QString str = text();
+    if ( str.length() > 0 && highlights() > 0 ) {
+        str.insert( highlights() , endTag );
+        str.insert( 0, startTag );
+    }
+
+    return str;
+    
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::LogsCntEntry()
+// -----------------------------------------------------------------------------
+//
+LogsCntEntry::LogsCntEntry( LogsCntEntryHandle& handle, 
+                            quint32 cid )
+    : mType( EntryTypeHistory ), mCid( cid ), 
+      mCached( true ),mHandle(&handle)
+{
+    LogsCntText empty;
+    mFirstName.append( empty );
+    mLastName.append( empty );
+    mAvatarPath = "";
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::LogsCntEntry()
+// -----------------------------------------------------------------------------
+//
+LogsCntEntry::LogsCntEntry( quint32 cid )
+    : mType( EntryTypeContact ), mCid( cid ), 
+      mCached( false ),mHandle(0)
+{
+    LogsCntText empty;
+    mFirstName.append( empty );
+    mLastName.append( empty );
+    mAvatarPath = "";
+}
+
+// -----------------------------------------------------------------------------
+// copy LogsCntEntry::LogsCntEntry()
+// -----------------------------------------------------------------------------
+//
+LogsCntEntry::LogsCntEntry( const LogsCntEntry& entry )
+    : mType(entry.mType),
+      mCid(entry.mCid),
+      mFirstName(entry.mFirstName),
+      mLastName(entry.mLastName),
+      mCached(entry.mCached),
+      mHandle(entry.mHandle),
+      mPhoneNumber(entry.mPhoneNumber),
+      mAvatarPath(entry.mAvatarPath)
+{
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::~LogsCntEntry()
+// -----------------------------------------------------------------------------
+//
+LogsCntEntry::~LogsCntEntry()
+{
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::firstName()
+// -----------------------------------------------------------------------------
+//
+const LogsCntTextList& LogsCntEntry::firstName() const 
+{
+    return mFirstName;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::lastName()
+// -----------------------------------------------------------------------------
+//
+const LogsCntTextList& LogsCntEntry::lastName() const
+{
+    return mLastName;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::avatarPath()
+// -----------------------------------------------------------------------------
+//
+const QString& LogsCntEntry::avatarPath() const
+{
+    return mAvatarPath;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::phoneNumber()
+// -----------------------------------------------------------------------------
+//
+const LogsCntText& LogsCntEntry::phoneNumber() const
+{
+    return mPhoneNumber;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::speedDial()
+// -----------------------------------------------------------------------------
+//
+const QString& LogsCntEntry::speedDial() const
+{
+    return mSpeedDial;
+}
+
+
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::contactId()
+// -----------------------------------------------------------------------------
+//
+quint32 LogsCntEntry::contactId() const
+{
+    return mCid;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::handle()
+// -----------------------------------------------------------------------------
+//
+LogsCntEntryHandle* LogsCntEntry::handle() const
+{
+    return mHandle;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::setFirstName()
+// -----------------------------------------------------------------------------
+//
+void LogsCntEntry::setFirstName( const QString& name ) 
+{
+    mCached=true;
+    mFirstName.clear();
+    doSetText( name, mFirstName );
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::setLastName()
+// -----------------------------------------------------------------------------
+//
+void LogsCntEntry::setLastName( const QString& name ) 
+{
+    mCached=true;
+    mLastName.clear();
+    doSetText( name, mLastName );
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::setAvatarPath()
+// -----------------------------------------------------------------------------
+//
+void LogsCntEntry::setAvatarPath( const QString& avatarpath ) 
+{
+    mCached=true;
+    mAvatarPath.clear();
+    mAvatarPath = avatarpath;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::tokens()
+// -----------------------------------------------------------------------------
+//
+QStringList LogsCntEntry::tokens( const QString& source, 
+                                  const QChar& separ ) const
+{
+    QStringList target = source.split( separ, QString::SkipEmptyParts );
+    if ( target.length() > 1 && separ == ZeroSepar ) {
+        QString& first = target[0];
+        QString& last = target[target.length()-1];
+        padWithZeros( first, source, 0 );
+        padWithZeros( last, source, last.length() );
+    }
+    return target;
+    
+}
+
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::padWithLeadingZeros()
+// -----------------------------------------------------------------------------
+//
+void LogsCntEntry::padWithZeros( QString& token, 
+                                 const QString& source, int padIndex ) const
+{
+    const QChar* content = source.data();
+    int index = !padIndex ? 0 : source.length()-1;
+            
+    while( index >= 0 && index < source.length() ) {
+        if ( content[ index ] == ZeroSepar ) {
+            token.insert( padIndex, ZeroSepar );
+            index = !padIndex ? index+1 : index-1;
+        } else {
+            index = -1;
+        }
+    }
+}
+
+
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::doSetText()
+// -----------------------------------------------------------------------------
+//
+void LogsCntEntry::doSetText( const QString& text, LogsCntTextList& textlist ) 
+{
+    QListIterator<QString> iter( tokens( text ) );
+
+    while( iter.hasNext() ) {
+        LogsCntText txt;
+        txt.mText = iter.next();
+        txt.mTranslatedText = 
+            LogsPredictiveTranslator::instance()->translate( txt.mText );
+        textlist.append( txt );
+    }
+    if ( textlist.count() == 0 ) {
+        textlist.append( LogsCntText() );
+    }
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::setPhoneNumber()
+// -----------------------------------------------------------------------------
+//
+void LogsCntEntry::setPhoneNumber( const QString& number )
+{
+    mCached=true;
+    mPhoneNumber.mText = number;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::resetHighlights()
+// -----------------------------------------------------------------------------
+//
+void LogsCntEntry::resetHighlights( LogsCntTextList& nameArray )
+{
+    QMutableListIterator<LogsCntText> names( nameArray ); 
+    while( names.hasNext() ) {
+        names.next().mHighlights = 0;
+    }
+    
+}
+
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::setHighlights()
+// -----------------------------------------------------------------------------
+//
+void LogsCntEntry::setHighlights( const QString& pattern )
+{
+    resetHighlights( mFirstName );
+    resetHighlights( mLastName );
+    
+    mPhoneNumber.mHighlights = 
+            mPhoneNumber.text().startsWith( pattern ) &&
+            mPhoneNumber.text().length() >= pattern.length() ?
+            pattern.length(): 0;
+    
+    doSetHighlights( pattern, mFirstName );
+    doSetHighlights( pattern, mLastName );
+    
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::doSetHighlights()
+// -----------------------------------------------------------------------------
+//
+void LogsCntEntry::doSetHighlights( const QString& pattern, 
+                                    LogsCntTextList& nameArray )
+{
+    
+    LogsPredictiveTranslator* translator = 
+            LogsPredictiveTranslator::instance();
+    QMutableListIterator<LogsCntText> names( nameArray ); 
+    bool hasZeros = pattern.contains( ZeroSepar );
+    
+    //simple
+    while( names.hasNext() ) {
+        LogsCntText& nameItem = names.next();
+        nameItem.mHighlights = 
+                translator->startsWith( nameItem.mText, pattern, false );
+    }
+    
+    //complex
+    QStringList tokenArray = tokens( pattern, ZeroSepar );
+    QListIterator<QString> patternArray( tokenArray  );
+    while( hasZeros && patternArray.hasNext() ) {
+        QString patternItem = patternArray.next();
+        names.toFront();
+        while( names.hasNext() ) {
+            LogsCntText& nameItem = names.next();
+            int matchSize = translator->startsWith( nameItem.mText, 
+                                                    patternItem, !hasZeros );
+            nameItem.mHighlights = matchSize > nameItem.mHighlights ?
+                                   matchSize : nameItem.mHighlights; 
+        }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::setSpeedDial()
+// -----------------------------------------------------------------------------
+//
+void LogsCntEntry::setSpeedDial( const QString& number )
+{
+    mSpeedDial = number;
+}
+
+
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::match()
+// -----------------------------------------------------------------------------
+//
+bool LogsCntEntry::match( const QString& pattern ) const
+{
+    bool match = false;
+    
+    //direct match with phone number is enough
+    match = mPhoneNumber.text().startsWith( pattern ) ||
+            doSimpleMatch( pattern );
+    
+    if ( !match && pattern.contains( ZeroSepar ) ) {
+        QStringList patternArray = tokens( pattern, ZeroSepar );
+        match = doComplexMatch( patternArray );
+    }
+    
+    return match;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::doSimpleMatch()
+// -----------------------------------------------------------------------------
+//
+bool LogsCntEntry::doSimpleMatch( const QString& pattern ) const
+{
+    LogsCntTextList nameArray = mFirstName + mLastName; //with empties
+    QListIterator<LogsCntText> names( nameArray ); 
+    int matchCount = 0;
+
+    while( names.hasNext() && !matchCount ) {
+        matchCount = (int)names.next().mTranslatedText.startsWith( pattern );
+    }
+
+    return matchCount > 0;
+}
+
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::doComplexMatch()
+// -----------------------------------------------------------------------------
+//
+bool LogsCntEntry::doComplexMatch( QStringList patternArray ) const
+{
+    const bool zero = false;
+
+    LogsCntTextList nameArray = mFirstName + mLastName; //with empties
+
+    int targetMatchCount = patternArray.count();
+    int namesCount = nameArray.count();
+
+    //if pattern has more tokens than name(s), it is a missmatch
+    if ( namesCount < targetMatchCount ) {
+        return false;
+    }
+
+    QListIterator<LogsCntText> names( nameArray ); 
+    QListIterator<QString> patterns( patternArray );
+    QVector<bool> matchVector(targetMatchCount, zero );
+    int currentPattern = 0;
+    int matchCount = 0;
+    bool match = false;
+    
+    while( names.hasNext() && matchCount < targetMatchCount ) {
+        LogsCntText name = names.next();
+        currentPattern = 0;
+        patterns.toFront();
+        match = false;
+        while ( !name.mText.isEmpty() && 
+                 patterns.hasNext() && !match ) {
+            QString pattern = patterns.next();
+            //unique match check
+            if ( !matchVector.at( currentPattern ) ) {
+                match = matchVector[ currentPattern ] 
+                      = name.mTranslatedText.startsWith( pattern );
+                matchCount = match ? matchCount+1 : matchCount;
+            }
+            currentPattern++;
+        }
+    }
+    return matchCount >= targetMatchCount;
+
+    }
+    
+    
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::isCached()
+// -----------------------------------------------------------------------------
+//
+bool LogsCntEntry::isCached() const
+{
+    return mCached;
+}
+
+
+// -----------------------------------------------------------------------------
+// LogsCntEntry::type()
+// -----------------------------------------------------------------------------
+//
+LogsCntEntry::EntryType LogsCntEntry::type() const
+{
+    return mType;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::LogsCntFinder()
+// -----------------------------------------------------------------------------
+//
+LogsCntFinder::LogsCntFinder()
+    : mCachedCounter(0)
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::LogsCntFinder()" )
+    
+    // Create manager ourselves, object takes care of deletion when registering
+    // as parent.
+    QMap<QString, QString> dummyParams;
+    mContactManager = new QContactManager("symbian", dummyParams, this);
+    
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::LogsCntFinder()" )
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::LogsCntFinder()
+// -----------------------------------------------------------------------------
+//
+LogsCntFinder::LogsCntFinder(QContactManager& contactManager)
+    : mCachedCounter(0)
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::LogsCntFinder(), cntmgr from client" )
+    
+    mContactManager = &contactManager;
+    
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::LogsCntFinder()" )
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::~LogsCntFinder()
+// -----------------------------------------------------------------------------
+//
+LogsCntFinder::~LogsCntFinder()
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::~LogsCntFinder()" )
+
+    qDeleteAll( mResults );
+    qDeleteAll( mHistoryEvents );
+    LogsPredictiveTranslator::deleteInstance();
+    
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::~LogsCntFinder()" )
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::isProgressivePattern
+// -----------------------------------------------------------------------------
+//
+bool LogsCntFinder::isProgressivePattern( const QString& pattern ) const
+{
+    //"" -> XXX not progressive
+    //XX -> YY not progressive
+    //XXX -> YY not progressive
+    int prevPatternLen = mCurrentPredictivePattern.length();
+    return prevPatternLen > 0 &&  
+           pattern.length() - prevPatternLen > 0;
+}
+
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::predictiveSearchQuery
+// -----------------------------------------------------------------------------
+//
+void LogsCntFinder::predictiveSearchQuery( const QString& pattern )
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::predictiveSearchQuery()" )
+    LOGS_QDEBUG_2( "logs [FINDER] pattern= ", pattern )
+
+    if ( pattern.length() > MaxPredSearchPatternLen ) {
+        LOGS_QDEBUG( "logs [FINDER] too long pattern. Exit quietly.")
+        LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::predictiveSearchQuery()" )
+        return;
+    }
+        
+    //in this point mCurrentPredictivePattern is previous
+    bool patternIsProgressive = isProgressivePattern( pattern );
+    bool resultsAreAllCached = resultsCount() > 0 && 
+                               mCachedCounter == resultsCount();
+    bool nothingToDo = resultsCount() == 0 &&
+                       patternIsProgressive;
+                                           
+    LOGS_QDEBUG_2( "logs [FINDER] patternIsProgressive = ", patternIsProgressive )
+    LOGS_QDEBUG_2( "logs [FINDER] resultsAreAllCached = ", resultsAreAllCached )
+    LOGS_QDEBUG_2( "logs [FINDER] nothingToDo = ", nothingToDo )
+    LOGS_QDEBUG_2( "logs [FINDER] cachedCounter = ", mCachedCounter )
+    
+    mCurrentPredictivePattern = pattern;
+    
+    if ( mCurrentPredictivePattern.isEmpty() ) {
+        qDeleteAll( mResults );
+        mResults.clear();
+        mCachedCounter = 0;
+    } else if ( ( patternIsProgressive &&
+                  resultsAreAllCached ) ||
+                nothingToDo ) {
+        doPredictiveCacheQuery();
+    } else {        
+        mCachedCounter = 0;
+        LogsCntEntryList recentResults = mResults;
+        mResults.clear();
+        doPredictiveHistoryQuery();
+        doPredictiveContactQuery( recentResults );
+        qDeleteAll( recentResults );
+    }
+    emit queryReady();
+ 
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::predictiveSearchQuery()" )
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::doPredictiveHistoryQuery
+// -----------------------------------------------------------------------------
+//
+void LogsCntFinder::doPredictiveHistoryQuery()
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::doPredictiveHistoryQuery()" )
+    
+    QListIterator<LogsCntEntry*> iter(mHistoryEvents);
+    
+    while( iter.hasNext() ) {
+        LogsCntEntry* e = iter.next();
+        if ( e->match( mCurrentPredictivePattern ) ) {
+            LogsCntEntry* entry = new LogsCntEntry( *e );
+            addResult( entry );
+        }
+    }
+        
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::doPredictiveHistoryQuery()" )
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::doPredictiveContactQuery
+// -----------------------------------------------------------------------------
+//
+void LogsCntFinder::doPredictiveContactQuery( LogsCntEntryList& recentResults )
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::doPredictiveContactQuery()" )
+    QContactDetailFilter df;
+    df.setDetailDefinitionName( QContactName::DefinitionName );
+    df.setMatchFlags( QContactFilter::MatchKeypadCollation );
+    df.setValue( mCurrentPredictivePattern );
+    QList<QContactLocalId> cntIds;
+    LOGS_QDEBUG( "logs [FINDER] about to call contacts manager" )
+    
+    cntIds = mContactManager->contactIds( df );
+    LOGS_QDEBUG_2( "logs [FINDER] number of matched contacts =", cntIds.count() )
+    int index = 0;
+    while( index < cntIds.count() ) {
+        addResult( cntIds.at( index++ ), recentResults );
+    }
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::doPredictiveContactQuery()" )
+    
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::doPredictiveCacheQuery()
+// -----------------------------------------------------------------------------
+//
+void LogsCntFinder::doPredictiveCacheQuery()
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::doPredictiveCacheQuery()" )
+    QMutableListIterator<LogsCntEntry*> iter(mResults);
+    while( iter.hasNext() ) {
+        LogsCntEntry* entry = iter.next();
+        if ( !entry->match( mCurrentPredictivePattern ) ) {
+            mCachedCounter = 
+                    entry->isCached() ? mCachedCounter-1 : mCachedCounter;
+            iter.remove();
+            delete entry;
+        } else {
+            entry->setHighlights( mCurrentPredictivePattern );
+        }
+    }
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::doPredictiveCacheQuery()" )
+    
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::addResult()
+// -----------------------------------------------------------------------------
+//
+void LogsCntFinder::addResult( quint32 cntId, LogsCntEntryList& recentResults )
+{
+    QMutableListIterator<LogsCntEntry*> iter(recentResults);
+    bool reused = false;
+    while( iter.hasNext() && !reused ) {
+        LogsCntEntry* entry = iter.next();
+        if ( entry->contactId() == cntId ) {
+            LOGS_QDEBUG_4( "logs [FINDER] LogsCntFinder::addResult() - \
+re-using entry. contact id ", cntId, "cached=", entry->isCached() );
+            iter.remove();
+            addResult( entry );
+            reused = true;
+        }
+    }
+    
+    if ( !reused ) {
+        LogsCntEntry* entry = new LogsCntEntry( cntId );
+        addResult( entry );
+    }
+}
+
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::addResult()
+// -----------------------------------------------------------------------------
+//
+void LogsCntFinder::addResult( LogsCntEntry* entry )
+{
+    updateResult( entry );
+    mResults.append( entry );
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::updateResult()
+// -----------------------------------------------------------------------------
+//
+void LogsCntFinder::updateResult( LogsCntEntry* entry )
+{
+    if ( entry->isCached() ) {
+        entry->setHighlights( mCurrentPredictivePattern );
+        mCachedCounter++;
+    }
+}
+
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::resultsCount
+// -----------------------------------------------------------------------------
+//
+int LogsCntFinder::resultsCount() const
+{
+    return mResults.count();
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::resultAt
+// -----------------------------------------------------------------------------
+//
+const LogsCntEntry& LogsCntFinder::resultAt( int index )
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::resultAt()" )
+    LOGS_QDEBUG_2( "logs [FINDER] index=", index )
+    
+    LogsCntEntry* entry = mResults.at( index );
+    if ( !entry->isCached() ) {
+        LOGS_QDEBUG_2( "logs [FINDER] caching from DB cid=", entry->contactId() )
+        QContact contact = mContactManager->contact( entry->contactId() );
+        QContactName contactName = contact.detail( QContactName::DefinitionName );
+        entry->setFirstName( contactName.value( QContactName::FieldFirst ) );
+        entry->setLastName( contactName.value( QContactName::FieldLast ) );
+        QContactPhoneNumber contactPhoneNumber = 
+              contact.detail( QContactPhoneNumber::DefinitionName );
+        entry->setPhoneNumber( 
+              contactPhoneNumber.value( QContactPhoneNumber::FieldNumber ) );
+        QContactAvatar contactAvatar = contact.detail<QContactAvatar>();  
+        if (contactAvatar.subType().compare(
+        QLatin1String(QContactAvatar::SubTypeImage)) == 0 && 
+               !contactAvatar.avatar().isEmpty()) {
+                  entry->setAvatarPath(contactAvatar.avatar());
+              } 
+        
+        updateResult( entry );      
+    }
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::resultAt()" )
+    return *entry;
+}
+
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::insertEntry
+// -----------------------------------------------------------------------------
+//
+void LogsCntFinder::insertEntry( int index, LogsCntEntry* entry )
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::insertEntry()" )
+    LOGS_QDEBUG_4( "logs [FINDER] handle=", entry->handle()," to index ", index )
+    
+    mHistoryEvents.insert( index, entry );
+    
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::insertEntry()" )
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::getEntry
+// -----------------------------------------------------------------------------
+//
+LogsCntEntry* LogsCntFinder::getEntry( const LogsCntEntryHandle& handle ) const
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::getEntry()" )
+    return doGetEntry( mHistoryEvents, handle );      
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::doGetEntry
+// -----------------------------------------------------------------------------
+//
+LogsCntEntry* LogsCntFinder::doGetEntry( const LogsCntEntryList& list, 
+                                         const LogsCntEntryHandle& handle ) const
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::doGetEntry()" )
+    LOGS_QDEBUG_2( "logs [FINDER] handle= ", &handle )
+    
+    LogsCntEntry* entry = 0;
+    QListIterator<LogsCntEntry*> iter(list);
+    
+    while( iter.hasNext() && !entry ) {
+        LogsCntEntry* e = iter.next();
+        entry = e->handle() == &handle ? e : 0;
+    }
+    
+    LOGS_QDEBUG_2( "logs [FINDER] found=", (entry!=0) )
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::doGetEntry()" )
+    return entry;
+}
+
+// -----------------------------------------------------------------------------
+// LogsCntFinder::deleteEntry
+// -----------------------------------------------------------------------------
+//
+void LogsCntFinder::deleteEntry( const LogsCntEntryHandle& handle )
+{
+    LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::deleteEntry()" )
+    LOGS_QDEBUG_2( "logs [FINDER] handle= ", &handle )
+    
+    LogsCntEntry* toRemoveHistoryEv = doGetEntry( mHistoryEvents, handle );
+    mHistoryEvents.removeOne( toRemoveHistoryEv );
+    delete toRemoveHistoryEv;
+    
+    LOGS_QDEBUG( "logs [FINDER] <- LogsCntFinder::deleteEntry()" )
+    
+}
+
+
+
+