logsui/logscntfinder/src/logscntfinder.cpp
changeset 2 7119b73b84d6
parent 0 4a5361db8937
child 4 e52d42f9500c
equal deleted inserted replaced
0:4a5361db8937 2:7119b73b84d6
    13 *
    13 *
    14 * Description:
    14 * Description:
    15 *
    15 *
    16 */
    16 */
    17 
    17 
    18 #include <QListIterator>
       
    19 
       
    20 #include <qcontactdetailfilter.h>
    18 #include <qcontactdetailfilter.h>
    21 #include <qcontactphonenumber.h>
    19 #include <qcontactphonenumber.h>
    22 #include <qcontactname.h>
    20 #include <qcontactname.h>
    23 #include <qcontactmanager.h>
    21 #include <qcontactmanager.h>
    24 #include <qcontactavatar.h>
    22 #include <qcontactavatar.h>
    25 #include <QVector>
    23 
    26 
    24 #include "logscntentry.h"
    27 #include "logscntfinder.h"
    25 #include "logscntfinder.h"
    28 #include "logspredictivetranslator.h"
    26 #include "logspredictivetranslator.h"
    29 #include "logslogger.h"
    27 #include "logslogger.h"
    30 
    28 
    31 const int MaxPredSearchPatternLen = 15;
    29 const int MaxPredSearchPatternLen = 15;
    32 const QChar ZeroSepar('0');
    30 
    33 
    31 
    34 
       
    35 // -----------------------------------------------------------------------------
       
    36 // LogsCntEntry::richText()
       
    37 // -----------------------------------------------------------------------------
       
    38 //
       
    39 QString LogsCntText::richText( QString startTag, 
       
    40                                QString endTag ) const
       
    41 {
       
    42     QString str = text();
       
    43     if ( str.length() > 0 && highlights() > 0 ) {
       
    44         str.insert( highlights() , endTag );
       
    45         str.insert( 0, startTag );
       
    46     }
       
    47 
       
    48     return str;
       
    49     
       
    50 }
       
    51 
       
    52 // -----------------------------------------------------------------------------
       
    53 // LogsCntEntry::LogsCntEntry()
       
    54 // -----------------------------------------------------------------------------
       
    55 //
       
    56 LogsCntEntry::LogsCntEntry( LogsCntEntryHandle& handle, 
       
    57                             quint32 cid )
       
    58     : mType( EntryTypeHistory ), mCid( cid ), 
       
    59       mCached( true ),mHandle(&handle)
       
    60 {
       
    61     LogsCntText empty;
       
    62     mFirstName.append( empty );
       
    63     mLastName.append( empty );
       
    64     mAvatarPath = "";
       
    65 }
       
    66 
       
    67 // -----------------------------------------------------------------------------
       
    68 // LogsCntEntry::LogsCntEntry()
       
    69 // -----------------------------------------------------------------------------
       
    70 //
       
    71 LogsCntEntry::LogsCntEntry( quint32 cid )
       
    72     : mType( EntryTypeContact ), mCid( cid ), 
       
    73       mCached( false ),mHandle(0)
       
    74 {
       
    75     LogsCntText empty;
       
    76     mFirstName.append( empty );
       
    77     mLastName.append( empty );
       
    78     mAvatarPath = "";
       
    79 }
       
    80 
       
    81 // -----------------------------------------------------------------------------
       
    82 // copy LogsCntEntry::LogsCntEntry()
       
    83 // -----------------------------------------------------------------------------
       
    84 //
       
    85 LogsCntEntry::LogsCntEntry( const LogsCntEntry& entry )
       
    86     : mType(entry.mType),
       
    87       mCid(entry.mCid),
       
    88       mFirstName(entry.mFirstName),
       
    89       mLastName(entry.mLastName),
       
    90       mCached(entry.mCached),
       
    91       mHandle(entry.mHandle),
       
    92       mPhoneNumber(entry.mPhoneNumber),
       
    93       mAvatarPath(entry.mAvatarPath)
       
    94 {
       
    95 }
       
    96 
       
    97 // -----------------------------------------------------------------------------
       
    98 // LogsCntEntry::~LogsCntEntry()
       
    99 // -----------------------------------------------------------------------------
       
   100 //
       
   101 LogsCntEntry::~LogsCntEntry()
       
   102 {
       
   103 }
       
   104 
       
   105 // -----------------------------------------------------------------------------
       
   106 // LogsCntEntry::firstName()
       
   107 // -----------------------------------------------------------------------------
       
   108 //
       
   109 const LogsCntTextList& LogsCntEntry::firstName() const 
       
   110 {
       
   111     return mFirstName;
       
   112 }
       
   113 
       
   114 // -----------------------------------------------------------------------------
       
   115 // LogsCntEntry::lastName()
       
   116 // -----------------------------------------------------------------------------
       
   117 //
       
   118 const LogsCntTextList& LogsCntEntry::lastName() const
       
   119 {
       
   120     return mLastName;
       
   121 }
       
   122 
       
   123 // -----------------------------------------------------------------------------
       
   124 // LogsCntEntry::avatarPath()
       
   125 // -----------------------------------------------------------------------------
       
   126 //
       
   127 const QString& LogsCntEntry::avatarPath() const
       
   128 {
       
   129     return mAvatarPath;
       
   130 }
       
   131 
       
   132 // -----------------------------------------------------------------------------
       
   133 // LogsCntEntry::phoneNumber()
       
   134 // -----------------------------------------------------------------------------
       
   135 //
       
   136 const LogsCntText& LogsCntEntry::phoneNumber() const
       
   137 {
       
   138     return mPhoneNumber;
       
   139 }
       
   140 
       
   141 // -----------------------------------------------------------------------------
       
   142 // LogsCntEntry::speedDial()
       
   143 // -----------------------------------------------------------------------------
       
   144 //
       
   145 const QString& LogsCntEntry::speedDial() const
       
   146 {
       
   147     return mSpeedDial;
       
   148 }
       
   149 
       
   150 
       
   151 
       
   152 // -----------------------------------------------------------------------------
       
   153 // LogsCntEntry::contactId()
       
   154 // -----------------------------------------------------------------------------
       
   155 //
       
   156 quint32 LogsCntEntry::contactId() const
       
   157 {
       
   158     return mCid;
       
   159 }
       
   160 
       
   161 // -----------------------------------------------------------------------------
       
   162 // LogsCntEntry::handle()
       
   163 // -----------------------------------------------------------------------------
       
   164 //
       
   165 LogsCntEntryHandle* LogsCntEntry::handle() const
       
   166 {
       
   167     return mHandle;
       
   168 }
       
   169 
       
   170 // -----------------------------------------------------------------------------
       
   171 // LogsCntEntry::setFirstName()
       
   172 // -----------------------------------------------------------------------------
       
   173 //
       
   174 void LogsCntEntry::setFirstName( const QString& name ) 
       
   175 {
       
   176     mCached=true;
       
   177     mFirstName.clear();
       
   178     doSetText( name, mFirstName );
       
   179 }
       
   180 
       
   181 // -----------------------------------------------------------------------------
       
   182 // LogsCntEntry::setLastName()
       
   183 // -----------------------------------------------------------------------------
       
   184 //
       
   185 void LogsCntEntry::setLastName( const QString& name ) 
       
   186 {
       
   187     mCached=true;
       
   188     mLastName.clear();
       
   189     doSetText( name, mLastName );
       
   190 }
       
   191 
       
   192 // -----------------------------------------------------------------------------
       
   193 // LogsCntEntry::setAvatarPath()
       
   194 // -----------------------------------------------------------------------------
       
   195 //
       
   196 void LogsCntEntry::setAvatarPath( const QString& avatarpath ) 
       
   197 {
       
   198     mCached=true;
       
   199     mAvatarPath.clear();
       
   200     mAvatarPath = avatarpath;
       
   201 }
       
   202 
       
   203 // -----------------------------------------------------------------------------
       
   204 // LogsCntEntry::tokens()
       
   205 // -----------------------------------------------------------------------------
       
   206 //
       
   207 QStringList LogsCntEntry::tokens( const QString& source, 
       
   208                                   const QChar& separ ) const
       
   209 {
       
   210     QStringList target = source.split( separ, QString::SkipEmptyParts );
       
   211     if ( target.length() > 1 && separ == ZeroSepar ) {
       
   212         QString& first = target[0];
       
   213         QString& last = target[target.length()-1];
       
   214         padWithZeros( first, source, 0 );
       
   215         padWithZeros( last, source, last.length() );
       
   216     }
       
   217     return target;
       
   218     
       
   219 }
       
   220 
       
   221 
       
   222 // -----------------------------------------------------------------------------
       
   223 // LogsCntEntry::padWithLeadingZeros()
       
   224 // -----------------------------------------------------------------------------
       
   225 //
       
   226 void LogsCntEntry::padWithZeros( QString& token, 
       
   227                                  const QString& source, int padIndex ) const
       
   228 {
       
   229     const QChar* content = source.data();
       
   230     int index = !padIndex ? 0 : source.length()-1;
       
   231             
       
   232     while( index >= 0 && index < source.length() ) {
       
   233         if ( content[ index ] == ZeroSepar ) {
       
   234             token.insert( padIndex, ZeroSepar );
       
   235             index = !padIndex ? index+1 : index-1;
       
   236         } else {
       
   237             index = -1;
       
   238         }
       
   239     }
       
   240 }
       
   241 
       
   242 
       
   243 
       
   244 // -----------------------------------------------------------------------------
       
   245 // LogsCntEntry::doSetText()
       
   246 // -----------------------------------------------------------------------------
       
   247 //
       
   248 void LogsCntEntry::doSetText( const QString& text, LogsCntTextList& textlist ) 
       
   249 {
       
   250     QListIterator<QString> iter( tokens( text ) );
       
   251 
       
   252     while( iter.hasNext() ) {
       
   253         LogsCntText txt;
       
   254         txt.mText = iter.next();
       
   255         txt.mTranslatedText = 
       
   256             LogsPredictiveTranslator::instance()->translate( txt.mText );
       
   257         textlist.append( txt );
       
   258     }
       
   259     if ( textlist.count() == 0 ) {
       
   260         textlist.append( LogsCntText() );
       
   261     }
       
   262 }
       
   263 
       
   264 // -----------------------------------------------------------------------------
       
   265 // LogsCntEntry::setPhoneNumber()
       
   266 // -----------------------------------------------------------------------------
       
   267 //
       
   268 void LogsCntEntry::setPhoneNumber( const QString& number )
       
   269 {
       
   270     mCached=true;
       
   271     mPhoneNumber.mText = number;
       
   272 }
       
   273 
       
   274 // -----------------------------------------------------------------------------
       
   275 // LogsCntEntry::resetHighlights()
       
   276 // -----------------------------------------------------------------------------
       
   277 //
       
   278 void LogsCntEntry::resetHighlights( LogsCntTextList& nameArray )
       
   279 {
       
   280     QMutableListIterator<LogsCntText> names( nameArray ); 
       
   281     while( names.hasNext() ) {
       
   282         names.next().mHighlights = 0;
       
   283     }
       
   284     
       
   285 }
       
   286 
       
   287 
       
   288 // -----------------------------------------------------------------------------
       
   289 // LogsCntEntry::setHighlights()
       
   290 // -----------------------------------------------------------------------------
       
   291 //
       
   292 void LogsCntEntry::setHighlights( const QString& pattern )
       
   293 {
       
   294     resetHighlights( mFirstName );
       
   295     resetHighlights( mLastName );
       
   296     
       
   297     mPhoneNumber.mHighlights = 
       
   298             mPhoneNumber.text().startsWith( pattern ) &&
       
   299             mPhoneNumber.text().length() >= pattern.length() ?
       
   300             pattern.length(): 0;
       
   301     
       
   302     doSetHighlights( pattern, mFirstName );
       
   303     doSetHighlights( pattern, mLastName );
       
   304     
       
   305 }
       
   306 
       
   307 // -----------------------------------------------------------------------------
       
   308 // LogsCntEntry::doSetHighlights()
       
   309 // -----------------------------------------------------------------------------
       
   310 //
       
   311 void LogsCntEntry::doSetHighlights( const QString& pattern, 
       
   312                                     LogsCntTextList& nameArray )
       
   313 {
       
   314     
       
   315     LogsPredictiveTranslator* translator = 
       
   316             LogsPredictiveTranslator::instance();
       
   317     QMutableListIterator<LogsCntText> names( nameArray ); 
       
   318     bool hasZeros = pattern.contains( ZeroSepar );
       
   319     
       
   320     //simple
       
   321     while( names.hasNext() ) {
       
   322         LogsCntText& nameItem = names.next();
       
   323         nameItem.mHighlights = 
       
   324                 translator->startsWith( nameItem.mText, pattern, false );
       
   325     }
       
   326     
       
   327     //complex
       
   328     QStringList tokenArray = tokens( pattern, ZeroSepar );
       
   329     QListIterator<QString> patternArray( tokenArray  );
       
   330     while( hasZeros && patternArray.hasNext() ) {
       
   331         QString patternItem = patternArray.next();
       
   332         names.toFront();
       
   333         while( names.hasNext() ) {
       
   334             LogsCntText& nameItem = names.next();
       
   335             int matchSize = translator->startsWith( nameItem.mText, 
       
   336                                                     patternItem, !hasZeros );
       
   337             nameItem.mHighlights = matchSize > nameItem.mHighlights ?
       
   338                                    matchSize : nameItem.mHighlights; 
       
   339         }
       
   340     }
       
   341 }
       
   342 
       
   343 // -----------------------------------------------------------------------------
       
   344 // LogsCntEntry::setSpeedDial()
       
   345 // -----------------------------------------------------------------------------
       
   346 //
       
   347 void LogsCntEntry::setSpeedDial( const QString& number )
       
   348 {
       
   349     mSpeedDial = number;
       
   350 }
       
   351 
       
   352 
       
   353 
       
   354 // -----------------------------------------------------------------------------
       
   355 // LogsCntEntry::match()
       
   356 // -----------------------------------------------------------------------------
       
   357 //
       
   358 bool LogsCntEntry::match( const QString& pattern ) const
       
   359 {
       
   360     bool match = false;
       
   361     
       
   362     //direct match with phone number is enough
       
   363     match = mPhoneNumber.text().startsWith( pattern ) ||
       
   364             doSimpleMatch( pattern );
       
   365     
       
   366     if ( !match && pattern.contains( ZeroSepar ) ) {
       
   367         QStringList patternArray = tokens( pattern, ZeroSepar );
       
   368         match = doComplexMatch( patternArray );
       
   369     }
       
   370     
       
   371     return match;
       
   372 }
       
   373 
       
   374 // -----------------------------------------------------------------------------
       
   375 // LogsCntEntry::doSimpleMatch()
       
   376 // -----------------------------------------------------------------------------
       
   377 //
       
   378 bool LogsCntEntry::doSimpleMatch( const QString& pattern ) const
       
   379 {
       
   380     LogsCntTextList nameArray = mFirstName + mLastName; //with empties
       
   381     QListIterator<LogsCntText> names( nameArray ); 
       
   382     int matchCount = 0;
       
   383 
       
   384     while( names.hasNext() && !matchCount ) {
       
   385         matchCount = (int)names.next().mTranslatedText.startsWith( pattern );
       
   386     }
       
   387 
       
   388     return matchCount > 0;
       
   389 }
       
   390 
       
   391 
       
   392 // -----------------------------------------------------------------------------
       
   393 // LogsCntEntry::doComplexMatch()
       
   394 // -----------------------------------------------------------------------------
       
   395 //
       
   396 bool LogsCntEntry::doComplexMatch( QStringList patternArray ) const
       
   397 {
       
   398     const bool zero = false;
       
   399 
       
   400     LogsCntTextList nameArray = mFirstName + mLastName; //with empties
       
   401 
       
   402     int targetMatchCount = patternArray.count();
       
   403     int namesCount = nameArray.count();
       
   404 
       
   405     //if pattern has more tokens than name(s), it is a missmatch
       
   406     if ( namesCount < targetMatchCount ) {
       
   407         return false;
       
   408     }
       
   409 
       
   410     QListIterator<LogsCntText> names( nameArray ); 
       
   411     QListIterator<QString> patterns( patternArray );
       
   412     QVector<bool> matchVector(targetMatchCount, zero );
       
   413     int currentPattern = 0;
       
   414     int matchCount = 0;
       
   415     bool match = false;
       
   416     
       
   417     while( names.hasNext() && matchCount < targetMatchCount ) {
       
   418         LogsCntText name = names.next();
       
   419         currentPattern = 0;
       
   420         patterns.toFront();
       
   421         match = false;
       
   422         while ( !name.mText.isEmpty() && 
       
   423                  patterns.hasNext() && !match ) {
       
   424             QString pattern = patterns.next();
       
   425             //unique match check
       
   426             if ( !matchVector.at( currentPattern ) ) {
       
   427                 match = matchVector[ currentPattern ] 
       
   428                       = name.mTranslatedText.startsWith( pattern );
       
   429                 matchCount = match ? matchCount+1 : matchCount;
       
   430             }
       
   431             currentPattern++;
       
   432         }
       
   433     }
       
   434     return matchCount >= targetMatchCount;
       
   435 
       
   436     }
       
   437     
       
   438     
       
   439 
       
   440 // -----------------------------------------------------------------------------
       
   441 // LogsCntEntry::isCached()
       
   442 // -----------------------------------------------------------------------------
       
   443 //
       
   444 bool LogsCntEntry::isCached() const
       
   445 {
       
   446     return mCached;
       
   447 }
       
   448 
       
   449 
       
   450 // -----------------------------------------------------------------------------
       
   451 // LogsCntEntry::type()
       
   452 // -----------------------------------------------------------------------------
       
   453 //
       
   454 LogsCntEntry::EntryType LogsCntEntry::type() const
       
   455 {
       
   456     return mType;
       
   457 }
       
   458 
    32 
   459 // -----------------------------------------------------------------------------
    33 // -----------------------------------------------------------------------------
   460 // LogsCntFinder::LogsCntFinder()
    34 // LogsCntFinder::LogsCntFinder()
   461 // -----------------------------------------------------------------------------
    35 // -----------------------------------------------------------------------------
   462 //
    36 //
   509 bool LogsCntFinder::isProgressivePattern( const QString& pattern ) const
    83 bool LogsCntFinder::isProgressivePattern( const QString& pattern ) const
   510 {
    84 {
   511     //"" -> XXX not progressive
    85     //"" -> XXX not progressive
   512     //XX -> YY not progressive
    86     //XX -> YY not progressive
   513     //XXX -> YY not progressive
    87     //XXX -> YY not progressive
   514     int prevPatternLen = mCurrentPredictivePattern.length();
    88     int prevPatternLen = mCurrentInputPattern.length();
   515     return prevPatternLen > 0 &&  
    89     return prevPatternLen > 0 &&  
   516            pattern.length() - prevPatternLen > 0;
    90            pattern.length() - prevPatternLen > 0;
   517 }
    91 }
   518 
    92 
   519 
    93 
   536     bool patternIsProgressive = isProgressivePattern( pattern );
   110     bool patternIsProgressive = isProgressivePattern( pattern );
   537     bool resultsAreAllCached = resultsCount() > 0 && 
   111     bool resultsAreAllCached = resultsCount() > 0 && 
   538                                mCachedCounter == resultsCount();
   112                                mCachedCounter == resultsCount();
   539     bool nothingToDo = resultsCount() == 0 &&
   113     bool nothingToDo = resultsCount() == 0 &&
   540                        patternIsProgressive;
   114                        patternIsProgressive;
   541                                            
   115     int patternSeparators = 
       
   116             LogsPredictiveTranslator::instance()->hasPatternSeparators( 
       
   117                                                         mCurrentInputPattern );
       
   118     bool doCacheQuery =  patternSeparators != mCurrentInputPattern.length() && 
       
   119                         ( ( patternIsProgressive && resultsAreAllCached ) || nothingToDo );
       
   120             
   542     LOGS_QDEBUG_2( "logs [FINDER] patternIsProgressive = ", patternIsProgressive )
   121     LOGS_QDEBUG_2( "logs [FINDER] patternIsProgressive = ", patternIsProgressive )
   543     LOGS_QDEBUG_2( "logs [FINDER] resultsAreAllCached = ", resultsAreAllCached )
   122     LOGS_QDEBUG_2( "logs [FINDER] resultsAreAllCached = ", resultsAreAllCached )
   544     LOGS_QDEBUG_2( "logs [FINDER] nothingToDo = ", nothingToDo )
   123     LOGS_QDEBUG_2( "logs [FINDER] nothingToDo = ", nothingToDo )
   545     LOGS_QDEBUG_2( "logs [FINDER] cachedCounter = ", mCachedCounter )
   124     LOGS_QDEBUG_2( "logs [FINDER] cachedCounter = ", mCachedCounter )
   546     
   125     LOGS_QDEBUG_2( "logs [FINDER] patternSeparators = ", patternSeparators )
   547     mCurrentPredictivePattern = pattern;
   126     LOGS_QDEBUG_2( "logs [FINDER] doCacheQuery = ", doCacheQuery )
       
   127     
       
   128     setCurrentPattern( pattern );
   548     
   129     
   549     if ( mCurrentPredictivePattern.isEmpty() ) {
   130     if ( mCurrentPredictivePattern.isEmpty() ) {
   550         qDeleteAll( mResults );
   131         qDeleteAll( mResults );
   551         mResults.clear();
   132         mResults.clear();
   552         mCachedCounter = 0;
   133         mCachedCounter = 0;
   553     } else if ( ( patternIsProgressive &&
   134     } else if ( doCacheQuery ) {
   554                   resultsAreAllCached ) ||
       
   555                 nothingToDo ) {
       
   556         doPredictiveCacheQuery();
   135         doPredictiveCacheQuery();
   557     } else {        
   136     } else {        
   558         mCachedCounter = 0;
   137         mCachedCounter = 0;
   559         LogsCntEntryList recentResults = mResults;
   138         LogsCntEntryList recentResults = mResults;
   560         mResults.clear();
   139         mResults.clear();
   596 {
   175 {
   597     LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::doPredictiveContactQuery()" )
   176     LOGS_QDEBUG( "logs [FINDER] -> LogsCntFinder::doPredictiveContactQuery()" )
   598     QContactDetailFilter df;
   177     QContactDetailFilter df;
   599     df.setDetailDefinitionName( QContactName::DefinitionName );
   178     df.setDetailDefinitionName( QContactName::DefinitionName );
   600     df.setMatchFlags( QContactFilter::MatchKeypadCollation );
   179     df.setMatchFlags( QContactFilter::MatchKeypadCollation );
   601     df.setValue( mCurrentPredictivePattern );
   180     df.setValue( mCurrentInputPattern );
   602     QList<QContactLocalId> cntIds;
   181     QList<QContactLocalId> cntIds;
   603     LOGS_QDEBUG( "logs [FINDER] about to call contacts manager" )
   182     LOGS_QDEBUG( "logs [FINDER] about to call contacts manager" )
   604     
   183     
   605     cntIds = mContactManager->contactIds( df );
   184     cntIds = mContactManager->contactIds( df );
   606     LOGS_QDEBUG_2( "logs [FINDER] number of matched contacts =", cntIds.count() )
   185     LOGS_QDEBUG_2( "logs [FINDER] number of matched contacts =", cntIds.count() )
   681         entry->setHighlights( mCurrentPredictivePattern );
   260         entry->setHighlights( mCurrentPredictivePattern );
   682         mCachedCounter++;
   261         mCachedCounter++;
   683     }
   262     }
   684 }
   263 }
   685 
   264 
       
   265 
       
   266 // -----------------------------------------------------------------------------
       
   267 // LogsCntFinder::setCurrentPattern()
       
   268 // -----------------------------------------------------------------------------
       
   269 //
       
   270 void LogsCntFinder::setCurrentPattern( const QString& pattern )
       
   271 {
       
   272     LogsPredictiveTranslator* translator = 
       
   273             LogsPredictiveTranslator::instance();
       
   274     
       
   275     mCurrentInputPattern = pattern;
       
   276     mCurrentPredictivePattern = translator->translate( mCurrentInputPattern );
       
   277     
       
   278 }
   686 
   279 
   687 // -----------------------------------------------------------------------------
   280 // -----------------------------------------------------------------------------
   688 // LogsCntFinder::resultsCount
   281 // LogsCntFinder::resultsCount
   689 // -----------------------------------------------------------------------------
   282 // -----------------------------------------------------------------------------
   690 //
   283 //