phonebookui/Phonebook/View/src/CPbkFindPrimitives.cpp
changeset 0 e686773b3f54
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/View/src/CPbkFindPrimitives.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,329 @@
+/*
+* Copyright (c) 2002 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: 
+*      MPbkFindPrimitives implementation for european Phonebook.
+*
+*/
+
+
+// INCLUDE FILES
+#include "CPbkFindPrimitives.h"
+#include <MPbkContactNameFormat.h>
+#include <MPbkFieldData.h>
+#include <PbkViewContactFieldDataAdapter.h>
+#include <PbkEngUtils.h>
+//#define PBK_ENABLE_DEBUG_PRINT
+#include <PbkDebug.h>
+
+namespace {
+
+const TInt KMinTextBufSize = 32;
+
+// ================= LOCAL FUNCTIONS =======================
+
+/** 
+ * Normalizes text by converting all sequences of space characters to a 
+ * single space.
+ *
+ * @param aBuffer   buffer where the normalized text will be stored. The buffer
+ *                  will be reallocated if necessary.
+ * @param aText     the text to be normalized.
+ * @return normalized text.
+ */
+const TDesC& NormalizeL(HBufC*& aBuffer, const TDesC& aText)
+    {
+    const TInt textLength = aText.Length();
+    aBuffer = PbkEngUtils::AllocL(aBuffer, Max(textLength,KMinTextBufSize));
+    TPtr bufPtr(aBuffer->Des());
+    bufPtr.Zero();
+    TBool uncommittedSpace = EFalse;
+    for (TInt i=0; i < textLength; ++i)
+        {
+        TChar ch(aText[i]);
+        if (ch.IsSpace())
+            {
+            uncommittedSpace = ETrue;
+            }
+        else
+            {
+            if (uncommittedSpace)
+                {
+                bufPtr.Append(' ');
+                uncommittedSpace = EFalse;
+                }
+            bufPtr.Append(ch);
+            }
+        }
+    // copy final trailing space
+    if (uncommittedSpace)
+        {
+        bufPtr.Append(' ');
+        }
+
+    return (*aBuffer);
+    }
+
+}
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+inline CPbkFindPrimitives::CPbkFindPrimitives(MPbkContactNameFormat& aNameFormatter) :
+    iNameFormatter(aNameFormatter)
+    {
+    }
+
+CPbkFindPrimitives* CPbkFindPrimitives::NewL(MPbkContactNameFormat& aNameFormatter)
+    {
+    CPbkFindPrimitives* self = new(ELeave) CPbkFindPrimitives(aNameFormatter);
+    return self;
+    }
+
+CPbkFindPrimitives::~CPbkFindPrimitives()
+    {
+    delete iFindText;
+    delete iFieldText;
+    delete iInitialFindText;
+    iViewSortOrder.Close();
+    }
+
+inline TBool CPbkFindPrimitives::IsWordSeparator(TChar aCh)
+    {
+    return aCh.IsSpace();
+    }
+
+void CPbkFindPrimitives::SetContactViewSortOrderL
+        (const RContactViewSortOrder& aSortOrder)
+    {
+    iViewSortOrder.CopyL(aSortOrder);
+    }
+
+/**
+ * Stores the initial find text.
+ *
+ * @see InitialFindText
+ * @see MatchesInitialFindText
+ */
+inline void CPbkFindPrimitives::StoreInitialFindTextL
+        (const TDesC& aInitialFindText)
+    {
+    iInitialFindText = PbkEngUtils::CopyL
+        (iInitialFindText, aInitialFindText, aInitialFindText.Length()+1);
+    TPtr ptr(iInitialFindText->Des());
+    ptr.Append('*');
+    }
+
+/**
+ * Returns the initial find text passed to StoreInitialFindTextL.
+ *
+ * @see StoreInitialFindTextL
+ * @see MatchesInitialFindText
+ */
+inline TPtrC CPbkFindPrimitives::InitialFindText() const
+    {
+    TPtrC result;
+    if (iInitialFindText)
+        {
+        // Strip trailing '*' appended for matching in StoreInitialFindTextL
+        return iInitialFindText->Left(iInitialFindText->Length()-1);
+        }
+    return result;
+    }
+
+/**
+ * Matches (Using TDesC::MatchC) the initial find text against aText. Returns
+ * ETrue if aText matches the initial find text.
+ *
+ * @see StoreInitialFindTextL
+ * @see InitialFindText
+ */
+inline TBool CPbkFindPrimitives::DoMatchesInitialFindText
+        (const TDesC& aText) const
+    {
+    if (iInitialFindText)
+        {
+        return (aText.MatchC(*iInitialFindText) != KErrNotFound);
+        }
+    return EFalse;
+    }
+
+
+/**
+ * Does a prefix matching of aFindText to aContactData. Returns ETrue if 
+ * the find text matches completely to contact data.
+ *
+ * @param aContactData  contact data to match against. Matching is done in
+ *                      field order.
+ * @param aFindText     normalized (see NormalizeL) find text.
+ */
+inline TBool CPbkFindPrimitives::IsMatchL
+        (const MPbkFieldDataArray& aContactData, const TDesC& aFindText)
+    {
+    /* Consuming of findtext is done in the sort order */
+    TPtrC findText(aFindText);
+    const TInt fieldCount = aContactData.PbkFieldCount();
+    for (TInt i=0; i < fieldCount; ++i)
+        {
+        const TDesC& fieldText = NormalizeL(iFieldText, aContactData.PbkFieldAt(i).PbkFieldText());
+        const TInt fieldTextLength = fieldText.Length();
+        // find word starts from fieldText
+        TInt cursor = 0;
+        TInt wordStart = 0;
+        while (cursor < fieldTextLength)
+            {
+            TBool lastCharWasSpace = EFalse;
+            TChar cursorChar(fieldText[cursor]);
+            if (IsWordSeparator(cursorChar))
+                {
+                TPtrC word(&fieldText[wordStart], fieldTextLength-wordStart);
+                TInt matchLen = Min(word.Length(), findText.Length());
+                if (word.Left(matchLen).MatchC(findText.Left(matchLen)) != KErrNotFound)
+                    {
+                    // Require space in find text between fields
+                    if (matchLen < findText.Length())
+                        {
+                        if (TChar(findText[matchLen]).IsSpace() && 
+                            i < fieldCount-1)
+                            {
+                            // Skip space
+                            ++matchLen;
+                            }
+                        else
+                            {
+                            return EFalse;
+                            }
+                        }
+                    // Consume findText
+                    findText.Set(findText.Mid(matchLen));
+                    }
+                lastCharWasSpace = ETrue;
+                }
+            ++cursor;
+            if (lastCharWasSpace)
+                {
+                wordStart = cursor;
+                }
+            }
+
+        if (cursor == fieldTextLength && wordStart != cursor)
+            {
+            TPtrC word(&fieldText[wordStart], fieldTextLength-wordStart);
+            TInt matchLen = Min(word.Length(), findText.Length());
+            if (word.Left(matchLen).MatchC(findText.Left(matchLen)) != KErrNotFound)
+                {
+                // Require space in find text between fields
+                if (matchLen < findText.Length())
+                    {
+                    if (TChar(findText[matchLen]).IsSpace() && 
+                        i < fieldCount-1)
+                        {
+                        // Skip space
+                        ++matchLen;
+                        }
+                    else
+                        {
+                        return EFalse;
+                        }
+                    }
+                // Consume findText
+                findText.Set(findText.Mid(matchLen));
+                }
+            }
+        }
+    // Find text must be fully consumed for a match
+    return (findText.Length() == 0);
+    }
+
+
+/**
+ * Converts aViewContact to MPbkFieldDataArray and calls 
+ * IsMatchL(const MPbkFieldDataArray& aContactData, const TDesC& aFindText).
+ */
+TBool CPbkFindPrimitives::IsMatchL
+        (const CViewContact& aViewContact, const TDesC& aFindText)
+    {
+    // Convert aViewContact to MPbkFieldDataArray
+    const TPbkViewContactFieldDataArray contactData
+        (aViewContact, iViewSortOrder);
+    
+    // Filter contactData to contain only fields used in find
+    // (same fields than in used in title)
+    const MPbkFieldDataArray& titleData = 
+        iNameFormatter.FilterContactTitleFields(contactData);
+    
+    // Do matching
+    return IsMatchL(titleData, aFindText);
+    }
+
+TBool CPbkFindPrimitives::IsFindMatchL
+        (const CViewContact& aViewContact, const TDesC& aFindText)
+    {
+    // Normalize aFindText by removing all extra spaces
+    const TDesC& findText = NormalizeL(iFindText,aFindText);
+
+    // Do matching
+    return IsMatchL(aViewContact, findText);
+    }
+
+void CPbkFindPrimitives::GetInitialMatchesL
+        (CContactViewBase& aView,
+        const TDesC& aFindText,
+        RPointerArray<CViewContact>& aMatchedContacts)
+    {
+    // Make first match with CContactViewBase::ContactsMatchingPrefixL
+    MDesCArray* findWords = PbkEngUtils::BreakInWordsLC
+        (aFindText, IsWordSeparator);
+	aView.ContactsMatchingPrefixL(*findWords, aMatchedContacts);
+    CleanupStack::PopAndDestroy();  // findWords
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkFindPrimitives::GetInitialMatchesL(%S): contact model returned %d matches"), 
+        &aFindText, aMatchedContacts.Count());
+
+    StoreInitialFindTextL(aFindText);
+
+    // Filter away contacts that do not fullfill this implementation's criteria
+    // like matching company name entries.
+    const TDesC& normFindText = NormalizeL(iFindText, aFindText);
+    for (TInt i=aMatchedContacts.Count()-1; i >= 0; --i)
+        {
+        CViewContact* contact = aMatchedContacts[i];
+        if (!IsMatchL(*contact, normFindText))
+            {
+            aMatchedContacts.Remove(i);
+            delete contact;
+            }
+        }    
+    }
+
+TBool CPbkFindPrimitives::MatchesInitialFindTextL(const TDesC& aText)
+    {
+    // NOTE: This must work the same way as cntmodel's matching! Otherwise
+    // we get problems in hungarian or czech matching with double-characters.
+    // The main problem case is in CFindState::SetFindTextL(). If you
+    // make this work differently from cntmodel's match, make sure
+    // it still works with hungarian "gy" or czech "ch" and "agy" etc...
+    return DoMatchesInitialFindText(aText);
+    }
+
+TBool CPbkFindPrimitives::MatchesInitialFindTextL(const CViewContact& aViewContact)
+    {
+    TPtrC findText(InitialFindText());
+    if (findText.Length() > 0)
+        {
+        return IsMatchL(aViewContact,findText);
+        }
+    return EFalse;
+    }
+
+
+// End of File