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) : |
31 mHeaderWidget(NULL), |
36 QObject(parent), |
32 mParentView(parentView), |
37 mHeader(NULL), |
33 mEditorLayout(NULL), |
38 mMessageBodyType(NmPlainText), |
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 mHeader = 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->findWidget(NMUI_EDITOR_SCROLL_AREA)); |
53 connect(mEditorWidget, SIGNAL(editorContentHeightChanged()), this, |
59 mScrollArea->setScrollDirections(Qt::Vertical | Qt::Horizontal); |
54 SLOT(setEditorContentHeight())); |
60 |
55 |
|
56 // Enable style picker menu item. |
61 // Enable style picker menu item. |
57 mEditorWidget->setFormatDialog(new HbFormatDialog()); |
62 mEditorWidget->setFormatDialog(new HbFormatDialog()); |
58 |
63 |
|
64 mScrollAreaContents = |
|
65 qobject_cast<HbWidget *>(documentLoader->findWidget(NMUI_EDITOR_SCROLL_AREA_CONTENTS)); |
|
66 |
59 // Create signal slot connections |
67 // Create signal slot connections |
60 createConnections(); |
68 createConnections(); |
61 } |
69 } |
62 |
70 |
63 /*! |
71 /*! |
64 Destructor |
72 Destructor |
65 */ |
73 */ |
66 NmEditorContent::~NmEditorContent() |
74 NmEditorContent::~NmEditorContent() |
67 { |
75 { |
68 NM_FUNCTION; |
76 NM_FUNCTION; |
69 |
|
70 delete mHeaderWidget; |
|
71 } |
77 } |
72 |
78 |
73 /*! |
79 /*! |
74 Fill message data into header and body fileds. If reply envelopw is |
80 Fill message data into header and body fileds. If reply envelopw is |
75 present, reply header is generated and set to editor. Reply |
81 present, reply header is generated and set to editor. Reply |
76 envelope ownership is not transferred here. |
82 envelope ownership is not transferred here. |
77 */ |
83 */ |
78 void NmEditorContent::setMessageData(const NmMessage &originalMessage, |
84 void NmEditorContent::setMessageData(const NmMessage &originalMessage, |
79 bool createReplyHeader) |
85 NmUiEditorStartMode &editorStartMode) |
80 { |
86 { |
81 NM_FUNCTION; |
87 NM_FUNCTION; |
82 |
88 |
83 QString bodyContent; |
89 QString bodyContent; |
84 |
90 |
85 // We create the "reply" header (also for forward message), but not to draft message. |
91 // Create the "reply" header (also for forward message) |
86 if (mEditorWidget && createReplyHeader) { |
92 if (editorStartMode==NmUiEditorReply || editorStartMode==NmUiEditorReplyAll || |
87 QTextCursor cursor = mEditorWidget->textCursor(); |
93 editorStartMode==NmUiEditorForward) { |
88 cursor.setPosition(0); |
94 bodyContent.append(NmUtilities::createReplyHeader(originalMessage.envelope())); |
89 cursor.insertHtml(NmUtilities::createReplyHeader(originalMessage.envelope())); |
95 } |
90 } |
|
91 // Take reply header as html format. |
|
92 bodyContent.append(mEditorWidget->toHtml()); |
|
93 |
96 |
94 // Check which part is present. Html or plain text part. We use the original message parts. |
97 // Check which part is present. Html or plain text part. We use the original message parts. |
95 const NmMessagePart *htmlPart = originalMessage.htmlBodyPart(); |
98 const NmMessagePart *htmlPart = originalMessage.htmlBodyPart(); |
96 const NmMessagePart *plainPart = originalMessage.plainTextBodyPart(); |
99 const NmMessagePart *plainPart = originalMessage.plainTextBodyPart(); |
97 |
100 |
98 if (htmlPart && mEditorWidget) { |
101 if (htmlPart) { |
99 bodyContent.append(htmlPart->textContent()); |
102 bodyContent.append(htmlPart->textContent()); |
|
103 if(editorStartMode==NmUiEditorReply || editorStartMode==NmUiEditorReplyAll ) { |
|
104 removeEmbeddedImages(bodyContent); |
|
105 } |
100 emit setHtml(bodyContent); |
106 emit setHtml(bodyContent); |
101 mMessageBodyType = HTMLText; |
107 mMessageBodyType = NmHTMLText; |
102 } |
108 } |
103 else if (plainPart) { |
109 else if (plainPart) { |
104 // Plain text part was present, set it to HbTextEdit |
110 // Plain text part was present, set it to HbTextEdit |
105 bodyContent.append(plainPart->textContent()); |
111 bodyContent.append(plainPart->textContent()); |
106 emit setPlainText(bodyContent); |
112 emit setPlainText(bodyContent); |
107 mMessageBodyType = PlainText; |
113 mMessageBodyType = NmPlainText; |
108 } |
114 } |
109 } |
115 } |
110 |
116 |
111 /*! |
117 /*! |
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 |
118 This method creates all needed signal-slot connections |
137 */ |
119 */ |
138 void NmEditorContent::createConnections() |
120 void NmEditorContent::createConnections() |
139 { |
121 { |
140 NM_FUNCTION; |
122 NM_FUNCTION; |
141 |
123 |
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 |
124 // Signal for setting HbTextEdit widgets html content |
146 connect(this, SIGNAL(setHtml(QString)), |
125 connect(this, SIGNAL(setHtml(QString)), |
147 mEditorWidget, SLOT(setHtml(QString)), Qt::QueuedConnection); |
126 mEditorWidget, SLOT(setHtml(QString)), Qt::QueuedConnection); |
|
127 |
148 // Signal for setting HbTextEdit widgets plain text content |
128 // Signal for setting HbTextEdit widgets plain text content |
149 connect(this, SIGNAL(setPlainText(QString)), |
129 connect(this, SIGNAL(setPlainText(QString)), |
150 mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection); |
130 mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection); |
|
131 |
151 // Inform text edit widget that header height has been changed |
132 // Inform text edit widget that header height has been changed |
152 connect(mHeaderWidget, SIGNAL(headerHeightChanged(int)), |
133 connect(mHeader, SIGNAL(headerHeightChanged(int)), this, SLOT(setEditorContentHeight()), |
153 mEditorWidget, SLOT(setHeaderHeight(int))); |
134 Qt::QueuedConnection); |
|
135 |
|
136 // we are interested in the document's height changes |
|
137 connect(mEditorWidget->document()->documentLayout(), SIGNAL(documentSizeChanged(QSizeF)), this, |
|
138 SLOT(setEditorContentHeight()), Qt::QueuedConnection); |
|
139 |
|
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); |
|
149 connect(mEditorWidget, SIGNAL(cursorPositionChanged(int, int)), this, |
|
150 SLOT(ensureCursorVisibility()), Qt::QueuedConnection); |
|
151 |
|
152 // listen to the parent's (NmEditorView) size changes which happen eg. when VKB is opened/closed |
|
153 connect(parent(), SIGNAL(sizeChanged()), this, SLOT(ensureCursorVisibility()), |
|
154 Qt::QueuedConnection); |
154 } |
155 } |
155 |
156 |
156 /*! |
157 /*! |
157 Return pointer to the email body text edit widget |
158 Return pointer to the email body text edit widget |
158 */ |
159 */ |
159 NmEditorTextEdit* NmEditorContent::editor() const |
160 NmEditorTextEdit *NmEditorContent::editor() const |
160 { |
161 { |
161 NM_FUNCTION; |
162 NM_FUNCTION; |
162 |
163 |
163 return mEditorWidget; |
164 return mEditorWidget; |
164 } |
165 } |
165 |
166 |
166 /*! |
167 /*! |
167 Return pointer to the header widget |
168 Return pointer to the header widget |
168 */ |
169 */ |
169 NmEditorHeader* NmEditorContent::header() const |
170 NmEditorHeader *NmEditorContent::header() const |
170 { |
171 { |
171 NM_FUNCTION; |
172 NM_FUNCTION; |
172 |
173 |
173 return mHeaderWidget; |
174 return mHeader; |
174 } |
175 } |
175 |
176 |
|
177 /*! |
|
178 This slot is called when header widget height has been changed. Function performs |
|
179 the repositioning of the body field and resizing of the editor and content area. |
|
180 */ |
|
181 void NmEditorContent::setEditorContentHeight() |
|
182 { |
|
183 NM_FUNCTION; |
|
184 |
|
185 // the height of the margin between the title bar and the header |
|
186 qreal topMargin = 0; |
|
187 HbStyle().parameter("hb-param-margin-gene-top", topMargin); |
|
188 |
|
189 // header height |
|
190 qreal headerHeight = mHeader->headerHeight(); |
|
191 |
|
192 // body area editor's document height with margins added |
|
193 qreal documentHeightAndMargins = mEditorWidget->document()->size().height() + |
|
194 (mEditorWidget->document()->documentMargin() * 2); |
|
195 |
|
196 // chrome height |
|
197 qreal chromeHeight = 0; |
|
198 HbStyle().parameter("hb-param-widget-chrome-height", chromeHeight); |
|
199 |
|
200 // screen height |
|
201 qreal screenHeight = mApplication.screenSize().height(); |
|
202 |
|
203 // set min size for the body area so that at least the screen area is always filled |
|
204 qreal bodyAreaMinSize = screenHeight - chromeHeight - topMargin - headerHeight; |
|
205 |
|
206 qreal bodyAreaSize = fmax(bodyAreaMinSize, documentHeightAndMargins); |
|
207 |
|
208 mScrollAreaContents->setPreferredHeight(topMargin + headerHeight + bodyAreaSize); |
|
209 } |
|
210 |
|
211 /*! |
|
212 This slot is called when the cursor visibility has to be ensured ie. the scroll position is |
|
213 adjusted so that the cursor can be seen. |
|
214 */ |
|
215 void NmEditorContent::ensureCursorVisibility() |
|
216 { |
|
217 NM_FUNCTION; |
|
218 |
|
219 // check which of the editors has the focus and get the x/y coordinates for the cursor position |
|
220 QGraphicsWidget *focused = mScrollAreaContents->focusWidget(); |
|
221 |
|
222 if (focused) { |
|
223 QRectF localRect(0, 0, 0, 0); |
|
224 bool notFound = false; |
|
225 |
|
226 if (focused == mHeader->toEdit()) { |
|
227 localRect = mHeader->toEdit()->rectForCursorPosition(); |
|
228 } |
|
229 else if (focused == mHeader->ccEdit()) { |
|
230 localRect = mHeader->ccEdit()->rectForCursorPosition(); |
|
231 } |
|
232 else if (focused == mHeader->bccEdit()) { |
|
233 localRect = mHeader->bccEdit()->rectForCursorPosition(); |
|
234 } |
|
235 else if (focused == mHeader->subjectEdit()) { |
|
236 localRect = mHeader->subjectEdit()->rectForCursorPosition(); |
|
237 } |
|
238 else if (focused == mEditorWidget) { |
|
239 localRect = mEditorWidget->rectForCursorPosition(); |
|
240 } |
|
241 else { |
|
242 notFound = true; |
|
243 } |
|
244 |
|
245 if (!notFound) { |
|
246 QPointF topLeftPos = focused->mapToItem(mScrollAreaContents, localRect.topLeft()); |
|
247 QPointF bottomRightPos = |
|
248 focused->mapToItem(mScrollAreaContents, localRect.bottomRight()); |
|
249 qreal marginRight = 0; |
|
250 HbStyle().parameter("hb-param-margin-gene-right", marginRight); |
|
251 bottomRightPos.rx() += marginRight; |
|
252 mScrollArea->ensureVisible(topLeftPos); |
|
253 mScrollArea->ensureVisible(bottomRightPos); |
|
254 } |
|
255 } |
|
256 } |
|
257 /*! |
|
258 Removes embedded images from the message body |
|
259 */ |
|
260 void NmEditorContent::removeEmbeddedImages(QString &bodyContent) |
|
261 { |
|
262 NM_FUNCTION; |
|
263 |
|
264 QRegExp regExp(NMUI_EDITOR_REMOVE_EMBD_IMAGES_REG, Qt::CaseInsensitive); |
|
265 bodyContent.remove(regExp); |
|
266 } |