--- a/src/hbwidgets/editors/hbabstractedit.cpp Mon Apr 19 14:02:13 2010 +0300
+++ b/src/hbwidgets/editors/hbabstractedit.cpp Mon May 03 12:48:33 2010 +0300
@@ -32,20 +32,23 @@
#include "hbwidget.h"
#include "hbscrollarea.h"
#include "hbevent.h"
-#include <hbwidgetfeedback.h>
+#include "hbwidgetfeedback.h"
#include "hbmenu.h"
#include "hbaction.h"
#include "hbselectioncontrol_p.h"
#include "hbmeshlayout_p.h"
-#include "hbsmileyengine.h"
+#include "hbsmileyengine_p.h"
#include "hbinputeditorinterface.h"
+#include "hbfeaturemanager_p.h"
+#include "hbtextmeasurementutility_p.h"
+#include "hbtapgesture.h"
+#include "hbpangesture.h"
#include <QApplication>
#include "hbpopup.h"
#include "hbformatdialog.h"
#include <QTextList>
#include <QFontMetrics>
-#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QTextBlock>
#include <QAbstractTextDocumentLayout>
@@ -171,6 +174,10 @@
*/
HbAbstractEdit::~HbAbstractEdit()
{
+ Q_D(HbAbstractEdit);
+ if (d->selectionControl) {
+ d->selectionControl->detachEditor();
+ }
}
/*!
@@ -213,30 +220,6 @@
return HbWidget::event(event);
}
-/*!
- \reimp
-*/
-bool HbAbstractEdit::eventFilter(QObject *obj, QEvent *e)
-{
- Q_D(HbAbstractEdit);
-
- if (obj == d->scrollArea
- && (e->type() == QEvent::GraphicsSceneMousePress
- || e->type() == QEvent::GraphicsSceneMouseMove
- || e->type() == QEvent::GraphicsSceneMouseRelease)) {
-
- // map e->pos to the editor's coordinate system
- QGraphicsSceneMouseEvent *event = static_cast<QGraphicsSceneMouseEvent*>(e);
- QPointF oldPos = event->pos();
- event->setPos(mapFromItem(d->scrollArea,oldPos));
- bool ret = sceneEvent(e);
- event->setPos(oldPos);
- return ret;
- }
-
- return false;
-}
-
QVariant HbAbstractEdit::inputMethodQuery (Qt::InputMethodQuery query) const
{
Q_D(const HbAbstractEdit);
@@ -479,106 +462,13 @@
/*!
\reimp
*/
-void HbAbstractEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
-{
- Q_D(HbAbstractEdit);
-
- if (d->selectionControl) {
- d->selectionControl->panStarted();
- }
-
- if (d->interactionFlags & Qt::NoTextInteraction)
- return;
-
- if (!(event->button() & Qt::LeftButton))
- return;
-
- if (!((d->interactionFlags & Qt::TextSelectableByMouse) || (d->interactionFlags & Qt::TextEditable)))
- return;
-
- d->mousePressPos = event->pos();
- d->wasGesture = false;
-
- HbWidgetFeedback::triggered(this, Hb::InstantPressed);
-
-// d->minimizeInputPanel();
-
- event->accept();
-}
-
-/*!
- \reimp
-*/
-void HbAbstractEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
-{
- Q_UNUSED(event)
-}
-
-/*!
- \reimp
-*/
-void HbAbstractEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+void HbAbstractEdit::focusInEvent(QFocusEvent *event)
{
Q_D(HbAbstractEdit);
- if (d->selectionControl) {
- d->selectionControl->panFinished();
- }
- if (d->wasGesture) return;
-
- if (d->interactionFlags & Qt::NoTextInteraction)
- return;
-
- if (d->mousePressPos != Hb_Invalid_Position) {
- d->mousePressPos = Hb_Invalid_Position;
-
- bool removeSelection = (d->hitTest(event->pos(), Qt::ExactHit) == -1);
-
- if (removeSelection && d->cursor.hasSelection()) {
- const QTextCursor oldCursor = d->cursor;
- d->cursor.clearSelection();
- d->repaintOldAndNewSelection(oldCursor);
- emit selectionChanged(oldCursor, d->cursor);
- }
-
- int newCursorPos = d->hitTest(event->pos(), Qt::FuzzyHit);
-
- if (d->cursor.hasSelection() &&
- newCursorPos >= d->cursor.selectionStart() &&
- newCursorPos <= d->cursor.selectionEnd()){
- // we have a selection under mouse click
- if (d->contextMenuShownOn.testFlag(Hb::ShowTextContextMenuOnSelectionClicked)) {
- showContextMenu(mapToScene(event->pos()));
- }
- } else {
-
- // Currently focused widget to listen to InputContext before updating the cursor position
- d->sendMouseEventToInputContext(event);
- setCursorPosition(newCursorPos);
-
- HbWidgetFeedback::triggered(this, Hb::InstantReleased);
-
- if (d->interactionFlags & Qt::TextEditable) {
- d->updateCurrentCharFormat();
- }
- d->cursorChanged(HbValidator::CursorChangeFromMouse);
- }
- }
-
- d->openInputPanel();
-
- event->accept();
-}
-
-
-/*!
- \reimp
-*/
-void HbAbstractEdit::focusInEvent(QFocusEvent *event)
-{
HbWidget::focusInEvent(event);
- Q_D(HbAbstractEdit);
+ d->selectionControl = HbSelectionControl::attachEditor(this);
if (d->interactionFlags & Qt::NoTextInteraction)
return;
@@ -591,7 +481,7 @@
d->cursorOn = (d->interactionFlags & Qt::TextSelectableByKeyboard);
}
- d->openInputPanel();
+ d->openInputPanel();
event->accept();
}
@@ -624,7 +514,7 @@
switch (event->type()) {
case QEvent::FontChange: {
- d->doc->setDefaultFont(font());
+ d->updatePlaceholderDocProperties();
updateGeometry();
break;
}
@@ -635,6 +525,7 @@
if (d->selectionControl) {
d->selectionControl->updatePrimitives();
}
+ d->updatePlaceholderDocProperties();
break;
}
default: {
@@ -655,19 +546,14 @@
*/
void HbAbstractEdit::hideEvent(QHideEvent *event)
{
+ Q_D(HbAbstractEdit);
HbWidget::hideEvent(event);
deselect();
-#if QT_VERSION >= 0x040600
- // Send close input panel event.
- QInputContext *ic = qApp->inputContext();
- if (ic && !panel()) {
- QEvent *closeEvent = new QEvent(QEvent::CloseSoftwareInputPanel);
- ic->filterEvent(closeEvent);
- delete closeEvent;
+ if(hasFocus() && !isReadOnly() && !panel()) {
+ d->closeInputPanel();
}
-#endif
}
@@ -769,6 +655,10 @@
}
/*!
+
+ \deprecated HbAbstractEdit::primitive(HbStyle::Primitive)
+ is deprecated.
+
Returns pointer to a \a primitive of HbAbstractEdit.
Available primitive is HbStyle::P_Edit_text.
@@ -797,16 +687,22 @@
if (d->scrollArea) {
d->doc->setTextWidth(d->scrollArea->size().width());
+ if(d->placeholderDoc) {
+ d->placeholderDoc->setTextWidth(d->scrollArea->size().width());
+ }
}
QRectF canvasGeom(QRectF(QPointF(0,0),d->doc->size()));
- if(d->scrollArea && canvasGeom.height()<d->scrollArea->size().height()) {
- canvasGeom.setHeight(d->scrollArea->size().height());
+ if(d->scrollArea) {
+ canvasGeom.setHeight(qMax(d->scrollArea->size().height(), d->doc->size().height()));
}
- d->canvas->setGeometry(canvasGeom);
- if (d->scrollArea) {
- d->scrollArea->updateScrollMetrics();
+ //Changed from setGeometry() to setPreferredSize() because it causes
+ //weird input behavior otherwise.
+ d->canvas->setPreferredSize(canvasGeom.size());
+ d->ensureCursorVisible();
+ if (d->selectionControl) {
+ d->selectionControl->updatePrimitives();
}
- d->ensureCursorVisible();
+
}
/*!
@@ -1017,7 +913,7 @@
{
Q_D(HbAbstractEdit);
- int cursorPos = d->hitTest(d->mousePressPos, Qt::FuzzyHit);
+ int cursorPos = d->hitTest(d->tapPosition, Qt::FuzzyHit);
if (cursorPos == -1)
return;
@@ -1308,12 +1204,38 @@
painter->setOpacity(1.0);
#endif
+ QRectF viewRect = d->viewPortRect();
+ QRectF intersected = option.exposedRect.intersected(mapRectToItem(d->canvas, viewRect));
+
+
QAbstractTextDocumentLayout::PaintContext ctx = d->getPaintContext();
- if (option.exposedRect.isValid())
- painter->setClipRect(option.exposedRect, Qt::IntersectClip);
- ctx.clip = option.exposedRect;
+ // Save painter state that will be modified
+ QRegion clipRegion = painter->clipRegion();
+
+ if (option.exposedRect.isValid()){
+ painter->setClipRect(intersected, Qt::IntersectClip);
+ }
+ ctx.clip = intersected;
d->drawContentBackground(painter, option);
+
+ if(document()->isEmpty() && d->placeholderDoc && !d->placeholderDoc->isEmpty()) {
+ QTextBlock block = d->cursor.block();
+ QTextLayout *layout = block.layout();
+
+ if(!layout->preeditAreaText().length()) {
+ QColor textColor(ctx.palette.color(QPalette::Text));
+ QColor hintText(ctx.palette.color(QPalette::NoRole));
+ int cursorPos = ctx.cursorPosition;
+ ctx.cursorPosition = -1;
+ ctx.palette.setColor(QPalette::Text, hintText);
+
+ d->placeholderDoc->documentLayout()->draw(painter, ctx);
+
+ ctx.palette.setColor(QPalette::Text, textColor);
+ ctx.cursorPosition = cursorPos;
+ }
+ }
document()->documentLayout()->draw(painter, ctx);
// Draw the pins for the selection handle
d->drawSelectionEdges(painter, ctx);
@@ -1329,6 +1251,8 @@
painter->setPen(Qt::red);
painter->drawRect(d->cursorRect());
#endif
+ // Restore state
+ painter->setClipRegion(clipRegion);
}
/*!
@@ -1367,15 +1291,17 @@
menu->setAttribute(Hb::InputMethodNeutral);
- if (d->cursor.hasSelection() && d->canCopy()) {
+ if (d->cursor.hasSelection() && d->canCut()) {
connect(
menu->addAction("Cut"), SIGNAL(triggered()),
- this, SLOT(cut()));
+ this, SLOT(cut()));
+ }
+ if (d->cursor.hasSelection() && d->canCopy()) {
connect(
menu->addAction("Copy"), SIGNAL(triggered()),
this, SLOT(copy()));
}
- else if (!d->doc->isEmpty() && d->canCopy()){
+ if (!d->cursor.hasSelection() && !d->doc->isEmpty() && d->canCopy()){
connect(
menu->addAction("Select"), SIGNAL(triggered()),
this, SLOT(selectClickedWord()));
@@ -1399,7 +1325,7 @@
this, SLOT(format()));
}
- emit aboutToShowContextMenu(menu, d->mousePressPos);
+ emit aboutToShowContextMenu(menu, d->tapPosition);
d->minimizeInputPanel();
@@ -1437,34 +1363,40 @@
d->updateEditingSize();
HbWidget::updateGeometry();
}
+
/*!
- Sets text alignment to \a alignment to the current text cursor.
+ Sets text default alignment to \a alignment.
+
+ \note This has impact only on those paragraphs (text blocks) for which
+ alignment was not set. This sets only a default value.
- \sa alignment textCursor setTextCursor
+ If Qt::AlingAbsolute flag is not used then layoutDirection is
+ taken into account.
+
+ \sa alignment
*/
void HbAbstractEdit::setAlignment(Qt::Alignment alignment)
{
Q_D(HbAbstractEdit);
d->acceptSignalContentsChanged = false; // no text content changes.
- QTextBlockFormat fmt;
- fmt.setAlignment(alignment);
- QTextCursor cursor = d->cursor;
- cursor.mergeBlockFormat(fmt);
+ QTextOption option = document()->defaultTextOption();
+ option.setAlignment(alignment);
+ document()->setDefaultTextOption(option);
+ if (d->selectionControl) {
+ d->selectionControl->updatePrimitives();
+ }
d->acceptSignalContentsChanged = true;
- setTextCursor(cursor);
d->mApiProtectionFlags |= HbWidgetBasePrivate::AC_TextAlign;
}
/*!
- Returns text alignment at the current text cursor.
+ Returns text default alignment.
\sa setAlignment()
*/
Qt::Alignment HbAbstractEdit::alignment() const
{
- Q_D(const HbAbstractEdit);
- return d->cursor.blockFormat().alignment();
-
+ return document()->defaultTextOption().alignment();
}
/*!
@@ -1511,6 +1443,60 @@
d->contextMenuShownOn&=~flag;
}
+
+/*!
+ \property HbAbstractEdit::placeholderText
+ \brief the editor's placeholder text
+
+ Setting this property makes the editor display a grayed-out
+ placeholder text as long as the text is empty.
+ By default, this property contains an empty string.
+*/
+QString HbAbstractEdit::placeholderText() const
+{
+ Q_D(const HbAbstractEdit);
+ if(d->placeholderDoc){
+ return d->placeholderDoc->toPlainText();
+ } else {
+ return QString();
+ }
+}
+
+/*!
+ \sa placeholderText()
+*/
+void HbAbstractEdit::setPlaceholderText(const QString& placeholderText)
+{
+ Q_D(HbAbstractEdit);
+
+ if(!d->placeholderDoc) {
+ d->placeholderDoc = new QTextDocument(this);
+ d->updatePlaceholderDocProperties();
+ }
+
+ QString txt( placeholderText );
+#ifdef HB_TEXT_MEASUREMENT_UTILITY
+ if ( HbFeatureManager::instance()->featureStatus( HbFeatureManager::TextMeasurement ) ) {
+ if (placeholderText.endsWith(QChar(LOC_TEST_END))) {
+ int index = placeholderText.indexOf(QChar(LOC_TEST_START));
+ setProperty( HbTextMeasurementUtilityNameSpace::textIdPropertyName, placeholderText.mid(index + 1, placeholderText.indexOf(QChar(LOC_TEST_END)) - index - 1) );
+ setProperty( HbTextMeasurementUtilityNameSpace::textMaxLines, -1 );
+ txt = placeholderText.left(index);
+ } else {
+ setProperty( HbTextMeasurementUtilityNameSpace::textIdPropertyName, QVariant::Invalid );
+ }
+ }
+#endif //HB_TEXT_MEASUREMENT_UTILITY
+
+
+ if (d->placeholderDoc->toPlainText() != txt) {
+ d->placeholderDoc->setPlainText(txt);
+ if (d->doc->isEmpty()) {
+ update();
+ }
+ }
+}
+
/*!
Returns the reference of the anchor at the given position,
or an empty string if no anchor exists at that point.
@@ -1625,37 +1611,42 @@
void HbAbstractEdit::polish( HbStyleParameters& params )
{
Q_D(HbAbstractEdit);
- const QString KTextAlignmentCSSName = "text-align";
- const QString KTextColorCSSName = "color";
+
+ if (isVisible()) {
+ const QString KTextAlignmentCSSName = "text-align";
+ const QString KTextColorCSSName = "color";
- // ------ adding css parameters ------
- params.addParameter(KTextAlignmentCSSName);
+ // ------ adding css parameters ------
+ params.addParameter(KTextAlignmentCSSName);
- QPalette cssPalette = palette();
- params.addParameter(KTextColorCSSName, cssPalette.color(QPalette::Text));
+ QPalette cssPalette = palette();
+ params.addParameter(KTextColorCSSName, cssPalette.color(QPalette::Text));
- HbWidget::polish(params);
+ HbWidget::polish(params);
- // ------ interpreting css parameters ------
- QVariant param = params.value(KTextAlignmentCSSName);
- if(param.canConvert(QVariant::String)) {
- Qt::Alignment align = HbAbstractEditPrivate::alignmentFromString(param.toString());
- if( align != 0 ) {
- if (!(d->mApiProtectionFlags & HbWidgetBasePrivate::AC_TextAlign)) {
- setAlignment(align);
- d->mApiProtectionFlags &= ~HbWidgetBasePrivate::AC_TextAlign;
+ // ------ interpreting css parameters ------
+ QVariant param = params.value(KTextAlignmentCSSName);
+ if(param.canConvert(QVariant::String)) {
+ Qt::Alignment align = HbAbstractEditPrivate::alignmentFromString(param.toString());
+ if( align != 0 ) {
+ if (!(d->mApiProtectionFlags & HbWidgetBasePrivate::AC_TextAlign)) {
+ setAlignment(align);
+ d->mApiProtectionFlags &= ~HbWidgetBasePrivate::AC_TextAlign;
+ }
+ } else {
+ qWarning("Unable to read CSS parameter \"text-alignment\" in editor");
}
- } else {
- qWarning("Unable to read CSS parameter \"text-alignment\" in editor");
}
- }
- param = params.value(KTextColorCSSName);
- if(param.canConvert(QVariant::Color)) {
- cssPalette.setColor(QPalette::Text, param.value<QColor>());
+ param = params.value(KTextColorCSSName);
+ if(param.canConvert(QVariant::Color)) {
+ cssPalette.setColor(QPalette::Text, param.value<QColor>());
+ }
+
+ setPalette(cssPalette);
+ } else {
+ HbWidget::polish(params);
}
-
- setPalette(cssPalette);
}
/*!
@@ -1679,3 +1670,44 @@
{
return document()->characterAt(pos);
}
+
+void HbAbstractEdit::gestureEvent(QGestureEvent* event) {
+ Q_D(HbAbstractEdit);
+
+ if(HbTapGesture *tap = qobject_cast<HbTapGesture*>(event->gesture(Qt::TapGesture))) {
+ // QTapGesture::position() is in screen coordinates and thus
+ // needs to be transformed into items own coordinate system.
+ // The QGestureEvent knows the viewport through which the gesture
+ // was triggered.
+ QPointF pos = mapFromScene(event->mapToGraphicsScene(tap->position()));
+ switch(tap->state()) {
+ case Qt::GestureStarted:
+ d->tapPosition = pos;
+ HbWidgetFeedback::triggered(this, Hb::InstantPressed);
+ break;
+ case Qt::GestureUpdated:
+ if(tap->tapStyleHint() == HbTapGesture::TapAndHold) {
+ d->longTapGesture(pos);
+ }
+ break;
+ case Qt::GestureFinished:
+ if(tap->tapStyleHint() == HbTapGesture::TapAndHold) {
+ } else {
+ d->tapGesture(pos);
+ }
+
+ HbWidgetFeedback::triggered(this, Hb::InstantReleased);
+
+ d->openInputPanel();
+
+ break;
+ case Qt::GestureCanceled:
+ break;
+ default:
+ break;
+ }
+ event->accept();
+ } else {
+ event->ignore();
+ }
+}