src/hbwidgets/editors/hbselectioncontrol_p.cpp
changeset 34 ed14f46c0e55
parent 7 923ff622b8b9
equal deleted inserted replaced
31:7516d6d86cf5 34:ed14f46c0e55
    38 #include "hbstyleoption_p.h"
    38 #include "hbstyleoption_p.h"
    39 #include "hbeffect.h"
    39 #include "hbeffect.h"
    40 #include "hbdialog_p.h"
    40 #include "hbdialog_p.h"
    41 #include "hbabstractedit.h"
    41 #include "hbabstractedit.h"
    42 #include "hbabstractedit_p.h"
    42 #include "hbabstractedit_p.h"
       
    43 #include "hblineedit.h"
    43 #include "hbtoucharea.h"
    44 #include "hbtoucharea.h"
    44 #include "hbpangesture.h"
    45 #include "hbpangesture.h"
    45 #include "hbtapgesture.h"
    46 #include "hbtapgesture.h"
    46 #include "hbevent.h"
    47 #include "hbevent.h"
    47 #include "hbpopup.h"
    48 #include "hbpopup.h"
       
    49 #include "hbmagnifier_p.h"
    48 #include "hbnamespace_p.h"
    50 #include "hbnamespace_p.h"
    49 #include "hbmainwindow.h"
    51 #include "hbmainwindow.h"
       
    52 #include "hbdeviceprofile.h"
       
    53 #include "hbiconitem.h"
    50 
    54 
    51 
    55 
    52 #include <QTextCursor>
    56 #include <QTextCursor>
       
    57 #include <QTextBlock>
    53 #include <QGraphicsItem>
    58 #include <QGraphicsItem>
       
    59 #include <QGraphicsWidget>
    54 #include <QAbstractTextDocumentLayout>
    60 #include <QAbstractTextDocumentLayout>
    55 #include <QGraphicsSceneMouseEvent>
    61 #include <QGraphicsSceneMouseEvent>
    56 #include <QBasicTimer>
    62 #include <QBasicTimer>
    57 #include <QSizeF>
    63 #include <QSizeF>
    58 #include <QPointF>
    64 #include <QPointF>
    59 #include <QHash>
    65 #include <QHash>
    60 #include <QGraphicsScene>
    66 #include <QGraphicsScene>
    61 
    67 
    62 #include <hbwidgetfeedback.h>
    68 #include <hbwidgetfeedback.h>
    63 
    69 
       
    70 
       
    71 #define HB_DEBUG_PAINT_INFO 0
       
    72 
    64 typedef QHash<HbMainWindow*,HbSelectionControl*> HbSelectionControlHash;
    73 typedef QHash<HbMainWindow*,HbSelectionControl*> HbSelectionControlHash;
    65 Q_GLOBAL_STATIC(HbSelectionControlHash, globalSelectionControlHash)
    74 Q_GLOBAL_STATIC(HbSelectionControlHash, globalSelectionControlHash)
    66 
    75 
    67 namespace {
    76 namespace {
    68     static const int SNAP_DELAY = 300;
    77     static const int SNAP_DELAY = 300;
    69 }
    78     static const int MAGNIFIER_OPEN_DELAY = 200;
       
    79     static const qreal MAGNIFIER_SCALE_FACTOR = 1.5;
       
    80 }
       
    81 
       
    82 class MyEditor: public HbAbstractEdit
       
    83 {
       
    84 public:
       
    85     using HbAbstractEdit::drawContents;
       
    86 };
       
    87 
       
    88 
       
    89 class HbMagnifierDelegateEditor : public HbMagnifierDelegate
       
    90 {
       
    91 public:
       
    92     HbMagnifierDelegateEditor(HbAbstractEdit * editor) {this->editor = editor;}
       
    93     virtual void drawContents(QPainter *painter, const QStyleOptionGraphicsItem *option)
       
    94     {
       
    95         if (option && editor) {
       
    96             static_cast<MyEditor*>(editor)->drawContents(painter,*option);
       
    97         }
       
    98     }
       
    99     void setEditor(HbAbstractEdit * editor){this->editor = editor;}
       
   100 private:
       
   101     HbAbstractEdit * editor;
       
   102 };
    70 
   103 
    71 
   104 
    72 class HbSelectionControlPrivate :public HbDialogPrivate
   105 class HbSelectionControlPrivate :public HbDialogPrivate
    73 {
   106 {
    74     Q_DECLARE_PUBLIC(HbSelectionControl)
   107     Q_DECLARE_PUBLIC(HbSelectionControl)
    75 
   108 
    76 public:
   109 public:
       
   110     enum InteractionMode {
       
   111         Selection,
       
   112         CursorPositioning
       
   113     };
       
   114 
       
   115     enum HandleType {
       
   116         DummyHandle,
       
   117         SelectionStartHandle,
       
   118         SelectionEndHandle
       
   119     };
       
   120 
       
   121 
    77     HbSelectionControlPrivate();
   122     HbSelectionControlPrivate();
       
   123     ~HbSelectionControlPrivate();
    78     void init();
   124     void init();
    79     void createPrimitives();
   125     void createPrimitives();
    80     void updateHandle(int newHandlePos,
   126     void updateHandle(int cursorPos,
       
   127                       int newHandlePos,
    81                       Qt::AlignmentFlag handleAlignment,
   128                       Qt::AlignmentFlag handleAlignment,
    82                       QGraphicsItem *handle,
   129                       QGraphicsItem *handle,
    83                       QGraphicsItem *handleTouchArea,
   130                       QGraphicsItem *handleTouchArea);
    84                       HbStyle::Primitive handlePrimitive);
   131     void updateMagnifier();
       
   132     void initMagnifier();
       
   133 
    85     QGraphicsItem * reparent(QGraphicsItem *item);
   134     QGraphicsItem * reparent(QGraphicsItem *item);
    86     void reparent(QGraphicsItem *item, QGraphicsItem *newParent);
   135     void reparent(QGraphicsItem *item, QGraphicsItem *newParent);
    87     void reparentHandles(QGraphicsItem *newParent);
   136     void reparentHandles(QGraphicsItem *newParent);
    88     void tapGestureFinished (const QPointF& point);
   137     QPointF constrainHitTestPoint(const QPointF& point);
       
   138     HbSelectionControlPrivate::HandleType handleForPoint(const QPointF& point);
       
   139     void gestureStarted(const QPointF &point);
       
   140     void tapGestureStarted(HbTapGesture *gesture);
       
   141     void tapGestureFinished();
       
   142     void delayedTapFinished();
    89     void panGestureStarted (HbPanGesture *gesture);
   143     void panGestureStarted (HbPanGesture *gesture);
    90     void panGestureUpdated (HbPanGesture *gesture);
   144     void panGestureUpdated (HbPanGesture *gesture);
    91     void panGestureFinished (HbPanGesture *gesture);
   145     void panGestureFinished (HbPanGesture *gesture);
       
   146     void panGestureCanceled();
    92     void show();
   147     void show();
    93     void _q_aboutToChangeView();
   148     void _q_aboutToChangeView();
    94     void detachEditor(bool updateAtthachedEditorState);
   149     void detachEditor(bool updateAtthachedEditorState);
    95 
   150 
       
   151 #if HB_DEBUG_PAINT_INFO
       
   152     void updateDebugPaintInfo();
       
   153 #endif
       
   154 
       
   155 
    96 public:
   156 public:
    97 
   157 
    98     HbAbstractEdit *mEdit;
   158     HbAbstractEdit *mEdit;
    99     QGraphicsItem *mTopLevelAncestor;
   159     HbMagnifierDelegateEditor *mMagnifierDelegate; // Owned by mMagnifier
   100 
   160     HbMagnifier* mMagnifier;
   101     QGraphicsItem *mSelectionStartHandle;
   161 
   102     QGraphicsItem *mSelectionEndHandle;
   162     QGraphicsItem *mTopLevelAncestor;    
       
   163     // The offset between the gesture start point and first hit test point
       
   164     QPointF mTouchOffsetFromHitTestPoint;
       
   165 
       
   166     HbIconItem *mSelectionStartHandle;
       
   167     HbIconItem *mSelectionEndHandle;
   103     HbTouchArea* mSelectionStartTouchArea;
   168     HbTouchArea* mSelectionStartTouchArea;
   104     HbTouchArea* mSelectionEndTouchArea;
   169     HbTouchArea* mSelectionEndTouchArea;
   105 
   170 
   106     HbSelectionControl::HandleType mPressed;
   171     InteractionMode mInteractionMode;
   107     bool mPanInProgress;
   172     HandleType mPressed;
       
   173     bool mScrollInProgress;
       
   174     QPointF mHitTestPoint;                 // HbSelectionControl's coordinate system
       
   175     QPointF mTouchPoint;                   // HbSelectionControl's coordinate system
       
   176     QPointF mStartHandleHitTestPoint;      // HbSelectionControl's coordinate system
       
   177     QPointF mEndHandleHitTestPoint;        // HbSelectionControl's coordinate system
   108     QBasicTimer mWordSnapTimer;
   178     QBasicTimer mWordSnapTimer;
       
   179     QBasicTimer mDelayedTapTimer;
       
   180 
       
   181     bool mMagnifierEnabled;
       
   182     qreal mLastCursorHeight;
       
   183     qreal mHandleMarginFromLine;
       
   184     qreal mMagnifierMarginFromLine;
       
   185     qreal mMagnifierLeftRightMarginFromHandle;
       
   186     qreal mMagnifierMaxDescent;
       
   187     qreal mVerticalScreenMargin;
       
   188     qreal mTouchYOffsetFromMagnifierReferenceLine; // HbSelectionControl's coordinate system
       
   189     qreal mStartHandleMagnifierReferenceLine;     // HbSelectionControl's coordinate system
       
   190     qreal mEndHandleMagnifierReferenceLine;       // HbSelectionControl's coordinate system
       
   191     qreal mMagnifierMaxYOffsetFromTouchPoint;
       
   192     qreal mMagnifierMinYOffsetFromTouchPoint;
       
   193     qreal mMaxHitTestPointOffsetYFromLine;
       
   194     bool mIsPanActive;
       
   195 
       
   196 #if HB_DEBUG_PAINT_INFO
       
   197     QRectF  mDocRectDebug;      // HbSelectionControl's coordinate system
       
   198 #endif
   109 };
   199 };
   110 
   200 
   111 
   201 
   112 HbSelectionControlPrivate::HbSelectionControlPrivate():
   202 HbSelectionControlPrivate::HbSelectionControlPrivate():
   113     mEdit(0),
   203     mEdit(0),
       
   204     mMagnifierDelegate(0),
       
   205     mMagnifier(0),
   114     mTopLevelAncestor(0),
   206     mTopLevelAncestor(0),
   115     mSelectionStartHandle(0),
   207     mSelectionStartHandle(0),
   116     mSelectionEndHandle(0),
   208     mSelectionEndHandle(0),
   117     mSelectionStartTouchArea(0),
   209     mSelectionStartTouchArea(0),
   118     mSelectionEndTouchArea(0),
   210     mSelectionEndTouchArea(0),
   119     mPressed(HbSelectionControl::HandleType(0)),
   211     mInteractionMode(InteractionMode(0)),
   120     mPanInProgress(false)
   212     mPressed(HandleType(0)),
       
   213     mScrollInProgress(false),
       
   214     mMagnifierEnabled(true),
       
   215     mLastCursorHeight(0.0),
       
   216     mHandleMarginFromLine(0.0),
       
   217     mMagnifierMarginFromLine(0.0),
       
   218     mMagnifierLeftRightMarginFromHandle(0.0),
       
   219     mMagnifierMaxDescent(0.0),
       
   220     mVerticalScreenMargin(0.0),
       
   221     mTouchYOffsetFromMagnifierReferenceLine(0.0),
       
   222     mStartHandleMagnifierReferenceLine(0.0),
       
   223     mEndHandleMagnifierReferenceLine(0.0),
       
   224     mMagnifierMaxYOffsetFromTouchPoint(0.0),
       
   225     mMagnifierMinYOffsetFromTouchPoint(0.0),
       
   226     mMaxHitTestPointOffsetYFromLine(0.0),
       
   227     mIsPanActive(false)
   121 {    
   228 {    
   122 }
   229 }
   123 
   230 
       
   231 HbSelectionControlPrivate::~HbSelectionControlPrivate()
       
   232 {
       
   233 }
       
   234 
   124 void HbSelectionControlPrivate::init()
   235 void HbSelectionControlPrivate::init()
   125 {
   236 {
   126     Q_Q(HbSelectionControl);
   237     Q_Q(HbSelectionControl);
       
   238 
       
   239     // Set the size of the control to 0
       
   240     q->resize(0,0);
       
   241 
       
   242 #if HB_DEBUG_PAINT_INFO
       
   243     // Override 0 size to be able to paint paint
       
   244     q->resize(1,1);
       
   245 #endif
       
   246 
       
   247     q->style()->parameter(QLatin1String("hb-param-margin-gene-middle-vertical"), mVerticalScreenMargin);
       
   248 
   127     createPrimitives();
   249     createPrimitives();
   128 
   250 
   129     q->setVisible(false);
   251     q->setVisible(false);
   130     QGraphicsItem::GraphicsItemFlags itemFlags = q->flags();
   252     QGraphicsItem::GraphicsItemFlags itemFlags = q->flags();
   131 #if QT_VERSION >= 0x040600
   253 #if QT_VERSION >= 0x040600
   134     itemFlags &= ~QGraphicsItem::ItemIsFocusable;
   256     itemFlags &= ~QGraphicsItem::ItemIsFocusable;
   135     itemFlags |=  QGraphicsItem::ItemIsPanel;
   257     itemFlags |=  QGraphicsItem::ItemIsPanel;
   136     q->setFlags(itemFlags);
   258     q->setFlags(itemFlags);
   137     q->setFocusPolicy(Qt::NoFocus);
   259     q->setFocusPolicy(Qt::NoFocus);
   138     q->setActive(false);
   260     q->setActive(false);
   139 
       
   140     // Control will handle all events going to different handlers.
       
   141     q->setHandlesChildEvents(true);
       
   142 }
   261 }
   143 
   262 
   144 void HbSelectionControlPrivate::createPrimitives()
   263 void HbSelectionControlPrivate::createPrimitives()
   145 {
   264 {
   146     Q_Q(HbSelectionControl);
   265     Q_Q(HbSelectionControl);
   147     if (!mSelectionStartHandle) {
   266     if (!mSelectionStartHandle) {
   148         mSelectionStartHandle = q->style()->createPrimitive(HbStyle::P_SelectionControl_selectionstart, q);
   267 
       
   268         mSelectionStartHandle = new HbIconItem(q);
       
   269         mSelectionStartHandle->setIconName(QLatin1String("qtg_graf_editor_handle_begin"));
       
   270         HbStyle::setItemName(mSelectionStartHandle, QLatin1String("handle-icon"));
   149         mSelectionStartHandle->setFlag(QGraphicsItem::ItemIsPanel);
   271         mSelectionStartHandle->setFlag(QGraphicsItem::ItemIsPanel);
   150         mSelectionStartHandle->setFlag(QGraphicsItem::ItemIsFocusable,false);
   272         mSelectionStartHandle->setFlag(QGraphicsItem::ItemIsFocusable,false);
   151         mSelectionStartHandle->setActive(false);
   273         mSelectionStartHandle->setActive(false);
   152     }
   274     }
   153 
   275 
   154     if (!mSelectionEndHandle) {
   276     if (!mSelectionEndHandle) {
   155         mSelectionEndHandle = q->style()->createPrimitive(HbStyle::P_SelectionControl_selectionend, q);
   277         mSelectionEndHandle = new HbIconItem(q);
       
   278         mSelectionEndHandle->setIconName(QLatin1String("qtg_graf_editor_handle_end"));
       
   279         HbStyle::setItemName(mSelectionEndHandle, QLatin1String("handle-icon"));
   156         mSelectionEndHandle->setFlag(QGraphicsItem::ItemIsPanel);
   280         mSelectionEndHandle->setFlag(QGraphicsItem::ItemIsPanel);
   157         mSelectionEndHandle->setFlag(QGraphicsItem::ItemIsFocusable,false);
   281         mSelectionEndHandle->setFlag(QGraphicsItem::ItemIsFocusable,false);
   158         mSelectionEndHandle->setActive(false);
   282         mSelectionEndHandle->setActive(false);
   159     }
   283     }
   160 
   284 
   161     if (!mSelectionStartTouchArea) {
   285     if (!mSelectionStartTouchArea) {
   162         mSelectionStartTouchArea = new HbTouchArea(q);
   286         mSelectionStartTouchArea = new HbTouchArea(q);
   163         mSelectionStartTouchArea->setFlag(QGraphicsItem::ItemIsPanel);
   287         mSelectionStartTouchArea->setFlag(QGraphicsItem::ItemIsPanel);
   164         mSelectionStartTouchArea->setFlag(QGraphicsItem::ItemIsFocusable,false);
   288         mSelectionStartTouchArea->setFlag(QGraphicsItem::ItemIsFocusable,false);
   165         mSelectionStartTouchArea->setActive(false);
   289         mSelectionStartTouchArea->setActive(false);
   166         HbStyle::setItemName(mSelectionStartTouchArea, "handle-toucharea");
   290         HbStyle::setItemName(mSelectionStartTouchArea, QLatin1String("handle-toucharea"));
   167         mSelectionStartTouchArea->grabGesture(Qt::TapGesture);
   291         mSelectionStartTouchArea->grabGesture(Qt::TapGesture);
   168         mSelectionStartTouchArea->grabGesture(Qt::PanGesture);
   292         mSelectionStartTouchArea->grabGesture(Qt::PanGesture);
       
   293         mSelectionStartTouchArea->installEventFilter(q);
   169     }
   294     }
   170 
   295 
   171     if (!mSelectionEndTouchArea) {
   296     if (!mSelectionEndTouchArea) {
   172         mSelectionEndTouchArea = new HbTouchArea(q);
   297         mSelectionEndTouchArea = new HbTouchArea(q);
   173         mSelectionEndTouchArea->setFlag(QGraphicsItem::ItemIsPanel);
   298         mSelectionEndTouchArea->setFlag(QGraphicsItem::ItemIsPanel);
   174         mSelectionEndTouchArea->setFlag(QGraphicsItem::ItemIsFocusable,false);
   299         mSelectionEndTouchArea->setFlag(QGraphicsItem::ItemIsFocusable,false);
   175         mSelectionEndTouchArea->setActive(false);
   300         mSelectionEndTouchArea->setActive(false);
   176         HbStyle::setItemName(mSelectionEndTouchArea, "handle-toucharea");
   301         HbStyle::setItemName(mSelectionEndTouchArea, QLatin1String("handle-toucharea"));
   177         mSelectionEndTouchArea->grabGesture(Qt::TapGesture);
   302         mSelectionEndTouchArea->grabGesture(Qt::TapGesture);
   178         mSelectionEndTouchArea->grabGesture(Qt::PanGesture);
   303         mSelectionEndTouchArea->grabGesture(Qt::PanGesture);
       
   304         mSelectionEndTouchArea->installEventFilter(q);
       
   305     }
       
   306     if(!mMagnifier) {
       
   307         mMagnifier = new HbMagnifier(q);
       
   308         mMagnifier->setFlag(QGraphicsItem::ItemIsPanel);
       
   309         mMagnifier->setFlag(QGraphicsItem::ItemIsFocusable,false);
       
   310         mMagnifier->setActive(false);
       
   311         HbStyle::setItemName(mMagnifier, QLatin1String("magnifier"));
       
   312         mMagnifierDelegate = new HbMagnifierDelegateEditor(mEdit);
       
   313         mMagnifier->setContentDelegate(mMagnifierDelegate);
       
   314         mMagnifier->hide();
       
   315         initMagnifier();
   179     }
   316     }
   180 }
   317 }
   181 
   318 
   182 /*
   319 /*
   183    Updates given handle associated with handleTouchArea to place it
   320    Updates given handle associated with handleTouchArea to place it
   184    newHandlePos in the selected text.
   321    newHandlePos in the selected text.
   185    handlePrimitive identifies handle graphics.
       
   186 */
   322 */
   187 void HbSelectionControlPrivate::updateHandle(int newHandlePos,
   323 void HbSelectionControlPrivate::updateHandle(
       
   324                   int cursorPos,
       
   325                   int newHandlePos,
   188                   Qt::AlignmentFlag handleAlignment,
   326                   Qt::AlignmentFlag handleAlignment,
   189                   QGraphicsItem *handle,
   327                   QGraphicsItem *handle,
   190                   QGraphicsItem *handleTouchArea,
   328                   QGraphicsItem *handleTouchArea)
   191                   HbStyle::Primitive handlePrimitive)
       
   192 {    
   329 {    
   193     Q_Q(HbSelectionControl);
   330     Q_Q(HbSelectionControl);
   194 
   331 
   195     HbStyleOption option;
   332     QRectF rect = mEdit->rectForPosition(newHandlePos,(Qt::AlignTop||mInteractionMode == CursorPositioning)?
   196 
   333                                                        QTextLine::Leading:QTextLine::Trailing);
   197     q->initStyleOption(&option);
   334     qreal lineHeight = rect.height();
   198     mEdit->style()->updatePrimitive(handle, handlePrimitive, &option);
   335 
   199 
   336     if(cursorPos == newHandlePos) {
   200     QRectF rect = mEdit->rectForPosition(newHandlePos,Qt::AlignTop?QTextLine::Leading:QTextLine::Trailing);
   337         mLastCursorHeight = lineHeight;
       
   338     }
       
   339 
       
   340     // Store the current hit test point for the given handle
       
   341     // Convert rect to HbSelectionControl's coordinate system
       
   342     QRectF rectInSelectionControlCoord = q->mapRectFromItem(mEdit,rect);
       
   343 
       
   344     if (handleAlignment == Qt::AlignTop) {
       
   345         mStartHandleHitTestPoint = rectInSelectionControlCoord.center();
       
   346         mStartHandleHitTestPoint.setY(qMin(mStartHandleHitTestPoint.y(),
       
   347                                            rectInSelectionControlCoord.top()+mMaxHitTestPointOffsetYFromLine));
       
   348         mStartHandleMagnifierReferenceLine = rectInSelectionControlCoord.top();
       
   349     } else {
       
   350         mEndHandleHitTestPoint = rectInSelectionControlCoord.center();
       
   351         mEndHandleHitTestPoint.setY(qMax(mEndHandleHitTestPoint.y(),
       
   352                                          rectInSelectionControlCoord.bottom()-mMaxHitTestPointOffsetYFromLine));
       
   353         mEndHandleMagnifierReferenceLine = rectInSelectionControlCoord.bottom();
       
   354     }
   201 
   355 
   202     // Convert rect to handle's parent coordinate system
   356     // Convert rect to handle's parent coordinate system
   203     rect = handle->parentItem()->mapRectFromItem(mEdit,rect);
   357     rect = handle->parentItem()->mapRectFromItem(mEdit,rect);
   204 
   358 
   205     // Center handle around center point of rect
   359     // Center handle around center point of rect
   206     QRectF boundingRect = handle->boundingRect();
   360     QRectF boundingRect = handle->boundingRect();
   207 
   361 
       
   362     bool positionHandlesTouchEachOther = (boundingRect.height()*2 > lineHeight);
       
   363 
   208     boundingRect.moveCenter(rect.center());
   364     boundingRect.moveCenter(rect.center());
   209 
   365 
       
   366     // Position handle either on top of rect using margin mHandleMarginFromLine or so that
       
   367     // the two handles touch eachother
   210     if (handleAlignment == Qt::AlignTop) {
   368     if (handleAlignment == Qt::AlignTop) {
   211        boundingRect.moveBottom(rect.top());
   369         if (positionHandlesTouchEachOther) {
       
   370             boundingRect.moveBottom(rect.center().y());
       
   371         } else {
       
   372             boundingRect.moveTop(rect.top()-mHandleMarginFromLine);
       
   373         }
   212     } else {
   374     } else {
   213        boundingRect.moveTop(rect.bottom());
   375         if (positionHandlesTouchEachOther) {
       
   376             boundingRect.moveTop(rect.center().y());
       
   377         } else {
       
   378             boundingRect.moveBottom(rect.bottom()+mHandleMarginFromLine);
       
   379         }
   214     }
   380     }
   215 
   381 
   216     handle->setPos(boundingRect.topLeft());
   382     handle->setPos(boundingRect.topLeft());
   217 
   383 
   218     // Center handle touch area around center pos of handle
   384     // Position handle touch area around center-top of handle
   219     QPointF centerPos = boundingRect.center();
   385     QPointF centerPos = boundingRect.center();
       
   386     rect = boundingRect;
   220     boundingRect = handleTouchArea->boundingRect();
   387     boundingRect = handleTouchArea->boundingRect();
   221     boundingRect.moveCenter(centerPos);
   388     boundingRect.moveCenter(centerPos);
       
   389 
       
   390     if (handleAlignment != Qt::AlignTop) {
       
   391         boundingRect.moveTop(rect.top());
       
   392     }
       
   393 
   222     handleTouchArea->setPos(boundingRect.topLeft());
   394     handleTouchArea->setPos(boundingRect.topLeft());
   223 
   395 
   224     if (!mPanInProgress) {
   396     if (!mScrollInProgress) {
   225         QGraphicsItem * newParent = reparent(handle);
   397         QGraphicsItem * newParent = reparent(handle);
   226         reparent(handleTouchArea, newParent);
   398         reparent(handleTouchArea, newParent);
   227     }
   399     }
   228 }
   400 }
   229 
   401 
       
   402 
       
   403 void HbSelectionControlPrivate::updateMagnifier()
       
   404 {
       
   405     Q_Q(HbSelectionControl);
       
   406 
       
   407     if (mMagnifier->isVisible()) {
       
   408         QPointF canvasHitTestPos = q->mapToItem(HbAbstractEditPrivate::d_ptr(mEdit)->canvas,mHitTestPoint);
       
   409         QRectF canvasCursorRect = HbAbstractEditPrivate::d_ptr(mEdit)->rectForPositionInCanvasCoords(mEdit->textCursor().position(),QTextLine::Leading);
       
   410         QPointF centerOfMagnification = canvasCursorRect.center();
       
   411         centerOfMagnification.setX(canvasHitTestPos.x());
       
   412         canvasCursorRect.moveCenter(centerOfMagnification);
       
   413 
       
   414         // Set the visible content to be magnified
       
   415         qreal magnifierHeight = mMagnifier->boundingRect().height();
       
   416 
       
   417         // Check if the line fits vertically to the magnifier if not align the bottom of the line with the bottom of the
       
   418         // magnifier constraining a maximum line descent.
       
   419         if (magnifierHeight < canvasCursorRect.height()*mMagnifier->contentScale()) {
       
   420             const QTextCursor cursor = mEdit->textCursor();
       
   421             const QTextBlock block = cursor.block();
       
   422             const int positionInBlock = cursor.position() - block.position();
       
   423             QTextLine line = block.layout()->lineForTextPosition(positionInBlock);
       
   424             qreal lineDescent = line.descent();
       
   425             qreal lineBottom  = canvasCursorRect.bottom();
       
   426             if (mMagnifierMaxDescent < lineDescent) {
       
   427                 lineBottom-= lineDescent-mMagnifierMaxDescent;
       
   428             }
       
   429             // Compensate for rounding error by adding +1
       
   430             centerOfMagnification.setY(lineBottom-magnifierHeight/(2*mMagnifier->contentScale())+1);
       
   431         }
       
   432 
       
   433         mMagnifier->centerOnContent(centerOfMagnification);
       
   434 
       
   435         // -- Position magnifier --
       
   436 
       
   437         // Convert cursorRect to HbSelectionControl's coordinate system
       
   438         QRectF rect = q->mapRectFromItem(HbAbstractEditPrivate::d_ptr(mEdit)->canvas,canvasCursorRect);
       
   439 
       
   440         QRectF boundingRect = mMagnifier->boundingRect();
       
   441         boundingRect.moveCenter(rect.center());
       
   442 
       
   443         const qreal KMagnifierBottomUpperBound = rect.top()-mMagnifierMarginFromLine+mTouchYOffsetFromMagnifierReferenceLine;
       
   444         const qreal KMagnifierBottomLowerBound = rect.bottom()-mMagnifierMarginFromLine+mTouchYOffsetFromMagnifierReferenceLine;
       
   445 
       
   446         qreal newMagnifierBottom = (mPressed == SelectionStartHandle?KMagnifierBottomUpperBound:KMagnifierBottomLowerBound);
       
   447 
       
   448         // -- Constrain vertical position --
       
   449 
       
   450         // Constrain maximum distance of bottom of the magnifier from touch point
       
   451         newMagnifierBottom = qMax(newMagnifierBottom,mTouchPoint.y()-mMagnifierMaxYOffsetFromTouchPoint);
       
   452 
       
   453         // Constrain minimum distance of bottom of the magnifier from touch point
       
   454         newMagnifierBottom = qMin(newMagnifierBottom,mTouchPoint.y()-mMagnifierMinYOffsetFromTouchPoint);
       
   455 
       
   456         // Constrain the bottom of the magnifier to be within the feasible bounds
       
   457         newMagnifierBottom = qMin(qMax(newMagnifierBottom,KMagnifierBottomUpperBound),KMagnifierBottomLowerBound);
       
   458 
       
   459         boundingRect.moveBottom(newMagnifierBottom);
       
   460         boundingRect.moveTop(qMax(mVerticalScreenMargin,boundingRect.top()));
       
   461 
       
   462         // Readjust magnifier position if there is not enough space at the top of the screen
       
   463         if (mTouchPoint.y()-mMagnifierMinYOffsetFromTouchPoint < boundingRect.bottom()) {
       
   464 
       
   465             boundingRect.moveRight(mTouchPoint.x()-mMagnifierLeftRightMarginFromHandle);
       
   466 
       
   467             if(boundingRect.left() < 0) {
       
   468                 boundingRect.moveLeft(mTouchPoint.x()+mMagnifierLeftRightMarginFromHandle);
       
   469             }
       
   470         }
       
   471         mMagnifier->setPos(boundingRect.topLeft());
       
   472 #if HB_DEBUG_PAINT_INFO
       
   473     updateDebugPaintInfo();
       
   474 #endif
       
   475     }
       
   476 
       
   477 }
       
   478 
       
   479 void HbSelectionControlPrivate::initMagnifier()
       
   480 {   
       
   481     mMagnifier->setContentScale(MAGNIFIER_SCALE_FACTOR);
       
   482     mMagnifier->setZValue(100); 
       
   483     mMagnifier->setMask(QLatin1String("qtg_fr_editor_magnifier_mask"));
       
   484     mMagnifier->setOverlay(QLatin1String("qtg_fr_editor_magnifier_overlay"));
       
   485     updateMagnifier();
       
   486 }
   230 
   487 
   231 
   488 
   232 /*
   489 /*
   233    Reparents item to q if item's bounding rect intersects mEdit's viewPort rectangle or otherwise to
   490    Reparents item to q if item's bounding rect intersects mEdit's viewPort rectangle or otherwise to
   234    HbAbstractEditPrivate::d_ptr(d->mEdit)->canvas.
   491    HbAbstractEditPrivate::d_ptr(d->mEdit)->canvas.
   254     return newParent;
   511     return newParent;
   255 }
   512 }
   256 
   513 
   257 void HbSelectionControlPrivate::reparent(QGraphicsItem *item, QGraphicsItem *newParent)
   514 void HbSelectionControlPrivate::reparent(QGraphicsItem *item, QGraphicsItem *newParent)
   258 {
   515 {
   259     Q_Q(HbSelectionControl);
       
   260 
       
   261     if (item && newParent && newParent != item->parentItem()) {
   516     if (item && newParent && newParent != item->parentItem()) {
   262 
   517 
   263         // Reparent handle items to newParent
   518         // Reparent handle items to newParent
   264         QPointF pos = newParent->mapFromItem(item->parentItem(),item->pos());
   519         QPointF pos = newParent->mapFromItem(item->parentItem(),item->pos());
   265 
   520 
   266         // If the item is parented to other then q we have to
   521         // ----------
   267         // turn off the QGraphicsItem::ItemIsPanel flag because
   522         // Workaround for Qt bug: Missing repaint when QGraphicsItem is reparented to another
   268         // otherwise the new parent loses its activeness.
   523         // item with flag QGraphicsItem::ItemClipsChildrenToShape is set.
   269         bool enablePanel = (newParent == q);
   524         // ----------
   270 
   525         // Remove when the bug is fixed
   271         item->setFlag(QGraphicsItem::ItemIsPanel,enablePanel);
   526         if(item->isWidget()) {
   272 
   527             if (qobject_cast<HbIconItem *>(static_cast<QGraphicsWidget *>(item))) {
   273         // TODO: This is a workaround for a Qt bug when reparenting from a clipping parent to a
   528                 item->scene()->invalidate(item->sceneBoundingRect());
   274         //       non-clipping parent
   529             }
   275         item->setParentItem(0);
   530         }
       
   531         // ----------------------------------------------------------------------------------
       
   532 
   276         item->setParentItem(newParent);
   533         item->setParentItem(newParent);
   277         item->setPos(pos);
   534         item->setPos(pos);
   278     }
   535     }
   279 }
   536 }
   280 
   537 
   286     reparent(mSelectionEndHandle, newParent);
   543     reparent(mSelectionEndHandle, newParent);
   287     reparent(mSelectionEndTouchArea, newParent);
   544     reparent(mSelectionEndTouchArea, newParent);
   288 }
   545 }
   289 
   546 
   290 
   547 
   291 void HbSelectionControlPrivate::tapGestureFinished(const QPointF &pos)
   548 /*
   292 {
   549     Returns the constrained hit test point calculated from point.
   293     if (mEdit->contextMenuFlags().testFlag(Hb::ShowTextContextMenuOnSelectionClicked)) {
   550     point has to be in HbSelectionControl's coordinate system.
   294         mEdit->showContextMenu(pos);
   551     The returned pos is also in HbSelectionControl's coordinate system.
   295     }
   552 */
   296 }
   553 QPointF HbSelectionControlPrivate::constrainHitTestPoint(const QPointF& point)
   297 
   554 {
   298 void HbSelectionControlPrivate::panGestureStarted(HbPanGesture *gesture)
   555     Q_Q(HbSelectionControl);
   299 {
   556 
   300     Q_Q(HbSelectionControl);
   557     QRectF docRect = QRectF(q->mapFromItem(HbAbstractEditPrivate::d_ptr(mEdit)->canvas->parentItem(),
   301 
   558                             HbAbstractEditPrivate::d_ptr(mEdit)->canvas->pos()),
   302     QPointF point = q->mapFromScene(gesture->sceneStartPos());
   559                             HbAbstractEditPrivate::d_ptr(mEdit)->doc->size());
   303     mPressed = HbSelectionControl::DummyHandle;
   560 
       
   561     // Constrain hitTestPos within docRect with mLastCursorHeight/2 top/bottom margins.
       
   562     QPointF hitTestPos = QPointF(qMin(qMax(point.x(),docRect.left()),docRect.right()),
       
   563                          qMin(qMax(point.y(),docRect.top()+mLastCursorHeight/2),docRect.bottom()-mLastCursorHeight/2));
       
   564 
       
   565 #if HB_DEBUG_PAINT_INFO
       
   566     mDocRectDebug = docRect;
       
   567 #endif
       
   568 
       
   569     return hitTestPos;
       
   570 }
       
   571 
       
   572 
       
   573 /*
       
   574     Returns the handle whose touch area contains point.
       
   575     point has to be in HbSelectionControl's coordinate system.
       
   576 */
       
   577 HbSelectionControlPrivate::HandleType HbSelectionControlPrivate::handleForPoint(const QPointF& point) {
       
   578 
       
   579     Q_Q(HbSelectionControl);
       
   580 
       
   581     HandleType pressed = DummyHandle;
   304 
   582 
   305     // Find out which handle is being moved
   583     // Find out which handle is being moved
   306     if (mSelectionStartTouchArea->contains(q->mapToItem(mSelectionStartTouchArea, point))) {
   584     if (mSelectionStartTouchArea->isVisible() &&
   307         mPressed = HbSelectionControl::SelectionStartHandle;
   585         mSelectionStartTouchArea->contains(q->mapToItem(mSelectionStartTouchArea, point))) {
       
   586         pressed = SelectionStartHandle;
   308     }
   587     }
   309     if (mSelectionEndTouchArea->contains(q->mapToItem(mSelectionEndTouchArea, point))) {
   588     if (mSelectionEndTouchArea->contains(q->mapToItem(mSelectionEndTouchArea, point))) {
   310         bool useArea = true;
   589         bool useArea = true;
   311         if(mPressed != HbSelectionControl::DummyHandle) {
   590         if(pressed != DummyHandle) {
   312 
   591 
   313             // The press point was inside in both of the touch areas
   592             // The press point was inside in both of the touch areas
   314             // choose the touch area whose center is closer to the press point
   593             // choose the touch area whose center is closer to the press point
   315             QRectF rect = mSelectionStartTouchArea->boundingRect();
   594             QRectF rect = mSelectionStartHandle->boundingRect();
   316             rect.moveTopLeft(mSelectionStartTouchArea->pos());
   595             rect.moveTopLeft(mSelectionStartHandle->pos());
   317             QLineF  lineEventPosSelStartCenter(point,rect.center());
   596             QLineF  lineEventPosSelStartCenter(point,rect.center());
   318 
   597 
   319             rect = mSelectionEndTouchArea->boundingRect();
   598             rect = mSelectionEndHandle->boundingRect();
   320             rect.moveTopLeft(mSelectionEndTouchArea->pos());
   599             rect.moveTopLeft(mSelectionEndHandle->pos());
   321             QLineF  lineEventPosSelEndCenter(point,rect.center());
   600             QLineF  lineEventPosSelEndCenter(point,rect.center());
   322 
   601 
   323             if (lineEventPosSelStartCenter.length() < lineEventPosSelEndCenter.length()) {
   602             if (lineEventPosSelStartCenter.length() < lineEventPosSelEndCenter.length()) {
   324                 useArea = false;
   603                 useArea = false;
   325             }
   604             }
   326         }
   605         }
   327         if (useArea) {
   606         if (useArea) {
   328             mPressed = HbSelectionControl::SelectionEndHandle;
   607             pressed = SelectionEndHandle;
   329         }
   608         }
   330     }
   609     }
   331 
   610 
   332     if (mPressed == HbSelectionControl::DummyHandle) {
   611     return pressed;
       
   612 }
       
   613 
       
   614 void HbSelectionControlPrivate::gestureStarted(const QPointF &point)
       
   615 {
       
   616     mPressed = handleForPoint(point);
       
   617     mTouchPoint = point;
       
   618 
       
   619     if (mPressed == DummyHandle) {
   333         // Hit is outside touch areas, ignore
   620         // Hit is outside touch areas, ignore
   334         return;
   621         return;
   335     }
   622     }
       
   623 
       
   624     // Calculate touch offsets
       
   625     mHitTestPoint = mStartHandleHitTestPoint;
       
   626     qreal magnifierReferenceLine = mStartHandleMagnifierReferenceLine;
       
   627     if (mPressed == SelectionEndHandle) {
       
   628         mHitTestPoint = mEndHandleHitTestPoint;
       
   629         magnifierReferenceLine = mEndHandleMagnifierReferenceLine;
       
   630     }
       
   631 
       
   632     mTouchYOffsetFromMagnifierReferenceLine = point.y() - magnifierReferenceLine;
       
   633     mTouchOffsetFromHitTestPoint = mHitTestPoint - point;
   336 
   634 
   337     // Position cursor at the pressed selection handle
   635     // Position cursor at the pressed selection handle
   338 
   636 
   339     QTextCursor cursor = mEdit->textCursor();
   637     QTextCursor cursor = mEdit->textCursor();
   340     int selStartPos = qMin(mEdit->textCursor().anchor(),mEdit->textCursor().position());
   638     int selStartPos = qMin(mEdit->textCursor().anchor(),mEdit->textCursor().position());
   341     int selEndPos = qMax(mEdit->textCursor().anchor(),mEdit->textCursor().position());
   639     int selEndPos = qMax(mEdit->textCursor().anchor(),mEdit->textCursor().position());
   342 
   640 
   343     if (mPressed == HbSelectionControl::SelectionStartHandle) {
   641     if (mPressed == SelectionStartHandle) {
   344         cursor.setPosition(selEndPos);
   642         cursor.setPosition(selEndPos);
   345         cursor.setPosition(selStartPos, QTextCursor::KeepAnchor);
   643         cursor.setPosition(selStartPos, QTextCursor::KeepAnchor);
   346     } else {
   644     } else {
   347         cursor.setPosition(selStartPos);
   645         cursor.setPosition(selStartPos);
   348         cursor.setPosition(selEndPos, QTextCursor::KeepAnchor);
   646         cursor.setPosition(selEndPos, QTextCursor::KeepAnchor);
   349     }
   647     }
   350     mEdit->setTextCursor(cursor);
   648     mEdit->setTextCursor(cursor);
   351 
   649 }
       
   650 
       
   651 void HbSelectionControlPrivate::tapGestureStarted(HbTapGesture *gesture)
       
   652 {
       
   653     Q_Q(HbSelectionControl);
       
   654 
       
   655     mMagnifier->hideWithEffect();
       
   656     if (!mDelayedTapTimer.isActive()) {
       
   657         mDelayedTapTimer.start(MAGNIFIER_OPEN_DELAY,q);
       
   658     }
       
   659     QPointF point = q->mapFromScene(gesture->sceneStartPos());
       
   660     gestureStarted(point);
       
   661 }
       
   662 
       
   663 void HbSelectionControlPrivate::tapGestureFinished()
       
   664 {
       
   665     mDelayedTapTimer.stop();
       
   666     if (!mIsPanActive) {
       
   667         mSelectionStartTouchArea->show();
       
   668         mSelectionStartHandle->show();
       
   669         mMagnifier->hideWithEffect();
       
   670     }
       
   671 }
       
   672 
       
   673 void HbSelectionControlPrivate::delayedTapFinished()
       
   674 {
       
   675     Q_Q(HbSelectionControl);
       
   676 
       
   677     // Reset gesture override to have enable more responsive pan
       
   678     q->scene()->setProperty(HbPrivate::OverridingGesture.latin1(),QVariant());
       
   679 
       
   680     if (mPressed == HbSelectionControlPrivate::SelectionEndHandle && mInteractionMode == HbSelectionControlPrivate::CursorPositioning) {
       
   681         mSelectionStartTouchArea->hide();
       
   682         mSelectionStartHandle->hide();
       
   683     }
       
   684     if (mMagnifierEnabled) {
       
   685         mMagnifier->showWithEffect();
       
   686         q->updatePrimitives();
       
   687     }
       
   688 }
       
   689 
       
   690 
       
   691 
       
   692 void HbSelectionControlPrivate::panGestureStarted(HbPanGesture *gesture)
       
   693 {
       
   694     Q_Q(HbSelectionControl);
       
   695 
       
   696     mIsPanActive = true;
       
   697     QPointF point = q->mapFromScene(gesture->sceneStartPos());
       
   698     gestureStarted(point);
       
   699     if (mPressed == SelectionEndHandle && mInteractionMode == HbSelectionControlPrivate::CursorPositioning) {
       
   700         mSelectionStartTouchArea->hide();
       
   701         mSelectionStartHandle->hide();
       
   702     }
   352 }
   703 }
   353 
   704 
   354 
   705 
   355 void HbSelectionControlPrivate::panGestureFinished(HbPanGesture *gesture)
   706 void HbSelectionControlPrivate::panGestureFinished(HbPanGesture *gesture)
   356 {
   707 {
   371         cursor.setPosition(anchPos);
   722         cursor.setPosition(anchPos);
   372         cursor.setPosition(curPos, QTextCursor::KeepAnchor);
   723         cursor.setPosition(curPos, QTextCursor::KeepAnchor);
   373         mEdit->setTextCursor(cursor);
   724         mEdit->setTextCursor(cursor);
   374     }
   725     }
   375 
   726 
   376     mPressed = HbSelectionControl::DummyHandle;
   727     mSelectionStartTouchArea->show();
       
   728     mSelectionStartHandle->show();
       
   729     // This has to be set before updatePrimitives call
       
   730     mIsPanActive = false;
   377     q->updatePrimitives();
   731     q->updatePrimitives();
       
   732     mMagnifier->hideWithEffect();
       
   733 
       
   734     // This has to be set at last
       
   735     mPressed = DummyHandle;
       
   736 }
       
   737 
       
   738 void HbSelectionControlPrivate::panGestureCanceled()
       
   739 {
       
   740     mMagnifier->hideWithEffect();
       
   741     mIsPanActive = false;
   378 }
   742 }
   379 
   743 
   380 
   744 
   381 void HbSelectionControlPrivate::panGestureUpdated(HbPanGesture *gesture)
   745 void HbSelectionControlPrivate::panGestureUpdated(HbPanGesture *gesture)
   382 {
   746 {
   383     Q_Q(HbSelectionControl);
   747     Q_Q(HbSelectionControl);
   384 
   748 
   385     QRectF docRect = QRectF(mEdit->mapFromItem(HbAbstractEditPrivate::d_ptr(mEdit)->canvas->parentItem(),
   749     // Calculate new hittest point
   386                             HbAbstractEditPrivate::d_ptr(mEdit)->canvas->pos()),
   750     QPointF point = q->mapFromScene(gesture->sceneStartPos() + gesture->sceneOffset());
   387                             HbAbstractEditPrivate::d_ptr(mEdit)->doc->size());
   751     mTouchPoint = point;
   388     
   752     mHitTestPoint = (point + mTouchOffsetFromHitTestPoint);
   389     QPointF editPos = mEdit->mapFromScene(gesture->sceneStartPos() + gesture->sceneOffset());
   753     mHitTestPoint = constrainHitTestPoint(mHitTestPoint);
   390     QPointF origEditPos = editPos;
   754 
   391     bool outsideCanvas = !docRect.contains(origEditPos);
   755 #if HB_DEBUG_PAINT_INFO
   392 
   756     updateDebugPaintInfo();
   393     // Constrain editPos within docRect
   757 #endif
   394     editPos = QPointF(qMin(qMax(editPos.x(),docRect.left()),docRect.right()),
       
   395                       qMin(qMax(editPos.y(),docRect.top()),docRect.bottom()));
       
   396 
       
   397     QRectF handleRect = mSelectionStartHandle->boundingRect();
       
   398 
       
   399     handleRect.moveCenter(editPos);
       
   400 
       
   401     // Set hitTestPos based on which handle was grabbed
       
   402     QPointF hitTestPos = handleRect.center();
       
   403 
       
   404     if (mPressed == HbSelectionControl::SelectionStartHandle) {
       
   405         hitTestPos.setY(handleRect.bottom()+1);
       
   406     } else {
       
   407         hitTestPos.setY(handleRect.top()-1);
       
   408     }
       
   409 
       
   410     // Override hitTestPos if origEditPos was outside the canvas
       
   411     if (outsideCanvas) {
       
   412         if (origEditPos.y() < docRect.top()) {
       
   413             hitTestPos.setY(handleRect.bottom()+1);
       
   414         } else if (docRect.bottom() < origEditPos.y()) {
       
   415             hitTestPos.setY(handleRect.top()-1);
       
   416         }
       
   417     }
       
   418 
   758 
   419     QTextCursor cursor;
   759     QTextCursor cursor;
   420     cursor = mEdit->textCursor();
   760     cursor = mEdit->textCursor();
       
   761 
   421     // Hit test for the center of current selection touch area
   762     // Hit test for the center of current selection touch area
   422     int hitPos = HbAbstractEditPrivate::d_ptr(mEdit)->hitTest(hitTestPos,Qt::FuzzyHit);
   763     int hitPos = HbAbstractEditPrivate::d_ptr(mEdit)->hitTest(q->mapToItem(mEdit,mHitTestPoint),Qt::FuzzyHit);
   423 
   764 
   424     // if no valid hit pos or empty selection return
   765     // if no valid hit pos or empty selection in read-only mode return
   425     if (hitPos == -1 || hitPos == cursor.anchor()) {
   766     if (hitPos == -1 || (mEdit->isReadOnly() && hitPos == cursor.anchor() && mInteractionMode == Selection)) {
   426         return;
   767         return;
   427     }
   768     }
   428 
   769 
   429     bool handlesMoved(false);
   770     bool isCursorMoved = false;
   430     if (hitPos != cursor.position()) {
   771     if (hitPos != cursor.position()) {
   431         handlesMoved = true;
   772         isCursorMoved = true;
   432     }
   773     }
   433     cursor.setPosition(hitPos, QTextCursor::KeepAnchor);
   774 
   434     if (handlesMoved) {
   775     cursor.setPosition(hitPos, ((mInteractionMode==Selection||mPressed == SelectionStartHandle)
       
   776                                ?QTextCursor::KeepAnchor:QTextCursor::MoveAnchor));
       
   777 
       
   778     if (isCursorMoved) {
   435         if (mEdit) {
   779         if (mEdit) {
   436             HbWidgetFeedback::triggered(mEdit, Hb::InstantDraggedOver);
   780             HbWidgetFeedback::triggered(mEdit, Hb::InstantDraggedOver);
   437         }
   781         }
   438         // Restart timer every time when a selection handle moved
   782         if (mInteractionMode==Selection) {
   439         mWordSnapTimer.start(SNAP_DELAY, q);
   783             // Restart timer every time when a selection handle moved
       
   784             mWordSnapTimer.start(SNAP_DELAY, q);
       
   785         }
   440         mEdit->setTextCursor(cursor);
   786         mEdit->setTextCursor(cursor);
   441     }
   787     }
   442 
   788 
   443     // Ensure that the hitPos is visible
   789     // Ensure that the hitPos is visible
   444     HbAbstractEditPrivate::d_ptr(mEdit)->ensurePositionVisible(hitPos);
   790     HbAbstractEditPrivate::d_ptr(mEdit)->ensurePositionVisible(hitPos);
       
   791     if (mMagnifierEnabled) {
       
   792         mMagnifier->showWithEffect();
       
   793     }
   445     q->updatePrimitives();
   794     q->updatePrimitives();
       
   795 
   446 }
   796 }
   447 
   797 
   448 void HbSelectionControlPrivate::show() {
   798 void HbSelectionControlPrivate::show() {
   449     Q_Q(HbSelectionControl);
   799     Q_Q(HbSelectionControl);
   450 
   800 
   454 
   804 
   455         q->setZValue(zValue);
   805         q->setZValue(zValue);
   456     }
   806     }
   457 
   807 
   458     if (q->scene() != mEdit->scene() && mEdit->scene()) {
   808     if (q->scene() != mEdit->scene() && mEdit->scene()) {
   459         mEdit->scene()->addItem(q);
   809         mEdit->scene()->addItem(q);    
   460     }
   810     }    
       
   811 
   461     q->show();    
   812     q->show();    
   462     q->updatePrimitives();
   813     q->updatePrimitives();
   463 }
   814 }
   464 
   815 
   465 
   816 
   467 {
   818 {
   468     Q_Q(HbSelectionControl);
   819     Q_Q(HbSelectionControl);
   469 
   820 
   470     if (mEdit && q->isVisible()) {
   821     if (mEdit && q->isVisible()) {
   471         mEdit->deselect();
   822         mEdit->deselect();
       
   823         q->hideHandles();
   472     }
   824     }
   473 }
   825 }
   474 
   826 
   475 void HbSelectionControlPrivate::detachEditor(bool updateAtthachedEditorState)
   827 void HbSelectionControlPrivate::detachEditor(bool updateAtthachedEditorState)
   476 {
   828 {
   486         mEdit = 0;
   838         mEdit = 0;
   487         mTopLevelAncestor = 0;
   839         mTopLevelAncestor = 0;
   488     }
   840     }
   489 }
   841 }
   490 
   842 
       
   843 #if HB_DEBUG_PAINT_INFO
       
   844 void HbSelectionControlPrivate::updateDebugPaintInfo()
       
   845 {
       
   846     Q_Q(HbSelectionControl);
       
   847     mEdit->update();
       
   848     q->update();
       
   849 }
       
   850 #endif
       
   851 
       
   852 
   491 HbSelectionControl::HbSelectionControl() : HbWidget(*new HbSelectionControlPrivate(),0)
   853 HbSelectionControl::HbSelectionControl() : HbWidget(*new HbSelectionControlPrivate(),0)
   492 
   854 
   493 {
   855 {
   494     Q_D(HbSelectionControl);
   856     Q_D(HbSelectionControl);
   495     d->q_ptr = this;
   857     d->q_ptr = this;
   517     if (edit != d->mEdit) {
   879     if (edit != d->mEdit) {
   518         control->detachEditor();
   880         control->detachEditor();
   519         d->mEdit = edit;        
   881         d->mEdit = edit;        
   520         QObject::connect(d->mEdit, SIGNAL(cursorPositionChanged(int, int)), control, SLOT(updatePrimitives()));
   882         QObject::connect(d->mEdit, SIGNAL(cursorPositionChanged(int, int)), control, SLOT(updatePrimitives()));
   521         QObject::connect(d->mEdit, SIGNAL(contentsChanged()), control, SLOT(updatePrimitives()));
   883         QObject::connect(d->mEdit, SIGNAL(contentsChanged()), control, SLOT(updatePrimitives()));
       
   884         d->mMagnifierDelegate->setEditor(d->mEdit);
       
   885 
       
   886 
       
   887         // Set the background of magnifier to the background of HbLineEdit or HbTextEdit
       
   888         QLatin1String magnifierBackground("qtg_fr_lineedit_normal_c");
       
   889         if (!qobject_cast<HbLineEdit*>(d->mEdit)) {
       
   890             magnifierBackground = QLatin1String("qtg_fr_textedit_normal_c");
       
   891 
       
   892         }
       
   893         d->mMagnifier->setBackground(magnifierBackground);
   522 
   894 
   523         // find first top-level ancestor of d->mEdit
   895         // find first top-level ancestor of d->mEdit
   524         for(d->mTopLevelAncestor = d->mEdit;
   896         for(d->mTopLevelAncestor = d->mEdit;
   525             d->mTopLevelAncestor->parentItem();
   897             d->mTopLevelAncestor->parentItem();
   526             d->mTopLevelAncestor = d->mTopLevelAncestor->parentItem()){};
   898             d->mTopLevelAncestor = d->mTopLevelAncestor->parentItem()){
       
   899 
       
   900             // Workaround for Qt bug: QTBUG-13473
       
   901             // This line could be removed after Qt fixes this bug.
       
   902             d->mTopLevelAncestor->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
       
   903 
       
   904         };
   527     }
   905     }
   528     return control;
   906     return control;
   529 }
   907 }
   530 
   908 
       
   909 void HbSelectionControl::detachEditor(HbAbstractEdit *edit)
       
   910 {
       
   911     if(!edit || !edit->mainWindow()) {
       
   912         qWarning("HbSelectionControl: attempting to detach to null editor pointer!");
       
   913     }
       
   914 
       
   915     HbSelectionControl *control = globalSelectionControlHash()->value(edit->mainWindow());
       
   916     if (control) {
       
   917         control->detachEditor();
       
   918     }
       
   919 }
       
   920 
   531 void HbSelectionControl::detachEditor()
   921 void HbSelectionControl::detachEditor()
   532 {
   922 {
   533     Q_D(HbSelectionControl);
   923     Q_D(HbSelectionControl);
       
   924     d->mMagnifierDelegate->setEditor(0);
   534     d->detachEditor(true);
   925     d->detachEditor(true);
   535 }
   926 }
   536 
   927 
   537 void HbSelectionControl::detachEditorFromDestructor()
   928 void HbSelectionControl::detachEditorFromDestructor()
   538 {
   929 {
   552 void HbSelectionControl::showHandles()
   943 void HbSelectionControl::showHandles()
   553 {
   944 {
   554     Q_D(HbSelectionControl);
   945     Q_D(HbSelectionControl);
   555     if (!isVisible() && d->mEdit) {
   946     if (!isVisible() && d->mEdit) {
   556         d->show();
   947         d->show();
   557     }
   948     }    
       
   949     // selection start handles might be hidden
       
   950     d->mSelectionStartTouchArea->show();
       
   951     d->mSelectionStartHandle->show();
   558 }
   952 }
   559 
   953 
   560 void HbSelectionControl::scrollStarted()
   954 void HbSelectionControl::scrollStarted()
   561 {
   955 {
   562     Q_D(HbSelectionControl);
   956     Q_D(HbSelectionControl);
   563 
   957 
   564     if (isVisible() && d->mEdit) {
   958     if (isVisible() && d->mEdit) {
   565         d->mPanInProgress = true;
   959         d->mScrollInProgress = true;
   566         // Reparent handle items to editor canvas on pan start
   960         // Reparent handle items to editor canvas on pan start
   567         d->reparentHandles(HbAbstractEditPrivate::d_ptr(d->mEdit)->canvas);
   961         d->reparentHandles(HbAbstractEditPrivate::d_ptr(d->mEdit)->canvas);
       
   962         d->mMagnifier->hideWithEffect();
       
   963         // Note: This call is not needed if it is guaranteed that this method
       
   964         // will be called before the scrolling started.
       
   965         updatePrimitives();
   568     }
   966     }
   569 }
   967 }
   570 
   968 
   571 void HbSelectionControl::scrollFinished()
   969 void HbSelectionControl::scrollFinished()
   572 {
   970 {
   573     Q_D(HbSelectionControl);
   971     Q_D(HbSelectionControl);
   574 
   972 
   575     if (isVisible() && d->mEdit) {
   973     if (isVisible() && d->mEdit) {
   576         d->mPanInProgress = false;
   974         d->mScrollInProgress = false;
   577         updatePrimitives();
   975         updatePrimitives();
   578     }
   976     }
   579 }
   977 }
   580 
   978 
   581 
   979 
   583 {
   981 {
   584     Q_D(HbSelectionControl);
   982     Q_D(HbSelectionControl);
   585 
   983 
   586     if (event->timerId() == d->mWordSnapTimer.timerId()) {
   984     if (event->timerId() == d->mWordSnapTimer.timerId()) {
   587         d->mWordSnapTimer.stop();
   985         d->mWordSnapTimer.stop();
       
   986     } else  if (event->timerId() == d->mDelayedTapTimer.timerId()) {
       
   987         d->mDelayedTapTimer.stop();
       
   988         d->delayedTapFinished();
   588     }
   989     }
   589 }
   990 }
   590 
   991 
   591 void HbSelectionControl::polish( HbStyleParameters& params )
   992 void HbSelectionControl::polish( HbStyleParameters& params )
   592 {
   993 {
   593     Q_D(HbSelectionControl);
   994     Q_D(HbSelectionControl);
   594 
   995 
   595     HbWidget::polish(params);
   996     if (isVisible()) {
   596     QSizeF size = d->mSelectionStartTouchArea->preferredSize();
   997 
   597     d->mSelectionStartTouchArea->resize(size);
   998         const QLatin1String KHandleMarginFromLine("handle-margin-from-line");
   598     d->mSelectionEndTouchArea->resize(size);
   999         const QLatin1String KMagnifierMarginFromLine("magnifier-margin-from-line");
   599     updatePrimitives();
  1000         const QLatin1String KMagnifierLeftRightMarginFromHandle("magnifier-left-right-margin-from-handle");
       
  1001         const QLatin1String KMagnifierMaxDescent("magnifier-max-descent");
       
  1002 
       
  1003         params.addParameter(KHandleMarginFromLine);
       
  1004         params.addParameter(KMagnifierMarginFromLine);
       
  1005         params.addParameter(KMagnifierLeftRightMarginFromHandle);
       
  1006         params.addParameter(KMagnifierMaxDescent);
       
  1007 
       
  1008         HbWidget::polish(params);
       
  1009 
       
  1010         // Set size of handles
       
  1011         QSizeF size = d->mSelectionStartHandle->preferredSize();
       
  1012         d->mSelectionStartHandle->setSize(size);
       
  1013         d->mSelectionEndHandle->setSize(size);
       
  1014 
       
  1015         // Set max y offset for hit test point
       
  1016         // TODO: consider setting this value from css
       
  1017         d->mMaxHitTestPointOffsetYFromLine = size.height();
       
  1018 
       
  1019         // Set size of touch areas
       
  1020         size = d->mSelectionEndTouchArea->preferredSize();
       
  1021         d->mSelectionEndTouchArea->resize(size);
       
  1022 
       
  1023 
       
  1024         // Increase the height of the touch area of the start selection handle
       
  1025         size.setHeight(size.height()*2-d->mSelectionStartHandle->size().height());
       
  1026         d->mSelectionStartTouchArea->resize(size);
       
  1027 
       
  1028 
       
  1029 
       
  1030         // Set size of magnifier
       
  1031         d->mMagnifier->resize(d->mMagnifier->preferredSize());
       
  1032 
       
  1033         if (params.value(KHandleMarginFromLine).isValid()) {
       
  1034             d->mHandleMarginFromLine = params.value(KHandleMarginFromLine).toReal();
       
  1035         }
       
  1036 
       
  1037         if (params.value(KMagnifierMarginFromLine).isValid()) {
       
  1038             d->mMagnifierMarginFromLine = params.value(KMagnifierMarginFromLine).toReal();
       
  1039         }
       
  1040         if (params.value(KMagnifierLeftRightMarginFromHandle).isValid()) {
       
  1041             d->mMagnifierLeftRightMarginFromHandle = params.value(KMagnifierLeftRightMarginFromHandle).toReal();
       
  1042         }
       
  1043 
       
  1044         if (params.value(KMagnifierMaxDescent).isValid()) {
       
  1045             d->mMagnifierMaxDescent = params.value(KMagnifierMaxDescent).toReal();
       
  1046         }
       
  1047 
       
  1048         // Set the min/max magnifier touch offsets
       
  1049         // TODO: consider setting this value from css
       
  1050         d->mMagnifierMaxYOffsetFromTouchPoint = d->mMagnifierMarginFromLine*2;
       
  1051         d->mMagnifierMinYOffsetFromTouchPoint = d->mMagnifierMarginFromLine/2;
       
  1052 
       
  1053         updatePrimitives();
       
  1054     } else {
       
  1055         HbWidget::polish(params);
       
  1056     }
   600 }
  1057 }
   601 
  1058 
   602 QVariant HbSelectionControl::itemChange(GraphicsItemChange change, const QVariant &value)
  1059 QVariant HbSelectionControl::itemChange(GraphicsItemChange change, const QVariant &value)
   603 {
  1060 {
   604     if (change == QGraphicsItem::ItemPositionChange) {
  1061     if (change == QGraphicsItem::ItemPositionChange) {
   608     return HbWidget::itemChange(change, value);
  1065     return HbWidget::itemChange(change, value);
   609 }
  1066 }
   610 
  1067 
   611 void HbSelectionControl::gestureEvent(QGestureEvent* event) {
  1068 void HbSelectionControl::gestureEvent(QGestureEvent* event) {
   612     Q_D(HbSelectionControl);
  1069     Q_D(HbSelectionControl);
       
  1070 
   613     if(HbTapGesture *tap = qobject_cast<HbTapGesture*>(event->gesture(Qt::TapGesture))) {
  1071     if(HbTapGesture *tap = qobject_cast<HbTapGesture*>(event->gesture(Qt::TapGesture))) {
   614         QPointF pos = event->mapToGraphicsScene(tap->position());
  1072         if (d->mEdit) {
       
  1073             // GestureFinshed is only delegated while the mDelayedTapTimer is active
       
  1074             if (tap->state() != Qt::GestureFinished || d->mDelayedTapTimer.isActive()) {
       
  1075                 HbAbstractEditPrivate::d_ptr(d->mEdit)->gestureEvent(event,this);
       
  1076             }
       
  1077         }
       
  1078 
   615         switch(tap->state()) {
  1079         switch(tap->state()) {
       
  1080 
   616         case Qt::GestureStarted:
  1081         case Qt::GestureStarted:
   617             if (d->mEdit) {
  1082             d->tapGestureStarted(tap);
   618                 HbWidgetFeedback::triggered(this, Hb::InstantPressed);
       
   619             }
       
   620             break;
  1083             break;
   621         case Qt::GestureUpdated:
  1084         case Qt::GestureCanceled:
       
  1085         case Qt::GestureFinished:
       
  1086             d->tapGestureFinished();
   622             break;
  1087             break;
   623       case Qt::GestureFinished:
  1088         default:
   624             if (d->mEdit) {
  1089               break;
   625                 d->tapGestureFinished(pos);
       
   626                 HbWidgetFeedback::triggered(this, Hb::InstantReleased);
       
   627             }
       
   628             break;
       
   629       case Qt::GestureCanceled:
       
   630             break;
       
   631       default:
       
   632             break;
       
   633         }
  1090         }
   634     }
  1091     }
   635 
  1092 
   636     if(HbPanGesture *pan = qobject_cast<HbPanGesture*>(event->gesture(Qt::PanGesture))) {
  1093     if(HbPanGesture *pan = qobject_cast<HbPanGesture*>(event->gesture(Qt::PanGesture))) {
   637         switch(pan->state()) {
  1094         switch(pan->state()) {
   650                 d->panGestureFinished(pan);
  1107                 d->panGestureFinished(pan);
   651                 HbWidgetFeedback::triggered(this, Hb::InstantReleased);
  1108                 HbWidgetFeedback::triggered(this, Hb::InstantReleased);
   652             }
  1109             }
   653             break;
  1110             break;
   654       case Qt::GestureCanceled:
  1111       case Qt::GestureCanceled:
       
  1112             if (d->mEdit) {
       
  1113                 d->panGestureCanceled();
       
  1114                 HbWidgetFeedback::triggered(d->mEdit, Hb::InstantReleased);
       
  1115             }
   655             break;
  1116             break;
   656       default:
  1117       default:
   657             break;
  1118             break;
   658         }
  1119         }
   659     }
  1120     }
   660 }
  1121 }
   661 
  1122 
       
  1123 bool HbSelectionControl::eventFilter(QObject * watched, QEvent *event)
       
  1124 {
       
  1125     Q_UNUSED(watched)
       
  1126 
       
  1127     // Filter gesture events and delegate to gestureEvent()
       
  1128     if (event->type() == QEvent::Gesture || event->type() == QEvent::GestureOverride) {
       
  1129         gestureEvent(static_cast<QGestureEvent*>(event));
       
  1130         return true;
       
  1131     }
       
  1132     return false;
       
  1133 }
       
  1134 
       
  1135 
   662 bool HbSelectionControl::event(QEvent *event)
  1136 bool HbSelectionControl::event(QEvent *event)
   663 {
  1137 {
   664     Q_D(HbSelectionControl);
  1138     Q_D(HbSelectionControl);
   665 
  1139 
   666     if (event->type() == HbEvent::DeviceProfileChanged && d->mEdit) {
  1140     if (event->type() == HbEvent::DeviceProfileChanged && d->mEdit) {
   667         HbDeviceProfileChangedEvent* dpEvent = static_cast<HbDeviceProfileChangedEvent*>(event);
  1141         HbDeviceProfileChangedEvent* dpEvent = static_cast<HbDeviceProfileChangedEvent*>(event);
   668         if ( dpEvent->profile().alternateProfileName() == dpEvent->oldProfile().name() ) {
  1142         if ( dpEvent->profile().alternateProfileName() == dpEvent->oldProfile().name() ) {
       
  1143             d->initMagnifier();
   669             updatePrimitives();
  1144             updatePrimitives();
   670         }
  1145         }
   671     }
  1146     }
   672     return HbWidget::event(event);
  1147     return HbWidget::event(event);
   673 }
  1148 }
   674 
  1149 
       
  1150 
       
  1151 void HbSelectionControl::setMagnifierEnabled(bool enable)
       
  1152 {
       
  1153     Q_D(HbSelectionControl);
       
  1154     d->mMagnifierEnabled = enable;
       
  1155 }
       
  1156 
       
  1157 bool HbSelectionControl::isMagnifierEnabled() const
       
  1158 {
       
  1159     Q_D(const HbSelectionControl);
       
  1160     return d->mMagnifierEnabled;
       
  1161 }
       
  1162 
       
  1163 void HbSelectionControl::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
       
  1164 {
       
  1165     Q_UNUSED(widget)
       
  1166     Q_UNUSED(option)    
       
  1167     Q_UNUSED(painter)
       
  1168 
       
  1169 #if HB_DEBUG_PAINT_INFO
       
  1170     Q_D(HbSelectionControl);
       
  1171     painter->save();
       
  1172 
       
  1173     // draw mHitTestPoint
       
  1174     painter->setPen(Qt::yellow);
       
  1175     painter->setBrush(Qt::yellow);
       
  1176     painter->drawEllipse(d->mHitTestPoint, 3,3);
       
  1177 
       
  1178     // draw mDocRectDebug
       
  1179     painter->setBrush(Qt::NoBrush);
       
  1180     painter->drawRect(d->mDocRectDebug);
       
  1181 
       
  1182     // draw line representing mMagnifierMaxYOffsetFromTouchPoint
       
  1183     painter->setPen(Qt::red);
       
  1184     qreal magnifierMaxYOffsetLine = d->mTouchPoint.y()-d->mMagnifierMaxYOffsetFromTouchPoint;
       
  1185     painter->drawLine(QPointF(0,magnifierMaxYOffsetLine),QPointF(500,magnifierMaxYOffsetLine));
       
  1186 
       
  1187     // draw line representing mMagnifierMinYOffsetFromTouchPoint
       
  1188     painter->setPen(Qt::green);
       
  1189     qreal magnifierMinYOffsetLine = d->mTouchPoint.y()-d->mMagnifierMinYOffsetFromTouchPoint;
       
  1190     painter->drawLine(QPointF(0,magnifierMinYOffsetLine),QPointF(500,magnifierMinYOffsetLine));
       
  1191 
       
  1192     // draw line representing magnifierStartYOffsetLine
       
  1193     painter->setPen(Qt::black);
       
  1194     qreal magnifierStartYOffsetLine = d->mStartHandleMagnifierReferenceLine - d->mMagnifierMarginFromLine;
       
  1195     painter->drawLine(QPointF(0,magnifierStartYOffsetLine),QPointF(500,magnifierStartYOffsetLine));
       
  1196 
       
  1197     // draw line representing magnifierStartYOffsetLine
       
  1198     painter->setPen(Qt::magenta);
       
  1199     qreal magnifierEndYOffsetLine = d->mEndHandleMagnifierReferenceLine - d->mMagnifierMarginFromLine;
       
  1200     painter->drawLine(QPointF(0,magnifierEndYOffsetLine),QPointF(500,magnifierEndYOffsetLine));
       
  1201 
       
  1202 
       
  1203     painter->drawRect(boundingRect());
       
  1204 
       
  1205     painter->restore();
       
  1206 #endif
       
  1207 
       
  1208 }
       
  1209 
       
  1210 
   675 void HbSelectionControl::updatePrimitives()
  1211 void HbSelectionControl::updatePrimitives()
   676 {
  1212 {
   677     Q_D(HbSelectionControl);
  1213     Q_D(HbSelectionControl);
   678 
  1214 
   679     if (isVisible() && d->polished && d->mEdit) {
  1215     if (isVisible() && d->polished && d->mEdit) {
   680         if (d->mEdit->textCursor().hasSelection() ) {
  1216 
   681            
  1217         const bool hasSelection = d->mEdit->textCursor().hasSelection();
   682             int selStartPos = qMin(d->mEdit->textCursor().anchor(),d->mEdit->textCursor().position());
  1218 
   683             int selEndPos = qMax(d->mEdit->textCursor().anchor(),d->mEdit->textCursor().position());
  1219         // The interaction mode can be change only when there is no pan in progress
   684 
  1220         if (!d->mIsPanActive) {
   685             d->updateHandle(selStartPos,Qt::AlignTop,d->mSelectionStartHandle,d->mSelectionStartTouchArea,HbStyle::P_SelectionControl_selectionstart);
  1221             d->mInteractionMode = (hasSelection?HbSelectionControlPrivate::Selection:
   686             d->updateHandle(selEndPos,Qt::AlignBottom,d->mSelectionEndHandle,d->mSelectionEndTouchArea,HbStyle::P_SelectionControl_selectionend);
  1222                                                 HbSelectionControlPrivate::CursorPositioning);
   687         }
  1223         }
   688         else {
  1224 
   689             hide();
  1225         const int cursorPos = d->mEdit->textCursor().position();
   690         }
  1226         int selStartPos = cursorPos;
       
  1227         int selEndPos = cursorPos;
       
  1228         d->mSelectionEndHandle->setIconName(QLatin1String("qtg_graf_editor_handle_finetune"));
       
  1229 
       
  1230         if (hasSelection) {
       
  1231             selStartPos = qMin(d->mEdit->textCursor().anchor(),cursorPos);
       
  1232             selEndPos = qMax(d->mEdit->textCursor().anchor(),cursorPos);
       
  1233             d->mSelectionEndHandle->setIconName(QLatin1String("qtg_graf_editor_handle_end"));
       
  1234         }
       
  1235 
       
  1236         d->updateHandle(cursorPos,selStartPos,Qt::AlignTop,d->mSelectionStartHandle,d->mSelectionStartTouchArea);
       
  1237         d->updateHandle(cursorPos,selEndPos,Qt::AlignBottom,d->mSelectionEndHandle,d->mSelectionEndTouchArea);
       
  1238         d->updateMagnifier();
   691     }
  1239     }
   692 }
  1240 }
   693 #include "moc_hbselectioncontrol_p.cpp"
  1241 #include "moc_hbselectioncontrol_p.cpp"
       
  1242