17 |
17 |
18 #include "nmuiheaders.h" |
18 #include "nmuiheaders.h" |
19 |
19 |
20 // Layout |
20 // Layout |
21 static const char *NMUI_EDITOR_BODY = "BodyTextEdit"; |
21 static const char *NMUI_EDITOR_BODY = "BodyTextEdit"; |
22 |
22 static const char *NMUI_EDITOR_SCROLL_AREA = "scrollArea"; |
|
23 static const char *NMUI_EDITOR_SCROLL_AREA_CONTENTS = "scrollAreaContents"; |
|
24 |
|
25 // Regular expression for selecting img tags with "cid" in the mail. |
|
26 static const char *NMUI_EDITOR_REMOVE_EMBD_IMAGES_REG = |
|
27 "(<img (src\\s*=\\s*)(.{0,1}cid)([^<]+)(>\\s*|/>\\s*|></img>\\s*))"; |
|
28 |
23 /*! |
29 /*! |
24 Constructor |
30 Constructor |
25 */ |
31 */ |
26 NmEditorContent::NmEditorContent(QGraphicsItem *parent, |
32 NmEditorContent::NmEditorContent(QObject *parent, |
27 NmEditorView *parentView, |
|
28 HbDocumentLoader *documentLoader, |
33 HbDocumentLoader *documentLoader, |
29 QNetworkAccessManager &manager) : |
34 QNetworkAccessManager &manager, |
30 HbWidget(parent), |
35 NmApplication &application) : |
|
36 QObject(parent), |
31 mHeaderWidget(NULL), |
37 mHeaderWidget(NULL), |
32 mParentView(parentView), |
38 mMessageBodyType(NmPlainText), |
33 mEditorLayout(NULL), |
|
34 mMessageBodyType(PlainText), |
|
35 mEditorWidget(NULL), |
39 mEditorWidget(NULL), |
36 mBackgroundScrollArea((NmBaseViewScrollArea*)parent) |
40 mScrollArea(NULL), |
37 { |
41 mScrollAreaContents(NULL), |
38 NM_FUNCTION; |
42 mApplication(application) |
39 |
43 { |
40 // Add header area handling widget into layout |
44 NM_FUNCTION; |
41 mHeaderWidget = new NmEditorHeader(documentLoader); |
45 |
|
46 // Construct container for the header widgets |
|
47 mHeaderWidget = new NmEditorHeader(this, documentLoader); |
42 |
48 |
43 // Get pointer to body text area handling widget |
49 // Get pointer to body text area handling widget |
44 mEditorWidget = qobject_cast<NmEditorTextEdit *>(documentLoader->findWidget(NMUI_EDITOR_BODY)); |
50 mEditorWidget = qobject_cast<NmEditorTextEdit *>(documentLoader->findWidget(NMUI_EDITOR_BODY)); |
45 |
51 |
46 // Set body editor to use NmEditorTextDocument |
52 // Set body editor to use NmEditorTextDocument |
47 NmEditorTextDocument *textDocument = new NmEditorTextDocument(manager); |
53 NmEditorTextDocument *textDocument = new NmEditorTextDocument(manager); |
48 mEditorWidget->setDocument(textDocument); |
54 mEditorWidget->setDocument(textDocument); |
49 textDocument->setParent(mEditorWidget); // ownership changes |
55 textDocument->setParent(mEditorWidget); // ownership changes |
50 |
56 |
51 mEditorWidget->init(mBackgroundScrollArea); |
57 mScrollArea = qobject_cast<NmBaseViewScrollArea *> |
52 // we are interested in the editor widget's height changes |
58 (documentLoader->findObject(NMUI_EDITOR_SCROLL_AREA)); |
53 connect(mEditorWidget, SIGNAL(editorContentHeightChanged()), this, |
|
54 SLOT(setEditorContentHeight())); |
|
55 |
59 |
56 // Enable style picker menu item. |
60 // Enable style picker menu item. |
57 mEditorWidget->setFormatDialog(new HbFormatDialog()); |
61 mEditorWidget->setFormatDialog(new HbFormatDialog()); |
58 |
62 |
|
63 mScrollAreaContents = |
|
64 qobject_cast<HbWidget *>(documentLoader->findWidget(NMUI_EDITOR_SCROLL_AREA_CONTENTS)); |
|
65 |
59 // Create signal slot connections |
66 // Create signal slot connections |
60 createConnections(); |
67 createConnections(); |
61 } |
68 } |
62 |
69 |
63 /*! |
70 /*! |
64 Destructor |
71 Destructor |
65 */ |
72 */ |
66 NmEditorContent::~NmEditorContent() |
73 NmEditorContent::~NmEditorContent() |
67 { |
74 { |
68 NM_FUNCTION; |
75 NM_FUNCTION; |
69 |
|
70 delete mHeaderWidget; |
|
71 } |
76 } |
72 |
77 |
73 /*! |
78 /*! |
74 Fill message data into header and body fileds. If reply envelopw is |
79 Fill message data into header and body fileds. If reply envelopw is |
75 present, reply header is generated and set to editor. Reply |
80 present, reply header is generated and set to editor. Reply |
76 envelope ownership is not transferred here. |
81 envelope ownership is not transferred here. |
77 */ |
82 */ |
78 void NmEditorContent::setMessageData(const NmMessage &originalMessage, |
83 void NmEditorContent::setMessageData(const NmMessage &originalMessage, |
79 bool createReplyHeader) |
84 NmUiEditorStartMode &editorStartMode) |
80 { |
85 { |
81 NM_FUNCTION; |
86 NM_FUNCTION; |
82 |
87 |
83 QString bodyContent; |
88 QString bodyContent; |
84 |
89 |
85 // We create the "reply" header (also for forward message), but not to draft message. |
90 // Create the "reply" header (also for forward message) |
86 if (mEditorWidget && createReplyHeader) { |
91 if (editorStartMode==NmUiEditorReply || editorStartMode==NmUiEditorReplyAll || |
87 QTextCursor cursor = mEditorWidget->textCursor(); |
92 editorStartMode==NmUiEditorForward) { |
88 cursor.setPosition(0); |
93 bodyContent.append(NmUtilities::createReplyHeader(originalMessage.envelope())); |
89 cursor.insertHtml(NmUtilities::createReplyHeader(originalMessage.envelope())); |
94 } |
90 } |
|
91 // Take reply header as html format. |
|
92 bodyContent.append(mEditorWidget->toHtml()); |
|
93 |
95 |
94 // Check which part is present. Html or plain text part. We use the original message parts. |
96 // Check which part is present. Html or plain text part. We use the original message parts. |
95 const NmMessagePart *htmlPart = originalMessage.htmlBodyPart(); |
97 const NmMessagePart *htmlPart = originalMessage.htmlBodyPart(); |
96 const NmMessagePart *plainPart = originalMessage.plainTextBodyPart(); |
98 const NmMessagePart *plainPart = originalMessage.plainTextBodyPart(); |
97 |
99 |
98 if (htmlPart && mEditorWidget) { |
100 if (htmlPart) { |
99 bodyContent.append(htmlPart->textContent()); |
101 bodyContent.append(htmlPart->textContent()); |
|
102 if(editorStartMode==NmUiEditorReply || editorStartMode==NmUiEditorReplyAll ) { |
|
103 removeEmbeddedImages(bodyContent); |
|
104 } |
100 emit setHtml(bodyContent); |
105 emit setHtml(bodyContent); |
101 mMessageBodyType = HTMLText; |
106 mMessageBodyType = NmHTMLText; |
102 } |
107 } |
103 else if (plainPart) { |
108 else if (plainPart) { |
104 // Plain text part was present, set it to HbTextEdit |
109 // Plain text part was present, set it to HbTextEdit |
105 bodyContent.append(plainPart->textContent()); |
110 bodyContent.append(plainPart->textContent()); |
106 emit setPlainText(bodyContent); |
111 emit setPlainText(bodyContent); |
107 mMessageBodyType = PlainText; |
112 mMessageBodyType = NmPlainText; |
108 } |
113 } |
109 } |
114 } |
110 |
115 |
111 /*! |
116 /*! |
112 This method set new height for the editor content when header or body field |
|
113 height has been changed. |
|
114 */ |
|
115 void NmEditorContent::setEditorContentHeight() |
|
116 { |
|
117 NM_FUNCTION; |
|
118 |
|
119 const QSizeF reso = HbDeviceProfile::current().logicalSize(); |
|
120 qreal containerHeight = mEditorWidget->contentHeight() + mHeaderWidget->headerHeight(); |
|
121 if (containerHeight < reso.height()) { |
|
122 //Currently content height is too long because Chrome hiding is not supported. |
|
123 //Fix this when Chrome works. |
|
124 containerHeight = reso.height(); |
|
125 qreal bodyContentHeight = |
|
126 reso.height() - mHeaderWidget->headerHeight(); |
|
127 mEditorWidget->setPreferredHeight(bodyContentHeight); |
|
128 mEditorWidget->setMaximumHeight(bodyContentHeight); |
|
129 } |
|
130 mParentView->scrollAreaContents()->setMinimumHeight(containerHeight); |
|
131 mParentView->scrollAreaContents()->setMaximumHeight(containerHeight); |
|
132 mBackgroundScrollArea->setMaximumHeight(containerHeight); |
|
133 } |
|
134 |
|
135 /*! |
|
136 This method creates all needed signal-slot connections |
117 This method creates all needed signal-slot connections |
137 */ |
118 */ |
138 void NmEditorContent::createConnections() |
119 void NmEditorContent::createConnections() |
139 { |
120 { |
140 NM_FUNCTION; |
121 NM_FUNCTION; |
141 |
122 |
142 // Body edit widget is also interested about bg scroll position change |
|
143 connect(mBackgroundScrollArea, SIGNAL(scrollPositionChanged(QPointF)), |
|
144 mEditorWidget, SLOT(updateScrollPosition(QPointF))); |
|
145 // Signal for setting HbTextEdit widgets html content |
123 // Signal for setting HbTextEdit widgets html content |
146 connect(this, SIGNAL(setHtml(QString)), |
124 connect(this, SIGNAL(setHtml(QString)), |
147 mEditorWidget, SLOT(setHtml(QString)), Qt::QueuedConnection); |
125 mEditorWidget, SLOT(setHtml(QString)), Qt::QueuedConnection); |
|
126 |
148 // Signal for setting HbTextEdit widgets plain text content |
127 // Signal for setting HbTextEdit widgets plain text content |
149 connect(this, SIGNAL(setPlainText(QString)), |
128 connect(this, SIGNAL(setPlainText(QString)), |
150 mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection); |
129 mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection); |
|
130 |
151 // Inform text edit widget that header height has been changed |
131 // Inform text edit widget that header height has been changed |
152 connect(mHeaderWidget, SIGNAL(headerHeightChanged(int)), |
132 connect(mHeaderWidget, SIGNAL(headerHeightChanged(int)), this, SLOT(setEditorContentHeight()), |
153 mEditorWidget, SLOT(setHeaderHeight(int))); |
133 Qt::QueuedConnection); |
|
134 |
|
135 // we are interested in the document's height changes |
|
136 connect(mEditorWidget->document()->documentLayout(), SIGNAL(documentSizeChanged(QSizeF)), this, |
|
137 SLOT(setEditorContentHeight()), Qt::QueuedConnection); |
|
138 |
|
139 // We need to update the scroll position according the editor cursor position |
|
140 connect(mEditorWidget, SIGNAL(cursorPositionChanged(int, int)), this, |
|
141 SLOT(setScrollPosition(int, int)), Qt::QueuedConnection); |
|
142 |
|
143 // We need to know the scroll area's current position for calculating the new position in |
|
144 // setScrollPosition |
|
145 connect(mScrollArea, SIGNAL(scrollPositionChanged(QPointF)), this, |
|
146 SLOT(updateScrollPosition(QPointF)), Qt::QueuedConnection); |
154 } |
147 } |
155 |
148 |
156 /*! |
149 /*! |
157 Return pointer to the email body text edit widget |
150 Return pointer to the email body text edit widget |
158 */ |
151 */ |
159 NmEditorTextEdit* NmEditorContent::editor() const |
152 NmEditorTextEdit *NmEditorContent::editor() const |
160 { |
153 { |
161 NM_FUNCTION; |
154 NM_FUNCTION; |
162 |
155 |
163 return mEditorWidget; |
156 return mEditorWidget; |
164 } |
157 } |
165 |
158 |
166 /*! |
159 /*! |
167 Return pointer to the header widget |
160 Return pointer to the header widget |
168 */ |
161 */ |
169 NmEditorHeader* NmEditorContent::header() const |
162 NmEditorHeader *NmEditorContent::header() const |
170 { |
163 { |
171 NM_FUNCTION; |
164 NM_FUNCTION; |
172 |
165 |
173 return mHeaderWidget; |
166 return mHeaderWidget; |
174 } |
167 } |
175 |
168 |
|
169 /*! |
|
170 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. |
|
172 */ |
|
173 void NmEditorContent::setEditorContentHeight() |
|
174 { |
|
175 NM_FUNCTION; |
|
176 |
|
177 qreal topMargin = 0; |
|
178 HbStyle().parameter("hb-param-margin-gene-top", topMargin); |
|
179 |
|
180 // header height |
|
181 qreal headerHeight = mHeaderWidget->headerHeight(); |
|
182 |
|
183 // body area editor's document height with margins added |
|
184 qreal documentHeightAndMargins = mEditorWidget->document()->size().height() + |
|
185 (mEditorWidget->document()->documentMargin() * 2); |
|
186 |
|
187 // get the chrome height |
|
188 qreal chromeHeight = 0; |
|
189 HbStyle().parameter("hb-param-widget-chrome-height", chromeHeight); |
|
190 |
|
191 qreal toolbarHeight = 0; |
|
192 HbStyle().parameter("hb-param-widget-toolbar-height", toolbarHeight); |
|
193 |
|
194 // screen height |
|
195 qreal screenHeight = mApplication.screenSize().height(); |
|
196 |
|
197 // set min size for the body area so that at least the screen area is always filled |
|
198 qreal bodyAreaMinSize = screenHeight - chromeHeight - topMargin - headerHeight; |
|
199 |
|
200 qreal bodyAreaSize = fmax(bodyAreaMinSize, documentHeightAndMargins); |
|
201 |
|
202 mScrollAreaContents->setPreferredHeight(topMargin + headerHeight + bodyAreaSize); |
|
203 } |
|
204 |
|
205 /*! |
|
206 This slot is called when cursor position is changed in body area using |
|
207 'pointing stick' or keyboard. Function will update the scroll position |
|
208 of the content so that cursor does not go outside of the screen or |
|
209 behind the virtual keyboard. |
|
210 */ |
|
211 void NmEditorContent::setScrollPosition(int oldPos, int newPos) |
|
212 { |
|
213 NM_FUNCTION; |
|
214 |
|
215 Q_UNUSED(oldPos); |
|
216 |
|
217 qreal chromeHeight = 0; |
|
218 HbStyle().parameter("hb-param-widget-chrome-height", chromeHeight); |
|
219 |
|
220 const QSizeF screenReso = mApplication.screenSize(); |
|
221 qreal maxHeight = screenReso.height() - chromeHeight; |
|
222 |
|
223 // Get cursor position coordinates |
|
224 QRectF cursorPosPix = mEditorWidget->rectForPosition(newPos); |
|
225 |
|
226 // Calculate the screen top and bottom boundaries, this means the part of the |
|
227 // background scroll area which is currently visible. |
|
228 qreal visibleRectTopBoundary; |
|
229 qreal visibleRectBottomBoundary; |
|
230 |
|
231 qreal headerHeight = mHeaderWidget->headerHeight(); |
|
232 |
|
233 if (mScrollPosition.y() < headerHeight) { |
|
234 // Header is completely or partially visible |
|
235 visibleRectTopBoundary = headerHeight - mScrollPosition.y(); |
|
236 visibleRectBottomBoundary = maxHeight - visibleRectTopBoundary; |
|
237 } |
|
238 else { |
|
239 // Header is not visible |
|
240 visibleRectTopBoundary = mScrollPosition.y() - headerHeight; |
|
241 visibleRectBottomBoundary = visibleRectTopBoundary + maxHeight; |
|
242 } |
|
243 |
|
244 // Do scrolling if cursor is out of the screen boundaries |
|
245 if (cursorPosPix.y() > visibleRectBottomBoundary) { |
|
246 // Do scroll forward |
|
247 mScrollArea->scrollContentsTo(QPointF(0, cursorPosPix.y() - maxHeight + headerHeight)); |
|
248 } |
|
249 else if (cursorPosPix.y() + headerHeight < mScrollPosition.y()) { |
|
250 // Do scroll backward |
|
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 /*! |
|
266 Removes embedded images from the message body |
|
267 */ |
|
268 void NmEditorContent::removeEmbeddedImages(QString &bodyContent) |
|
269 { |
|
270 NM_FUNCTION; |
|
271 |
|
272 QRegExp regExp(NMUI_EDITOR_REMOVE_EMBD_IMAGES_REG, Qt::CaseInsensitive); |
|
273 bodyContent.remove(regExp); |
|
274 } |