src/hbwidgets/editors/hbselectioncontrol_p.cpp
changeset 1 f7ac710697a9
parent 0 16d8024aca5e
child 2 06ff229162e9
equal deleted inserted replaced
0:16d8024aca5e 1:f7ac710697a9
    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 "hbtoucharea.h"
    43 #include "hbtoucharea.h"
       
    44 #include "hbpangesture.h"
       
    45 #include "hbtapgesture.h"
       
    46 #include "hbevent.h"
       
    47 #include "hbpopup.h"
       
    48 #include "hbnamespace_p.h"
       
    49 #include "hbmainwindow.h"
    44 
    50 
    45 
    51 
    46 #include <QTextCursor>
    52 #include <QTextCursor>
    47 #include <QGraphicsItem>
    53 #include <QGraphicsItem>
    48 #include <QAbstractTextDocumentLayout>
    54 #include <QAbstractTextDocumentLayout>
    49 #include <QGraphicsSceneMouseEvent>
    55 #include <QGraphicsSceneMouseEvent>
    50 #include <QBasicTimer>
    56 #include <QBasicTimer>
    51 #include <QSizeF>
    57 #include <QSizeF>
    52 #include <QPointF>
    58 #include <QPointF>
       
    59 #include <QHash>
       
    60 #include <QGraphicsScene>
    53 
    61 
    54 #include <hbwidgetfeedback.h>
    62 #include <hbwidgetfeedback.h>
       
    63 
       
    64 typedef QHash<HbMainWindow*,HbSelectionControl*> HbSelectionControlHash;
       
    65 Q_GLOBAL_STATIC(HbSelectionControlHash, globalSelectionControlHash)
    55 
    66 
    56 namespace {
    67 namespace {
    57     static const int SNAP_DELAY = 300;
    68     static const int SNAP_DELAY = 300;
    58 }
    69 }
    59 
    70 
    61 class HbSelectionControlPrivate :public HbDialogPrivate
    72 class HbSelectionControlPrivate :public HbDialogPrivate
    62 {
    73 {
    63     Q_DECLARE_PUBLIC(HbSelectionControl)
    74     Q_DECLARE_PUBLIC(HbSelectionControl)
    64 
    75 
    65 public:
    76 public:
    66     HbSelectionControlPrivate(HbAbstractEdit *edit);
    77     HbSelectionControlPrivate();
    67     void init();
    78     void init();
    68     void createPrimitives();
    79     void createPrimitives();
    69     void updateHandle(int newHandlePos,
    80     void updateHandle(int newHandlePos,
    70                       Qt::AlignmentFlag handleAlignment,
    81                       Qt::AlignmentFlag handleAlignment,
    71                       QGraphicsItem *handle,
    82                       QGraphicsItem *handle,
    72                       QGraphicsItem *handleTouchArea,
    83                       QGraphicsItem *handleTouchArea,
    73                       HbStyle::Primitive handlePrimitive);
    84                       HbStyle::Primitive handlePrimitive);
    74     QGraphicsItem * reparent(QGraphicsItem *item);
    85     QGraphicsItem * reparent(QGraphicsItem *item);
    75     void reparent(QGraphicsItem *item, QGraphicsItem *newParent);
    86     void reparent(QGraphicsItem *item, QGraphicsItem *newParent);
    76     void reparentHandles(QGraphicsItem *newParent);
    87     void reparentHandles(QGraphicsItem *newParent);
       
    88     void tapGestureFinished (const QPointF& point);
       
    89     void panGestureStarted (HbPanGesture *gesture);
       
    90     void panGestureUpdated (HbPanGesture *gesture);
       
    91     void panGestureFinished (HbPanGesture *gesture);
       
    92     void show();
       
    93     void _q_aboutToChangeView();
    77 
    94 
    78 public:
    95 public:
    79 
    96 
    80     HbAbstractEdit *mEdit;
    97     HbAbstractEdit *mEdit;
       
    98     QGraphicsItem *mTopLevelAncestor;
    81     QPointF mMouseOffset;
    99     QPointF mMouseOffset;
    82 
   100 
    83     QGraphicsItem *mSelectionStartHandle;
   101     QGraphicsItem *mSelectionStartHandle;
    84     QGraphicsItem *mSelectionEndHandle;
   102     QGraphicsItem *mSelectionEndHandle;
    85     HbTouchArea* mSelectionStartTouchArea;
   103     HbTouchArea* mSelectionStartTouchArea;
    86     HbTouchArea* mSelectionEndTouchArea;
   104     HbTouchArea* mSelectionEndTouchArea;
    87 
   105 
    88     HbSelectionControl::HandleType mPressed;
   106     HbSelectionControl::HandleType mPressed;
    89     bool mHandlesDisabled;
       
    90     bool mPanInProgress;
   107     bool mPanInProgress;
    91     bool mHandlesMoved;
       
    92     QBasicTimer mWordSnapTimer;
   108     QBasicTimer mWordSnapTimer;
    93 };
   109 };
    94 
   110 
    95 
   111 
    96 HbSelectionControlPrivate::HbSelectionControlPrivate(HbAbstractEdit *edit):
   112 HbSelectionControlPrivate::HbSelectionControlPrivate():
    97     mEdit(edit),
   113     mEdit(0),
       
   114     mTopLevelAncestor(0),
    98     mSelectionStartHandle(0),
   115     mSelectionStartHandle(0),
    99     mSelectionEndHandle(0),
   116     mSelectionEndHandle(0),
   100     mSelectionStartTouchArea(0),
   117     mSelectionStartTouchArea(0),
   101     mSelectionEndTouchArea(0),
   118     mSelectionEndTouchArea(0),
   102     mPressed(HbSelectionControl::HandleType(0)),
   119     mPressed(HbSelectionControl::HandleType(0)),
   103     mHandlesDisabled(true),
   120     mPanInProgress(false)
   104     mPanInProgress(false),
   121 {    
   105     mHandlesMoved(false)
       
   106 {
       
   107 }
   122 }
   108 
   123 
   109 void HbSelectionControlPrivate::init()
   124 void HbSelectionControlPrivate::init()
   110 {
   125 {
   111     Q_Q(HbSelectionControl);
   126     Q_Q(HbSelectionControl);
   112     createPrimitives();
   127     createPrimitives();
   113 
   128 
   114     q->setBackgroundItem(HbStyle::P_None);
   129     q->setVisible(false);
       
   130     q->setFlag(QGraphicsItem::ItemIsFocusable,false);
       
   131     q->setFlag(QGraphicsItem::ItemIsPanel,true);
   115     q->setFocusPolicy(Qt::NoFocus);
   132     q->setFocusPolicy(Qt::NoFocus);
   116     q->setTimeout(HbPopup::NoTimeout);
   133     q->setActive(false);
   117     q->setBackgroundFaded(false);
       
   118     q->setVisible(false);
       
   119     q->setDismissPolicy(HbPopup::NoDismiss);
       
   120     q->setModal(false);
       
   121 
       
   122     #ifdef HB_EFFECTS
       
   123     HbEffect::disable(q);
       
   124     #endif    
       
   125 
       
   126     q->setParent(mEdit);
       
   127 
   134 
   128     // Control will handle all events going to different handlers.
   135     // Control will handle all events going to different handlers.
   129     q->setHandlesChildEvents(true);
   136     q->setHandlesChildEvents(true);
   130 
       
   131     QObject::connect(mEdit, SIGNAL(cursorPositionChanged(int, int)), q, SLOT(updatePrimitives()));
       
   132     QObject::connect(mEdit, SIGNAL(selectionChanged(const QTextCursor&, const QTextCursor&)), q, SLOT(updatePrimitives()));
       
   133     QObject::connect(mEdit, SIGNAL(contentsChanged()), q, SLOT(updatePrimitives()));
       
   134 
       
   135     q->updatePrimitives();
       
   136 
       
   137 }
   137 }
   138 
   138 
   139 void HbSelectionControlPrivate::createPrimitives()
   139 void HbSelectionControlPrivate::createPrimitives()
   140 {
   140 {
   141     Q_Q(HbSelectionControl);
   141     Q_Q(HbSelectionControl);
   142     if (!mSelectionStartHandle) {
   142     if (!mSelectionStartHandle) {
   143         mSelectionStartHandle = mEdit->style()->createPrimitive(HbStyle::P_SelectionControl_selectionstart, q);
   143         mSelectionStartHandle = q->style()->createPrimitive(HbStyle::P_SelectionControl_selectionstart, q);
   144         mSelectionStartHandle->hide();
   144         mSelectionStartHandle->setFlag(QGraphicsItem::ItemIsPanel);
       
   145         mSelectionStartHandle->setFlag(QGraphicsItem::ItemIsFocusable,false);
       
   146         mSelectionStartHandle->setActive(false);
   145     }
   147     }
   146 
   148 
   147     if (!mSelectionEndHandle) {
   149     if (!mSelectionEndHandle) {
   148         mSelectionEndHandle = mEdit->style()->createPrimitive(HbStyle::P_SelectionControl_selectionend, q);
   150         mSelectionEndHandle = q->style()->createPrimitive(HbStyle::P_SelectionControl_selectionend, q);
   149         mSelectionEndHandle->hide();
   151         mSelectionEndHandle->setFlag(QGraphicsItem::ItemIsPanel);
       
   152         mSelectionEndHandle->setFlag(QGraphicsItem::ItemIsFocusable,false);
       
   153         mSelectionEndHandle->setActive(false);
   150     }
   154     }
   151 
   155 
   152     if (!mSelectionStartTouchArea) {
   156     if (!mSelectionStartTouchArea) {
   153         mSelectionStartTouchArea = new HbTouchArea(q);
   157         mSelectionStartTouchArea = new HbTouchArea(q);
   154         mSelectionStartTouchArea->hide();
   158         mSelectionStartTouchArea->setFlag(QGraphicsItem::ItemIsPanel);
       
   159         mSelectionStartTouchArea->setFlag(QGraphicsItem::ItemIsFocusable,false);
       
   160         mSelectionStartTouchArea->setActive(false);
   155         HbStyle::setItemName(mSelectionStartTouchArea, "handle-toucharea");
   161         HbStyle::setItemName(mSelectionStartTouchArea, "handle-toucharea");
   156 
   162         mSelectionStartTouchArea->grabGesture(Qt::TapGesture);
       
   163         mSelectionStartTouchArea->grabGesture(Qt::PanGesture);
   157     }
   164     }
   158 
   165 
   159     if (!mSelectionEndTouchArea) {
   166     if (!mSelectionEndTouchArea) {
   160         mSelectionEndTouchArea = new HbTouchArea(q);
   167         mSelectionEndTouchArea = new HbTouchArea(q);
   161         mSelectionEndTouchArea->hide();
   168         mSelectionEndTouchArea->setFlag(QGraphicsItem::ItemIsPanel);
       
   169         mSelectionEndTouchArea->setFlag(QGraphicsItem::ItemIsFocusable,false);
       
   170         mSelectionEndTouchArea->setActive(false);
   162         HbStyle::setItemName(mSelectionEndTouchArea, "handle-toucharea");
   171         HbStyle::setItemName(mSelectionEndTouchArea, "handle-toucharea");
       
   172         mSelectionEndTouchArea->grabGesture(Qt::TapGesture);
       
   173         mSelectionEndTouchArea->grabGesture(Qt::PanGesture);
   163     }
   174     }
   164 }
   175 }
   165 
   176 
   166 /*
   177 /*
   167    Updates given handle associated with handleTouchArea to place it
   178    Updates given handle associated with handleTouchArea to place it
   207 
   218 
   208     if (!mPanInProgress) {
   219     if (!mPanInProgress) {
   209         QGraphicsItem * newParent = reparent(handle);
   220         QGraphicsItem * newParent = reparent(handle);
   210         reparent(handleTouchArea, newParent);
   221         reparent(handleTouchArea, newParent);
   211     }
   222     }
   212 
       
   213     handle->show();
       
   214     handleTouchArea->show() ;
       
   215 }
   223 }
   216 
   224 
   217 
   225 
   218 
   226 
   219 /*
   227 /*
   220    Reparents item to q if item's bounding rect intersects mEdit bounding rectangle or otherwise to
   228    Reparents item to q if item's bounding rect intersects mEdit's viewPort rectangle or otherwise to
   221    HbAbstractEditPrivate::d_ptr(d->mEdit)->canvas.
   229    HbAbstractEditPrivate::d_ptr(d->mEdit)->canvas.
   222    Returns new parent.
   230    Returns new parent.
   223 */
   231 */
   224 QGraphicsItem * HbSelectionControlPrivate::reparent(QGraphicsItem *item)
   232 QGraphicsItem * HbSelectionControlPrivate::reparent(QGraphicsItem *item)
   225 {
   233 {
   229 
   237 
   230     // Convert bounding rect to mEdit's coordinate system
   238     // Convert bounding rect to mEdit's coordinate system
   231     QRectF rect = item->boundingRect();
   239     QRectF rect = item->boundingRect();
   232     rect = item->mapRectToItem(mEdit,rect);
   240     rect = item->mapRectToItem(mEdit,rect);
   233 
   241 
   234     if (mEdit->contains(rect.topLeft()) || mEdit->contains(rect.bottomRight())) {
   242     QRectF scrollAreaRect = HbAbstractEditPrivate::d_ptr(mEdit)->scrollArea->geometry();
       
   243 
       
   244     if (rect.intersects(scrollAreaRect)) {
   235         newParent = q;
   245         newParent = q;
   236     }
   246     }
   237 
   247 
   238     reparent(item, newParent);
   248     reparent(item, newParent);
   239     return newParent;
   249     return newParent;
   240 }
   250 }
   241 
   251 
   242 void HbSelectionControlPrivate::reparent(QGraphicsItem *item, QGraphicsItem *newParent)
   252 void HbSelectionControlPrivate::reparent(QGraphicsItem *item, QGraphicsItem *newParent)
   243 {
   253 {
       
   254     Q_Q(HbSelectionControl);
       
   255 
   244     if (item && newParent && newParent != item->parentItem()) {
   256     if (item && newParent && newParent != item->parentItem()) {
   245 
   257 
   246         // Reparent handle items to newParent
   258         // Reparent handle items to newParent
   247         QPointF pos = newParent->mapFromItem(item->parentItem(),item->pos());
   259         QPointF pos = newParent->mapFromItem(item->parentItem(),item->pos());
       
   260 
       
   261         // If the item is parented to other then q we have to
       
   262         // turn off the QGraphicsItem::ItemIsPanel flag because
       
   263         // otherwise the new parent loses its activeness.
       
   264         bool enablePanel = (newParent == q);
       
   265 
       
   266         item->setFlag(QGraphicsItem::ItemIsPanel,enablePanel);
   248 
   267 
   249         // TODO: This is a workaround for a Qt bug when reparenting from a clipping parent to a
   268         // TODO: This is a workaround for a Qt bug when reparenting from a clipping parent to a
   250         //       non-clipping parent
   269         //       non-clipping parent
   251         item->setParentItem(0);
   270         item->setParentItem(0);
   252         item->setParentItem(newParent);
   271         item->setParentItem(newParent);
   262     reparent(mSelectionEndHandle, newParent);
   281     reparent(mSelectionEndHandle, newParent);
   263     reparent(mSelectionEndTouchArea, newParent);
   282     reparent(mSelectionEndTouchArea, newParent);
   264 }
   283 }
   265 
   284 
   266 
   285 
   267 HbSelectionControl::HbSelectionControl(HbAbstractEdit *edit) :
   286 void HbSelectionControlPrivate::tapGestureFinished(const QPointF &pos)
   268     HbPopup(*new HbSelectionControlPrivate(edit),0)
   287 {
   269 
   288     if (mEdit->contextMenuFlags().testFlag(Hb::ShowTextContextMenuOnSelectionClicked)) {
   270 {
   289         mEdit->showContextMenu(pos);
   271     Q_D(HbSelectionControl);
   290     }
   272     d->q_ptr = this;
   291 }
   273     d->init();
   292 
   274     //TODO: selection control could be singleton per main window
   293 void HbSelectionControlPrivate::panGestureStarted(HbPanGesture *gesture)
   275     //      since only one selection control is used at a time
   294 {
   276 }
   295     Q_Q(HbSelectionControl);
   277 
   296 
   278 
   297     QPointF point = q->mapFromScene(gesture->sceneStartPos());
   279 void HbSelectionControl::updatePrimitives()
   298     mPressed = HbSelectionControl::DummyHandle;
   280 {
       
   281     Q_D(HbSelectionControl);
       
   282     if (!d->mHandlesDisabled && d->polished) {
       
   283         if (d->mEdit->textCursor().hasSelection() ||
       
   284             (!d->mEdit->textCursor().hasSelection() && (d->mPressed == SelectionStartHandle || d->mPressed == SelectionEndHandle))) {
       
   285 
       
   286             int selStartPos = qMin(d->mEdit->textCursor().anchor(),d->mEdit->textCursor().position());
       
   287             int selEndPos = qMax(d->mEdit->textCursor().anchor(),d->mEdit->textCursor().position());
       
   288 
       
   289             d->updateHandle(selStartPos,Qt::AlignTop,d->mSelectionStartHandle,d->mSelectionStartTouchArea,HbStyle::P_SelectionControl_selectionstart);
       
   290             d->updateHandle(selEndPos,Qt::AlignBottom,d->mSelectionEndHandle,d->mSelectionEndTouchArea,HbStyle::P_SelectionControl_selectionend);
       
   291         }
       
   292         else {
       
   293             d->mSelectionStartHandle->hide();
       
   294             d->mSelectionStartTouchArea->hide() ;
       
   295             d->mSelectionEndHandle->hide();
       
   296             d->mSelectionEndTouchArea->hide() ;
       
   297         }
       
   298     }
       
   299 }
       
   300 
       
   301 void HbSelectionControl::hideHandles()
       
   302 {
       
   303     Q_D(HbSelectionControl);
       
   304     if (!d->mHandlesDisabled) {
       
   305         d->mHandlesDisabled = true;
       
   306         hide();
       
   307         d->reparentHandles(this);
       
   308     }
       
   309 }
       
   310 
       
   311 void HbSelectionControl::showHandles()
       
   312 {
       
   313     Q_D(HbSelectionControl);
       
   314     if (d->mHandlesDisabled) {
       
   315         d->mHandlesDisabled = false;
       
   316         show();
       
   317     }
       
   318 }
       
   319 
       
   320 void HbSelectionControl::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
       
   321 {
       
   322     Q_D(HbSelectionControl);
       
   323 
       
   324     QPointF editPos = d->mEdit->mapFromScene(event->scenePos());
       
   325 
       
   326     QRectF handleRect = d->mSelectionStartHandle->boundingRect();
       
   327     handleRect.moveTopLeft(editPos + d->mMouseOffset);
       
   328 
       
   329     QPointF hitTestPos = handleRect.center();
       
   330 
       
   331     if (d->mPressed == SelectionStartHandle) {
       
   332         hitTestPos.setY(handleRect.bottom()+1);
       
   333     } else {
       
   334         hitTestPos.setY(handleRect.top()-1);
       
   335     }
       
   336 
       
   337     // Hit test for the center of current selection touch area
       
   338     int hitPos = HbAbstractEditPrivate::d_ptr(d->mEdit)->hitTest(hitTestPos,Qt::FuzzyHit);
       
   339     if (hitPos == -1) {
       
   340         return;
       
   341     }
       
   342 
       
   343     QTextCursor cursor = d->mEdit->textCursor();
       
   344 
       
   345     if (hitPos != cursor.position()) {
       
   346         d->mHandlesMoved = true;
       
   347     }
       
   348     cursor.setPosition(hitPos, QTextCursor::KeepAnchor);
       
   349     if (d->mHandlesMoved) {
       
   350         if (d->mEdit) {
       
   351             HbWidgetFeedback::triggered(d->mEdit, Hb::InstantDraggedOver);
       
   352         }
       
   353         // Restart timer every time when a selection handle moved
       
   354         d->mWordSnapTimer.start(SNAP_DELAY, this);
       
   355         d->mEdit->setTextCursor(cursor);
       
   356     }
       
   357 
       
   358     // Ensure that the hitPos is visible
       
   359     HbAbstractEditPrivate::d_ptr(d->mEdit)->ensurePositionVisible(hitPos);
       
   360     updatePrimitives();
       
   361 }
       
   362 
       
   363 void HbSelectionControl::mousePressEvent (QGraphicsSceneMouseEvent *event)
       
   364 {
       
   365     Q_D(HbSelectionControl);
       
   366 
       
   367     if (d->mEdit) {
       
   368         HbWidgetFeedback::triggered(d->mEdit, Hb::InstantPressed);
       
   369     }
       
   370 
       
   371     d->mPressed = DummyHandle;
       
   372 
   299 
   373     // Find out which handle is being moved
   300     // Find out which handle is being moved
   374     if (d->mSelectionStartTouchArea->contains(mapToItem(d->mSelectionStartTouchArea, event->pos()))) {
   301     if (mSelectionStartTouchArea->contains(q->mapToItem(mSelectionStartTouchArea, point))) {
   375         d->mPressed = SelectionStartHandle;
   302         mPressed = HbSelectionControl::SelectionStartHandle;
   376         d->mMouseOffset = d->mSelectionStartHandle->pos() - event->pos();
   303         mMouseOffset = mSelectionStartHandle->pos() - point;
   377     }
   304     }
   378     if (d->mSelectionEndTouchArea->contains(mapToItem(d->mSelectionEndTouchArea, event->pos()))) {
   305     if (mSelectionEndTouchArea->contains(q->mapToItem(mSelectionEndTouchArea, point))) {
   379         bool useArea = true;
   306         bool useArea = true;
   380         if(d->mPressed != DummyHandle) {
   307         if(mPressed != HbSelectionControl::DummyHandle) {
   381 
   308 
   382             // The press point was inside in both of the touch areas
   309             // The press point was inside in both of the touch areas
   383             // choose the touch area whose center is closer to the press point
   310             // choose the touch area whose center is closer to the press point
   384             QRectF rect = d->mSelectionStartTouchArea->boundingRect();
   311             QRectF rect = mSelectionStartTouchArea->boundingRect();
   385             rect.moveTopLeft(d->mSelectionStartTouchArea->pos());
   312             rect.moveTopLeft(mSelectionStartTouchArea->pos());
   386             QLineF  lineEventPosSelStartCenter(event->pos(),rect.center());
   313             QLineF  lineEventPosSelStartCenter(point,rect.center());
   387 
   314 
   388             rect = d->mSelectionEndTouchArea->boundingRect();
   315             rect = mSelectionEndTouchArea->boundingRect();
   389             rect.moveTopLeft(d->mSelectionEndTouchArea->pos());
   316             rect.moveTopLeft(mSelectionEndTouchArea->pos());
   390             QLineF  lineEventPosSelEndCenter(event->pos(),rect.center());
   317             QLineF  lineEventPosSelEndCenter(point,rect.center());
   391 
   318 
   392             if (lineEventPosSelStartCenter.length() < lineEventPosSelEndCenter.length()) {
   319             if (lineEventPosSelStartCenter.length() < lineEventPosSelEndCenter.length()) {
   393                 useArea = false;
   320                 useArea = false;
   394             }
   321             }
   395         }
   322         }
   396         if (useArea) {
   323         if (useArea) {
   397             d->mPressed = SelectionEndHandle;
   324             mPressed = HbSelectionControl::SelectionEndHandle;
   398             d->mMouseOffset = d->mSelectionEndHandle->pos() - event->pos();
   325             mMouseOffset = mSelectionEndHandle->pos() - point;
   399         }
   326         }
   400     }
   327     }
   401 
   328 
   402     if (d->mPressed == DummyHandle) {
   329     if (mPressed == HbSelectionControl::DummyHandle) {
   403         // Hit is outside touch areas, ignore
   330         // Hit is outside touch areas, ignore
   404         event->ignore();
       
   405         return;
   331         return;
   406     }
   332     }
   407 
   333 
   408     // Position cursor at the pressed selection handle
   334     // Position cursor at the pressed selection handle
   409 
   335 
   410     QTextCursor cursor = d->mEdit->textCursor();
   336     QTextCursor cursor = mEdit->textCursor();
   411     int selStartPos = qMin(d->mEdit->textCursor().anchor(),d->mEdit->textCursor().position());
   337     int selStartPos = qMin(mEdit->textCursor().anchor(),mEdit->textCursor().position());
   412     int selEndPos = qMax(d->mEdit->textCursor().anchor(),d->mEdit->textCursor().position());
   338     int selEndPos = qMax(mEdit->textCursor().anchor(),mEdit->textCursor().position());
   413 
   339 
   414     if (d->mPressed == SelectionStartHandle) {
   340     if (mPressed == HbSelectionControl::SelectionStartHandle) {
   415         cursor.setPosition(selEndPos);
   341         cursor.setPosition(selEndPos);
   416         cursor.setPosition(selStartPos, QTextCursor::KeepAnchor);
   342         cursor.setPosition(selStartPos, QTextCursor::KeepAnchor);
   417     } else {
   343     } else {
   418         cursor.setPosition(selStartPos);
   344         cursor.setPosition(selStartPos);
   419         cursor.setPosition(selEndPos, QTextCursor::KeepAnchor);
   345         cursor.setPosition(selEndPos, QTextCursor::KeepAnchor);
   420     }
   346     }
   421     d->mEdit->setTextCursor(cursor);
   347     mEdit->setTextCursor(cursor);
   422 
   348 
   423 }
   349 }
   424 
   350 
   425 void HbSelectionControl::mouseReleaseEvent (QGraphicsSceneMouseEvent *event)
   351 
   426 {
   352 void HbSelectionControlPrivate::panGestureFinished(HbPanGesture *gesture)
   427     Q_D(HbSelectionControl);
   353 {
   428     Q_UNUSED(event);
   354     Q_Q(HbSelectionControl);
   429 
   355     Q_UNUSED(gesture)
   430     if (d->mEdit) {
   356 
   431         HbWidgetFeedback::triggered(d->mEdit, Hb::InstantReleased);
   357     if (mWordSnapTimer.isActive()) {
   432     }
       
   433 
       
   434     if (d->mWordSnapTimer.isActive()) {
       
   435 
   358 
   436         // Snap selection to word beginning or end
   359         // Snap selection to word beginning or end
   437         QTextCursor cursor = d->mEdit->textCursor();
   360         QTextCursor cursor = mEdit->textCursor();
   438         int curPos = d->mEdit->textCursor().position();
   361         int curPos = mEdit->textCursor().position();
   439         int anchPos = d->mEdit->textCursor().anchor();
   362         int anchPos = mEdit->textCursor().anchor();
   440         cursor.select(QTextCursor::WordUnderCursor);
   363         cursor.select(QTextCursor::WordUnderCursor);
   441 
   364 
   442         // Snap direction depends on cursor position
   365         // Snap direction depends on cursor position
   443         curPos = ((curPos > anchPos)?cursor.position():cursor.anchor());
   366         curPos = ((curPos > anchPos)?cursor.position():cursor.anchor());
   444 
   367 
   445         cursor.setPosition(anchPos);
   368         cursor.setPosition(anchPos);
   446         cursor.setPosition(curPos, QTextCursor::KeepAnchor);
   369         cursor.setPosition(curPos, QTextCursor::KeepAnchor);
   447         d->mEdit->setTextCursor(cursor);
   370         mEdit->setTextCursor(cursor);
   448     }
   371     }
   449 
   372 
   450     d->mPressed = DummyHandle;
   373     mPressed = HbSelectionControl::DummyHandle;
   451     updatePrimitives();
   374     q->updatePrimitives();
   452 
   375 }
   453     if (!d->mHandlesMoved) {
   376 
   454         if (d->mEdit->contextMenuFlags().testFlag(Hb::ShowTextContextMenuOnSelectionClicked)) {
   377 
   455             d->mEdit->showContextMenu(event->scenePos());
   378 void HbSelectionControlPrivate::panGestureUpdated(HbPanGesture *gesture)
   456         }
   379 {
   457     }
   380     Q_Q(HbSelectionControl);
   458     d->mHandlesMoved = false;
   381 
   459 }
   382     QPointF editPos = mEdit->mapFromScene(gesture->sceneStartPos() + gesture->sceneOffset());
   460 
   383 
   461 void HbSelectionControl::panStarted()
   384     QRectF handleRect = mSelectionStartHandle->boundingRect();
   462 {
   385     handleRect.moveTopLeft(editPos + mMouseOffset);
   463     Q_D(HbSelectionControl);
   386 
   464 
   387     QPointF hitTestPos = handleRect.center();
   465     if (!d->mHandlesDisabled) {
   388 
       
   389     if (mPressed == HbSelectionControl::SelectionStartHandle) {
       
   390         hitTestPos.setY(handleRect.bottom()+1);
       
   391     } else {
       
   392         hitTestPos.setY(handleRect.top()-1);
       
   393     }
       
   394 
       
   395     QTextCursor cursor = mEdit->textCursor();
       
   396     // Hit test for the center of current selection touch area
       
   397     int hitPos = HbAbstractEditPrivate::d_ptr(mEdit)->hitTest(hitTestPos,Qt::FuzzyHit);
       
   398     if (hitPos == -1 || hitPos == cursor.anchor()) {
       
   399         return;
       
   400     }
       
   401 
       
   402 
       
   403     bool handlesMoved(false);
       
   404     if (hitPos != cursor.position()) {
       
   405         handlesMoved = true;
       
   406     }
       
   407     cursor.setPosition(hitPos, QTextCursor::KeepAnchor);
       
   408     if (handlesMoved) {
       
   409         if (mEdit) {
       
   410             HbWidgetFeedback::triggered(mEdit, Hb::InstantDraggedOver);
       
   411         }
       
   412         // Restart timer every time when a selection handle moved
       
   413         mWordSnapTimer.start(SNAP_DELAY, q);
       
   414         mEdit->setTextCursor(cursor);
       
   415     }
       
   416 
       
   417     // Ensure that the hitPos is visible
       
   418     HbAbstractEditPrivate::d_ptr(mEdit)->ensurePositionVisible(hitPos);
       
   419     q->updatePrimitives();
       
   420 }
       
   421 
       
   422 void HbSelectionControlPrivate::show() {
       
   423     Q_Q(HbSelectionControl);
       
   424 
       
   425     // Set the z-value of the selection control above its top-level ancestor
       
   426     if (mTopLevelAncestor) {
       
   427         qreal zValue = mTopLevelAncestor->zValue() + HbPrivate::SelectionControlHandlesValueUnit;
       
   428 
       
   429         q->setZValue(zValue);
       
   430     }
       
   431 
       
   432     if (q->scene() != mEdit->scene() && mEdit->scene()) {
       
   433         mEdit->scene()->addItem(q);
       
   434     }
       
   435     q->show();    
       
   436     q->updatePrimitives();
       
   437 }
       
   438 
       
   439 
       
   440 void HbSelectionControlPrivate::_q_aboutToChangeView()
       
   441 {
       
   442     Q_Q(HbSelectionControl);
       
   443 
       
   444     if (mEdit && q->isVisible()) {
       
   445         mEdit->deselect();
       
   446     }
       
   447 }
       
   448 
       
   449 
       
   450 HbSelectionControl::HbSelectionControl() : HbWidget(*new HbSelectionControlPrivate(),0)
       
   451 
       
   452 {
       
   453     Q_D(HbSelectionControl);
       
   454     d->q_ptr = this;
       
   455     d->init();
       
   456     //TODO: selection control could be singleton per main window
       
   457     //      since only one selection control is used at a time
       
   458 }
       
   459 
       
   460 HbSelectionControl* HbSelectionControl::attachEditor(HbAbstractEdit *edit)
       
   461 {
       
   462     if(!edit || !edit->mainWindow()) {
       
   463         qWarning("HbSelectionControl: attempting to attach to null editor pointer!");
       
   464     }
       
   465 
       
   466     HbSelectionControl *control = globalSelectionControlHash()->value(edit->mainWindow());
       
   467 
       
   468     if (!control) {
       
   469         control = new HbSelectionControl();
       
   470         globalSelectionControlHash()->insert(edit->mainWindow(),control);
       
   471         QObject::connect(edit->mainWindow(), SIGNAL(aboutToChangeView(HbView *, HbView *)), control, SLOT(_q_aboutToChangeView()));
       
   472     }
       
   473 
       
   474     HbSelectionControlPrivate *d = control->d_func();
       
   475 
       
   476     if (edit != d->mEdit) {
       
   477         control->detachEditor();
       
   478         d->mEdit = edit;        
       
   479         QObject::connect(d->mEdit, SIGNAL(cursorPositionChanged(int, int)), control, SLOT(updatePrimitives()));
       
   480         QObject::connect(d->mEdit, SIGNAL(contentsChanged()), control, SLOT(updatePrimitives()));
       
   481 
       
   482         // find first top-level ancestor of d->mEdit
       
   483         for(d->mTopLevelAncestor = d->mEdit;
       
   484             d->mTopLevelAncestor->parentItem();
       
   485             d->mTopLevelAncestor = d->mTopLevelAncestor->parentItem()){};
       
   486     }
       
   487     return control;
       
   488 }
       
   489 
       
   490 void HbSelectionControl::detachEditor()
       
   491 {
       
   492     Q_D(HbSelectionControl);
       
   493     if (d->mEdit) {
       
   494         hideHandles();
       
   495         d->reparentHandles(this);
       
   496         d->mEdit->disconnect(this);
       
   497         d->mEdit->d_func()->selectionControl = 0;        
       
   498         d->mEdit->deselect();
       
   499         d->mEdit = 0;
       
   500         d->mTopLevelAncestor = 0;
       
   501     }
       
   502 }
       
   503 
       
   504 
       
   505 void HbSelectionControl::hideHandles()
       
   506 {
       
   507     Q_D(HbSelectionControl);
       
   508     if (isVisible() && d->mEdit) {
       
   509         hide();
       
   510         d->reparentHandles(this);
       
   511     }
       
   512 }
       
   513 
       
   514 void HbSelectionControl::showHandles()
       
   515 {
       
   516     Q_D(HbSelectionControl);
       
   517     if (!isVisible() && d->mEdit) {
       
   518         d->show();
       
   519     }
       
   520 }
       
   521 
       
   522 void HbSelectionControl::scrollStarted()
       
   523 {
       
   524     Q_D(HbSelectionControl);
       
   525 
       
   526     if (isVisible() && d->mEdit) {
   466         d->mPanInProgress = true;
   527         d->mPanInProgress = true;
   467         // Reparent handle items to editor canvas on pan start
   528         // Reparent handle items to editor canvas on pan start
   468         d->reparentHandles(HbAbstractEditPrivate::d_ptr(d->mEdit)->canvas);
   529         d->reparentHandles(HbAbstractEditPrivate::d_ptr(d->mEdit)->canvas);
   469     }
   530     }
   470 }
   531 }
   471 
   532 
   472 void HbSelectionControl::panFinished()
   533 void HbSelectionControl::scrollFinished()
   473 {
   534 {
   474     Q_D(HbSelectionControl);
   535     Q_D(HbSelectionControl);
   475 
   536 
   476     if (!d->mHandlesDisabled) {
   537     if (isVisible() && d->mEdit) {
   477         d->mPanInProgress = false;
   538         d->mPanInProgress = false;
   478         updatePrimitives();
   539         updatePrimitives();
   479     }
   540     }
   480 }
   541 }
   481 
   542 
   491 
   552 
   492 void HbSelectionControl::polish( HbStyleParameters& params )
   553 void HbSelectionControl::polish( HbStyleParameters& params )
   493 {
   554 {
   494     Q_D(HbSelectionControl);
   555     Q_D(HbSelectionControl);
   495 
   556 
   496     HbPopup::polish(params);
   557     HbWidget::polish(params);
   497     QSizeF size = d->mSelectionStartTouchArea->preferredSize();
   558     QSizeF size = d->mSelectionStartTouchArea->preferredSize();
   498     d->mSelectionStartTouchArea->resize(size);
   559     d->mSelectionStartTouchArea->resize(size);
   499     d->mSelectionEndTouchArea->resize(size);
   560     d->mSelectionEndTouchArea->resize(size);
       
   561     updatePrimitives();
   500 }
   562 }
   501 
   563 
   502 QVariant HbSelectionControl::itemChange(GraphicsItemChange change, const QVariant &value)
   564 QVariant HbSelectionControl::itemChange(GraphicsItemChange change, const QVariant &value)
   503 {
   565 {
   504     if (change == QGraphicsItem::ItemPositionChange) {
   566     if (change == QGraphicsItem::ItemPositionChange) {
   505         return qVariantFromValue(QPointF(0,0));
   567         return qVariantFromValue(QPointF(0,0));
   506     } else if (change == QGraphicsItem::ItemVisibleChange) {        
   568     }
   507         updatePrimitives();
   569 
   508     }
   570     return HbWidget::itemChange(change, value);
   509 
   571 }
   510     return HbPopup::itemChange(change, value);
   572 
   511 }
   573 void HbSelectionControl::gestureEvent(QGestureEvent* event) {
       
   574     Q_D(HbSelectionControl);
       
   575     if(HbTapGesture *tap = qobject_cast<HbTapGesture*>(event->gesture(Qt::TapGesture))) {
       
   576         QPointF pos = event->mapToGraphicsScene(tap->position());
       
   577         switch(tap->state()) {
       
   578         case Qt::GestureStarted:
       
   579             if (d->mEdit) {
       
   580                 HbWidgetFeedback::triggered(d->mEdit, Hb::InstantPressed);
       
   581             }
       
   582             break;
       
   583         case Qt::GestureUpdated:
       
   584             break;
       
   585       case Qt::GestureFinished:
       
   586             if (d->mEdit) {
       
   587                 d->tapGestureFinished(pos);
       
   588                 HbWidgetFeedback::triggered(d->mEdit, Hb::InstantReleased);
       
   589             }
       
   590             break;
       
   591       case Qt::GestureCanceled:
       
   592             break;
       
   593       default:
       
   594             break;
       
   595         }
       
   596     }
       
   597 
       
   598     if(HbPanGesture *pan = qobject_cast<HbPanGesture*>(event->gesture(Qt::PanGesture))) {
       
   599         switch(pan->state()) {
       
   600         case Qt::GestureStarted:
       
   601             if (d->mEdit) {
       
   602                 d->panGestureStarted(pan);
       
   603             }
       
   604             break;
       
   605         case Qt::GestureUpdated:
       
   606             if (d->mEdit) {
       
   607                 d->panGestureUpdated(pan);
       
   608             }
       
   609             break;
       
   610         case Qt::GestureFinished:
       
   611             if (d->mEdit) {
       
   612                 d->panGestureFinished(pan);
       
   613                 HbWidgetFeedback::triggered(d->mEdit, Hb::InstantReleased);
       
   614             }
       
   615             break;
       
   616       case Qt::GestureCanceled:
       
   617             break;
       
   618       default:
       
   619             break;
       
   620         }
       
   621     }
       
   622 }
       
   623 
       
   624 bool HbSelectionControl::event(QEvent *event)
       
   625 {
       
   626     Q_D(HbSelectionControl);
       
   627 
       
   628     if (event->type() == HbEvent::DeviceProfileChanged && d->mEdit) {
       
   629         HbDeviceProfileChangedEvent* dpEvent = static_cast<HbDeviceProfileChangedEvent*>(event);
       
   630         if ( dpEvent->profile().alternateProfileName() == dpEvent->oldProfile().name() ) {
       
   631             updatePrimitives();
       
   632         }
       
   633     }
       
   634     return HbWidget::event(event);
       
   635 }
       
   636 
       
   637 void HbSelectionControl::updatePrimitives()
       
   638 {
       
   639     Q_D(HbSelectionControl);
       
   640 
       
   641     if (isVisible() && d->polished && d->mEdit) {
       
   642         if (d->mEdit->textCursor().hasSelection() ) {
       
   643            
       
   644             int selStartPos = qMin(d->mEdit->textCursor().anchor(),d->mEdit->textCursor().position());
       
   645             int selEndPos = qMax(d->mEdit->textCursor().anchor(),d->mEdit->textCursor().position());
       
   646 
       
   647             d->updateHandle(selStartPos,Qt::AlignTop,d->mSelectionStartHandle,d->mSelectionStartTouchArea,HbStyle::P_SelectionControl_selectionstart);
       
   648             d->updateHandle(selEndPos,Qt::AlignBottom,d->mSelectionEndHandle,d->mSelectionEndTouchArea,HbStyle::P_SelectionControl_selectionend);
       
   649         }
       
   650         else {
       
   651             hide();
       
   652         }
       
   653     }
       
   654 }
       
   655 #include "moc_hbselectioncontrol_p.cpp"