22 static const char *NMUI_EDITOR_SCROLL_AREA = "scrollArea"; |
22 static const char *NMUI_EDITOR_SCROLL_AREA = "scrollArea"; |
23 static const char *NMUI_EDITOR_SCROLL_AREA_CONTENTS = "scrollAreaContents"; |
23 static const char *NMUI_EDITOR_SCROLL_AREA_CONTENTS = "scrollAreaContents"; |
24 |
24 |
25 // Regular expression for selecting img tags with "cid" in the mail. |
25 // Regular expression for selecting img tags with "cid" in the mail. |
26 static const char *NMUI_EDITOR_REMOVE_EMBD_IMAGES_REG = |
26 static const char *NMUI_EDITOR_REMOVE_EMBD_IMAGES_REG = |
27 "(<img (src\\s*=\\s*)(.{0,1}cid)([^<]+)(>\\s*|/>\\s*|></img>\\s*))"; |
27 "(<img[^<]+(src\\s*=\\s*)(.{0,1}cid)([^<]+)(>\\s*|/>\\s*|></img>\\s*))"; |
28 |
28 |
29 /*! |
29 /*! |
30 Constructor |
30 Constructor |
31 */ |
31 */ |
32 NmEditorContent::NmEditorContent(QObject *parent, |
32 NmEditorContent::NmEditorContent(QObject *parent, |
33 HbDocumentLoader *documentLoader, |
33 HbDocumentLoader *documentLoader, |
34 QNetworkAccessManager &manager, |
34 QNetworkAccessManager &manager, |
35 NmApplication &application) : |
35 NmApplication &application) : |
36 QObject(parent), |
36 QObject(parent), |
37 mHeaderWidget(NULL), |
37 mHeader(NULL), |
38 mMessageBodyType(NmPlainText), |
38 mMessageBodyType(NmPlainText), |
39 mEditorWidget(NULL), |
39 mEditorWidget(NULL), |
40 mScrollArea(NULL), |
40 mScrollArea(NULL), |
41 mScrollAreaContents(NULL), |
41 mScrollAreaContents(NULL), |
42 mApplication(application) |
42 mApplication(application) |
43 { |
43 { |
44 NM_FUNCTION; |
44 NM_FUNCTION; |
45 |
45 |
46 // Construct container for the header widgets |
46 // Construct container for the header widgets |
47 mHeaderWidget = new NmEditorHeader(this, documentLoader); |
47 mHeader = new NmEditorHeader(this, documentLoader); |
48 |
48 |
49 // Get pointer to body text area handling widget |
49 // Get pointer to body text area handling widget |
50 mEditorWidget = qobject_cast<NmEditorTextEdit *>(documentLoader->findWidget(NMUI_EDITOR_BODY)); |
50 mEditorWidget = qobject_cast<NmEditorTextEdit *>(documentLoader->findWidget(NMUI_EDITOR_BODY)); |
51 |
51 |
52 // Set body editor to use NmEditorTextDocument |
52 // Set body editor to use NmEditorTextDocument |
54 mEditorWidget->setDocument(textDocument); |
54 mEditorWidget->setDocument(textDocument); |
55 textDocument->setParent(mEditorWidget); // ownership changes |
55 textDocument->setParent(mEditorWidget); // ownership changes |
56 |
56 |
57 mScrollArea = qobject_cast<NmBaseViewScrollArea *> |
57 mScrollArea = qobject_cast<NmBaseViewScrollArea *> |
58 (documentLoader->findObject(NMUI_EDITOR_SCROLL_AREA)); |
58 (documentLoader->findObject(NMUI_EDITOR_SCROLL_AREA)); |
59 |
59 mScrollArea->setScrollDirections(Qt::Vertical | Qt::Horizontal); |
|
60 |
60 // Enable style picker menu item. |
61 // Enable style picker menu item. |
61 mEditorWidget->setFormatDialog(new HbFormatDialog()); |
62 mEditorWidget->setFormatDialog(new HbFormatDialog()); |
62 |
63 |
63 mScrollAreaContents = |
64 mScrollAreaContents = |
64 qobject_cast<HbWidget *>(documentLoader->findWidget(NMUI_EDITOR_SCROLL_AREA_CONTENTS)); |
65 qobject_cast<HbWidget *>(documentLoader->findWidget(NMUI_EDITOR_SCROLL_AREA_CONTENTS)); |
127 // Signal for setting HbTextEdit widgets plain text content |
128 // Signal for setting HbTextEdit widgets plain text content |
128 connect(this, SIGNAL(setPlainText(QString)), |
129 connect(this, SIGNAL(setPlainText(QString)), |
129 mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection); |
130 mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection); |
130 |
131 |
131 // Inform text edit widget that header height has been changed |
132 // Inform text edit widget that header height has been changed |
132 connect(mHeaderWidget, SIGNAL(headerHeightChanged(int)), this, SLOT(setEditorContentHeight()), |
133 connect(mHeader, SIGNAL(headerHeightChanged(int)), this, SLOT(setEditorContentHeight()), |
133 Qt::QueuedConnection); |
134 Qt::QueuedConnection); |
134 |
135 |
135 // we are interested in the document's height changes |
136 // we are interested in the document's height changes |
136 connect(mEditorWidget->document()->documentLayout(), SIGNAL(documentSizeChanged(QSizeF)), this, |
137 connect(mEditorWidget->document()->documentLayout(), SIGNAL(documentSizeChanged(QSizeF)), this, |
137 SLOT(setEditorContentHeight()), Qt::QueuedConnection); |
138 SLOT(setEditorContentHeight()), Qt::QueuedConnection); |
138 |
139 |
139 // We need to update the scroll position according the editor cursor position |
140 // We need to update the scroll position according the editor's cursor position |
|
141 connect(mHeader->toEdit(), SIGNAL(cursorPositionChanged(int, int)), this, |
|
142 SLOT(ensureCursorVisibility()), Qt::QueuedConnection); |
|
143 connect(mHeader->ccEdit(), SIGNAL(cursorPositionChanged(int, int)), this, |
|
144 SLOT(ensureCursorVisibility()), Qt::QueuedConnection); |
|
145 connect(mHeader->bccEdit(), SIGNAL(cursorPositionChanged(int, int)), this, |
|
146 SLOT(ensureCursorVisibility()), Qt::QueuedConnection); |
|
147 connect(mHeader->subjectEdit(), SIGNAL(cursorPositionChanged(int, int)), this, |
|
148 SLOT(ensureCursorVisibility()), Qt::QueuedConnection); |
140 connect(mEditorWidget, SIGNAL(cursorPositionChanged(int, int)), this, |
149 connect(mEditorWidget, SIGNAL(cursorPositionChanged(int, int)), this, |
141 SLOT(setScrollPosition(int, int)), Qt::QueuedConnection); |
150 SLOT(ensureCursorVisibility()), Qt::QueuedConnection); |
142 |
151 |
143 // We need to know the scroll area's current position for calculating the new position in |
152 // listen to the parent's (NmEditorView) size changes which happen eg. when VKB is opened/closed |
144 // setScrollPosition |
153 connect(parent(), SIGNAL(sizeChanged()), this, SLOT(ensureCursorVisibility()), |
145 connect(mScrollArea, SIGNAL(scrollPositionChanged(QPointF)), this, |
154 Qt::QueuedConnection); |
146 SLOT(updateScrollPosition(QPointF)), Qt::QueuedConnection); |
|
147 } |
155 } |
148 |
156 |
149 /*! |
157 /*! |
150 Return pointer to the email body text edit widget |
158 Return pointer to the email body text edit widget |
151 */ |
159 */ |
161 */ |
169 */ |
162 NmEditorHeader *NmEditorContent::header() const |
170 NmEditorHeader *NmEditorContent::header() const |
163 { |
171 { |
164 NM_FUNCTION; |
172 NM_FUNCTION; |
165 |
173 |
166 return mHeaderWidget; |
174 return mHeader; |
167 } |
175 } |
168 |
176 |
169 /*! |
177 /*! |
170 This slot is called when header widget height has been changed. Function performs |
178 This slot is called when header widget height has been changed. Function performs |
171 the repositioning of the body field and resizing of the editor and content area. |
179 the repositioning of the body field and resizing of the editor and content area. |
172 */ |
180 */ |
173 void NmEditorContent::setEditorContentHeight() |
181 void NmEditorContent::setEditorContentHeight() |
174 { |
182 { |
175 NM_FUNCTION; |
183 NM_FUNCTION; |
176 |
184 |
|
185 // the height of the margin between the title bar and the header |
177 qreal topMargin = 0; |
186 qreal topMargin = 0; |
178 HbStyle().parameter("hb-param-margin-gene-top", topMargin); |
187 HbStyle().parameter("hb-param-margin-gene-top", topMargin); |
179 |
188 |
180 // header height |
189 // header height |
181 qreal headerHeight = mHeaderWidget->headerHeight(); |
190 qreal headerHeight = mHeader->headerHeight(); |
182 |
191 |
183 // body area editor's document height with margins added |
192 // body area editor's document height with margins added |
184 qreal documentHeightAndMargins = mEditorWidget->document()->size().height() + |
193 qreal documentHeightAndMargins = mEditorWidget->document()->size().height() + |
185 (mEditorWidget->document()->documentMargin() * 2); |
194 (mEditorWidget->document()->documentMargin() * 2); |
186 |
195 |
187 // get the chrome height |
196 // chrome height |
188 qreal chromeHeight = 0; |
197 qreal chromeHeight = 0; |
189 HbStyle().parameter("hb-param-widget-chrome-height", chromeHeight); |
198 HbStyle().parameter("hb-param-widget-chrome-height", chromeHeight); |
190 |
199 |
191 qreal toolbarHeight = 0; |
|
192 HbStyle().parameter("hb-param-widget-toolbar-height", toolbarHeight); |
|
193 |
|
194 // screen height |
200 // screen height |
195 qreal screenHeight = mApplication.screenSize().height(); |
201 qreal screenHeight = mApplication.screenSize().height(); |
196 |
202 |
197 // set min size for the body area so that at least the screen area is always filled |
203 // set min size for the body area so that at least the screen area is always filled |
198 qreal bodyAreaMinSize = screenHeight - chromeHeight - topMargin - headerHeight; |
204 qreal bodyAreaMinSize = screenHeight - chromeHeight - topMargin - headerHeight; |
201 |
207 |
202 mScrollAreaContents->setPreferredHeight(topMargin + headerHeight + bodyAreaSize); |
208 mScrollAreaContents->setPreferredHeight(topMargin + headerHeight + bodyAreaSize); |
203 } |
209 } |
204 |
210 |
205 /*! |
211 /*! |
206 This slot is called when cursor position is changed in body area using |
212 This slot is called when the cursor visibility has to be ensured ie. the scroll position is |
207 'pointing stick' or keyboard. Function will update the scroll position |
213 adjusted so that the cursor can be seen. |
208 of the content so that cursor does not go outside of the screen or |
214 */ |
209 behind the virtual keyboard. |
215 void NmEditorContent::ensureCursorVisibility() |
210 */ |
216 { |
211 void NmEditorContent::setScrollPosition(int oldPos, int newPos) |
217 NM_FUNCTION; |
212 { |
218 |
213 NM_FUNCTION; |
219 // check which of the editors has the focus and get the x/y coordinates for the cursor position |
214 |
220 QGraphicsWidget *focused = mScrollAreaContents->focusWidget(); |
215 Q_UNUSED(oldPos); |
221 |
216 |
222 if (focused) { |
217 qreal chromeHeight = 0; |
223 QRectF localRect(0, 0, 0, 0); |
218 HbStyle().parameter("hb-param-widget-chrome-height", chromeHeight); |
224 bool notFound = false; |
219 |
225 |
220 const QSizeF screenReso = mApplication.screenSize(); |
226 if (focused == mHeader->toEdit()) { |
221 qreal maxHeight = screenReso.height() - chromeHeight; |
227 localRect = mHeader->toEdit()->rectForCursorPosition(); |
222 |
228 } |
223 // Get cursor position coordinates |
229 else if (focused == mHeader->ccEdit()) { |
224 QRectF cursorPosPix = mEditorWidget->rectForPosition(newPos); |
230 localRect = mHeader->ccEdit()->rectForCursorPosition(); |
225 |
231 } |
226 // Calculate the screen top and bottom boundaries, this means the part of the |
232 else if (focused == mHeader->bccEdit()) { |
227 // background scroll area which is currently visible. |
233 localRect = mHeader->bccEdit()->rectForCursorPosition(); |
228 qreal visibleRectTopBoundary; |
234 } |
229 qreal visibleRectBottomBoundary; |
235 else if (focused == mHeader->subjectEdit()) { |
230 |
236 localRect = mHeader->subjectEdit()->rectForCursorPosition(); |
231 qreal headerHeight = mHeaderWidget->headerHeight(); |
237 } |
232 |
238 else if (focused == mEditorWidget) { |
233 if (mScrollPosition.y() < headerHeight) { |
239 localRect = mEditorWidget->rectForCursorPosition(); |
234 // Header is completely or partially visible |
240 } |
235 visibleRectTopBoundary = headerHeight - mScrollPosition.y(); |
241 else { |
236 visibleRectBottomBoundary = maxHeight - visibleRectTopBoundary; |
242 notFound = true; |
237 } |
243 } |
238 else { |
244 |
239 // Header is not visible |
245 if (!notFound) { |
240 visibleRectTopBoundary = mScrollPosition.y() - headerHeight; |
246 QPointF topLeftPos = focused->mapToItem(mScrollAreaContents, localRect.topLeft()); |
241 visibleRectBottomBoundary = visibleRectTopBoundary + maxHeight; |
247 QPointF bottomRightPos = |
242 } |
248 focused->mapToItem(mScrollAreaContents, localRect.bottomRight()); |
243 |
249 qreal marginRight = 0; |
244 // Do scrolling if cursor is out of the screen boundaries |
250 HbStyle().parameter("hb-param-margin-gene-right", marginRight); |
245 if (cursorPosPix.y() > visibleRectBottomBoundary) { |
251 bottomRightPos.rx() += marginRight; |
246 // Do scroll forward |
252 mScrollArea->ensureVisible(topLeftPos); |
247 mScrollArea->scrollContentsTo(QPointF(0, cursorPosPix.y() - maxHeight + headerHeight)); |
253 mScrollArea->ensureVisible(bottomRightPos); |
248 } |
254 } |
249 else if (cursorPosPix.y() + headerHeight < mScrollPosition.y()) { |
255 } |
250 // Do scroll backward |
256 } |
251 mScrollArea->scrollContentsTo(QPointF(0, cursorPosPix.y() + headerHeight)); |
|
252 } |
|
253 } |
|
254 |
|
255 /*! |
|
256 This slot is called when background scroll areas scroll position has been shanged. |
|
257 */ |
|
258 void NmEditorContent::updateScrollPosition(const QPointF &newPosition) |
|
259 { |
|
260 NM_FUNCTION; |
|
261 |
|
262 mScrollPosition = newPosition; |
|
263 } |
|
264 |
|
265 /*! |
257 /*! |
266 Removes embedded images from the message body |
258 Removes embedded images from the message body |
267 */ |
259 */ |
268 void NmEditorContent::removeEmbeddedImages(QString &bodyContent) |
260 void NmEditorContent::removeEmbeddedImages(QString &bodyContent) |
269 { |
261 { |