1 /* |
1 /* |
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
3 * All rights reserved. |
3 * All rights reserved. |
4 * This component and the accompanying materials are made available |
4 * |
5 * under the terms of "Eclipse Public License v1.0" |
5 * This program is free software: you can redistribute it and/or modify |
6 * which accompanies this distribution, and is available |
6 * it under the terms of the GNU Lesser General Public License as published by |
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
7 * the Free Software Foundation, version 2.1 of the License. |
8 * |
8 * |
9 * Initial Contributors: |
9 * This program is distributed in the hope that it will be useful, |
10 * Nokia Corporation - initial contribution. |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * Contributors: |
12 * GNU Lesser General Public License for more details. |
13 * |
13 * |
14 * Description: |
14 * You should have received a copy of the GNU Lesser General Public License |
|
15 * along with this program. If not, |
|
16 * see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/". |
|
17 * |
|
18 * Description: |
15 * |
19 * |
16 */ |
20 */ |
17 |
|
18 |
21 |
19 #include <QGraphicsTextItem> |
22 #include <QGraphicsTextItem> |
20 #include "TextEditItem.h" |
23 #include "TextEditItem.h" |
21 #include "ChromeSnippet.h" |
24 #include "ChromeSnippet.h" |
22 #include "GreenChromeSnippet.h" |
|
23 |
25 |
24 namespace GVA { |
26 namespace GVA { |
25 EditorWidget::EditorWidget(QGraphicsItem * parent) |
27 EditorWidget::EditorWidget(QGraphicsItem * parent) |
26 : QGraphicsTextItem(parent) |
28 : QGraphicsTextItem(parent) |
27 { |
29 { |
40 // The editor document signals cursor movements when the document modified (because characters |
42 // The editor document signals cursor movements when the document modified (because characters |
41 // are being added or removed, but not when the cursor is simply being moved. Also, the |
43 // are being added or removed, but not when the cursor is simply being moved. Also, the |
42 // document's idea of cursor position is based on the character count, not the actual pixel |
44 // document's idea of cursor position is based on the character count, not the actual pixel |
43 // position. To implement scrolling, we need our own cursor change event that supplies the |
45 // position. To implement scrolling, we need our own cursor change event that supplies the |
44 // pixel change in all cases. |
46 // pixel change in all cases. |
45 |
47 |
46 void EditorWidget::keyPressEvent(QKeyEvent *event) |
48 void EditorWidget::keyPressEvent(QKeyEvent *event) |
47 { |
49 { |
48 qreal oldX = cursorX(); |
50 qreal oldX = cursorX(); |
49 QGraphicsTextItem::keyPressEvent(event); |
51 QGraphicsTextItem::keyPressEvent(event); |
50 emit cursorXChanged(cursorX(), oldX); |
52 emit cursorXChanged(cursorX(), oldX); |
51 } |
53 } |
52 |
54 |
53 void EditorWidget::setText(const QString& text, bool html) |
55 void EditorWidget::setText(const QString& text, bool html) |
54 { |
56 { |
55 if(html) |
57 if (html) |
56 setHtml(text); |
58 setHtml(text); |
57 else |
59 else |
58 setPlainText(text); |
60 setPlainText(text); |
59 //All this just to get the first (and only) text line of the document! |
61 //All this just to get the first (and only) text line of the document! |
60 m_textLine = document()->begin().layout()->lineForTextPosition(0); |
62 m_textLine = document()->begin().layout()->lineForTextPosition(0); |
77 m_viewPort->setFlags(QGraphicsItem::ItemClipsChildrenToShape); |
79 m_viewPort->setFlags(QGraphicsItem::ItemClipsChildrenToShape); |
78 //The actual text editor item |
80 //The actual text editor item |
79 m_editor = new EditorWidget(m_viewPort); |
81 m_editor = new EditorWidget(m_viewPort); |
80 m_cursor = m_editor->textCursor(); |
82 m_cursor = m_editor->textCursor(); |
81 connect(m_editor, SIGNAL(cursorXChanged(qreal, qreal)), this, SLOT(onCursorXChanged(qreal, qreal))); |
83 connect(m_editor, SIGNAL(cursorXChanged(qreal, qreal)), this, SLOT(onCursorXChanged(qreal, qreal))); |
82 |
84 |
83 //Force the editor to be a single text line |
85 //Force the editor to be a single text line |
84 m_textOption = m_editor->document()->defaultTextOption(); |
86 m_textOption = m_editor->document()->defaultTextOption(); |
85 m_textOption.setWrapMode(QTextOption::NoWrap); |
87 m_textOption.setWrapMode(QTextOption::NoWrap); |
86 m_editor->document()->setDefaultTextOption(m_textOption); |
88 m_editor->document()->setDefaultTextOption(m_textOption); |
87 |
89 |
88 //Not exactly well-documented, but this flag is needed to make cursor keys work |
90 //Not exactly well-documented, but this flag is needed to make cursor keys work |
89 m_editor->setTextInteractionFlags(Qt::TextEditorInteraction); |
91 m_editor->setTextInteractionFlags(Qt::TextEditorInteraction); |
90 |
92 |
91 //Non-default key handling for scrolling, etc. |
93 //Non-default key handling for scrolling, etc. |
92 m_editor->installEventFilter(this); |
94 m_editor->installEventFilter(this); |
93 |
95 |
94 //Set text and background colors from element css |
96 //Set text and background colors from element css |
95 QString cssVal = m_snippet->element().styleProperty("color", QWebElement::ComputedStyle); |
97 QString cssVal = m_snippet->element().styleProperty("color", QWebElement::ComputedStyle); |
96 CSSToQColor(cssVal, m_textColor); |
98 CSSToQColor(cssVal, m_textColor); |
97 m_editor->setDefaultTextColor(m_textColor); |
99 m_editor->setDefaultTextColor(m_textColor); |
98 cssVal = m_snippet->element().styleProperty("background-color", QWebElement::ComputedStyle); |
100 cssVal = m_snippet->element().styleProperty("background-color", QWebElement::ComputedStyle); |
119 |
121 |
120 TextEditItem::~TextEditItem() |
122 TextEditItem::~TextEditItem() |
121 { |
123 { |
122 delete m_editor; |
124 delete m_editor; |
123 } |
125 } |
124 |
126 |
125 void TextEditItem::resizeEvent(QGraphicsSceneResizeEvent * ev) |
127 void TextEditItem::resizeEvent(QGraphicsSceneResizeEvent * ev) |
126 { |
128 { |
127 NativeChromeItem::resizeEvent(ev); |
129 NativeChromeItem::resizeEvent(ev); |
128 m_viewPortWidth = boundingRect().width()-m_padding*2; |
130 m_viewPortWidth = boundingRect().width()-m_padding*2; |
129 m_viewPort->setGeometry(m_padding,(boundingRect().height()-m_editor->boundingRect().height())/2,m_viewPortWidth, m_editor->boundingRect().height() ); |
131 m_viewPort->setGeometry(m_padding,(boundingRect().height()-m_editor->boundingRect().height())/2,m_viewPortWidth, m_editor->boundingRect().height() ); |
130 m_editor->setTextWidth(m_viewPortWidth); |
132 m_editor->setTextWidth(m_viewPortWidth); |
131 //Make a rectangular background with a cut-out for the text. The width of the surrounding |
133 //Make a rectangular background with a cut-out for the text. The width of the surrounding |
132 //background is set by padding |
134 //background is set by padding |
133 m_background.addRect(boundingRect()); |
135 m_background.addRect(boundingRect()); |
134 m_background.addRoundedRect(m_padding, m_padding, m_viewPortWidth, boundingRect().height()-m_padding*2,4,4); |
136 m_background.addRoundedRect(m_padding, m_padding, m_viewPortWidth, boundingRect().height()-m_padding*2,4,4); |
135 } |
137 } |
136 |
138 |
137 //Filter key events to emit activate signal absorb up, down keys |
139 //Filter key events to emit activate signal absorb up, down keys |
138 |
140 |
139 bool TextEditItem::eventFilter(QObject * obj, QEvent *ev) |
141 bool TextEditItem::eventFilter(QObject * obj, QEvent *ev) |
140 { |
142 { |
141 if(obj == m_editor){ |
143 if (obj == m_editor){ |
142 if(ev->type() == QEvent::KeyPress){ |
144 if (ev->type() == QEvent::KeyPress){ |
143 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(ev); |
145 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(ev); |
144 if(keyEvent->key() == Qt::Key_Select || keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { |
146 if (keyEvent->key() == Qt::Key_Select || keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { |
145 //Signal that a carriage return-like key-press happened |
147 //Signal that a carriage return-like key-press happened |
146 emit activated(); |
148 emit activated(); |
147 return true; |
149 return true; |
148 } |
150 } |
149 if(keyEvent->key() == Qt::Key_Down || keyEvent->key() == Qt::Key_Up) |
151 if (keyEvent->key() == Qt::Key_Down || keyEvent->key() == Qt::Key_Up) |
150 return true; |
152 return true; |
151 //Otherwise, pass keypress to the text editor |
153 //Otherwise, pass keypress to the text editor |
152 return false; |
154 return false; |
153 } |
155 } |
154 } |
156 } |
155 return NativeChromeItem::eventFilter(obj, ev); |
157 return NativeChromeItem::eventFilter(obj, ev); |
156 } |
158 } |
157 |
159 |
158 void TextEditItem::internalScroll(qreal deltaX) |
160 void TextEditItem::internalScroll(qreal deltaX) |
159 { |
161 { |
160 if(deltaX > -m_scrollPos) |
162 if (deltaX > -m_scrollPos) |
161 m_editor->moveBy(-m_scrollPos,0); |
163 m_editor->moveBy(-m_scrollPos,0); |
162 else |
164 else |
163 m_editor->moveBy(deltaX,0); |
165 m_editor->moveBy(deltaX,0); |
164 m_scrollPos = m_editor->pos().x(); |
166 m_scrollPos = m_editor->pos().x(); |
165 } |
167 } |
169 //inserting! Rewrite as state machine? |
171 //inserting! Rewrite as state machine? |
170 |
172 |
171 void TextEditItem::onCursorXChanged(qreal newX, qreal oldX) |
173 void TextEditItem::onCursorXChanged(qreal newX, qreal oldX) |
172 { |
174 { |
173 qreal oldTextWidth = m_textWidth; |
175 qreal oldTextWidth = m_textWidth; |
174 m_textWidth = m_editor->document()->size().width(); |
176 m_textWidth = m_editor->document()->size().width(); |
175 if(oldTextWidth == 0) |
177 if (oldTextWidth == 0) |
176 return; |
178 return; |
177 qreal textDelta = m_textWidth - oldTextWidth; |
179 qreal textDelta = m_textWidth - oldTextWidth; |
178 qreal deltaX = oldX - newX; |
180 qreal deltaX = oldX - newX; |
179 //Just moving the cursor, slide window as needed |
181 //Just moving the cursor, slide window as needed |
180 if(textDelta == 0){ |
182 if (textDelta == 0){ |
181 //NB: Currently slides by one character, in some browsers slides by multiple characters |
183 //NB: Currently slides by one character, in some browsers slides by multiple characters |
182 if((newX <= -m_scrollPos)||(newX >= (m_viewPortWidth - m_scrollPos))){ |
184 if ((newX <= -m_scrollPos)||(newX >= (m_viewPortWidth - m_scrollPos))){ |
183 internalScroll(deltaX); |
185 internalScroll(deltaX); |
184 } |
186 } |
185 } |
187 } |
186 //Inserting characters |
188 //Inserting characters |
187 else if (textDelta > 0){ |
189 else if (textDelta > 0){ |
188 if(newX >= (m_viewPortWidth - m_scrollPos)){ |
190 if (newX >= (m_viewPortWidth - m_scrollPos)){ |
189 internalScroll(deltaX); |
191 internalScroll(deltaX); |
190 } |
192 } |
191 } |
193 } |
192 //Deleting characters. |
194 //Deleting characters. |
193 else { |
195 else { |
194 if(m_scrollPos < 0){ |
196 if (m_scrollPos < 0){ |
195 //Delete may be a selected block, in which case the cursor movement may be |
197 //Delete may be a selected block, in which case the cursor movement may be |
196 //different from the text delta. |
198 //different from the text delta. |
197 internalScroll(-textDelta); |
199 internalScroll(-textDelta); |
198 } |
200 } |
199 } |
201 } |
205 NativeChromeItem::paint(painter, option,widget); |
207 NativeChromeItem::paint(painter, option,widget); |
206 QPainterPath path; |
208 QPainterPath path; |
207 painter->save(); |
209 painter->save(); |
208 painter->setRenderHint(QPainter::Antialiasing); |
210 painter->setRenderHint(QPainter::Antialiasing); |
209 painter->setBrush(m_backgroundColor); |
211 painter->setBrush(m_backgroundColor); |
210 if(m_border > 0){ |
212 if (m_border > 0){ |
211 QPen pen; |
213 QPen pen; |
212 pen.setWidth(m_border); |
214 pen.setWidth(m_border); |
213 pen.setBrush(m_borderColor); |
215 pen.setBrush(m_borderColor); |
214 painter->setPen(pen); |
216 painter->setPen(pen); |
215 } |
217 } |