--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ginebra2/TextEditItem.cpp Tue May 04 12:39:35 2010 +0300
@@ -0,0 +1,231 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+#include <QGraphicsTextItem>
+#include "TextEditItem.h"
+#include "ChromeSnippet.h"
+#include "GreenChromeSnippet.h"
+
+namespace GVA {
+ EditorWidget::EditorWidget(QGraphicsItem * parent)
+ : QGraphicsTextItem(parent)
+ {
+ setText("");
+ }
+ void EditorWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem * option, QWidget* widget)
+ {
+ //Hack to get rid of the ugly selection ants. This should be tunable in QGraphicsTextItem!
+ QStyleOptionGraphicsItem newOption = *option;
+ newOption.state &= (!QStyle::State_Selected | !QStyle::State_HasFocus);
+ painter->save();
+ QGraphicsTextItem::paint(painter, &newOption, widget);
+ painter->restore();
+ }
+
+ // The editor document signals cursor movements when the document modified (because characters
+ // are being added or removed, but not when the cursor is simply being moved. Also, the
+ // document's idea of cursor position is based on the character count, not the actual pixel
+ // position. To implement scrolling, we need our own cursor change event that supplies the
+ // pixel change in all cases.
+
+ void EditorWidget::keyPressEvent(QKeyEvent *event)
+ {
+ qreal oldX = cursorX();
+ QGraphicsTextItem::keyPressEvent(event);
+ emit cursorXChanged(cursorX(), oldX);
+ }
+
+ void EditorWidget::setText(const QString& text, bool html)
+ {
+ if(html)
+ setHtml(text);
+ else
+ setPlainText(text);
+ //All this just to get the first (and only) text line of the document!
+ m_textLine = document()->begin().layout()->lineForTextPosition(0);
+ }
+
+ // Use QTextLine to compute the text metrics for the current cursor position.
+
+ qreal EditorWidget::cursorX() {
+ return m_textLine.cursorToX(textCursor().position());
+ }
+
+ TextEditItem::TextEditItem(ChromeSnippet * snippet, QGraphicsItem* parent)
+ : NativeChromeItem(snippet, parent),
+ m_textWidth(0),
+ m_scrollPos(0)
+ {
+ setFlags(QGraphicsItem::ItemIsMovable);
+ //The viewport clips the editor when text overflows
+ m_viewPort = new QGraphicsWidget(this);
+ m_viewPort->setFlags(QGraphicsItem::ItemClipsChildrenToShape);
+ //The actual text editor item
+ m_editor = new EditorWidget(m_viewPort);
+ m_cursor = m_editor->textCursor();
+ connect(m_editor, SIGNAL(cursorXChanged(qreal, qreal)), this, SLOT(onCursorXChanged(qreal, qreal)));
+
+ //Force the editor to be a single text line
+ m_textOption = m_editor->document()->defaultTextOption();
+ m_textOption.setWrapMode(QTextOption::NoWrap);
+ m_editor->document()->setDefaultTextOption(m_textOption);
+
+ //Not exactly well-documented, but this flag is needed to make cursor keys work
+ m_editor->setTextInteractionFlags(Qt::TextEditorInteraction);
+
+ //Non-default key handling for scrolling, etc.
+ m_editor->installEventFilter(this);
+
+ //Set text and background colors from element css
+ QString cssVal = m_snippet->element().styleProperty("color", QWebElement::ComputedStyle);
+ CSSToQColor(cssVal, m_textColor);
+ m_editor->setDefaultTextColor(m_textColor);
+ cssVal = m_snippet->element().styleProperty("background-color", QWebElement::ComputedStyle);
+ CSSToQColor(cssVal, m_backgroundColor);
+
+ //For border-related properties, we constrain all values (top, left, etc.) to be the same.
+ //These can be set using the css shorthand (e.g. padding:10px), but the computed css style will be for
+ //the four primitive values (padding-top, padding-left) etc, which will all be equal.
+ //Hence we just use one of the computed primitive values (top) to represent the common value.
+
+ cssVal = m_snippet->element().styleProperty("border-top-color", QWebElement::ComputedStyle);
+ CSSToQColor(cssVal, m_borderColor);
+ cssVal = m_snippet->element().styleProperty("padding-top", QWebElement::ComputedStyle);
+ m_padding = cssVal.remove("px").toInt();
+ cssVal = m_snippet->element().styleProperty("border-top-width", QWebElement::ComputedStyle);
+ m_border = cssVal.remove("px").toInt();
+
+ //Cool effect, but shadow, if any, should be set by js
+ //m_shadow = new QGraphicsDropShadowEffect();
+ //m_shadow->setOffset(3.0,3.0);
+ //m_shadow->setBlurRadius(2.0);
+ //setGraphicsEffect(m_shadow);
+ }
+
+ TextEditItem::~TextEditItem()
+ {
+ delete m_editor;
+ }
+
+ void TextEditItem::resizeEvent(QGraphicsSceneResizeEvent * ev)
+ {
+ NativeChromeItem::resizeEvent(ev);
+ m_viewPortWidth = boundingRect().width()-m_padding*2;
+ m_viewPort->setGeometry(m_padding,(boundingRect().height()-m_editor->boundingRect().height())/2,m_viewPortWidth, m_editor->boundingRect().height() );
+ m_editor->setTextWidth(m_viewPortWidth);
+ //Make a rectangular background with a cut-out for the text. The width of the surrounding
+ //background is set by padding
+ m_background.addRect(boundingRect());
+ m_background.addRoundedRect(m_padding, m_padding, m_viewPortWidth, boundingRect().height()-m_padding*2,4,4);
+ }
+
+ //Filter key events to emit activate signal absorb up, down keys
+
+ bool TextEditItem::eventFilter(QObject * obj, QEvent *ev)
+ {
+ if(obj == m_editor){
+ if(ev->type() == QEvent::KeyPress){
+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(ev);
+ if(keyEvent->key() == Qt::Key_Select || keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
+ //Signal that a carriage return-like key-press happened
+ emit activated();
+ return true;
+ }
+ if(keyEvent->key() == Qt::Key_Down || keyEvent->key() == Qt::Key_Up)
+ return true;
+ //Otherwise, pass keypress to the text editor
+ return false;
+ }
+ }
+ return NativeChromeItem::eventFilter(obj, ev);
+ }
+
+ void TextEditItem::internalScroll(qreal deltaX)
+ {
+ if(deltaX > -m_scrollPos)
+ m_editor->moveBy(-m_scrollPos,0);
+ else
+ m_editor->moveBy(deltaX,0);
+ m_scrollPos = m_editor->pos().x();
+ }
+
+ //Handle text scrolling
+ //NB: Still needs some tweaking, for example to keep the last character visibile when
+ //inserting! Rewrite as state machine?
+
+ void TextEditItem::onCursorXChanged(qreal newX, qreal oldX)
+ {
+ qreal oldTextWidth = m_textWidth;
+ m_textWidth = m_editor->document()->size().width();
+ if(oldTextWidth == 0)
+ return;
+ qreal textDelta = m_textWidth - oldTextWidth;
+ qreal deltaX = oldX - newX;
+ //Just moving the cursor, slide window as needed
+ if(textDelta == 0){
+ //NB: Currently slides by one character, in some browsers slides by multiple characters
+ if((newX <= -m_scrollPos)||(newX >= (m_viewPortWidth - m_scrollPos))){
+ internalScroll(deltaX);
+ }
+ }
+ //Inserting characters
+ else if (textDelta > 0){
+ if(newX >= (m_viewPortWidth - m_scrollPos)){
+ internalScroll(deltaX);
+ }
+ }
+ //Deleting characters.
+ else {
+ if(m_scrollPos < 0){
+ //Delete may be a selected block, in which case the cursor movement may be
+ //different from the text delta.
+ internalScroll(-textDelta);
+ }
+ }
+ }
+
+ // Paint background and any border
+
+ void TextEditItem::paint(QPainter* painter, const QStyleOptionGraphicsItem * option, QWidget* widget){
+ NativeChromeItem::paint(painter, option,widget);
+ QPainterPath path;
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+ painter->setBrush(m_backgroundColor);
+ if(m_border > 0){
+ QPen pen;
+ pen.setWidth(m_border);
+ pen.setBrush(m_borderColor);
+ painter->setPen(pen);
+ }
+ painter->drawPath(m_background);
+ painter->restore();
+ }
+
+ //NB: Move these slots to the containing snippet so they can be exported to JS
+
+ QString TextEditItem::text(){
+ return m_editor->toPlainText();
+ }
+
+ void TextEditItem::setText(const QString & text){
+ m_editor->setText(text);
+ }
+
+}
+