src/hbcore/primitives/hbrichtextitem.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     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 HbCore 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 "hbrichtextitem.h"
       
    27 #include "hbrichtextitem_p.h"
       
    28 #include "hbtextutils_p.h"
       
    29 #include "hbcolorscheme.h"
       
    30 #include "hbevent.h"
       
    31 
       
    32 #include <QTextDocument>
       
    33 #include <QStyle>
       
    34 #include <QGraphicsSceneResizeEvent>
       
    35 #include <QTextBlock>
       
    36 #include <QTextLayout>
       
    37 #include <QPainter>
       
    38 #include <QAbstractTextDocumentLayout>
       
    39 
       
    40 const int KMinimumLetersToShow = 4;
       
    41 
       
    42 static const QString KDefaultColorThemeName = "qtc_view_normal";
       
    43 
       
    44 HbRichTextItemPrivate::HbRichTextItemPrivate() :
       
    45     mAlignment(Qt::AlignLeft|Qt::AlignVCenter),
       
    46     mTextOption(mAlignment),
       
    47     mDontPrint(false),
       
    48     mDontClip(false),
       
    49     mRtf(0)
       
    50 {
       
    51 }
       
    52 
       
    53 HbRichTextItemPrivate::~HbRichTextItemPrivate()
       
    54 {
       
    55 }
       
    56 
       
    57 /*
       
    58  * private constructor
       
    59  */
       
    60 void HbRichTextItemPrivate::init()
       
    61 {
       
    62     Q_Q(HbRichTextItem);
       
    63 
       
    64     q->setFlag(QGraphicsItem::ItemClipsToShape, !mDontClip);
       
    65     q->setFlag(QGraphicsItem::ItemIsSelectable, false);
       
    66     q->setFlag(QGraphicsItem::ItemIsFocusable,  false);
       
    67 
       
    68     mRtf = new QTextDocument(q);
       
    69     mRtf->setDocumentMargin(0.0); // no margins needed
       
    70 
       
    71     mTextOption.setWrapMode(QTextOption::NoWrap);
       
    72     mRtf->setDefaultTextOption(mTextOption);
       
    73 
       
    74     mRtf->setDefaultFont(q->font());
       
    75 }
       
    76 
       
    77 void HbRichTextItemPrivate::clear()
       
    78 {
       
    79     delete mRtf;
       
    80 }
       
    81 
       
    82 int HbRichTextItemPrivate::textFlagsFromTextOption() const
       
    83 {
       
    84     int flags = (int)mAlignment;
       
    85 
       
    86     switch(mTextOption.wrapMode()) {
       
    87     case QTextOption::NoWrap:
       
    88         flags |= Qt::TextSingleLine;
       
    89         break;
       
    90     case QTextOption::WordWrap:
       
    91         flags |=Qt::TextWordWrap;
       
    92         break;
       
    93     case QTextOption::ManualWrap:
       
    94         break;
       
    95     case QTextOption::WrapAnywhere:
       
    96         flags |=Qt::TextWrapAnywhere;
       
    97         break;
       
    98     case QTextOption::WrapAtWordBoundaryOrAnywhere:
       
    99         flags |=Qt::TextWordWrap | Qt::TextWrapAnywhere;
       
   100         break;
       
   101     }
       
   102 
       
   103     if(mDontClip)  flags |= Qt::TextDontClip;
       
   104     if(mDontPrint) flags |= Qt::TextDontPrint;
       
   105 
       
   106     return flags;
       
   107 }
       
   108 
       
   109 bool HbRichTextItemPrivate::setLayoutDirection(Qt::LayoutDirection newDirection)
       
   110 {
       
   111     Qt::Alignment oldAlign = mTextOption.alignment();
       
   112     Qt::Alignment alignment = QStyle::visualAlignment(newDirection, mAlignment);
       
   113     if(alignment!=oldAlign) {
       
   114         mTextOption.setAlignment(alignment);
       
   115         mRtf->setDefaultTextOption(mTextOption);
       
   116         return true;
       
   117     }
       
   118     return false;
       
   119 }
       
   120 
       
   121 void HbRichTextItemPrivate::setSize(const QSizeF &newSize)
       
   122 {
       
   123     if(mRtf->size()!=newSize) {
       
   124         Q_Q(HbRichTextItem);
       
   125         mRtf->setTextWidth(newSize.width());
       
   126         calculateOffset();
       
   127         q->update();
       
   128     }
       
   129 }
       
   130 
       
   131 // #define HB_RICH_TEXT_ITEM_ALWAS_SHOW_FIRST_LINE
       
   132 void HbRichTextItemPrivate::calculateOffset()
       
   133 {
       
   134     Q_Q(HbRichTextItem);
       
   135 
       
   136     qreal diff;
       
   137     if(mAlignment.testFlag(Qt::AlignTop)) {
       
   138         diff = 0.0;
       
   139     } else {
       
   140         diff = q->geometry().height() - mRtf->size().height();
       
   141         if(!mAlignment.testFlag(Qt::AlignBottom)) {
       
   142             // default align Qt::AlignVCenter if no flags are set
       
   143             diff*=0.5;
       
   144         }
       
   145     }
       
   146 #ifdef HB_RICH_TEXT_ITEM_ALWAS_SHOW_FIRST_LINE
       
   147     diff = qMax(diff, (qreal)0.0);
       
   148 #endif
       
   149 
       
   150     if(diff!=mOffset.y()) {
       
   151         mOffset.setY(diff);
       
   152         q->prepareGeometryChange();
       
   153     }
       
   154 }
       
   155 
       
   156 /*!
       
   157   @proto
       
   158   @hbcore
       
   159  \class HbRichTextItem
       
   160  \brief HbRichTextItem is a item for showing formatted text.
       
   161 
       
   162 
       
   163  This is mainly used as a primitive in widgets.
       
   164  It derives from HbWidgetBase so it can be layouted.
       
   165 
       
   166  */
       
   167 
       
   168 /*!
       
   169     Constructor for the class.
       
   170  */
       
   171 
       
   172 HbRichTextItem::HbRichTextItem(QGraphicsItem *parent) :
       
   173     HbWidgetBase(*new HbRichTextItemPrivate, parent)
       
   174 {
       
   175     Q_D(HbRichTextItem);
       
   176     d->init();
       
   177 }
       
   178 
       
   179 /*!
       
   180     Constructor which set content using \a html format.
       
   181  */
       
   182 HbRichTextItem::HbRichTextItem(const QString &html, QGraphicsItem *parent) :
       
   183     HbWidgetBase(*new HbRichTextItemPrivate, parent)
       
   184 {
       
   185     Q_D(HbRichTextItem);
       
   186     d->init();
       
   187     setText(html);
       
   188 }
       
   189 
       
   190 /*
       
   191     Constructor for internal use only
       
   192  */
       
   193 HbRichTextItem::HbRichTextItem(HbRichTextItemPrivate &dd, QGraphicsItem *parent) :
       
   194     HbWidgetBase(dd, parent)
       
   195 {
       
   196     Q_D(HbRichTextItem);
       
   197     d->init();
       
   198 }
       
   199 
       
   200 /*!
       
   201     Destructor for the class.
       
   202  */
       
   203 HbRichTextItem::~HbRichTextItem()
       
   204 {
       
   205     Q_D(HbRichTextItem);
       
   206     d->clear();
       
   207 }
       
   208 
       
   209 /*!
       
   210     Sets the \a text in html format.
       
   211 
       
   212     \sa HbRichTextItem::text()
       
   213  */
       
   214 void HbRichTextItem::setText(const QString &text)
       
   215 {
       
   216     Q_D(HbRichTextItem);
       
   217     if (d->mText != text) {
       
   218         d->mText = text;
       
   219         d->mRtf->setHtml(text);
       
   220         updateGeometry();
       
   221     }
       
   222 }
       
   223 
       
   224 /*!
       
   225     Returns the text in html format.
       
   226 
       
   227     \sa HbRichTextItem::setText()
       
   228  */
       
   229 
       
   230 QString HbRichTextItem::text() const
       
   231 {
       
   232     Q_D( const HbRichTextItem );
       
   233     return d->mText;
       
   234 }
       
   235 
       
   236 /*!
       
   237     Sets \a alignment for the text from Qt::Alignment enumeration.
       
   238 
       
   239     \sa HbRichTextItem::alignment()
       
   240  */
       
   241 void HbRichTextItem::setAlignment(Qt::Alignment alignment)
       
   242 {
       
   243     Q_D( HbRichTextItem );
       
   244 	d->setApiProtectionFlag(HbWidgetBasePrivate::AC_TextAlign, true);
       
   245     alignment &= Qt::AlignVertical_Mask | Qt::AlignHorizontal_Mask;
       
   246     if( d->mAlignment!=alignment ) {
       
   247         prepareGeometryChange();
       
   248         d->mAlignment = alignment;
       
   249         d->calculateOffset();
       
   250         if(d->setLayoutDirection(layoutDirection())) {
       
   251             update();
       
   252         }
       
   253     }
       
   254 }
       
   255 
       
   256 /*!
       
   257     Returns alignment for the text from Qt::Alignment enumeration.
       
   258 
       
   259     \sa HbRichTextItem::setAlignment()
       
   260  */
       
   261 Qt::Alignment HbRichTextItem::alignment() const
       
   262 {
       
   263     Q_D( const HbRichTextItem );
       
   264     return d->mAlignment;
       
   265 }
       
   266 
       
   267 /*!
       
   268     \reimp
       
   269  */
       
   270 void HbRichTextItem::paint(QPainter *painter, 
       
   271                             const QStyleOptionGraphicsItem *option, 
       
   272                             QWidget *widget)
       
   273 {
       
   274     Q_UNUSED(option);
       
   275     Q_UNUSED(widget);
       
   276 
       
   277     Q_D(HbRichTextItem);
       
   278 
       
   279     if(!d->mDontPrint) {
       
   280         if(!d->mDontClip) {
       
   281             painter->setClipRect(contentsRect(), Qt::IntersectClip);
       
   282         }
       
   283         painter->translate(d->mOffset);
       
   284         QAbstractTextDocumentLayout::PaintContext context;
       
   285         context.palette.setColor(QPalette::Text, textDefaultColor());
       
   286         d->mRtf->documentLayout()->draw(painter, context);
       
   287     }
       
   288 }
       
   289 
       
   290 /*!
       
   291     \reimp
       
   292 
       
   293     Sets new position and relayouts text according to new size.
       
   294  */
       
   295 void HbRichTextItem::setGeometry(const QRectF & rect)
       
   296 {
       
   297     Q_D(HbRichTextItem);
       
   298 
       
   299     HbWidgetBase::setGeometry(rect);
       
   300 
       
   301     if(rect.isValid()) {
       
   302         d->setSize(rect.size());
       
   303     }
       
   304 }
       
   305 
       
   306 /*!
       
   307     \reimp
       
   308  */
       
   309 QRectF HbRichTextItem::boundingRect () const
       
   310 {
       
   311     Q_D(const HbRichTextItem);
       
   312 
       
   313     QRectF result(d->mOffset, d->mRtf->size());
       
   314 
       
   315     if(!d->mDontClip) {
       
   316         // clip
       
   317         result = result.intersect(QRectF(QPointF(),
       
   318                                           size()));
       
   319     }
       
   320     return result;
       
   321 }
       
   322 
       
   323 /*!
       
   324     \reimp
       
   325     Relayouts text according to new size.
       
   326  */
       
   327 void HbRichTextItem::resizeEvent(QGraphicsSceneResizeEvent *event)
       
   328 {
       
   329     Q_D(HbRichTextItem);
       
   330 
       
   331     d->setSize(event->newSize());
       
   332 }
       
   333 
       
   334 /*!
       
   335     \reimp
       
   336     This impelementation detects layout direction changes, font changes and theme changes.
       
   337  */
       
   338 void HbRichTextItem::changeEvent(QEvent *event)
       
   339 {
       
   340     Q_D(HbRichTextItem);
       
   341 
       
   342     switch(event->type()) {
       
   343     case QEvent::LayoutDirectionChange: {
       
   344             prepareGeometryChange();
       
   345             if(d->setLayoutDirection(layoutDirection())) {
       
   346                 update();
       
   347             }
       
   348         }
       
   349         break;
       
   350 
       
   351     case QEvent::FontChange: {
       
   352             d->mRtf->setDefaultFont(font());
       
   353             updateGeometry();
       
   354         }
       
   355         break;
       
   356 
       
   357     default:
       
   358         // Listens theme changed event so that item size hint is
       
   359         // update when physical font is changed.
       
   360         if (event->type() == HbEvent::ThemeChanged) {
       
   361             Q_D(HbRichTextItem);
       
   362             d->mDefaultColor = QColor();
       
   363             if(!d->mColor.isValid()) { 
       
   364                 update();
       
   365             }
       
   366         }
       
   367     }
       
   368     HbWidgetBase::changeEvent(event);
       
   369 }
       
   370 
       
   371 /*!
       
   372     \reimp
       
   373     For which = PreferredSize returns reasonable size (QTextDocument::adjustSize()).
       
   374     For which = MinimumSize returns size of 4 first letters
       
   375     \a constraint width is taken into account.
       
   376  */
       
   377 QSizeF HbRichTextItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
       
   378 {
       
   379     Q_D(const HbRichTextItem);
       
   380     QSizeF result;
       
   381     switch(which) {
       
   382     case Qt::MinimumSize: {
       
   383             QTextBlock textBlock = d->mRtf->begin();
       
   384             if(textBlock.isValid() && textBlock.layout()->lineCount() > 0) {
       
   385                 QTextLine line = textBlock.layout()->lineAt(0);
       
   386                 result.setHeight(line.height());
       
   387                 int cursorPos(KMinimumLetersToShow);
       
   388                 result.setWidth( line.cursorToX(&cursorPos) );
       
   389 
       
   390                 qreal doubleDocMargin = d->mRtf->documentMargin() * (qreal)2.0;
       
   391                 result.rheight() += doubleDocMargin;
       
   392                 result.rwidth() += doubleDocMargin;
       
   393             } else {
       
   394                 result = HbWidgetBase::sizeHint(which, constraint);
       
   395             }
       
   396         }
       
   397         break;
       
   398 
       
   399     case Qt::PreferredSize: {
       
   400             if(constraint.width()<=0) {
       
   401                 d->mRtf->adjustSize();
       
   402             } else {
       
   403                 d->mRtf->setTextWidth(constraint.width());
       
   404             }
       
   405             result = d->mRtf->size();
       
   406         }
       
   407         break;
       
   408 
       
   409     default:
       
   410         result = HbWidgetBase::sizeHint(which, constraint);
       
   411     }
       
   412     return result;
       
   413 }
       
   414 
       
   415 /*!
       
   416  * @proto
       
   417  * Sets the text wrapping mode.
       
   418  *
       
   419  * \sa HbRichTextItem::textWrapping
       
   420  * \sa QTextOption::setWrapMode
       
   421  */
       
   422 void HbRichTextItem::setTextWrapping(Hb::TextWrapping mode)
       
   423 {
       
   424     Q_D(HbRichTextItem);
       
   425 	d->setApiProtectionFlag(HbWidgetBasePrivate::AC_TextWrapMode, true);
       
   426     QTextOption::WrapMode textWrapMode = static_cast<QTextOption::WrapMode>(mode);
       
   427 
       
   428     if(d->mTextOption.wrapMode()!=textWrapMode) {
       
   429         prepareGeometryChange();
       
   430         d->mTextOption.setWrapMode(textWrapMode);
       
   431         d->mRtf->setDefaultTextOption(d->mTextOption);
       
   432         updateGeometry();
       
   433     }
       
   434 }
       
   435 
       
   436 /*!
       
   437  * @proto
       
   438  * Returns style of text wrapping.
       
   439  *
       
   440  * \sa HbRichTextItem::setTextWrapping
       
   441  * \sa QTextOption::wrapMode
       
   442  */
       
   443 Hb::TextWrapping HbRichTextItem::textWrapping() const
       
   444 {
       
   445     Q_D(const HbRichTextItem);
       
   446 
       
   447     return static_cast<Hb::TextWrapping>(d->mTextOption.wrapMode());
       
   448 }
       
   449 
       
   450 /*!
       
   451  * Returns color used as a default text color.
       
   452  * If invalid color was set color for text is fetch from parent widget.
       
   453  * If invalid color was set and no parent widget was set this will return
       
   454  * default foreground color.
       
   455  *
       
   456  * \sa setTextDefaultColor()
       
   457  */
       
   458 QColor HbRichTextItem::textDefaultColor() const
       
   459 {
       
   460     Q_D( const HbRichTextItem );
       
   461 
       
   462     if (d->mColor.isValid()) { // Means user has set text color
       
   463         return d->mColor;
       
   464     } 
       
   465     if (!d->mDefaultColor.isValid()) {
       
   466         d->mDefaultColor = HbColorScheme::color(KDefaultColorThemeName);
       
   467     }
       
   468     
       
   469     return d->mDefaultColor;
       
   470 }
       
   471 
       
   472 /*!
       
   473  * Sets color of text.
       
   474  * If invalid color was set color for text is fetch from parent widget.
       
   475  * If invalid color was set and no parent widget was set default foreground color
       
   476  * will be used
       
   477  *
       
   478  * \sa textDefaultColor()
       
   479  */
       
   480 void HbRichTextItem::setTextDefaultColor(const QColor &color)
       
   481 {
       
   482     Q_D(HbRichTextItem);
       
   483     if (d->mColor != color) {
       
   484         d->mColor = color;
       
   485         update();
       
   486     }
       
   487 }
       
   488 
       
   489 /*!
       
   490  * Shows (default) or hides text. Size hint remains unchanged (same as when text is visible).
       
   491  */
       
   492 void HbRichTextItem::setTextVisible(bool isVisible)
       
   493 {
       
   494     Q_D(HbRichTextItem);
       
   495     if( d->mDontPrint == isVisible ) {
       
   496         d->mDontPrint = !isVisible;
       
   497         update();
       
   498     }
       
   499 }
       
   500 
       
   501 /*!
       
   502  * Returns if text is visible.
       
   503  */
       
   504 bool HbRichTextItem::isTextVisible() const
       
   505 {
       
   506     Q_D(const HbRichTextItem);
       
   507     return !d->mDontPrint;
       
   508 }
       
   509 
       
   510 /*!
       
   511  * Enables (default) or disables text clipping when item geometry is too small.
       
   512  */
       
   513 void HbRichTextItem::setTextClip(bool cliping)
       
   514 {
       
   515     Q_D(HbRichTextItem);
       
   516     if( d->mDontClip == cliping ) {
       
   517         prepareGeometryChange();
       
   518         d->mDontClip = !cliping;
       
   519         setFlag(QGraphicsItem::ItemClipsToShape, cliping);
       
   520         update();
       
   521     }
       
   522 }
       
   523 
       
   524 /*!
       
   525  * Returns true if text is clipped when item geometry is too small.
       
   526  */
       
   527 bool HbRichTextItem::isTextClip() const
       
   528 {
       
   529     Q_D(const HbRichTextItem);
       
   530     return !d->mDontClip;
       
   531 }
       
   532 
       
   533 // end of file