src/hbwidgets/editors/hbabstractedit_p.cpp
changeset 34 ed14f46c0e55
parent 7 923ff622b8b9
equal deleted inserted replaced
31:7516d6d86cf5 34:ed14f46c0e55
    41 #include "hbvalidator.h"
    41 #include "hbvalidator.h"
    42 #include "hbmenu.h"
    42 #include "hbmenu.h"
    43 #include "hbselectioncontrol_p.h"
    43 #include "hbselectioncontrol_p.h"
    44 #include "hbcolorscheme.h"
    44 #include "hbcolorscheme.h"
    45 #include "hbsmileyengine_p.h"
    45 #include "hbsmileyengine_p.h"
    46 #include "hbtextmeasurementutility_p.h"
    46 #ifdef HB_TEXT_MEASUREMENT_UTILITY
    47 #include "hbfeaturemanager_r.h"
    47 #include "hbtextmeasurementutility_r.h"
       
    48 #include "hbtextmeasurementutility_r_p.h"
       
    49 #endif
    48 #include "hbinputeditorinterface.h"
    50 #include "hbinputeditorinterface.h"
    49 #include "hbinputvkbhost.h"
    51 #include "hbinputvkbhost.h"
    50 #include "hbinputmethod.h"
    52 #include "hbinputmethod.h"
    51 #include "hbinputfocusobject.h"
    53 #include "hbinputfocusobject.h"
       
    54 #include "hbtapgesture.h"
       
    55 #include "hbpangesture.h"
       
    56 #include "hbnamespace_p.h"
       
    57 #include "hbwidgetfeedback.h"
       
    58 
    52 
    59 
    53 
    60 
    54 #include <QValidator>
    61 #include <QValidator>
    55 #include <QTextLayout>
    62 #include <QTextLayout>
    56 #include <QTextBlock>
    63 #include <QTextBlock>
    61 #include <QPainter>
    68 #include <QPainter>
    62 #include <QtDebug>
    69 #include <QtDebug>
    63 #include <QClipboard>
    70 #include <QClipboard>
    64 #include <QInputContext>
    71 #include <QInputContext>
    65 #include <QRegExp>
    72 #include <QRegExp>
       
    73 #include <QGraphicsScene>
       
    74 
       
    75 
       
    76 namespace { 
       
    77     static const int DOUBLE_TAP_DELAY = 400;
       
    78 }
    66 
    79 
    67 static inline bool firstFramePosLessThanCursorPos(QTextFrame *frame, int position)
    80 static inline bool firstFramePosLessThanCursorPos(QTextFrame *frame, int position)
    68 {
    81 {
    69     return frame->firstPosition() < position;
    82     return frame->firstPosition() < position;
    70 }
    83 }
    89             r |= frame->document()->documentLayout()->frameBoundingRect(*it);
   102             r |= frame->document()->documentLayout()->frameBoundingRect(*it);
    90     }
   103     }
    91     return r;
   104     return r;
    92 }
   105 }
    93 
   106 
       
   107 
       
   108 class HbEditScrollArea: public HbScrollArea
       
   109 {
       
   110 public:
       
   111     explicit HbEditScrollArea(HbAbstractEdit* edit, QGraphicsItem* parent = 0):HbScrollArea(parent), mEdit(edit) {}
       
   112     virtual ~HbEditScrollArea() {}
       
   113 
       
   114     void resizeEvent(QGraphicsSceneResizeEvent *event)
       
   115     {
       
   116         HbScrollArea::resizeEvent(event);
       
   117         mEdit->updatePrimitives();
       
   118     }
       
   119 
       
   120 private:
       
   121     HbAbstractEdit* mEdit;
       
   122 };
       
   123 
       
   124 
    94 class HbEditItem : public HbWidget
   125 class HbEditItem : public HbWidget
    95 {
   126 {
    96 public:
   127 public:
    97 
   128 
    98     HbEditItem(HbAbstractEdit *parent) : HbWidget(parent), edit(parent)
   129     HbEditItem(HbAbstractEdit *parent) : HbWidget(parent), edit(parent)
    99     {
   130     {
   100     	setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
   131         setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
   101     };
   132     }
   102 
   133 
   103     virtual ~HbEditItem() {};
   134     virtual ~HbEditItem() {}
   104 
   135 
   105     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
   136     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
   106     {
   137     {
   107         Q_UNUSED(widget)
   138         Q_UNUSED(widget)
   108 
   139 
   177 
   208 
   178 HbAbstractEditPrivate::HbAbstractEditPrivate () :
   209 HbAbstractEditPrivate::HbAbstractEditPrivate () :
   179     HbWidgetPrivate(),
   210     HbWidgetPrivate(),
   180     doc(0),
   211     doc(0),
   181     placeholderDoc(0),
   212     placeholderDoc(0),
       
   213     previousCursorAnchor(-1),
       
   214     previousCursorPosition(-1),
   182     validator(0),
   215     validator(0),
   183     imEditInProgress(false),
   216     imEditInProgress(false),
   184     imPosition(0),
   217     imPosition(0),
   185     imAdded(0),
   218     imAdded(0),
   186     imRemoved(0),
   219     imRemoved(0),
   187     interactionFlags(Qt::TextEditorInteraction),
   220     interactionFlags(Qt::TextEditorInteraction),
   188     tapPosition(-1, -1),
   221     tapPosition(-1, -1),
   189     cursorOn(false),
   222     cursorOn(false),
       
   223     tapCounter(0),
       
   224     showContextMenu(false),
   190     preeditCursor(0),
   225     preeditCursor(0),
   191     preeditCursorVisible(true),
   226     preeditCursorVisible(true),
   192     apiCursorVisible(true),
   227     apiCursorVisible(true),
   193     canvas(0),
   228     canvas(0),
   194     scrollArea(0),
   229     scrollArea(0),
   195     scrollable(false),
   230     scrollable(false),
   196     hadSelectionOnMousePress(false),
   231     hadSelectionOnMousePress(false),
   197     selectionControl(0),
   232     selectionControl(0),
       
   233     enableSelectionControl(true),
   198     acceptSignalContentsChange(true),
   234     acceptSignalContentsChange(true),
   199     acceptSignalContentsChanged(true),
   235     acceptSignalContentsChanged(true),
   200     validRevision(0),
   236     validRevision(0),
   201     wasGesture(false),
   237     wasGesture(false),
   202     smileysEnabled(false),
   238     smileysEnabled(false),
   203     smileyEngine(0),
   239     smileyEngine(0),
   204     formatDialog(0),
   240     formatDialog(0),
   205     updatePrimitivesInProgress(false)
   241     updatePrimitivesInProgress(false),
       
   242     enableMagnifier(true),
       
   243     cursorType(CursorTypeBlinking)
   206 {
   244 {
   207 }
   245 }
   208 
   246 
   209 HbAbstractEditPrivate::~HbAbstractEditPrivate ()
   247 HbAbstractEditPrivate::~HbAbstractEditPrivate ()
   210 {
   248 {
   213 void HbAbstractEditPrivate::init()
   251 void HbAbstractEditPrivate::init()
   214 {
   252 {
   215     Q_Q(HbAbstractEdit);
   253     Q_Q(HbAbstractEdit);
   216 
   254 
   217     canvas = new HbEditItem(q);
   255     canvas = new HbEditItem(q);
   218     canvas->setSizePolicy(QSizePolicy::Ignored,QSizePolicy::Ignored);
   256 
   219 
   257     q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
   220 
   258 
   221     setContent(Qt::RichText, QString());
   259     setContent(Qt::RichText, QString());
   222 
   260 
   223     QTextOption textOption = doc->defaultTextOption();
   261     QTextOption textOption = doc->defaultTextOption();
   224     textOption.setTextDirection(q->layoutDirection());
   262     textOption.setTextDirection(q->layoutDirection());
   225     doc->setDefaultTextOption(textOption);
   263     doc->setDefaultTextOption(textOption);
   226     doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
   264     doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
   227 
   265 
   228     updatePaletteFromTheme();
   266     updatePaletteFromTheme();
   229 
   267 
   230     scrollArea = new HbScrollArea(q);
   268     scrollArea = new HbEditScrollArea(q,q);
   231     scrollArea->setClampingStyle(HbScrollArea::StrictClamping);
   269     scrollArea->setClampingStyle(HbScrollArea::StrictClamping);
   232     scrollArea->setFrictionEnabled(true);
   270     scrollArea->setFrictionEnabled(true);
   233     scrollArea->setScrollDirections(Qt::Vertical);
   271     scrollArea->setScrollDirections(Qt::Vertical);
   234     scrollArea->setVerticalScrollBarPolicy(HbScrollArea::ScrollBarAlwaysOff);
   272     scrollArea->setVerticalScrollBarPolicy(HbScrollArea::ScrollBarAlwaysOff);
   235     scrollArea->setContentWidget(canvas);
   273     scrollArea->setContentWidget(canvas);
       
   274     canvas->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   236     scrollArea->setFlag(QGraphicsItem::ItemIsFocusable, false);
   275     scrollArea->setFlag(QGraphicsItem::ItemIsFocusable, false);
   237     QObject::connect(scrollArea, SIGNAL(scrollingStarted()), q, SLOT(_q_scrollStarted()));
   276     QObject::connect(scrollArea, SIGNAL(scrollingStarted()), q, SLOT(_q_scrollStarted()));
   238     QObject::connect(scrollArea, SIGNAL(scrollingEnded()), q, SLOT(_q_scrollEnded()));
   277     QObject::connect(scrollArea, SIGNAL(scrollingEnded()), q, SLOT(_q_scrollEnded()));
   239     QObject::connect(q, SIGNAL(selectionChanged(QTextCursor,QTextCursor)), q, SLOT(_q_selectionChanged()));
   278     QObject::connect(q, SIGNAL(selectionChanged(const QTextCursor&,const QTextCursor&)), q, SLOT(_q_selectionChanged(const QTextCursor&,const QTextCursor&)));
   240     HbStyle::setItemName(scrollArea, QString("text"));
   279     HbStyle::setItemName(scrollArea, QString("text"));
   241 
   280 
   242     // These are the default values which are then overridden in subclasses
   281     // These are the default values which are then overridden in subclasses
   243     // and when different options are enabled.
   282     // and when different options are enabled.
   244     q->setFlag(QGraphicsItem::ItemIsFocusable);
   283     q->setFlag(QGraphicsItem::ItemIsFocusable); 
   245     q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
       
   246     q->setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
   284     q->setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
   247     q->setFlag(QGraphicsItem::ItemHasNoContents, false);
   285     q->setFlag(QGraphicsItem::ItemHasNoContents, false);
   248     q->setFocusPolicy(Qt::StrongFocus);
   286     q->setFocusPolicy(Qt::StrongFocus);
   249     q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   287     q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   250 
   288 
   275     Q_Q(HbAbstractEdit);
   313     Q_Q(HbAbstractEdit);
   276 
   314 
   277     // for localization text support
   315     // for localization text support
   278     QString txt( text );
   316     QString txt( text );
   279 #ifdef HB_TEXT_MEASUREMENT_UTILITY
   317 #ifdef HB_TEXT_MEASUREMENT_UTILITY
   280     if ( HbFeatureManager::instance()->featureStatus( HbFeatureManager::TextMeasurement ) ) {
   318     if (HbTextMeasurementUtility::instance()->locTestMode()) {
   281         if (text.endsWith(QChar(LOC_TEST_END))) {
   319         if (text.endsWith(QChar(LOC_TEST_END))) {
   282             int index = text.indexOf(QChar(LOC_TEST_START));
   320             int index = text.indexOf(QChar(LOC_TEST_START));
   283             q->setProperty( HbTextMeasurementUtilityNameSpace::textIdPropertyName,
   321             q->setProperty( HbTextMeasurementUtilityNameSpace::textIdPropertyName,
   284                     text.mid(index + 1, text.indexOf(QChar(LOC_TEST_END)) - index - 1) );
   322                     text.mid(index + 1, text.indexOf(QChar(LOC_TEST_END)) - index - 1) );
   285             txt = text.left(index);
   323             txt = text.left(index);
   346 
   384 
   347     doc->setModified(false);
   385     doc->setModified(false);
   348 
   386 
   349     ensureCursorVisible();
   387     ensureCursorVisible();
   350 
   388 
   351     smileyEngineInstance()->setDocument(doc);
       
   352     if(q->isSmileysEnabled()) {
   389     if(q->isSmileysEnabled()) {
   353         smileyEngineInstance()->insertSmileys();
   390         smileyEngineInstance()->insertSmileys();
   354     }
   391     }
   355 }
   392 }
   356 
   393 
   523         differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
   560         differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
   524         canvas->update(selectionRect(differenceSelection));
   561         canvas->update(selectionRect(differenceSelection));
   525     } else {
   562     } else {
   526         if (!oldSelection.isNull())
   563         if (!oldSelection.isNull())
   527             canvas->update(selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection.position()));
   564             canvas->update(selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection.position()));
   528         canvas->update(selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor.position()));
   565         canvas->update(selectionRect(cursor) | cursorRectPlusUnicodeDirectionMarkers(cursor.position()));
   529     }
   566     }
   530 }
   567 }
   531 
   568 
   532 void HbAbstractEditPrivate::updateCurrentCharFormat()
   569 void HbAbstractEditPrivate::updateCurrentCharFormat()
   533 {
   570 {
   540 QRectF HbAbstractEditPrivate::cursorRectPlusUnicodeDirectionMarkers(int position) const
   577 QRectF HbAbstractEditPrivate::cursorRectPlusUnicodeDirectionMarkers(int position) const
   541 {
   578 {
   542     return rectForPositionInCanvasCoords(position,QTextLine::Leading).adjusted(-4, 0, 4, 0);
   579     return rectForPositionInCanvasCoords(position,QTextLine::Leading).adjusted(-4, 0, 4, 0);
   543 }
   580 }
   544 
   581 
   545 void HbAbstractEditPrivate::setBlinkingCursorEnabled(bool enable)
   582 void HbAbstractEditPrivate::updateCursorType()
       
   583 {
       
   584     updateCursorType(hasInputFocus());
       
   585 }
       
   586 
       
   587 void HbAbstractEditPrivate::updateCursorType(bool hasInputFocus)
       
   588 {
       
   589     CursorType type = hasInputFocus?CursorTypeBlinking:CursorTypeNone;
       
   590 
       
   591     if (hasInputFocus) {
       
   592         if (cursor.hasSelection()) {
       
   593             type = CursorTypeNone;
       
   594         } else if (selectionControl && selectionControl->isVisible()) {
       
   595             type = CursorTypeStill;
       
   596         }
       
   597     }
       
   598     setCursorType(type);
       
   599 }
       
   600 
       
   601 void HbAbstractEditPrivate::setCursorType(CursorType type)
   546 {
   602 {
   547     Q_Q(HbAbstractEdit);
   603     Q_Q(HbAbstractEdit);
   548 
   604 
   549     if (enable && QApplication::cursorFlashTime() > 0)
   605     if (cursorType != type) {
   550         cursorBlinkTimer.start(QApplication::cursorFlashTime() / 2, q);
   606         cursorType = type;
   551     else
   607 
   552         cursorBlinkTimer.stop();
   608         if (cursorType == CursorTypeBlinking && QApplication::cursorFlashTime() > 0)
   553 
   609             cursorBlinkTimer.start(QApplication::cursorFlashTime() / 2, q);
   554     cursorOn = enable;
   610         else
   555 
   611             cursorBlinkTimer.stop();
   556     repaintCursor();
   612 
       
   613         cursorOn = (cursorType != CursorTypeNone);
       
   614 
       
   615         repaintCursor();
       
   616     }
       
   617 }
       
   618 
       
   619 void HbAbstractEditPrivate::setCursorColor(const QColor& color)
       
   620 {
       
   621     cursorColor = color;
   557 }
   622 }
   558 
   623 
   559 void HbAbstractEditPrivate::repaintCursor()
   624 void HbAbstractEditPrivate::repaintCursor()
   560 {
   625 {
   561     canvas->update(cursorRectPlusUnicodeDirectionMarkers(cursor.position()));
   626     canvas->update(cursorRectPlusUnicodeDirectionMarkers(cursor.position()));
   563 
   628 
   564 void HbAbstractEditPrivate::ensurePositionVisible(int position)
   629 void HbAbstractEditPrivate::ensurePositionVisible(int position)
   565 {
   630 {
   566     if (scrollArea && scrollable) {
   631     if (scrollArea && scrollable) {
   567         QRectF rect = rectForPositionInCanvasCoords(position, QTextLine::Leading);
   632         QRectF rect = rectForPositionInCanvasCoords(position, QTextLine::Leading);
   568         rect.adjust(0, -doc->documentMargin(), 0, doc->documentMargin());
   633         qreal docMargin = doc->documentMargin();
       
   634         rect.adjust(0, -docMargin, 0, docMargin);
   569         // TODO: it seems that scrollArea->ensureVisible() expects the point
   635         // TODO: it seems that scrollArea->ensureVisible() expects the point
   570         //       in its content coordinates. Probably it should use viewport
   636         //       in its content coordinates. Probably it should use viewport
   571         //       coordinates i.e. its own item coordinate system
   637         //       coordinates i.e. its own item coordinate system
   572         //QRectF recScroll = canvas->mapToItem(scrollArea, rect).boundingRect();
   638         //QRectF recScroll = canvas->mapToItem(scrollArea, rect).boundingRect();
       
   639 
       
   640         const QTextBlock block = doc->findBlock(position);
       
   641         if (block.isValid()) {
       
   642             const QTextLayout *layout = block.layout();
       
   643             if(layout->preeditAreaText().length()) {
       
   644                 // Adjust cursor rect so that predictive text will be also visible
       
   645                 int preeditStart = layout->preeditAreaPosition();
       
   646                 int preeditStop = preeditStart+layout->preeditAreaText().length();
       
   647                 QTextLine line = layout->lineForTextPosition(preeditStart);
       
   648                 qreal preeditWidth = qAbs(line.cursorToX(preeditStop)-line.cursorToX(preeditStart));
       
   649                 // rect.adjust(0,0,preeditWidth*0.5,0);
       
   650                 rect.setWidth(rect.width()+preeditWidth*0.5);
       
   651             }
       
   652         }
   573         scrollArea->ensureVisible(rect.center(), rect.width(), rect.height()/2);
   653         scrollArea->ensureVisible(rect.center(), rect.width(), rect.height()/2);
   574     }
   654     }
   575 }
   655 }
   576 
   656 
   577 void HbAbstractEditPrivate::ensureCursorVisible()
   657 void HbAbstractEditPrivate::ensureCursorVisible()
   585 void HbAbstractEditPrivate::setTextInteractionFlags(Qt::TextInteractionFlags flags)
   665 void HbAbstractEditPrivate::setTextInteractionFlags(Qt::TextInteractionFlags flags)
   586 {
   666 {
   587     if (flags == interactionFlags)
   667     if (flags == interactionFlags)
   588         return;
   668         return;
   589     interactionFlags = flags;
   669     interactionFlags = flags;
   590 
       
   591     if (hasInputFocus()) {
       
   592         setBlinkingCursorEnabled(flags & Qt::TextEditable);
       
   593     }
       
   594 }
   670 }
   595 
   671 
   596 void HbAbstractEditPrivate::_q_updateRequest(QRectF rect)
   672 void HbAbstractEditPrivate::_q_updateRequest(QRectF rect)
   597 {
   673 {
   598     canvas->update(rect);
   674     canvas->update(rect);
   614             validateAndCorrect();
   690             validateAndCorrect();
   615         }
   691         }
   616         updateCurrentCharFormat();
   692         updateCurrentCharFormat();
   617 
   693 
   618         emit q->contentsChanged();
   694         emit q->contentsChanged();
       
   695 
       
   696         canvas->setPreferredSize(calculatePreferredDocSize());
   619 
   697 
   620         acceptSignalContentsChanged = true; // end of prevent recurence
   698         acceptSignalContentsChanged = true; // end of prevent recurence
   621     }
   699     }
   622 }
   700 }
   623 
   701 
   628         imRemoved = charsRemoved;
   706         imRemoved = charsRemoved;
   629         imAdded = charsAdded;
   707         imAdded = charsAdded;
   630     }
   708     }
   631 }
   709 }
   632 
   710 
   633 void HbAbstractEditPrivate::_q_selectionChanged()
   711 void HbAbstractEditPrivate::_q_selectionChanged(const QTextCursor& oldSelection, const QTextCursor& newSelection)
   634 {
   712 {
   635     Q_Q(HbAbstractEdit);
   713     Q_Q(HbAbstractEdit);
   636 
   714 
   637     if (cursor.hasSelection()) {   
   715     if (newSelection.hasSelection()) {
   638         selectionControl = HbSelectionControl::attachEditor(q);
   716         selectionControl = HbSelectionControl::attachEditor(q);
   639         selectionControl->showHandles();
   717         selectionControl->setMagnifierEnabled(q->isSelectionControlEnabled()&&enableMagnifier);
       
   718         if (q->isSelectionControlEnabled()) {
       
   719             selectionControl->showHandles();
       
   720         }
   640     } else if (selectionControl){
   721     } else if (selectionControl){
   641         selectionControl->hideHandles();
   722         if (q->isReadOnly()) {
       
   723             selectionControl->hideHandles();
       
   724         }
       
   725         selectionControl->updatePrimitives();
   642     }
   726     }
   643     
   727     
   644     QTextCursor oldSelection(selectionCursor);
   728     updateCursorType();
   645     selectionCursor = cursor;
       
   646     repaintOldAndNewSelection(oldSelection);
   729     repaintOldAndNewSelection(oldSelection);
   647 }
   730 }
   648 
   731 
   649 void HbAbstractEditPrivate::_q_scrollStarted()
   732 void HbAbstractEditPrivate::_q_scrollStarted()
   650 {
   733 {
   744         }
   827         }
   745         if (!selectionCursor.hasSelection() && !cursor.hasSelection()) {
   828         if (!selectionCursor.hasSelection() && !cursor.hasSelection()) {
   746             return;
   829             return;
   747         }
   830         }
   748     }
   831     }
   749 
       
   750     emit q->selectionChanged(selectionCursor, cursor);
   832     emit q->selectionChanged(selectionCursor, cursor);
       
   833     selectionCursor = cursor;
   751 }
   834 }
   752 
   835 
   753 void HbAbstractEditPrivate::acceptKeyPressEvent(QKeyEvent *event)
   836 void HbAbstractEditPrivate::acceptKeyPressEvent(QKeyEvent *event)
   754 {
   837 {
   755     event->accept();
   838     event->accept();
   756     cursorOn = true;
       
   757     ensureCursorVisible();
   839     ensureCursorVisible();
   758 
   840 
   759     updateCurrentCharFormat();
   841     updateCurrentCharFormat();
   760 }
   842 }
   761 
   843 
   783         selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText));
   865         selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText));
   784 
   866 
   785         HbStyleOption opt;
   867         HbStyleOption opt;
   786         q->initStyleOption(&opt);
   868         q->initStyleOption(&opt);
   787 
   869 
   788 		if (qApp->style()->styleHint(QStyle::SH_RichText_FullWidthSelection, &opt, 0)) {
   870         if (qApp->style()->styleHint(QStyle::SH_RichText_FullWidthSelection, &opt, 0)) {
   789             selection.format.setProperty(QTextFormat::FullWidthSelection, true);
   871             selection.format.setProperty(QTextFormat::FullWidthSelection, true);
   790         }
   872         }
   791         ctx.selections.append(selection);
   873         ctx.selections.append(selection);
   792     }
   874     }
   793 
   875 
   854     }
   936     }
   855 
   937 
   856     return r;
   938     return r;
   857 }
   939 }
   858 
   940 
   859 QRectF HbAbstractEditPrivate::selectionRect() const
       
   860 {
       
   861     return selectionRect(selectionCursor);
       
   862 }
       
   863 
   941 
   864 QRectF HbAbstractEditPrivate::rectForPositionInCanvasCoords(int position, QTextLine::Edge edge) const
   942 QRectF HbAbstractEditPrivate::rectForPositionInCanvasCoords(int position, QTextLine::Edge edge) const
   865 {
   943 {
   866     Q_Q(const HbAbstractEdit);
   944     Q_Q(const HbAbstractEdit);
   867 
   945 
   900                    cursorWidth + w, line.height());
   978                    cursorWidth + w, line.height());
   901     } else {
   979     } else {
   902         r = QRectF(layoutPos.x(), layoutPos.y(), cursorWidth, 10); // #### correct height
   980         r = QRectF(layoutPos.x(), layoutPos.y(), cursorWidth, 10); // #### correct height
   903     }
   981     }
   904 
   982 
   905     if(layout->preeditAreaText().length()) {
       
   906         r.adjust(0,0,q->blockBoundingRect(block).width()/2,0);
       
   907     }
       
   908 
       
   909     return r;
   983     return r;
   910 }
   984 }
   911 
   985 
   912 /*
   986 /*
   913   Returns the viewport rectangle in editor coordinate system.
   987   Returns the viewport rectangle in editor coordinate system.
   916 {
   990 {
   917     QRectF viewRect = scrollArea->geometry();
   991     QRectF viewRect = scrollArea->geometry();
   918     qreal margin = doc->documentMargin();
   992     qreal margin = doc->documentMargin();
   919     viewRect.adjust(0,margin,0,-margin);
   993     viewRect.adjust(0,margin,0,-margin);
   920     return viewRect;
   994     return viewRect;
       
   995 }
       
   996 
       
   997 /*
       
   998   Returns the constrained hit test point in editor coordinate system.
       
   999 */
       
  1000 QPointF HbAbstractEditPrivate::constrainHitTestPoint(const QPointF& point)
       
  1001 {
       
  1002     QRectF viewRect = viewPortRect();
       
  1003 
       
  1004     // Constrain hitTestPos within docRect with 1 top/bottom margins.
       
  1005     QPointF hitTestPos = QPointF(qMin(qMax(point.x(),viewRect.left()),viewRect.right()),
       
  1006                          qMin(qMax(point.y(),viewRect.top()+1),viewRect.bottom()-1));
       
  1007 
       
  1008     return hitTestPos;
   921 }
  1009 }
   922 
  1010 
   923 int HbAbstractEditPrivate::contentLength() const
  1011 int HbAbstractEditPrivate::contentLength() const
   924 {
  1012 {
   925     QTextBlock block = doc->lastBlock();
  1013     QTextBlock block = doc->lastBlock();
   971 
  1059 
   972 bool HbAbstractEditPrivate::isCursorVisible() const
  1060 bool HbAbstractEditPrivate::isCursorVisible() const
   973 {
  1061 {
   974     return preeditCursorVisible && apiCursorVisible;
  1062     return preeditCursorVisible && apiCursorVisible;
   975 }
  1063 }
       
  1064 
       
  1065 /*
       
  1066     base implementation of void gestureEvent(QGestureEvent* event) designed to be used by widgets
       
  1067     that delegate gesture event to the editor. Client widgets calling this method should pass themselves
       
  1068     as parameter in widget. If widget is 0 it is assumed that it is called by this HbAbstractEdit object.
       
  1069 
       
  1070 */
       
  1071 void HbAbstractEditPrivate::gestureEvent(QGestureEvent* event, HbWidget* widget)
       
  1072 {
       
  1073     Q_Q(HbAbstractEdit);
       
  1074 
       
  1075     bool ownEvent = !widget;
       
  1076 
       
  1077     if(HbTapGesture *tap = qobject_cast<HbTapGesture*>(event->gesture(Qt::TapGesture))) {
       
  1078         // QTapGesture::position() is in screen coordinates and thus
       
  1079         // needs to be transformed into items own coordinate system.
       
  1080         // The QGestureEvent knows the viewport through which the gesture
       
  1081         // was triggered.
       
  1082         QPointF pos = q->mapFromScene(event->mapToGraphicsScene(tap->position()));
       
  1083         pos = constrainHitTestPoint(pos);
       
  1084         switch(tap->state()) {
       
  1085         case Qt::GestureStarted:
       
  1086             if (tapCounter == 0) {
       
  1087                 tapPosition = pos;
       
  1088             }
       
  1089             HbWidgetFeedback::triggered(q, Hb::InstantPressed);
       
  1090             if (!doubleTapTimer.isActive()) {
       
  1091                 doubleTapTimer.start(DOUBLE_TAP_DELAY,q);
       
  1092             }            
       
  1093             break;
       
  1094         case Qt::GestureUpdated:
       
  1095             if(q->isReadOnly() && tap->tapStyleHint() == HbTapGesture::TapAndHold && !cursor.hasSelection() && ownEvent &&
       
  1096                contextMenuShownOn.testFlag(Hb::ShowTextContextMenuOnLongPress)) {
       
  1097                q->showContextMenu(q->mapToScene(tapPosition));
       
  1098                doubleTapTimer.stop();
       
  1099                tapCounter = 0;
       
  1100             }
       
  1101             break;
       
  1102         case Qt::GestureFinished:
       
  1103             tapCounter++;
       
  1104 
       
  1105             // if doubleTapTimer is already triggered
       
  1106             if (!doubleTapTimer.isActive()){
       
  1107                 if (ownEvent){
       
  1108                     tapGesture(tapPosition,false);
       
  1109                 } else {
       
  1110                     if (contextMenuShownOn.testFlag(Hb::ShowTextContextMenuOnSelectionClicked)) {
       
  1111                         q->showContextMenu(q->mapToScene(tapPosition));
       
  1112                     }
       
  1113                 }
       
  1114                 tapCounter = 0;
       
  1115                 showContextMenu = false;
       
  1116             } else {
       
  1117                 // if tapCounter is 1 the doubleTapTimer is still active so delay showing the context menu
       
  1118                 if (tapCounter == 1){
       
  1119                     if (ownEvent){
       
  1120                         tapGesture(tapPosition,true);
       
  1121                     } else {
       
  1122                         showContextMenu = true;
       
  1123                     }
       
  1124                 }
       
  1125                 // if tapCounter is 2 the tap gesture is double-tap cancel showing the context menu
       
  1126                 else if (tapCounter == 2) {
       
  1127                     doubleTapTimer.stop();
       
  1128                     tapCounter = 0;
       
  1129                     showContextMenu = false;
       
  1130                     if (contextMenuShownOn.testFlag(Hb::ShowTextContextMenuOnSelectionClicked) ||
       
  1131                         contextMenuShownOn.testFlag(Hb::ShowTextContextMenuOnLongPress)) {
       
  1132                         q->selectClickedWord();
       
  1133                     }
       
  1134                 }
       
  1135             }
       
  1136 
       
  1137             HbWidgetFeedback::triggered(q, Hb::InstantReleased);
       
  1138 
       
  1139                 break;
       
  1140           case Qt::GestureCanceled:
       
  1141                 doubleTapTimer.stop();
       
  1142                 tapCounter = 0;
       
  1143                 break;
       
  1144           default:
       
  1145                 break;
       
  1146         }
       
  1147         event->accept();
       
  1148     } else {
       
  1149         event->ignore();
       
  1150     }
       
  1151 }
       
  1152 
   976 
  1153 
   977 void HbAbstractEditPrivate::sendMouseEventToInputContext(const QPointF &tapPos) const
  1154 void HbAbstractEditPrivate::sendMouseEventToInputContext(const QPointF &tapPos) const
   978 {
  1155 {
   979     Q_Q(const HbAbstractEdit);
  1156     Q_Q(const HbAbstractEdit);
   980 
  1157 
  1019 {
  1196 {
  1020     Q_Q(HbAbstractEdit);
  1197     Q_Q(HbAbstractEdit);
  1021 
  1198 
  1022     doc = newDoc;
  1199     doc = newDoc;
  1023     cursor = QTextCursor(doc);
  1200     cursor = QTextCursor(doc);
       
  1201     if(smileysEnabled) {
       
  1202         smileyEngineInstance()->setDocument(doc);
       
  1203     }
  1024 
  1204 
  1025     QObject::connect(doc, SIGNAL(contentsChanged()), q, SLOT(_q_contentsChanged()));
  1205     QObject::connect(doc, SIGNAL(contentsChanged()), q, SLOT(_q_contentsChanged()));
  1026     QObject::connect(doc, SIGNAL(contentsChange(int, int, int)), q, SLOT(_q_contentsChange(int, int, int)));
  1206     QObject::connect(doc, SIGNAL(contentsChange(int, int, int)), q, SLOT(_q_contentsChange(int, int, int)));
  1027     QObject::connect(doc, SIGNAL(documentLayoutChanged()), q, SLOT(documentLayoutChanged()));
  1207     QObject::connect(doc, SIGNAL(documentLayoutChanged()), q, SLOT(documentLayoutChanged()));
  1028     QObject::connect(doc, SIGNAL(blockCountChanged(int)), q, SLOT(blockCountChanged(int)));
  1208     QObject::connect(doc, SIGNAL(blockCountChanged(int)), q, SLOT(blockCountChanged(int)));
  1030     doc->setModified(false);
  1210     doc->setModified(false);
  1031 
  1211 
  1032     q->documentLayoutChanged();
  1212     q->documentLayoutChanged();
  1033 }
  1213 }
  1034 
  1214 
  1035 void HbAbstractEditPrivate::longTapGesture(const QPointF &point)
  1215 void HbAbstractEditPrivate::tapGesture(const QPointF &point, bool delayMenu)
  1036 {
  1216 {
  1037     Q_Q(HbAbstractEdit);
  1217     Q_Q(HbAbstractEdit);
  1038 
  1218 
  1039     if(contextMenuShownOn.testFlag(Hb::ShowTextContextMenuOnLongPress)) {
       
  1040 
       
  1041         int cursorPos = hitTest(point, Qt::FuzzyHit);
       
  1042         if (cursorPos == -1)
       
  1043             return;
       
  1044 
       
  1045         // don't do anything if longpress inside the selection
       
  1046         if (cursor.hasSelection()
       
  1047             && cursorPos >= cursor.selectionStart()
       
  1048             && cursorPos <= cursor.selectionEnd()){
       
  1049             return;
       
  1050         }
       
  1051         q->showContextMenu(q->mapToScene(point));
       
  1052     }
       
  1053 }
       
  1054 
       
  1055 void HbAbstractEditPrivate::tapGesture(const QPointF &point)
       
  1056 {
       
  1057     Q_Q(HbAbstractEdit);
       
  1058 
       
  1059     if (interactionFlags & Qt::NoTextInteraction)
       
  1060         return;
       
  1061 
       
  1062     bool removeSelection = (hitTest(point, Qt::ExactHit) == -1);
  1219     bool removeSelection = (hitTest(point, Qt::ExactHit) == -1);
  1063 
  1220 
  1064     if (removeSelection && cursor.hasSelection()) {
  1221     if (removeSelection && cursor.hasSelection()) {        
  1065         const QTextCursor oldCursor = cursor;
       
  1066         cursor.clearSelection();
  1222         cursor.clearSelection();
  1067         emit q->selectionChanged(oldCursor, cursor);
  1223         selectionChanged();
  1068     }
  1224     }
  1069 
  1225 
  1070     int newCursorPos = hitTest(point, Qt::FuzzyHit);
  1226     int newCursorPos = hitTest(point, Qt::FuzzyHit);
  1071 
  1227 
  1072     if (cursor.hasSelection() &&
  1228     if (cursor.hasSelection() &&
  1073         newCursorPos >= cursor.selectionStart() &&
  1229         newCursorPos >= cursor.selectionStart() &&
  1074         newCursorPos <= cursor.selectionEnd()){
  1230         newCursorPos <= cursor.selectionEnd()){
  1075         // we have a selection under mouse click
  1231         // we have a selection under mouse click
  1076         if (contextMenuShownOn.testFlag(Hb::ShowTextContextMenuOnSelectionClicked)) {
  1232         if (contextMenuShownOn.testFlag(Hb::ShowTextContextMenuOnSelectionClicked)) {
  1077             q->showContextMenu(q->mapToScene(point));
  1233             if (delayMenu) {
  1078         }
  1234                 showContextMenu = true;
  1079     } else {
  1235             } else {
       
  1236                 q->showContextMenu(q->mapToScene(point));
       
  1237             }
       
  1238         }
       
  1239     } else {        
  1080         // Currently focused widget to listen to InputContext before updating the cursor position
  1240         // Currently focused widget to listen to InputContext before updating the cursor position
  1081         sendMouseEventToInputContext(point);
  1241         sendMouseEventToInputContext(point);
  1082 
  1242 
  1083         // translate the point to have the Y ccordinate inside the viewport
       
  1084         QPointF translatedPoint(point);
       
  1085         if(translatedPoint.y() < viewPortRect().top()) {
       
  1086             translatedPoint.setY(viewPortRect().top() + 1);
       
  1087         } else if(translatedPoint.y() > viewPortRect().bottom()){
       
  1088             translatedPoint.setY(viewPortRect().bottom() - 1);
       
  1089         }
       
  1090 
       
  1091         // need to get the cursor position again since input context can change the document
  1243         // need to get the cursor position again since input context can change the document
  1092         newCursorPos = hitTest(translatedPoint, Qt::FuzzyHit);
  1244         newCursorPos = hitTest(point, Qt::FuzzyHit);
  1093         setCursorPosition(newCursorPos);
  1245         setCursorPosition(newCursorPos);
  1094 
  1246 
  1095         if (interactionFlags & Qt::TextEditable) {
  1247         if (interactionFlags & Qt::TextEditable) {
  1096             updateCurrentCharFormat();
  1248             updateCurrentCharFormat();
  1097         }
  1249         }
  1098 
  1250 
  1099         QString anchor(q->anchorAt(translatedPoint));
  1251         // workaround for a Qt crash
  1100         if(!anchor.isEmpty()) {
  1252         // If there preedit are isn't empty the QTextDocumentLayout::anchorAt crashes
  1101             emit q->anchorTapped(anchor);
  1253         if (cursor.block().layout()->preeditAreaText().isEmpty()) {
  1102         }
  1254             QString anchor(q->anchorAt(point));
       
  1255             if(!anchor.isEmpty()) {
       
  1256                 emit q->anchorTapped(anchor);
       
  1257             }
       
  1258         }
       
  1259     }
       
  1260 
       
  1261     if(!q->isReadOnly()) {
       
  1262         if (selectionControl && hasInputFocus() && isCursorVisible()) {
       
  1263             if (q->isSelectionControlEnabled()) {
       
  1264                 selectionControl->showHandles();
       
  1265             }
       
  1266             updateCursorType();
       
  1267         }
       
  1268         openInputPanel();
  1103     }
  1269     }
  1104 }
  1270 }
  1105 
  1271 
  1106 
  1272 
  1107 
  1273 
  1109 {
  1275 {
  1110     wasGesture = true;
  1276     wasGesture = true;
  1111 }
  1277 }
  1112 
  1278 
  1113 
  1279 
  1114 void HbAbstractEditPrivate::drawSelectionEdges(QPainter *painter, QAbstractTextDocumentLayout::PaintContext ctx)
  1280 void HbAbstractEditPrivate::drawCursor(QPainter *painter, QAbstractTextDocumentLayout::PaintContext ctx)
  1115 {
  1281 {
  1116     if (cursor.hasSelection() && selectionControl && selectionControl->isVisible()){
  1282     // save painter state
  1117         painter->setPen(ctx.palette.color(QPalette::Text));
  1283     QPen oldPen = painter->pen();
  1118         painter->setBrush(ctx.palette.color(QPalette::Text));
  1284     QBrush oldBrush = painter->brush();
  1119         painter->drawRect(rectForPositionInCanvasCoords(cursor.selectionStart(), QTextLine::Leading));
  1285 
  1120         painter->drawRect(rectForPositionInCanvasCoords(cursor.selectionEnd(), QTextLine::Trailing));
  1286     // Draw cursor
  1121     }
  1287     if (ctx.cursorPosition != -1) {
       
  1288         painter->setPen(cursorColor);
       
  1289         painter->setBrush(cursorColor);
       
  1290         painter->drawRect(rectForPositionInCanvasCoords(ctx.cursorPosition, QTextLine::Leading));
       
  1291     }
       
  1292 
       
  1293    // restore painter state
       
  1294     painter->setPen(oldPen);
       
  1295     painter->setBrush(oldBrush);
  1122 }
  1296 }
  1123 
  1297 
  1124 /*
  1298 /*
  1125  * Prepares the document for pasting. Derived classes can override this method,
  1299  * Prepares the document for pasting. Derived classes can override this method,
  1126  * e.g. HbLineEdit clears the document before pasting when in password edit mode
  1300  * e.g. HbLineEdit clears the document before pasting when in password edit mode
  1255     return false;
  1429     return false;
  1256 }
  1430 }
  1257 
  1431 
  1258 void HbAbstractEditPrivate::setInputFocusEnabled(bool enable)
  1432 void HbAbstractEditPrivate::setInputFocusEnabled(bool enable)
  1259 {
  1433 {
  1260     QGraphicsItem *focusItem = focusPrimitive(HbWidget::FocusHighlightActive);
  1434     setFocusHighlightVisible(HbWidget::FocusHighlightActive, enable);
  1261     if (focusItem) {
  1435     if (!enable && selectionControl && !cursor.hasSelection()) {
  1262         focusItem->setVisible(enable);
  1436         selectionControl->hideHandles();
  1263     }
  1437     }
  1264 
  1438     updateCursorType(enable);
  1265     setBlinkingCursorEnabled(enable);
       
  1266     repaintOldAndNewSelection(selectionCursor);
  1439     repaintOldAndNewSelection(selectionCursor);
  1267 }
  1440 }
  1268 
  1441 
       
  1442 QSizeF HbAbstractEditPrivate::calculatePreferredDocSize() const
       
  1443 {
       
  1444     if (doc->isEmpty()) {
       
  1445         QFontMetricsF metrics(doc->defaultFont());
       
  1446         qreal margins = doc->documentMargin()*2.0;
       
  1447         QSizeF result(5+margins, metrics.height()+margins);
       
  1448         if (placeholderDoc) {
       
  1449             result = result.expandedTo(placeholderDoc->size());
       
  1450         }
       
  1451         return result;
       
  1452     }
       
  1453     QTextBlock block = doc->begin();
       
  1454     qreal prefWidth = 5; // minimum value 5
       
  1455     while (block.isValid()) {
       
  1456         const QTextLayout *layout = block.layout();
       
  1457         prefWidth = qMax(layout->maximumWidth() + layout->position().x(),
       
  1458                          prefWidth);
       
  1459         block=block.next();
       
  1460     }
       
  1461     prefWidth += doc->documentMargin(); // only once since position was added
       
  1462                             // so it is already contains right margin
       
  1463     return QSizeF(prefWidth, doc->size().height());
       
  1464 }
       
  1465 
  1269 #include "moc_hbabstractedit.cpp"
  1466 #include "moc_hbabstractedit.cpp"