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