src/hbwidgets/editors/hbsmileyengine.cpp
changeset 1 f7ac710697a9
parent 0 16d8024aca5e
child 2 06ff229162e9
equal deleted inserted replaced
0:16d8024aca5e 1:f7ac710697a9
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbWidgets module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 
       
    26 #include "hbsmileyengine.h"
       
    27 #include "hbsmileyengine_p.h"
       
    28 #include <hbiconanimator.h>
       
    29 #include <hbicon.h>
       
    30 #include <QTextDocument>
       
    31 #include <QFontMetricsF>
       
    32 #include <QChar>
       
    33 
       
    34 namespace {
       
    35     const qreal ICON_SCALE_FACTOR = 1.5;
       
    36 }
       
    37 
       
    38 HbSmileyTheme HbSmileyEnginePrivate::mDefaultTheme = HbSmileyTheme();
       
    39 
       
    40 QSizeF HbIconTextObject::intrinsicSize(QTextDocument *doc, int posInDocument,
       
    41                                     const QTextFormat &format)
       
    42 {
       
    43     Q_UNUSED(doc)
       
    44     Q_UNUSED(posInDocument)
       
    45 
       
    46     HbSmileyDataType smiley = qVariantValue<HbSmileyDataType>(format.property(HbSmileyData));
       
    47     HbIconAnimator *animator = smiley.second;
       
    48     Q_ASSERT(animator);
       
    49 
       
    50     QFont f = static_cast<const QTextCharFormat&>(format).font();
       
    51     QFontMetricsF fm(f);
       
    52 
       
    53     // TODO: optimize this
       
    54     HbIcon icon = animator->icon();
       
    55     qreal iconHeight = fm.height() * ICON_SCALE_FACTOR;
       
    56     if(icon.height() != iconHeight) {
       
    57         icon.setHeight(iconHeight);
       
    58         animator->setIcon(icon);
       
    59     }
       
    60     return icon.size();
       
    61 }
       
    62 
       
    63 void HbIconTextObject::drawObject(QPainter *painter, const QRectF &rect,
       
    64                                QTextDocument *doc, int posInDocument,
       
    65                                const QTextFormat &format)
       
    66 {
       
    67     Q_UNUSED(doc)
       
    68     Q_UNUSED(posInDocument)
       
    69 
       
    70     HbSmileyDataType smiley = qVariantValue<HbSmileyDataType>(format.property(HbSmileyData));
       
    71     HbIconAnimator *animator = smiley.second;
       
    72     animator->paint(painter,rect);
       
    73 }
       
    74 
       
    75 HbSmileyEnginePrivate::HbSmileyEnginePrivate()
       
    76     :mDocument(0),
       
    77      mEdited(true),
       
    78      mIconTextObject(new HbIconTextObject)
       
    79 {
       
    80     q_ptr = 0;
       
    81 }
       
    82 
       
    83 HbSmileyEnginePrivate::~HbSmileyEnginePrivate()
       
    84 {
       
    85     cleanUp();
       
    86     delete mIconTextObject;
       
    87 }
       
    88 
       
    89 
       
    90 void HbSmileyEnginePrivate::init()
       
    91 {
       
    92     // Load default smiley theme
       
    93     if(mDefaultTheme.isNull()) {
       
    94         HbSmileyEnginePrivate::mDefaultTheme.load(":smileys/smileys_theme.sml");
       
    95         //
       
    96         //TODO: uncomment the lines below if animation definition file is provided for
       
    97         //      default smiley theme.
       
    98         //HbIconAnimationManager* m = HbIconAnimationManager::global();
       
    99         //m->addDefinitionFile(":smileys/smileys_animations.xml");
       
   100     }
       
   101     mSmileyTheme = HbSmileyEnginePrivate::mDefaultTheme;
       
   102 }
       
   103 
       
   104 void HbSmileyEnginePrivate::cleanUp()
       
   105 {
       
   106     QList<QTextCursor*> cursors = mCursorToAnimator.keys();
       
   107     qDeleteAll(cursors);
       
   108 
       
   109     QList<HbIconAnimator*> animators = mAnimatorToCursors.keys();
       
   110     qDeleteAll(animators);
       
   111 
       
   112     mAnimatorToCursors.clear();
       
   113     mCursorToAnimator.clear();
       
   114     mSmileyAnimator.clear();
       
   115 }
       
   116 
       
   117 void HbSmileyEnginePrivate::setDocument(QTextDocument *doc)
       
   118 {
       
   119     Q_Q(HbSmileyEngine);
       
   120     mDocument = doc;
       
   121     mDocument->documentLayout()->registerHandler(HbIconTextFormat, mIconTextObject);
       
   122     q->connect(mDocument, SIGNAL(contentsChange(int,int,int)), q, SLOT(_q_documentContentsChanged(int,int,int)));
       
   123     cleanUp();
       
   124 }
       
   125 
       
   126 void HbSmileyEnginePrivate::insertSmiley( QTextCursor cursor, const QString& name)
       
   127 {
       
   128     QTextCharFormat hbiconFormat;
       
   129     QTextCursor *tmpCursor = new QTextCursor(cursor);
       
   130     hbiconFormat.setObjectType(HbIconTextFormat);
       
   131 
       
   132     HbIconTextObject::HbSmileyDataType smiley;
       
   133     HbIconAnimator *animator = lookupAnimator(name);
       
   134     smiley.first = tmpCursor;
       
   135     smiley.second = animator;
       
   136 
       
   137     hbiconFormat.setProperty(HbIconTextObject::HbSmileyData, qVariantFromValue(smiley));
       
   138 
       
   139     mEdited = false;
       
   140     tmpCursor->insertText(QString(QChar::ObjectReplacementCharacter), hbiconFormat);
       
   141     mEdited = true;
       
   142     tmpCursor->setPosition(tmpCursor->position()-1);
       
   143     mAnimatorToCursors[animator] << tmpCursor;
       
   144     mCursorToAnimator[tmpCursor] = animator;
       
   145 }
       
   146 
       
   147 void HbSmileyEnginePrivate::insertSmileys( QTextCursor cursor, bool insertOne)
       
   148 {
       
   149     QString regexpStr;
       
   150     foreach (QString pattern, mSmileyTheme.patterns()) {
       
   151         regexpStr += QRegExp::escape(pattern) + "|";
       
   152     }
       
   153     regexpStr.remove(regexpStr.count()-1, 1);
       
   154 
       
   155     QRegExp rx(regexpStr);
       
   156     cursor = mDocument->find(rx, cursor);
       
   157     while ( !cursor.isNull()){
       
   158         insertSmiley(cursor, mSmileyTheme.smiley(cursor.selectedText()));
       
   159         if (insertOne) {
       
   160             break;
       
   161         }
       
   162         cursor = mDocument->find(rx, cursor);
       
   163     }
       
   164 }
       
   165 
       
   166 
       
   167 HbIconAnimator* HbSmileyEnginePrivate::lookupAnimator(const QString& name)
       
   168 {
       
   169     Q_Q(HbSmileyEngine);
       
   170     HbIconAnimator *animator = mSmileyAnimator.value(name);
       
   171 
       
   172     // Init icon if it doesn't already exits
       
   173     if (!animator) {
       
   174         HbIconAnimator *newAnimator = new HbIconAnimator();
       
   175         animator = newAnimator;
       
   176         HbIcon icon = HbIcon(name);
       
   177         icon.setFlags(HbIcon::NoAutoStartAnimation);
       
   178         animator->setIcon(icon);
       
   179         q->connect(animator,SIGNAL(animationProgressed()),q,SLOT(_q_animationProgressed()));
       
   180         animator->startAnimation();
       
   181         mSmileyAnimator[name] = animator;
       
   182     }
       
   183 
       
   184     return animator;
       
   185 }
       
   186 
       
   187 
       
   188 bool HbSmileyEnginePrivate::isCursorValid(QTextCursor* cursor) const
       
   189 {
       
   190     bool ret = true;
       
   191 
       
   192     if (cursor) {
       
   193         if (mDocument->characterAt(cursor->position()) != QChar::ObjectReplacementCharacter) {
       
   194             ret = false;
       
   195          } else {
       
   196              QTextCursor tmpCursor(*cursor);
       
   197              tmpCursor.setPosition(tmpCursor.position()+1);
       
   198              QTextCharFormat format = tmpCursor.charFormat();
       
   199 
       
   200              HbIconTextObject::HbSmileyDataType smiley =
       
   201                      qVariantValue<HbIconTextObject::HbSmileyDataType>(format.property(HbIconTextObject::HbSmileyData));
       
   202              if (cursor != smiley.first) {
       
   203                 ret = false;
       
   204              }
       
   205          }
       
   206      } else {
       
   207         ret = false;
       
   208      }
       
   209     return ret;
       
   210 }
       
   211 
       
   212 void HbSmileyEnginePrivate::convertToText(QTextDocument *copyDoc) const
       
   213 {
       
   214     QList<QTextCursor> cursors;
       
   215     // copy the cursors to copy document so that the positions get automatically updated
       
   216     foreach(QTextCursor *cursor, mCursorToAnimator.keys()) {
       
   217         if(isCursorValid(cursor)) {
       
   218             QTextCursor copyCursor(copyDoc);
       
   219             copyCursor.setPosition(cursor->position());
       
   220             cursors << copyCursor;
       
   221         }
       
   222     }
       
   223 
       
   224     foreach(QTextCursor copyCursor, cursors) {
       
   225         copyCursor.setPosition(copyCursor.position()+1, QTextCursor::KeepAnchor);
       
   226         QTextFormat format = copyCursor.charFormat();
       
   227         HbIconTextObject::HbSmileyDataType smiley =
       
   228                 qVariantValue<HbIconTextObject::HbSmileyDataType>(format.property(HbIconTextObject::HbSmileyData));
       
   229         HbIconAnimator *animator = smiley.second;
       
   230         Q_ASSERT(animator);
       
   231 
       
   232         QString pattern = mSmileyTheme.patterns(mSmileyAnimator.key(animator)).first();
       
   233         copyCursor.deleteChar();
       
   234         copyCursor.insertText(pattern);
       
   235     }
       
   236 }
       
   237 
       
   238 void HbSmileyEnginePrivate::_q_animationProgressed()
       
   239 {
       
   240     Q_Q(HbSmileyEngine);
       
   241     HbIconAnimator *animator = qobject_cast<HbIconAnimator *>(q->sender());
       
   242     Q_ASSERT(animator);
       
   243 
       
   244     foreach(QTextCursor *cursor, mAnimatorToCursors.value(animator)) {
       
   245         QTextCursor tmpCursor(*cursor);
       
   246         tmpCursor.setPosition(tmpCursor.position()+1, QTextCursor::KeepAnchor);
       
   247 
       
   248         // update a bogus property, which will trigger a paint
       
   249         QTextCharFormat format;
       
   250         format.setProperty(HbIconTextObject::HbSmileyData+1, QString("Dummy"));
       
   251         mEdited = false;
       
   252         tmpCursor.mergeCharFormat(format);
       
   253         mEdited = true;
       
   254     }
       
   255 }
       
   256 
       
   257 void HbSmileyEnginePrivate::_q_documentContentsChanged(int position, int charsRemoved, int charsAdded)
       
   258 {
       
   259     Q_UNUSED(position);
       
   260     Q_UNUSED(charsRemoved);
       
   261     Q_UNUSED(charsAdded);
       
   262 
       
   263     if(charsRemoved > 0 && mEdited) {
       
   264         foreach (QTextCursor* cursor, mCursorToAnimator.keys()) {          
       
   265             if (!isCursorValid(cursor)) {
       
   266                 HbIconAnimator * animator = mCursorToAnimator.value(cursor);
       
   267                 mCursorToAnimator.remove(cursor);
       
   268                 QList<QTextCursor*> & cursorList = mAnimatorToCursors[animator];
       
   269                 cursorList.removeFirst();
       
   270                 if (!cursorList.count()) {
       
   271                     mAnimatorToCursors.remove(animator);
       
   272                     mSmileyAnimator.remove(mSmileyAnimator.key(animator));
       
   273                     animator->deleteLater();
       
   274                 }
       
   275                 delete cursor;
       
   276             }
       
   277         }
       
   278     }
       
   279 }
       
   280 
       
   281 
       
   282 HbSmileyEngine::HbSmileyEngine(QObject *parent)
       
   283     :QObject(parent),
       
   284     d_ptr(new HbSmileyEnginePrivate)
       
   285 
       
   286 {
       
   287     Q_D(HbSmileyEngine);
       
   288     d->q_ptr = this;
       
   289     d->init();
       
   290 }
       
   291 
       
   292 HbSmileyEngine::HbSmileyEngine(HbSmileyEnginePrivate &dd, QObject *parent)
       
   293     :QObject(parent),
       
   294     d_ptr(&dd)
       
   295 {
       
   296     Q_D(HbSmileyEngine);
       
   297     d->q_ptr = this;
       
   298     d->init();
       
   299 }
       
   300 
       
   301 HbSmileyEngine::~HbSmileyEngine()
       
   302 {
       
   303     delete d_ptr;
       
   304 }
       
   305 
       
   306 void HbSmileyEngine::setDocument(QTextDocument *doc)
       
   307 {
       
   308     Q_D(HbSmileyEngine);
       
   309     d->setDocument(doc);
       
   310 }
       
   311 
       
   312 void HbSmileyEngine::setTheme(const HbSmileyTheme& theme)
       
   313 {
       
   314     Q_D(HbSmileyEngine);
       
   315     d->mSmileyTheme = theme;
       
   316 }
       
   317 
       
   318 HbSmileyTheme HbSmileyEngine::theme() const
       
   319 {
       
   320     Q_D(const HbSmileyEngine);
       
   321     return d->mSmileyTheme;
       
   322 }
       
   323 
       
   324 HbSmileyTheme HbSmileyEngine::defaultTheme() const
       
   325 {
       
   326     return HbSmileyEnginePrivate::mDefaultTheme;
       
   327 }
       
   328 
       
   329 
       
   330 QString HbSmileyEngine::toPlainText() const
       
   331 {
       
   332     Q_D(const HbSmileyEngine);
       
   333     QTextDocument *copyDoc = d->mDocument->clone();
       
   334     d->convertToText(copyDoc);
       
   335     QString plainText = copyDoc->toPlainText();
       
   336     delete copyDoc;
       
   337     return plainText;
       
   338 }
       
   339 
       
   340 QString HbSmileyEngine::toHtml() const
       
   341 {
       
   342     Q_D(const HbSmileyEngine);
       
   343     QTextDocument *copyDoc = d->mDocument->clone();
       
   344     d->convertToText(copyDoc);
       
   345     QString htmlString = copyDoc->toHtml();
       
   346     return htmlString;
       
   347 }
       
   348 
       
   349 void HbSmileyEngine::startAnimation()
       
   350 {
       
   351     Q_D(HbSmileyEngine);
       
   352     foreach (HbIconAnimator *animator, d->mAnimatorToCursors.keys()) {
       
   353         animator->startAnimation();
       
   354     }
       
   355 }
       
   356 
       
   357 void HbSmileyEngine::stopAnimation()
       
   358 {
       
   359     Q_D(HbSmileyEngine);
       
   360     foreach (HbIconAnimator *animator, d->mAnimatorToCursors.keys()) {
       
   361         animator->stopAnimation();
       
   362     }
       
   363 }
       
   364 
       
   365 void HbSmileyEngine::insertSmileys()
       
   366 {
       
   367     Q_D(HbSmileyEngine);
       
   368 
       
   369     QTextCursor cursor(d->mDocument);
       
   370     d->insertSmileys(cursor);
       
   371 }
       
   372 
       
   373 void HbSmileyEngine::insertSmileys(const QTextCursor& cursor)
       
   374 {
       
   375     Q_D(HbSmileyEngine);
       
   376     d->insertSmileys(cursor);
       
   377 }
       
   378 
       
   379 void HbSmileyEngine::insertSmiley(const QTextCursor& cursor)
       
   380 {
       
   381     Q_D(HbSmileyEngine);
       
   382     d->insertSmileys(cursor,true);
       
   383 }
       
   384 
       
   385 #include "moc_hbsmileyengine.cpp"