src/hbwidgets/editors/hbabstractedit.cpp
changeset 34 ed14f46c0e55
parent 7 923ff622b8b9
--- a/src/hbwidgets/editors/hbabstractedit.cpp	Mon Oct 04 17:49:30 2010 +0300
+++ b/src/hbwidgets/editors/hbabstractedit.cpp	Mon Oct 18 18:23:13 2010 +0300
@@ -38,11 +38,10 @@
 #include "hbselectioncontrol_p.h"
 #include "hbsmileyengine_p.h"
 #include "hbinputeditorinterface.h"
-#include "hbfeaturemanager_r.h"
-#include "hbtextmeasurementutility_p.h"
-#include "hbtapgesture.h"
-#include "hbpangesture.h"
-#include "hbnamespace_p.h"
+#ifdef HB_TEXT_MEASUREMENT_UTILITY
+#include "hbtextmeasurementutility_r.h"
+#include "hbtextmeasurementutility_r_p.h"
+#endif
 
 #include <QApplication>
 #include "hbpopup.h"
@@ -93,8 +92,9 @@
     editor widget only one or the other type might be supported. Plain text content is set with 
     method \ref setPlainText. Method \ref toPlainText returns the content converted to plain text. 
 
-    \li Focus control: Editor is responsble for controlling the input panel visibility. In some situations special editor may need to also handle this, but in general it is always handled by HbAbstractEdit. 
-    Input panel is closed when editor loses focus.
+    \li Focus control: Editor is responsble for controlling the input panel visibility. In some situations special editor may need to also handle this,
+    but in general it is always handled by HbAbstractEdit. Input panel is closed when editor loses focus.
+    However when setting the editor focus programmatically with setFocus() it is the responsibility of client to control the visibility of input panel.
 
     \li Cursor control: A convenience method \ref moveCursor can also be used to move the cursor.
 
@@ -107,14 +107,7 @@
 
     \section composition Widget composition
 
-    Editor widget consists of these sub-items visible in the picture. 
-    In this example editor shows only one visible line of the content.
-
-    \image html editor_composition.jpg
-
-    The size of the canvas is always same as the size of the document, and the width of the scroll area 
-    is same as the width of the document. The editor margins are defined in the CSS.
-
+    The size of the canvas is always same as the size of the document, and the width of the scroll area is same as the width of the document.
 */
 
 /*!
@@ -153,6 +146,9 @@
 
 #define Hb_Invalid_Position QPointF(-1.0, -1.0)
 
+
+
+
 /*!
     Constructs a HbAbstractEdit with parent \a parent.
  */
@@ -225,6 +221,18 @@
             d->smileyEngineInstance()->insertSmiley(matchCursor);
 
             d->cursorChanged(HbValidator::CursorChangeFromContentUpdate);
+        } else if (p == "Magnifier") {
+            QString param = property("Magnifier").toString();
+
+            if (param == "Enabled") {
+                d->enableMagnifier = true;
+            } else if (param == "Disabled") {
+                d->enableMagnifier = false;
+            }
+
+            if (d->selectionControl) {
+                d->selectionControl->setMagnifierEnabled(d->enableMagnifier);
+            }
         }
     } else { //HbEvent handler
         if (event->type() == HbEvent::InputMethodFocusIn) {
@@ -283,6 +291,10 @@
     d->cursor.beginEditBlock();
 
     if (isGettingInput) {
+        if (d->selectionControl) {
+            d->selectionControl->hideHandles();
+            d->updateCursorType();
+        }
         if (!d->imEditInProgress) {
             d->imEditInProgress = true;
             d->imPosition = d->selectionCursor.selectionStart();
@@ -345,10 +357,8 @@
         d->_q_contentsChanged();
     }
 
-    if(d->hasInputFocus()) {
-        d->cursorOn = true;
-    }
     d->ensureCursorVisible();
+    d->canvas->setPreferredSize(d->calculatePreferredDocSize());
 }
 
 /*!
@@ -358,8 +368,10 @@
 {
     Q_D(HbAbstractEdit);
 
-    if (d->interactionFlags & Qt::NoTextInteraction)
-        return;
+    if (d->selectionControl) {
+        d->selectionControl->hideHandles();
+        d->updateCursorType();
+    }
 
 #ifndef QT_NO_SHORTCUT
 #ifndef QT_NO_CLIPBOARD
@@ -489,9 +501,7 @@
     HbWidget::focusInEvent(event);
 
     d->selectionControl = HbSelectionControl::attachEditor(this);
-
-    if (d->interactionFlags & Qt::NoTextInteraction)
-        return;
+    d->selectionControl->setMagnifierEnabled(isSelectionControlEnabled()&&d->enableMagnifier);
 
     // It sets the cursor the focus item's depending on if
     // the input panel is connceted or not
@@ -509,9 +519,6 @@
 
     Q_D(HbAbstractEdit);
 
-    if (d->interactionFlags & Qt::NoTextInteraction)
-        return;
-
     // It sets the cursor the focus item's depending on if
     // the input panel is connceted or not
     d->setInputFocusEnabled(d->hasInputFocus());
@@ -680,7 +687,7 @@
 
     Returns pointer to a \a primitive of HbAbstractEdit.
 
-    Available primitive is HbStyle::P_Edit_text.
+    Available primitive is HbStylePrivate::P_Edit_text.
 
     \reimp
     \sa HbStyle::Primitive, HbWidget::primitive()
@@ -688,8 +695,8 @@
 QGraphicsItem *HbAbstractEdit::primitive (HbStyle::Primitive primitive) const
 {
     Q_D(const HbAbstractEdit);
-
-    if (primitive == HbStyle::P_Edit_text) {
+    const HbStylePrivate::Primitive p = (HbStylePrivate::Primitive)primitive;
+    if (p == HbStylePrivate::P_Edit_text) {
         return d->scrollArea;
     } else {
         return HbWidget::primitive(primitive);
@@ -723,6 +730,7 @@
         }
 
         d->canvas->setGeometry(canvasGeom);
+        d->canvas->setPreferredSize(d->calculatePreferredDocSize());
 
         d->ensureCursorVisible();
         if (d->selectionControl) {
@@ -777,12 +785,15 @@
     Q_D(HbAbstractEdit);
 
     if (e->timerId() == d->cursorBlinkTimer.timerId()) {
-        d->cursorOn = !d->cursorOn;
+        d->cursorOn = !d->cursorOn;       
+        d->repaintCursor();
+    } else if (e->timerId() == d->doubleTapTimer.timerId()) {
+        d->doubleTapTimer.stop();
 
-        if (d->cursor.hasSelection())
-            d->cursorOn &= (QApplication::style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected) != 0);
-
-        d->repaintCursor();
+        if (d->tapCounter == 1 && d->showContextMenu && contextMenuFlags().testFlag(Hb::ShowTextContextMenuOnSelectionClicked)) {
+            showContextMenu(mapToScene(d->tapPosition));
+        }
+        d->tapCounter = 0;
     }
 }
 
@@ -885,8 +896,9 @@
     Q_D(HbAbstractEdit);
     if (!(d->interactionFlags & Qt::TextEditable) || !d->cursor.hasSelection())
         return;
-    copy();
+    copy();    
     d->cursor.removeSelectedText();
+    d->cursorChanged(HbValidator::CursorChangeFromContentUpdate);
 #endif//QT_NO_CLIPBOARD
 }
 
@@ -926,8 +938,8 @@
         if (md) {
             insertFromMimeData(md);
         }
+        d->cursorChanged(HbValidator::CursorChangeFromContentUpdate);
     }
-
 #endif//QT_NO_CLIPBOARD
 }
 
@@ -945,7 +957,7 @@
     if (cursorPos == -1)
         return;
 
-    setCursorPosition(cursorPos);
+    d->cursor.setPosition(cursorPos);
     d->cursor.select(QTextCursor::WordUnderCursor);
     d->cursorChanged(HbValidator::CursorChangeFromMouse);
 }
@@ -1064,6 +1076,7 @@
     return rect;
 }
 
+
 /*!
     Returns the contents as plain text. If smiley recognition is enabled
     all the smiley images will be replaced by their textual representations.
@@ -1111,7 +1124,9 @@
     Q_D(HbAbstractEdit);
 
     d->validator = validator;
-    d->initValidator();
+    if (d->validator) {
+        d->initValidator();
+    }
 }
 
 /*!
@@ -1202,8 +1217,24 @@
     Q_D(HbAbstractEdit);
 #ifdef HB_DEBUG_EDITOR_DRAW_RECTS
     painter->setPen(Qt::green);
-    /*for(QTextBlock tb = d->doc->begin(); tb.isValid(); tb=tb.next()) {
-        painter->drawRect(blockBoundingRect(tb));
+    /*
+    for(QTextBlock tb = d->doc->begin(); tb.isValid(); tb=tb.next()) {
+       painter->drawRect(blockBoundingRect(tb));
+
+        // Draw lines
+        const QPointF layoutPos = blockBoundingRect(tb).topLeft();
+
+        painter->setPen(Qt::red);
+        const QTextLayout *layout = tb.layout();
+        for(int i = 0;i < layout->lineCount();i++) {
+            QTextLine line = layout->lineAt(i);
+
+            // Draw descent rect
+            QRectF rect = QRectF(layoutPos.x() + line.x(),
+                                 layoutPos.y() + line.y() + line.ascent(),
+                                 line.width(),line.descent()+1);
+            painter->drawRect(rect);
+        }
     }*/
     painter->drawRect(d->doc->documentLayout()->frameBoundingRect(
         d->doc->rootFrame()).adjusted(2,2,-2,-2));
@@ -1218,13 +1249,14 @@
 
 
     QAbstractTextDocumentLayout::PaintContext ctx = d->getPaintContext();
-    // Save painter state that will be modified
-    QRegion clipRegion = painter->clipRegion();
 
     if (option.exposedRect.isValid()){
         painter->setClipRect(intersected, Qt::IntersectClip);
     }
     ctx.clip = intersected;
+    // Disable drawing of Qt cursor and save old cursor position
+    int oldCursorPosition = ctx.cursorPosition;
+    ctx.cursorPosition = -1;
 
     d->drawContentBackground(painter, option);
 
@@ -1235,19 +1267,16 @@
         if(!layout->preeditAreaText().length()) {
             QColor textColor(ctx.palette.color(QPalette::Text));
             QColor hintText(ctx.palette.color(QPalette::NoRole));
-            int cursorPos = ctx.cursorPosition;
-            ctx.cursorPosition = -1;
             ctx.palette.setColor(QPalette::Text, hintText);
 
             d->placeholderDoc->documentLayout()->draw(painter, ctx);
 
             ctx.palette.setColor(QPalette::Text, textColor);
-            ctx.cursorPosition = cursorPos;
         }
     }
     document()->documentLayout()->draw(painter, ctx);
-    // Draw the pins for the selection handle
-    d->drawSelectionEdges(painter, ctx);
+    ctx.cursorPosition = oldCursorPosition;
+    d->drawCursor(painter, ctx);
 
 #ifdef HB_DEBUG_EDITOR_HANDLES
     QRectF a = rectForPosition(d->cursor.anchor());
@@ -1260,8 +1289,6 @@
     painter->setPen(Qt::red);
     painter->drawRect(d->cursorRect());
 #endif
-    // Restore state
-    painter->setClipRegion(clipRegion);
 }
 
 /*!
@@ -1310,45 +1337,36 @@
 
     if (d->cursor.hasSelection() && d->canCut()) {
         connect(
-            menu->addAction(hbTrId("txt_common_menu_cut")), SIGNAL(triggered()),
-            this, SLOT(cut()));       
+            menu->addAction(hbTrId("txt_common_menu_cut")), SIGNAL(triggered()), this, SLOT(cut()));
     }
     if (d->cursor.hasSelection() && d->canCopy()) {
         connect(
-            menu->addAction(hbTrId("txt_common_menu_copy")), SIGNAL(triggered()),
-            this, SLOT(copy()));
+            menu->addAction(hbTrId("txt_common_menu_copy")), SIGNAL(triggered()), this, SLOT(copy()));
     }
     if (!d->cursor.hasSelection() && !d->doc->isEmpty() && d->canCopy()){
         connect(
-            menu->addAction(hbTrId("txt_common_menu_select")), SIGNAL(triggered()),
-            this, SLOT(selectClickedWord()));
-        connect(
-            menu->addAction(hbTrId("txt_common_menu_select_all_contents")), SIGNAL(triggered()),
-            this, SLOT(selectAll()));
+            menu->addAction(hbTrId("txt_common_menu_select_all_contents")), SIGNAL(triggered()), this, SLOT(selectAll()));
     }
     if (d->canPaste()) {
         connect(
-            menu->addAction(hbTrId("txt_common_menu_paste")), SIGNAL(triggered()),
-            this, SLOT(paste()));
+            menu->addAction(hbTrId("txt_common_menu_paste")), SIGNAL(triggered()), this, SLOT(paste()));
     }
     if (d->cursor.hasSelection()) {
         connect(
-            menu->addAction(hbTrId("txt_common_menu_deselect")), SIGNAL(triggered()),
-            this, SLOT(deselect()));
+            menu->addAction(hbTrId("txt_common_menu_deselect")), SIGNAL(triggered()), this, SLOT(deselect()));
     }
     if (d->canFormat()) {
         connect(
-            menu->addAction(hbTrId("txt_common_menu_format")), SIGNAL(triggered()),
-            this, SLOT(format()));
+            menu->addAction(hbTrId("txt_common_menu_format")), SIGNAL(triggered()), this, SLOT(format()));
     }
 
     emit aboutToShowContextMenu(menu, d->tapPosition);
 
     if(menu->actions().count() > 0){
-//        d->minimizeInputPanel();
         menu->setPreferredPos(position);
         menu->show();
     }
+    d->showContextMenu = false;
 }
 
 /*!
@@ -1416,8 +1434,8 @@
 }
 
 /*!
-    Returns current flags describing on which events context menu is shown
-
+    Returns current flags describing on which events context menu is shown.
+    The default value is both Hb::ShowTextContextMenuOnSelectionClicked and Hb::ShowTextContextMenuOnLongPress are set.
     \sa Hb::TextContextMenuFlag
  */
 Hb::TextContextMenuFlags HbAbstractEdit::contextMenuFlags() const
@@ -1428,7 +1446,8 @@
 }
 
 /*!
-    Sets \a flags describing on which events context menu is shown
+    Sets \a flags describing on which events context menu is shown.
+    To disable context menu completely set \a flags to 0.
     \sa Hb::TextContextMenuFlag
  */
 void HbAbstractEdit::setContextMenuFlags(Hb::TextContextMenuFlags flags)
@@ -1492,7 +1511,7 @@
 
     QString txt( placeholderText );
 #ifdef HB_TEXT_MEASUREMENT_UTILITY
-    if ( HbFeatureManager::instance()->featureStatus( HbFeatureManager::TextMeasurement ) ) {
+    if (HbTextMeasurementUtility::instance()->locTestMode()) {
         if (placeholderText.endsWith(QChar(LOC_TEST_END))) {
             int index = placeholderText.indexOf(QChar(LOC_TEST_START));
             setProperty( HbTextMeasurementUtilityNameSpace::textIdPropertyName,  placeholderText.mid(index + 1, placeholderText.indexOf(QChar(LOC_TEST_END)) - index - 1) );
@@ -1520,7 +1539,7 @@
 QString HbAbstractEdit::anchorAt(const QPointF &pos) const
 {
     Q_D(const HbAbstractEdit);
-    return d->doc->documentLayout()->anchorAt(pos);
+    return d->doc->documentLayout()->anchorAt(mapToItem(d->canvas,pos));
 }
 
 /*!
@@ -1670,11 +1689,19 @@
  */
 QVariant HbAbstractEdit::itemChange(GraphicsItemChange change, const QVariant &value)
 {
-    Q_D(const HbAbstractEdit);
+    Q_D(HbAbstractEdit);
     if (change == QGraphicsItem::ItemScenePositionHasChanged) {
         if (d->selectionControl) {
             d->selectionControl->updatePrimitives();
         }
+    } else if (change == QGraphicsItem::ItemEnabledHasChanged) {
+        if(!value.toBool()) {
+            if (d->hasInputFocus()) {
+                d->closeInputPanel();
+            }
+            deselect();
+        }
+        updatePrimitives();
     }
     return HbWidget::itemChange(change, value);
 }
@@ -1687,55 +1714,41 @@
     return document()->characterAt(pos);
 }
 
+/*!
+    Activates or deactivates the selection control in the editor.
+    The selection control can be used to resize the selection or fine tune the cursor position.
+    Note: if the selection control is disabled the word selection is still possible by double-tap on word of text.
+*/
+void HbAbstractEdit::setSelectionControlEnabled(bool enabled)
+{
+    Q_D(HbAbstractEdit);
+    if(d->enableSelectionControl != enabled) {
+        d->enableSelectionControl = enabled;
+        if(enabled && (d->hasInputFocus() || d->cursor.hasSelection())) {
+            d->selectionControl = HbSelectionControl::attachEditor(this);
+            d->selectionControl->setMagnifierEnabled(d->enableMagnifier);
+            d->selectionControl->showHandles();
+        } else if (d->selectionControl) {
+            d->selectionControl->hideHandles();
+        }
+        d->updateCursorType();
+    }
+}
+
+/*!
+    Return true if selection control is enabled in the editor otherwise returns false.
+*/
+bool HbAbstractEdit::isSelectionControlEnabled() const
+{
+    Q_D(const HbAbstractEdit);
+    return d->enableSelectionControl;
+}
+
+
 void HbAbstractEdit::gestureEvent(QGestureEvent* event) {
     Q_D(HbAbstractEdit);
 
-    if(HbTapGesture *tap = qobject_cast<HbTapGesture*>(event->gesture(Qt::TapGesture))) {
-        // QTapGesture::position() is in screen coordinates and thus
-        // needs to be transformed into items own coordinate system.
-        // The QGestureEvent knows the viewport through which the gesture
-        // was triggered.
-        QPointF pos = mapFromScene(event->mapToGraphicsScene(tap->position()));
-        switch(tap->state()) {
-        case Qt::GestureStarted:
-            scene()->setProperty(HbPrivate::OverridingGesture.latin1(),Qt::TapGesture);
-            if (!tap->property(HbPrivate::ThresholdRect.latin1()).toRect().isValid()) {
-                tap->setProperty(HbPrivate::ThresholdRect.latin1(), mapRectToScene(boundingRect()).toRect());
-            }
-
-            d->tapPosition = pos;
-            HbWidgetFeedback::triggered(this, Hb::InstantPressed);
-            break;
-        case Qt::GestureUpdated:
-            if(tap->tapStyleHint() == HbTapGesture::TapAndHold) {
-                d->openInputPanel();
-                d->longTapGesture(pos);                
-            }
-            break;
-      case Qt::GestureFinished:
-            scene()->setProperty(HbPrivate::OverridingGesture.latin1(),QVariant());
-
-            if(tap->tapStyleHint() == HbTapGesture::TapAndHold) {
-            } else {
-                d->tapGesture(pos);
-            }
-
-            HbWidgetFeedback::triggered(this, Hb::InstantReleased);
-
-            d->openInputPanel();
-            
-            break;
-      case Qt::GestureCanceled:
-            scene()->setProperty(HbPrivate::OverridingGesture.latin1(),QVariant());
-
-            break;
-      default:
-            break;
-        }
-        event->accept();
-    } else {
-        event->ignore();
-    }
+    d->gestureEvent(event);
 }
 
 /*!