src/hbcore/primitives/hbrichtextitem.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbcore/primitives/hbrichtextitem.cpp	Mon Apr 19 14:02:13 2010 +0300
@@ -0,0 +1,533 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbCore module of the UI Extensions for Mobile.
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at developer.feedback@nokia.com.
+**
+****************************************************************************/
+
+#include "hbrichtextitem.h"
+#include "hbrichtextitem_p.h"
+#include "hbtextutils_p.h"
+#include "hbcolorscheme.h"
+#include "hbevent.h"
+
+#include <QTextDocument>
+#include <QStyle>
+#include <QGraphicsSceneResizeEvent>
+#include <QTextBlock>
+#include <QTextLayout>
+#include <QPainter>
+#include <QAbstractTextDocumentLayout>
+
+const int KMinimumLetersToShow = 4;
+
+static const QString KDefaultColorThemeName = "qtc_view_normal";
+
+HbRichTextItemPrivate::HbRichTextItemPrivate() :
+    mAlignment(Qt::AlignLeft|Qt::AlignVCenter),
+    mTextOption(mAlignment),
+    mDontPrint(false),
+    mDontClip(false),
+    mRtf(0)
+{
+}
+
+HbRichTextItemPrivate::~HbRichTextItemPrivate()
+{
+}
+
+/*
+ * private constructor
+ */
+void HbRichTextItemPrivate::init()
+{
+    Q_Q(HbRichTextItem);
+
+    q->setFlag(QGraphicsItem::ItemClipsToShape, !mDontClip);
+    q->setFlag(QGraphicsItem::ItemIsSelectable, false);
+    q->setFlag(QGraphicsItem::ItemIsFocusable,  false);
+
+    mRtf = new QTextDocument(q);
+    mRtf->setDocumentMargin(0.0); // no margins needed
+
+    mTextOption.setWrapMode(QTextOption::NoWrap);
+    mRtf->setDefaultTextOption(mTextOption);
+
+    mRtf->setDefaultFont(q->font());
+}
+
+void HbRichTextItemPrivate::clear()
+{
+    delete mRtf;
+}
+
+int HbRichTextItemPrivate::textFlagsFromTextOption() const
+{
+    int flags = (int)mAlignment;
+
+    switch(mTextOption.wrapMode()) {
+    case QTextOption::NoWrap:
+        flags |= Qt::TextSingleLine;
+        break;
+    case QTextOption::WordWrap:
+        flags |=Qt::TextWordWrap;
+        break;
+    case QTextOption::ManualWrap:
+        break;
+    case QTextOption::WrapAnywhere:
+        flags |=Qt::TextWrapAnywhere;
+        break;
+    case QTextOption::WrapAtWordBoundaryOrAnywhere:
+        flags |=Qt::TextWordWrap | Qt::TextWrapAnywhere;
+        break;
+    }
+
+    if(mDontClip)  flags |= Qt::TextDontClip;
+    if(mDontPrint) flags |= Qt::TextDontPrint;
+
+    return flags;
+}
+
+bool HbRichTextItemPrivate::setLayoutDirection(Qt::LayoutDirection newDirection)
+{
+    Qt::Alignment oldAlign = mTextOption.alignment();
+    Qt::Alignment alignment = QStyle::visualAlignment(newDirection, mAlignment);
+    if(alignment!=oldAlign) {
+        mTextOption.setAlignment(alignment);
+        mRtf->setDefaultTextOption(mTextOption);
+        return true;
+    }
+    return false;
+}
+
+void HbRichTextItemPrivate::setSize(const QSizeF &newSize)
+{
+    if(mRtf->size()!=newSize) {
+        Q_Q(HbRichTextItem);
+        mRtf->setTextWidth(newSize.width());
+        calculateOffset();
+        q->update();
+    }
+}
+
+// #define HB_RICH_TEXT_ITEM_ALWAS_SHOW_FIRST_LINE
+void HbRichTextItemPrivate::calculateOffset()
+{
+    Q_Q(HbRichTextItem);
+
+    qreal diff;
+    if(mAlignment.testFlag(Qt::AlignTop)) {
+        diff = 0.0;
+    } else {
+        diff = q->geometry().height() - mRtf->size().height();
+        if(!mAlignment.testFlag(Qt::AlignBottom)) {
+            // default align Qt::AlignVCenter if no flags are set
+            diff*=0.5;
+        }
+    }
+#ifdef HB_RICH_TEXT_ITEM_ALWAS_SHOW_FIRST_LINE
+    diff = qMax(diff, (qreal)0.0);
+#endif
+
+    if(diff!=mOffset.y()) {
+        mOffset.setY(diff);
+        q->prepareGeometryChange();
+    }
+}
+
+/*!
+  @proto
+  @hbcore
+ \class HbRichTextItem
+ \brief HbRichTextItem is a item for showing formatted text.
+
+
+ This is mainly used as a primitive in widgets.
+ It derives from HbWidgetBase so it can be layouted.
+
+ */
+
+/*!
+    Constructor for the class.
+ */
+
+HbRichTextItem::HbRichTextItem(QGraphicsItem *parent) :
+    HbWidgetBase(*new HbRichTextItemPrivate, parent)
+{
+    Q_D(HbRichTextItem);
+    d->init();
+}
+
+/*!
+    Constructor which set content using \a html format.
+ */
+HbRichTextItem::HbRichTextItem(const QString &html, QGraphicsItem *parent) :
+    HbWidgetBase(*new HbRichTextItemPrivate, parent)
+{
+    Q_D(HbRichTextItem);
+    d->init();
+    setText(html);
+}
+
+/*
+    Constructor for internal use only
+ */
+HbRichTextItem::HbRichTextItem(HbRichTextItemPrivate &dd, QGraphicsItem *parent) :
+    HbWidgetBase(dd, parent)
+{
+    Q_D(HbRichTextItem);
+    d->init();
+}
+
+/*!
+    Destructor for the class.
+ */
+HbRichTextItem::~HbRichTextItem()
+{
+    Q_D(HbRichTextItem);
+    d->clear();
+}
+
+/*!
+    Sets the \a text in html format.
+
+    \sa HbRichTextItem::text()
+ */
+void HbRichTextItem::setText(const QString &text)
+{
+    Q_D(HbRichTextItem);
+    if (d->mText != text) {
+        d->mText = text;
+        d->mRtf->setHtml(text);
+        updateGeometry();
+    }
+}
+
+/*!
+    Returns the text in html format.
+
+    \sa HbRichTextItem::setText()
+ */
+
+QString HbRichTextItem::text() const
+{
+    Q_D( const HbRichTextItem );
+    return d->mText;
+}
+
+/*!
+    Sets \a alignment for the text from Qt::Alignment enumeration.
+
+    \sa HbRichTextItem::alignment()
+ */
+void HbRichTextItem::setAlignment(Qt::Alignment alignment)
+{
+    Q_D( HbRichTextItem );
+	d->setApiProtectionFlag(HbWidgetBasePrivate::AC_TextAlign, true);
+    alignment &= Qt::AlignVertical_Mask | Qt::AlignHorizontal_Mask;
+    if( d->mAlignment!=alignment ) {
+        prepareGeometryChange();
+        d->mAlignment = alignment;
+        d->calculateOffset();
+        if(d->setLayoutDirection(layoutDirection())) {
+            update();
+        }
+    }
+}
+
+/*!
+    Returns alignment for the text from Qt::Alignment enumeration.
+
+    \sa HbRichTextItem::setAlignment()
+ */
+Qt::Alignment HbRichTextItem::alignment() const
+{
+    Q_D( const HbRichTextItem );
+    return d->mAlignment;
+}
+
+/*!
+    \reimp
+ */
+void HbRichTextItem::paint(QPainter *painter, 
+                            const QStyleOptionGraphicsItem *option, 
+                            QWidget *widget)
+{
+    Q_UNUSED(option);
+    Q_UNUSED(widget);
+
+    Q_D(HbRichTextItem);
+
+    if(!d->mDontPrint) {
+        if(!d->mDontClip) {
+            painter->setClipRect(contentsRect(), Qt::IntersectClip);
+        }
+        painter->translate(d->mOffset);
+        QAbstractTextDocumentLayout::PaintContext context;
+        context.palette.setColor(QPalette::Text, textDefaultColor());
+        d->mRtf->documentLayout()->draw(painter, context);
+    }
+}
+
+/*!
+    \reimp
+
+    Sets new position and relayouts text according to new size.
+ */
+void HbRichTextItem::setGeometry(const QRectF & rect)
+{
+    Q_D(HbRichTextItem);
+
+    HbWidgetBase::setGeometry(rect);
+
+    if(rect.isValid()) {
+        d->setSize(rect.size());
+    }
+}
+
+/*!
+    \reimp
+ */
+QRectF HbRichTextItem::boundingRect () const
+{
+    Q_D(const HbRichTextItem);
+
+    QRectF result(d->mOffset, d->mRtf->size());
+
+    if(!d->mDontClip) {
+        // clip
+        result = result.intersect(QRectF(QPointF(),
+                                          size()));
+    }
+    return result;
+}
+
+/*!
+    \reimp
+    Relayouts text according to new size.
+ */
+void HbRichTextItem::resizeEvent(QGraphicsSceneResizeEvent *event)
+{
+    Q_D(HbRichTextItem);
+
+    d->setSize(event->newSize());
+}
+
+/*!
+    \reimp
+    This impelementation detects layout direction changes, font changes and theme changes.
+ */
+void HbRichTextItem::changeEvent(QEvent *event)
+{
+    Q_D(HbRichTextItem);
+
+    switch(event->type()) {
+    case QEvent::LayoutDirectionChange: {
+            prepareGeometryChange();
+            if(d->setLayoutDirection(layoutDirection())) {
+                update();
+            }
+        }
+        break;
+
+    case QEvent::FontChange: {
+            d->mRtf->setDefaultFont(font());
+            updateGeometry();
+        }
+        break;
+
+    default:
+        // Listens theme changed event so that item size hint is
+        // update when physical font is changed.
+        if (event->type() == HbEvent::ThemeChanged) {
+            Q_D(HbRichTextItem);
+            d->mDefaultColor = QColor();
+            if(!d->mColor.isValid()) { 
+                update();
+            }
+        }
+    }
+    HbWidgetBase::changeEvent(event);
+}
+
+/*!
+    \reimp
+    For which = PreferredSize returns reasonable size (QTextDocument::adjustSize()).
+    For which = MinimumSize returns size of 4 first letters
+    \a constraint width is taken into account.
+ */
+QSizeF HbRichTextItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+    Q_D(const HbRichTextItem);
+    QSizeF result;
+    switch(which) {
+    case Qt::MinimumSize: {
+            QTextBlock textBlock = d->mRtf->begin();
+            if(textBlock.isValid() && textBlock.layout()->lineCount() > 0) {
+                QTextLine line = textBlock.layout()->lineAt(0);
+                result.setHeight(line.height());
+                int cursorPos(KMinimumLetersToShow);
+                result.setWidth( line.cursorToX(&cursorPos) );
+
+                qreal doubleDocMargin = d->mRtf->documentMargin() * (qreal)2.0;
+                result.rheight() += doubleDocMargin;
+                result.rwidth() += doubleDocMargin;
+            } else {
+                result = HbWidgetBase::sizeHint(which, constraint);
+            }
+        }
+        break;
+
+    case Qt::PreferredSize: {
+            if(constraint.width()<=0) {
+                d->mRtf->adjustSize();
+            } else {
+                d->mRtf->setTextWidth(constraint.width());
+            }
+            result = d->mRtf->size();
+        }
+        break;
+
+    default:
+        result = HbWidgetBase::sizeHint(which, constraint);
+    }
+    return result;
+}
+
+/*!
+ * @proto
+ * Sets the text wrapping mode.
+ *
+ * \sa HbRichTextItem::textWrapping
+ * \sa QTextOption::setWrapMode
+ */
+void HbRichTextItem::setTextWrapping(Hb::TextWrapping mode)
+{
+    Q_D(HbRichTextItem);
+	d->setApiProtectionFlag(HbWidgetBasePrivate::AC_TextWrapMode, true);
+    QTextOption::WrapMode textWrapMode = static_cast<QTextOption::WrapMode>(mode);
+
+    if(d->mTextOption.wrapMode()!=textWrapMode) {
+        prepareGeometryChange();
+        d->mTextOption.setWrapMode(textWrapMode);
+        d->mRtf->setDefaultTextOption(d->mTextOption);
+        updateGeometry();
+    }
+}
+
+/*!
+ * @proto
+ * Returns style of text wrapping.
+ *
+ * \sa HbRichTextItem::setTextWrapping
+ * \sa QTextOption::wrapMode
+ */
+Hb::TextWrapping HbRichTextItem::textWrapping() const
+{
+    Q_D(const HbRichTextItem);
+
+    return static_cast<Hb::TextWrapping>(d->mTextOption.wrapMode());
+}
+
+/*!
+ * Returns color used as a default text color.
+ * If invalid color was set color for text is fetch from parent widget.
+ * If invalid color was set and no parent widget was set this will return
+ * default foreground color.
+ *
+ * \sa setTextDefaultColor()
+ */
+QColor HbRichTextItem::textDefaultColor() const
+{
+    Q_D( const HbRichTextItem );
+
+    if (d->mColor.isValid()) { // Means user has set text color
+        return d->mColor;
+    } 
+    if (!d->mDefaultColor.isValid()) {
+        d->mDefaultColor = HbColorScheme::color(KDefaultColorThemeName);
+    }
+    
+    return d->mDefaultColor;
+}
+
+/*!
+ * Sets color of text.
+ * If invalid color was set color for text is fetch from parent widget.
+ * If invalid color was set and no parent widget was set default foreground color
+ * will be used
+ *
+ * \sa textDefaultColor()
+ */
+void HbRichTextItem::setTextDefaultColor(const QColor &color)
+{
+    Q_D(HbRichTextItem);
+    if (d->mColor != color) {
+        d->mColor = color;
+        update();
+    }
+}
+
+/*!
+ * Shows (default) or hides text. Size hint remains unchanged (same as when text is visible).
+ */
+void HbRichTextItem::setTextVisible(bool isVisible)
+{
+    Q_D(HbRichTextItem);
+    if( d->mDontPrint == isVisible ) {
+        d->mDontPrint = !isVisible;
+        update();
+    }
+}
+
+/*!
+ * Returns if text is visible.
+ */
+bool HbRichTextItem::isTextVisible() const
+{
+    Q_D(const HbRichTextItem);
+    return !d->mDontPrint;
+}
+
+/*!
+ * Enables (default) or disables text clipping when item geometry is too small.
+ */
+void HbRichTextItem::setTextClip(bool cliping)
+{
+    Q_D(HbRichTextItem);
+    if( d->mDontClip == cliping ) {
+        prepareGeometryChange();
+        d->mDontClip = !cliping;
+        setFlag(QGraphicsItem::ItemClipsToShape, cliping);
+        update();
+    }
+}
+
+/*!
+ * Returns true if text is clipped when item geometry is too small.
+ */
+bool HbRichTextItem::isTextClip() const
+{
+    Q_D(const HbRichTextItem);
+    return !d->mDontClip;
+}
+
+// end of file