diff -r 16d8024aca5e -r f7ac710697a9 src/hbwidgets/editors/hbabstractedit.cpp --- 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 +#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 #include "hbpopup.h" #include "hbformatdialog.h" #include #include -#include #include #include #include @@ -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(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()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()); + param = params.value(KTextColorCSSName); + if(param.canConvert(QVariant::Color)) { + cssPalette.setColor(QPalette::Text, param.value()); + } + + 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(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(); + } +}