uifw/AvKon/src/AknSmileyModel.cpp
branchRCL_3
changeset 56 d48ab3b357f1
parent 55 aecbbf00d063
child 72 a5e7a4f63858
--- a/uifw/AvKon/src/AknSmileyModel.cpp	Tue Aug 31 15:28:30 2010 +0300
+++ b/uifw/AvKon/src/AknSmileyModel.cpp	Wed Sep 01 12:16:19 2010 +0100
@@ -15,7 +15,6 @@
 *
 */
 
-
 #include <barsread.h>
 #include <AknUtils.h>
 #include <aknlayoutscalable_avkon.cdl.h>
@@ -23,12 +22,15 @@
 #include <centralrepository.h>
 #include <AvkonInternalCRKeys.h>
 
+#include <AknBidiTextUtils.h>
+#include <AknPanic.h>
+
 #include <smiley.rsg>
 #include <smiley.mbg>
 
 #include "AknSmileyModel.h"
 #include "AknSmileyImage.h"
-
+#include "akntrace.h"
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 // TSmileyIconInfo
@@ -40,21 +42,17 @@
     }
 
 TSmileyIconInfo::TSmileyIconInfo(const TSmileyIconInfo& aInfo) : 
-iName(aInfo.iName), 
-iId(aInfo.iId), 
 iSkinItemID(aInfo.iSkinItemID), 
-iDefaultThumbnailID(aInfo.iDefaultThumbnailID), 
-iDefaultAnimationID(aInfo.iDefaultAnimationID)
+iDefaultStillImageID(aInfo.iDefaultStillImageID), 
+iDefaultAnimationImageID(aInfo.iDefaultAnimationImageID)
     {
     }
 
 void TSmileyIconInfo::Reset()
     {
-    iName.Zero();
-    iId = 0;
     iSkinItemID.Set(0, 0);
-    iDefaultThumbnailID = 0;
-    iDefaultAnimationID = 0;
+    iDefaultStillImageID = 0;
+    iDefaultAnimationImageID = 0;
     }
 
 
@@ -63,76 +61,84 @@
 // CSmileyIcon
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-CSmileyIcon* CSmileyIcon::NewL(const TSmileyIconInfo& aInfo, MSmileyIconObserver* aObserver)
+CSmileyIcon* CSmileyIcon::NewL(const TSmileyIconInfo& aInfo, MAknSmileyObserver* aObserver)
     {
-    CSmileyIcon* self = new (ELeave) CSmileyIcon(aInfo, aObserver);
+    CSmileyIcon* self = new (ELeave) CSmileyIcon(aObserver);
     CleanupStack::PushL(self);
-    self->ConstructL();
+    self->ConstructL(aInfo);
     CleanupStack::Pop(); // self;
     return self;
     }
 
-void CSmileyIcon::ConstructL()
+void CSmileyIcon::ConstructL(const TSmileyIconInfo& aInfo)
     {
-    iThumbnailImage = CSmileyImage::NewL(iInfo.iSkinItemID, iInfo.iDefaultThumbnailID, FALSE, this);
+    iIndex = aInfo.iIndex;
+    
+    iStillImage = CSmileyImage::NewL(aInfo.iSkinItemID, aInfo.iDefaultStillImageID, EFalse, this);
     
-    if(iInfo.iSkinItemID.iMinor==0 && iInfo.iDefaultAnimationID>0)
+    if(aInfo.iSkinItemID.iMinor==0 && aInfo.iDefaultAnimationImageID>0)
         {
-        iAnimationImage = CSmileyImage::NewL(iInfo.iSkinItemID, iInfo.iDefaultAnimationID, TRUE, this);
+        TAknsItemID nullID;
+        nullID.Set(0, 0);
+        iAnimationImage = CSmileyImage::NewL(nullID, aInfo.iDefaultAnimationImageID, ETrue, this);
         }
     }
 
-CSmileyIcon::CSmileyIcon(const TSmileyIconInfo& aInfo, MSmileyIconObserver* aObserver) : 
-iInfo(aInfo), iSmileyIconObserver(aObserver)
+CSmileyIcon::CSmileyIcon(MAknSmileyObserver* aObserver) : iSmileyIconObserver(aObserver)
     {
     }
 
 CSmileyIcon::~CSmileyIcon()
     {
-    delete iThumbnailImage;
+    delete iStillImage;
     delete iAnimationImage;
-    }
-
-TBool CSmileyIcon::ReadyToDraw() const
-    {
-    TBool thumbnailCanDraw = iThumbnailImage->ReadyToDraw();
-    TBool animationCanDraw = iAnimationImage ? iAnimationImage->ReadyToDraw() : FALSE;
     
-    return (thumbnailCanDraw || animationCanDraw);
+    iTextArray.Close();
+    iCodeArray.Close();
     }
 
 const CFbsBitmap* CSmileyIcon::Image() const
     {
-    if(ShouldShowAnimation())
+    if(AnimationImageIsReadyToDraw())
         {
         return iAnimationImage->Image();
         }
     else
         {
-        return iThumbnailImage->Image();
+        return iStillImage->Image();
         }
     }
 
 const CFbsBitmap* CSmileyIcon::Mask() const
     {
-    if(ShouldShowAnimation())
+    if(AnimationImageIsReadyToDraw())
         {
         return iAnimationImage->Mask();
         }
     else
         {
-        return iThumbnailImage->Mask();
+        return iStillImage->Mask();
         }
     }
 
-void CSmileyIcon::LoadThumbnailL()
+TBool CSmileyIcon::ReadyToDraw() const
     {
-    iThumbnailImage->LoadL();
+    return StillImageIsReadyToDraw() || AnimationImageIsReadyToDraw();
     }
 
-TBool CSmileyIcon::ThumbnailReady() const
+void CSmileyIcon::SetSize(const TSize& aSize)
     {
-    return iThumbnailImage->ReadyToDraw();
+    iStillImage->SetSize(aSize);
+    
+    if(iAnimationImage)
+        {
+        iAnimationImage->SetSize(aSize);
+        }
+    }
+
+const TSize& CSmileyIcon::Size() const
+    {
+    return iStillImage->Size();
     }
 
 void CSmileyIcon::PlayAnimationL(TInt aRepeat, TInt aDelay)
@@ -151,38 +157,86 @@
         }
     }
 
-void CSmileyIcon::SetSize(const TSize& aSize)
+void CSmileyIcon::BitmapChanged(CSmileyImage* aSmileyImage, CFbsBitmap* /*aBitmap*/)
     {
-    iThumbnailImage->SetSize(aSize);
-    
-    if(iAnimationImage)
+    if(aSmileyImage == iStillImage)
         {
-        iAnimationImage->SetSize(aSize);
+        if(iSmileyIconObserver) iSmileyIconObserver->SmileyStillImageLoaded(this);
+        }
+    else
+        {
+        if(iSmileyIconObserver) iSmileyIconObserver->SmileyAnimationChanged(this);
         }
     }
 
-const TSize& CSmileyIcon::Size() const
+TInt CSmileyIcon::Index() const
     {
-    return iThumbnailImage->Size();
+    return iIndex;
     }
 
-void CSmileyIcon::BitmapChanged(CSmileyImage* aSmileyImage, CFbsBitmap* /*aBitmap*/)
+void CSmileyIcon::LoadStillImageL(TInt aDelay)
     {
-    if(aSmileyImage == iThumbnailImage)
-        {
-        if(iSmileyIconObserver) iSmileyIconObserver->ThumbnailLoaded(this);
-        }
-    else
-        {
-        if(iSmileyIconObserver) iSmileyIconObserver->AnimationChanged(this);
-        }
+    iStillImage->LoadL(0, aDelay);
     }
 
-TBool CSmileyIcon::ShouldShowAnimation() const
+TBool CSmileyIcon::StillImageIsReadyToDraw() const
+    {
+    return iStillImage->ReadyToDraw();
+    }
+
+TBool CSmileyIcon::AnimationImageIsReadyToDraw() const
     {
     return (iAnimationImage && iAnimationImage->ReadyToDraw());
     }
 
+void CSmileyIcon::AddVariant(const TDesC& aText, TChar aBaseCode)
+    {
+    TPtrC ptr(aText);
+    TUint16 baseCode = aBaseCode;
+
+    while(ptr.Length())
+        {
+        TInt left = ptr.Find(_L(" "));
+        TInt right = ptr.Length() - left - 1;
+        if(left == KErrNotFound)
+            {
+            left = ptr.Length();
+            right = 0;
+            }
+
+        iTextArray.Append(ptr.Left(left));
+        ptr.Set(ptr.Right(right));
+        iCodeArray.Append(baseCode++);
+        }
+    }
+
+TInt CSmileyIcon::VariantCount() const
+    {
+    return iTextArray.Count();
+    }
+const TDesC& CSmileyIcon::Text(TInt aVariant) const
+    {
+    if(aVariant>=0 && aVariant<VariantCount())
+        {
+        return iTextArray[aVariant];
+        }
+    else
+        {
+        return KNullDesC;
+        }
+    }
+
+TChar CSmileyIcon::Code(TInt aVariant) const
+    {
+    if(aVariant>=0 && aVariant<VariantCount())
+        {
+        return iCodeArray[aVariant];
+    }
+    else
+        {
+        return 0;
+        }
+    }
 
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -196,15 +250,16 @@
 
 CSmileyTnumbnailAsynLoader::~CSmileyTnumbnailAsynLoader()
     {
-    iTaskArray.Close();
+    iLoadingTaskArray.Close();
     }
 
 void CSmileyTnumbnailAsynLoader::AddTaskL(CSmileyIcon* aSmileyIcon)
     {
     if(aSmileyIcon)
         {
-        iTaskArray.Append(aSmileyIcon);
-        if(!iIsLoading)
+        TBool isIdel = (TaskCount() == 0);
+        iLoadingTaskArray.Append(aSmileyIcon);
+        if(isIdel)
             {
             DoNextTaskL();
             }
@@ -213,45 +268,184 @@
 
 void CSmileyTnumbnailAsynLoader::DiscardAll()
     {
-    iTaskArray.Reset();
+    iLoadingTaskArray.Reset();
     }
 
 TInt CSmileyTnumbnailAsynLoader::TaskCount() const
     {
-    return iTaskArray.Count();
+    return iLoadingTaskArray.Count();
     }
 
 void CSmileyTnumbnailAsynLoader::DoNextTaskL()
     {
-    TInt count = TaskCount();
-    if(count > 0)
+    if(TaskCount() > 0)
         {
-        CSmileyIcon* icon = iTaskArray[0];
-        iTaskArray.Remove(0);
+        CSmileyIcon* icon = iLoadingTaskArray[0];
+        iLoadingTaskArray.Remove(0);
         
-        if(icon->ThumbnailReady())
+        if(icon->StillImageIsReadyToDraw())
             {
             DoNextTaskL();
             }
         else
             {
-            icon->LoadThumbnailL();
-            iIsLoading = TRUE;
+            icon->LoadStillImageL();
             }
         }
+    }
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// CSmileyTextTreeNode
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+NONSHARABLE_CLASS(CSmileyTextTreeNode) : public CBase
+    {
+public:
+    CSmileyTextTreeNode(TChar aChar);
+    ~CSmileyTextTreeNode();
+
+    TChar Char() const;
+
+    CSmileyTextTreeNode* AddTreeL(const TDesC& aText, TChar aCode);
+    TInt ChildCount() const;
+    CSmileyTextTreeNode* Child(TInt aIndex) const;
+    CSmileyTextTreeNode* Child(TChar aChar) const;
+    
+private:
+    CSmileyTextTreeNode* AddChildAscendingL(TChar aChar);
+    
+private:
+    TChar   iChar;
+    
+    typedef CArrayPtrFlat<CSmileyTextTreeNode> CSmileyTextTreeNodeArrayPtrFlat;
+    CSmileyTextTreeNodeArrayPtrFlat* iChildArray;
+    
+    };
+
+
+CSmileyTextTreeNode::CSmileyTextTreeNode(TChar aChar) : iChar(aChar)
+    {
+    }
+
+CSmileyTextTreeNode::~CSmileyTextTreeNode()
+    {
+    if(iChildArray)
+        {
+        iChildArray->ResetAndDestroy();
+        delete iChildArray;
+        }
+    }
+
+TChar CSmileyTextTreeNode::Char() const
+    {
+    return iChar;
+    }
+
+
+
+CSmileyTextTreeNode* CSmileyTextTreeNode::AddTreeL(const TDesC& aText, TChar aCode)
+    {
+    TInt length = aText.Length();
+    if(length > 0)
+        {
+        CSmileyTextTreeNode* node = AddChildAscendingL(aText[0]);
+        return node->AddTreeL(aText.Right(length-1), aCode);
+        }
     else
         {
-        iIsLoading = FALSE;
+        return AddChildAscendingL(aCode);
+        }
+    }
+
+TInt CSmileyTextTreeNode::ChildCount() const
+    {
+    if(iChildArray)
+        {
+        return iChildArray->Count();
+        }
+    else
+        {
+        return 0;
+        }
+    }
+
+CSmileyTextTreeNode* CSmileyTextTreeNode::Child(TInt aIndex) const
+    {
+    if(aIndex>=0 && aIndex<ChildCount())
+        {
+        return iChildArray->At(aIndex);
+        }
+    else
+        {
+        return NULL;
         }
     }
 
+CSmileyTextTreeNode* CSmileyTextTreeNode::Child(TChar aChar) const
+    {
+    if(iChildArray)
+        {
+        const TInt KFirstPos = 0;
+        const TInt KEndPos = iChildArray->Count() - 1;
+        if(aChar<iChildArray->At(KFirstPos)->Char() || aChar>iChildArray->At(KEndPos)->Char())
+            {
+            return NULL;
+            }
+        for(TInt i=KEndPos; i>=KFirstPos; i--)
+            {
+            CSmileyTextTreeNode* node = iChildArray->At(i);
+            if(node->Char() == aChar)
+                {
+                return node;
+                }
+            }
+        }
+    
+    return NULL;
+    }
+
+CSmileyTextTreeNode* CSmileyTextTreeNode::AddChildAscendingL(TChar aChar)
+    {
+    // new
+    if(!iChildArray)
+        {
+        iChildArray = new (ELeave) CSmileyTextTreeNodeArrayPtrFlat(1);
+        }
+    
+    // sequential search
+    TInt pos = 0;
+    for(; pos<iChildArray->Count(); pos++)
+        {
+        CSmileyTextTreeNode* node = iChildArray->At(pos);
+        TChar character = node->Char();
+        if(aChar == character)
+            {
+            return node;
+            }
+        else if(aChar < character)
+            {
+            break;
+            }
+        }
+    
+    CSmileyTextTreeNode* node = new (ELeave) CSmileyTextTreeNode(aChar);
+    iChildArray->InsertL(pos, node);
+    return node;
+    }
+
 
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 // CSmileyModel
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-CSmileyModel::CSmileyModel(MSmileyIconObserver* aObserver) : iSmileyIconObserver(aObserver)
+const TUint16 KBaseCode = 0xf880;
+//const TUint16 KBaseCodeOff = 0x7FFF;
+_LIT(KPlaceHolder, "\xf880i");
+
+CSmileyModel::CSmileyModel(MAknSmileyObserver* aObserver) : iSmileyIconObserver(aObserver)
     {
     }
 
@@ -260,23 +454,12 @@
     ReleaseResource();
     
     iSmileyIconArray.Close();
+    iSmileyCodeIndexArray.Close();
     }
 
 void CSmileyModel::LoadResourceL()
     {
     if(Count() > 0) return;
-    
-    // append sct & smiley switch icon
-        {
-        TSmileyIconInfo info;
-        info.iSkinItemID = KAknsIIDQgnIndiSwitchSmiley2;
-        info.iDefaultThumbnailID = EMbmSmileyQgn_indi_switch_smiley2;
-        iSmileyIconArray.Append(CSmileyIcon::NewL(info, this));
-        
-        info.iSkinItemID = KAknsIIDQgnIndiSwitchSct2;
-        info.iDefaultThumbnailID = EMbmSmileyQgn_indi_switch_sct2;
-        iSmileyIconArray.Append(CSmileyIcon::NewL(info, this));
-        }
 
     // append image resourece
     TResourceReader reader;
@@ -285,13 +468,16 @@
     TInt offset = CCoeEnv::Static()->AddResourceFileL(smileyRscName);
     CCoeEnv::Static()->CreateResourceReaderLC(reader, R_SMILEY_ICONS_INFO);
 
+    TUint16 codeRef = KBaseCode;
+    TInt index = 0;
+    
+    iTextSearchTree = new (ELeave) CSmileyTextTreeNode(0);
+    
     TInt count(reader.ReadInt16());
-    for(TInt id(1); id<=count; id++)
+    for(TInt i(0); i<count; i++)
         {
         TSmileyIconInfo info;
-        
-        info.iId = id; // id
-        
+
         TBool isAnimation = (reader.ReadInt16() == 1);
         TInt16 code = reader.ReadInt16();
         TInt bmpId1 = reader.ReadInt32();
@@ -299,60 +485,477 @@
         TInt bmpId2 = reader.ReadInt32();
         TInt maskId2 = reader.ReadInt32();
         
+        
+        info.iIndex = index++;
+
         if(bmpId2 > 0)
             {
-            info.iDefaultThumbnailID = bmpId2;
-            info.iDefaultAnimationID = bmpId1;
+            info.iDefaultStillImageID = bmpId2;
+            info.iDefaultAnimationImageID = bmpId1;
             }
         else
             {
-            info.iDefaultThumbnailID = bmpId1;
-            info.iDefaultAnimationID = 0;
+            info.iDefaultStillImageID = bmpId1;
+            info.iDefaultAnimationImageID = 0;
             }
 
         TBuf<64> smileyName = reader.ReadTPtrC(); // strings
-        TInt pos = smileyName.Find(_L(" "));
-        if(pos > 0) smileyName.SetLength(pos);
-        info.iName = smileyName;
-
-        iSmileyIconArray.Append(CSmileyIcon::NewL(info, this));
+        
+        CSmileyIcon* icon = CSmileyIcon::NewL(info, this);
+        icon->AddVariant(smileyName, codeRef);
+        iSmileyIconArray.Append(icon);
+        
+        // build text search tree
+        for(TInt j=0; j<icon->VariantCount(); j++)
+            {
+            iTextSearchTree->AddTreeL(icon->Text(j), codeRef++);
+            iSmileyCodeIndexArray.Append(TSmileyCodeIndex(icon,j));
+            }
         }
     
     CCoeEnv::Static()->DeleteResourceFile(offset);
     CleanupStack::PopAndDestroy(); // reader
+    
+    // sct & smiley switch icon
+    TSmileyIconInfo info;
+    info.iIndex = index++;
+    info.iSkinItemID = KAknsIIDQgnIndiSwitchSmiley2;
+    info.iDefaultStillImageID = EMbmSmileyQgn_indi_switch_smiley2;
+    CSmileyIcon* switchSmileyIcon = CSmileyIcon::NewL(info, this);
+    iSmileyIconArray.Append(switchSmileyIcon);
+    iSmileyCodeIndexArray.Append(TSmileyCodeIndex(switchSmileyIcon));
+
+    info.iIndex = index++;
+    info.iSkinItemID = KAknsIIDQgnIndiSwitchSct2;
+    info.iDefaultStillImageID = EMbmSmileyQgn_indi_switch_sct2;
+    CSmileyIcon* switchSctIcon = CSmileyIcon::NewL(info,this);
+    iSmileyIconArray.Append(switchSctIcon);
+    iSmileyCodeIndexArray.Append(TSmileyCodeIndex(switchSctIcon));
 
     }
 
 void CSmileyModel::ReleaseResource()
     {
+    if(Count() == 0) return;
+
     // reset array
-    for(TInt i(0); i<Count(); i++)
+    for(TInt i(0); i<ArrayCount(); i++)
         {
         delete iSmileyIconArray[i];
         iSmileyIconArray[i] = NULL;
         }
     iSmileyIconArray.Reset();
     
+    iSmileyCodeIndexArray.Reset();
     // reset task loader
-    iSmileyThumbnailLoader.DiscardAll();
+    iSmileyLoader.DiscardAll();
+    
+    delete iTextSearchTree;
+    iTextSearchTree = NULL;
+    
+    }
+
+TInt CSmileyModel::ConvertCodesToTextL(TDes& aText)
+    {
+    TInt converted = 0;
+    iConvertBuffer.Zero();
+    
+    // deal all
+    TInt pos = 0;
+    while(pos < aText.Length())
+        {
+        TChar character = aText[pos++];
+        if(IsSmiley(character))
+            {
+            converted++;
+            pos++; // jump the 'i'
+            iConvertBuffer.Append(Text(character));
+            }
+        else
+            {
+            iConvertBuffer.Append(character);
+            }
+        }
+    
+    // replace
+    if(converted)
+        {
+        aText.Copy(iConvertBuffer);
+        }
+
+    return converted;
     }
 
-void CSmileyModel::LoadThumbnailAsyn(TInt aIndex)
+TInt CSmileyModel::ConvertTextToCodesL(TDes& aText)
     {
-    TRAP_IGNORE(iSmileyThumbnailLoader.AddTaskL((*this)[aIndex]));
+    _AKNTRACE_FUNC_ENTER;
+    TInt converted = 0;
+    iConvertBuffer.Zero();
+
+    CSmileyTextTreeNode* node = iTextSearchTree;
+    TInt matchedLength = 0;
+
+    // deal all
+    TInt pos = 0;
+    while(pos < aText.Length())
+        {
+        TChar character = aText[pos++];
+        iConvertBuffer.Append(character);
+
+            CSmileyTextTreeNode* find = node->Child(character);
+            if(find)
+                {
+                matchedLength++; // character is mathed
+                
+                CSmileyTextTreeNode* child = find->Child(0);
+            TBool notFinished = (child && child->ChildCount());
+            if(notFinished) // not ended
+                    {
+                node = find; // match next 
+                continue;
+                }
+            else if(child) // whole combination is matched and ended
+                {
+                    TChar code = child->Char();
+
+                    // replace with code
+                    iConvertBuffer.SetLength(iConvertBuffer.Length() - matchedLength);
+                    iConvertBuffer.Append(code);
+                    iConvertBuffer.Append('i');
+                converted++; // returned value added
+                    // load thumnail
+                    LoadStillImageL(code);
+
+                    // restart
+                    matchedLength = 0;
+                    node = iTextSearchTree;
+                continue;
+                    }
+            else // in this case matchedLength already increased by 1
+                {
+                matchedLength--;
+                }
+            }
+        
+        // matching failed
+        if(matchedLength)
+            {
+            // back to the 2nd char
+            TInt rollBack = matchedLength;
+            iConvertBuffer.SetLength(iConvertBuffer.Length() - rollBack);
+            pos -= rollBack;
+
+            // reset matching context
+            matchedLength = 0;
+            node = iTextSearchTree;
+            }
+        }
+    
+    // replace
+    if(converted)
+        {
+        aText.Copy(iConvertBuffer);
+        }
+
+    _AKNTRACE_FUNC_EXIT;
+    return converted;
+    }
+
+TBool CSmileyModel::IsSmiley(TChar aCode) const
+    {
+    TInt smileyCodeIndex = (TUint16)aCode - KBaseCode;
+    return (smileyCodeIndex>=0 && smileyCodeIndex<iSmileyCodeIndexArray.Count());
+    }
+
+const TDesC& CSmileyModel::Text(TChar aCode) const
+    {
+    if(IsSmiley(aCode))
+        {
+        TInt smileyCodeIndex = (TUint16)aCode - KBaseCode;
+        return iSmileyCodeIndexArray[smileyCodeIndex].Text();
+        }
+    else
+        {
+        return KNullDesC;
+        }
     }
 
 void CSmileyModel::SetSize(const TSize& aSize)
     {
-    for(TInt i(0); i<Count(); i++)
+    if(ArrayCount() && iSmileyIconArray[0]->Size()!=aSize)
+        {
+        for(TInt i(0); i<ArrayCount(); i++)
+            {
+            iSmileyIconArray[i]->SetSize(aSize);
+            }
+        }
+    }
+
+void CSmileyModel::SetSizeByFont(const CFont* aFont)
+    {
+    TSize size(aFont->TextWidthInPixels(KPlaceHolder),aFont->HeightInPixels());
+    SetSize(size);
+    }
+
+void CSmileyModel::DrawText(CWindowGc& aGc, const TDesC& aText, const CFont* aFont, const TPoint& aPosition) const
+    {
+    TPtrC ptr = aText;
+    TPoint pos = aPosition;
+    
+    aGc.UseFont(aFont);
+    
+    TBool metSmileyNotReady = EFalse;
+ 
+    while(ptr.Length())
         {
-        iSmileyIconArray[i]->SetSize(aSize);
+        TInt i = 0;
+        for(; i<ptr.Length(); i++) // find next smiley code
+            {
+            if(IsSmiley(ptr[i]))
+                {
+                break;
+                }
+            }
+        
+        if(i > 0) // have text
+            {
+            TPtrC txt = ptr.Left(i);
+            aGc.DrawText(txt, pos);
+            pos += TPoint(aFont->TextWidthInPixels(txt),0);
+
+            ptr.Set(ptr.Right(ptr.Length()-i));
+            i = 0;
+            }
+        
+        if(ptr.Length()) // breaked by smiley code
+            {
+            CAknSmileyIcon* icon = Smiley(ptr[i]);
+            if(icon)
+                {
+                TSize size = icon->Size();
+                TPoint tl = pos;
+                tl.iY = tl.iY - (size.iHeight + aFont->HeightInPixels()) / 2;
+                if(!metSmileyNotReady && icon->ReadyToDraw())
+                    {
+                    aGc.BitBltMasked(tl, icon->Image(), TRect(size), icon->Mask(), EFalse);
+                    }
+                else
+                    {
+                    metSmileyNotReady = ETrue;
+                    }
+                pos += TPoint(aFont->TextWidthInPixels(ptr.Left(2)),0);
+                }
+            
+            ptr.Set(ptr.Right(ptr.Length()-2));
+            }
         }
     }
 
-CSmileyIcon* CSmileyModel::operator[](TInt aIndex) const
+void CSmileyModel::DrawText(CWindowGc& aGc, const TDesC& aText, const TAknLayoutText& aLayout, TBool aUseLogicalToVisualConversion) const
+    {
+    _AKNTRACE_FUNC_ENTER;
+    // adapter variables
+    const CFont* font = aLayout.Font();
+    TRect textRect = aLayout.TextRect();
+    TInt offset = aLayout.BaselineOffset();
+    CGraphicsContext::TTextAlign align = aLayout.Align();
+    
+    // belows are all from 
+    // void TAknLayoutText::DrawText(CGraphicsContext& aGc,const TDesC& aText,TBool aUseLogicalToVisualConversion, const TRgb &aColor) const
+    
+    __ASSERT_DEBUG(font, Panic(EAknPanicLayoutTextNotCalled));
+    
+    //aGc.UseFont( font );
+    //aGc.SetPenColor( aColor );
+    if ( aText.Length() )
+        {
+        HBufC* visualBuf = NULL;
+        TPtrC text( aText );
+        
+        if ( aUseLogicalToVisualConversion )
+            {
+            visualBuf = HBufC::New( aText.Length() + KAknBidiExtraSpacePerLine );
+            
+            // In OOM, logical to visual conversion is not performed...
+            
+            if ( visualBuf )
+                {
+                *visualBuf = aText; // copy
+                TPtr ptr = visualBuf->Des();
+                
+                TInt maxWidth = textRect.Size().iWidth;
+                // Logical to visual conversion.
+                AknBidiTextUtils::ConvertToVisualAndClip(
+                    aText,
+                    ptr,
+                    *font,
+                    maxWidth,
+                    maxWidth );
+                // for smiley begin
+                const TInt length = ptr.Length();
+                if(length>1 && IsSmiley(ptr[length-2]))
+                    {
+                    if(ptr[length-1] != 'i')
+                        {
+                        // smiley is clipped for visual, del this smiley
+                        ptr.Delete(length-2, 1);
+                        }
+                    }
+                // for smiley end
+
+                text.Set( ptr );
+                }
+            }
+        
+        // Calculate x-offset based on the used alignment
+        TInt margin = 0;
+        if ( align != CGraphicsContext::ELeft )
+            {
+            // Measure the full width of the text (ie. what DrawText needs)
+            TInt textWidth = AknBidiTextUtils::MeasureTextBoundsWidth( *font, text,CFont::TMeasureTextInput::EFVisualOrder );
+            
+            const TInt extraWidth = textRect.Width() - textWidth;
+            if ( align == CGraphicsContext::ECenter )
+                {
+                margin = extraWidth / 2;
+                }
+            else // right aligned
+                {
+                margin = extraWidth;
+                }
+            }
+
+        // Need to make the drawing rectangle bigger to account for underlines
+        TRect drawRect(textRect);
+        TInt height = drawRect.Height();
+        // The underline position is not available from the GC. The following code imitates what Symbian CFbsBitGC implements.
+        // (height-offset) is the part below the baseline. Check if it sufficient
+        TInt extraHeightForUnderlining =   1 + Max(1, height/10)-(height-offset);
+        if ( extraHeightForUnderlining > 0 )
+            drawRect.iBr.iY += extraHeightForUnderlining;
+
+        // for smiley
+        //aGc.DrawText( text, drawRect, offset, CGraphicsContext::ELeft, margin );
+        DrawText(aGc, text, font, drawRect, offset, CGraphicsContext::ELeft, margin);
+        
+        delete visualBuf;
+        }
+    
+    //aGc.DiscardFont(); // Release the font cache
+    _AKNTRACE_FUNC_EXIT;
+    }
+
+void CSmileyModel::DrawText(CWindowGc& aGc, const TDesC& aText, const CFont* aFont, const TRect& aBox, TInt aBaselineOffset, 
+                            CGraphicsContext::TTextAlign aAlignment, TInt aLeftMargin) const
     {
-    if(aIndex>=0 && aIndex<Count())
+    TInt boxWidth = aBox.Width();
+    TInt textWidth = aFont->TextWidthInPixels(aText);
+    
+    TPoint offset;
+    offset.iY = aBaselineOffset;
+    
+    switch(aAlignment)
+        {
+        case CGraphicsContext::ELeft:
+            offset.iX = aLeftMargin;
+            break;
+            
+        case CGraphicsContext::ERight:
+            offset.iX = boxWidth - textWidth - aLeftMargin;
+            break;
+            
+        case CGraphicsContext::ECenter:
+            offset.iX = (boxWidth - textWidth) / 2;
+            break;
+            
+        default:
+            break;
+        }
+    
+    DrawText(aGc, aText, aFont, aBox, offset);
+    }
+
+void CSmileyModel::DrawText(CWindowGc& aGc, const TDesC& aText, const CFont* aFont, const TRect& aBox, const TPoint& aOffset) const
+    {
+    TPtrC ptr = aText;
+    TPoint offset = aOffset;
+    
+    aGc.UseFont(aFont);
+    
+    TInt fontH = aFont->FontMaxHeight();
+    
+    TBool metSmileyNotReady = EFalse;
+ 
+    while(ptr.Length())
+        {
+        TInt i = 0;
+        for(; i<ptr.Length(); i++) // find next smiley code
+            {
+            if(IsSmiley(ptr[i]))
+                {
+                break;
+                }
+            }
+        
+        if(i > 0) // have text
+            {
+            TPtrC txt = ptr.Left(i);
+            aGc.DrawText(txt, aBox, offset.iY, CGraphicsContext::ELeft, offset.iX);
+            offset.iX += aFont->TextWidthInPixels(txt);
+
+            ptr.Set(ptr.Right(ptr.Length()-i));
+            i = 0;
+            }
+        
+        if(ptr.Length()) // breaked by smiley code
+            {
+            CAknSmileyIcon* icon = Smiley(ptr[i]);
+            if(icon)
+                {
+                TSize size = icon->Size();
+                TPoint tl = aBox.iTl;
+                tl.iX += offset.iX;
+                //tl.iY = tl.iY - size.iHeight/*(size.iHeight + fontH) / 2*/;
+                TRect imgWindow(tl, size);
+                imgWindow.Intersection(aBox);
+                if(!imgWindow.IsEmpty())
+                    {
+                    TRect innerRect = TRect(imgWindow.iTl-tl,imgWindow.Size());
+                    if(!metSmileyNotReady && icon->ReadyToDraw())
+                        {
+                        aGc.BitBltMasked(imgWindow.iTl, icon->Image(), innerRect, icon->Mask(), EFalse);
+                        }
+                    else
+                        {
+                        metSmileyNotReady = ETrue;
+                        }
+                    }
+
+                //offset += TPoint(aFont->TextWidthInPixels(ptr.Left(2)),0);
+                offset.iX += size.iWidth;
+                }
+            
+            ptr.Set(ptr.Right(ptr.Length()-2));
+            }
+        }
+    }
+
+CAknSmileyIcon* CSmileyModel::Smiley(TChar aCode) const
+    {
+    if(IsSmiley(aCode))
+        {
+        TInt smileyCodeIndex = (TUint16)aCode - KBaseCode;
+        return iSmileyCodeIndexArray[smileyCodeIndex].Smiley();
+        }
+    else
+        {
+        return NULL;
+        }
+    }
+
+CAknSmileyIcon* CSmileyModel::operator[](TInt aIndex) const
+    {
+    if(aIndex>=0 && aIndex<ArrayCount())
         {
         return iSmileyIconArray[aIndex];
         }
@@ -364,19 +967,129 @@
 
 TInt CSmileyModel::Count() const
     {
-    return iSmileyIconArray.Count();
+    return iSmileyIconArray.Count() - 2;
+    }
+
+CAknSmileyIcon* CSmileyModel::SwitchToSmileyIcon() const
+    {
+    return (*this)[Count()];
+    }
+
+CAknSmileyIcon* CSmileyModel::SwitchToSctIcon() const
+    {
+    return (*this)[Count()+1];
+    }
+
+TChar CSmileyModel::SwitchToSmileyCode() const
+    {
+    return SmileyCode(Count());
+    }
+
+TChar CSmileyModel::SwitchToSctCode() const
+    {
+    return SmileyCode(Count()+1);
+    }
+
+TChar CSmileyModel::SmileyCode(TInt aIndex, TInt aVariant) const
+    {
+    const CAknSmileyIcon* iconWrapper = (*this)[aIndex];
+    const CSmileyIcon* icon = static_cast<const CSmileyIcon*>(iconWrapper);
+    if(icon)
+        {
+        return icon->Code(aVariant);
+        }
+    else
+        {
+        return 0;
+        }
+    }
+
+TChar CSmileyModel::SmileyCode(const CAknSmileyIcon* aSmileyIcon) const
+    {
+    if(aSmileyIcon)
+        {
+        const CSmileyIcon* icon = static_cast<const CSmileyIcon*>(aSmileyIcon);
+        return icon->Code();
+        }
+    else
+        {
+        return 0;
+        }
+    }
+
+void CSmileyModel::LoadStillImagesL(const TDesC& aText)
+    {
+    for(TInt i(0); i<aText.Length(); i++)
+        {
+        LoadStillImageL(aText[i]);
+        }
     }
 
-void CSmileyModel::ThumbnailLoaded(CSmileyIcon* aSmileyIcon)
+void CSmileyModel::PlayAnimationL(const TDesC& aText, TInt aRepeat, TInt aDelay)
+    {
+    for(TInt i(0); i<aText.Length(); i++)
+        {
+        PlayAnimationL(aText[i], aRepeat, aDelay);
+        }
+    }
+
+void CSmileyModel::StopAnimation(const TDesC& aText)
     {
-    TRAP_IGNORE(iSmileyThumbnailLoader.DoNextTaskL());
+    for(TInt i(0); i<aText.Length(); i++)
+        {
+        StopAnimation(aText[i]);
+        }
+    }
 
-    if(iSmileyIconObserver) iSmileyIconObserver->ThumbnailLoaded(aSmileyIcon);
+void CSmileyModel::LoadStillImageL(TChar aChar)
+    {
+    CSmileyIcon* icon = static_cast<CSmileyIcon*>(Smiley(aChar));
+    iSmileyLoader.AddTaskL(icon);
+    }
+
+void CSmileyModel::PlayAnimationL(TChar aChar, TInt aRepeat, TInt aDelay)
+    {
+    CSmileyIcon* icon = static_cast<CSmileyIcon*>(Smiley(aChar));
+    if(icon) icon->PlayAnimationL(aRepeat, aDelay);
     }
 
-void CSmileyModel::AnimationChanged(CSmileyIcon* aSmileyIcon)
+void CSmileyModel::StopAnimation(TChar aChar)
+    {
+    CSmileyIcon* icon = static_cast<CSmileyIcon*>(Smiley(aChar));
+    if(icon) icon->StopAnimation();
+    }
+
+const TDesC& CSmileyModel::Text(TInt aIndex, TInt aVariant) const
     {
-    if(iSmileyIconObserver) iSmileyIconObserver->AnimationChanged(aSmileyIcon);
+    CSmileyIcon* icon = static_cast<CSmileyIcon*>((*this)[aIndex]);
+    if(icon)
+        {
+        return icon->Text(aVariant);
+        }
+    else
+        {
+        return KNullDesC;
+        }
+    }
+
+TInt CSmileyModel::ArrayCount() const
+    {
+    return iSmileyIconArray.Count();
+
+
+
+    }
+
+void CSmileyModel::SmileyStillImageLoaded(CAknSmileyIcon* aSmileyIcon)
+    {
+    TRAP_IGNORE(iSmileyLoader.DoNextTaskL());
+
+    if(iSmileyIconObserver) iSmileyIconObserver->SmileyStillImageLoaded(aSmileyIcon);
+    }
+
+void CSmileyModel::SmileyAnimationChanged(CAknSmileyIcon* aSmileyIcon)
+    {
+    if(iSmileyIconObserver) iSmileyIconObserver->SmileyAnimationChanged(aSmileyIcon);
     }