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 double Un = 6.66; |
23 static const char *NMUI_EDITOR_SCROLL_AREA_CONTENTS = "scrollAreaContents"; |
24 static const double HeaderAreaMarginsTotal = 3 * Un; |
24 |
25 |
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 |
26 /*! |
29 /*! |
27 Constructor |
30 Constructor |
28 */ |
31 */ |
29 NmEditorContent::NmEditorContent(QGraphicsItem *parent, |
32 NmEditorContent::NmEditorContent(QObject *parent, |
30 NmEditorView *parentView, |
|
31 HbDocumentLoader *documentLoader, |
33 HbDocumentLoader *documentLoader, |
32 QNetworkAccessManager &manager) : |
34 QNetworkAccessManager &manager, |
33 HbWidget(parent), |
35 NmApplication &application) : |
34 mHeaderWidget(NULL), |
36 QObject(parent), |
35 mParentView(parentView), |
37 mHeader(NULL), |
36 mEditorLayout(NULL), |
38 mMessageBodyType(NmPlainText), |
37 mMessageBodyType(PlainText), |
|
38 mEditorWidget(NULL), |
39 mEditorWidget(NULL), |
39 mBackgroundScrollArea((NmBaseViewScrollArea*)parent) |
40 mScrollArea(NULL), |
40 { |
41 mScrollAreaContents(NULL), |
41 mBackgroundScrollArea->setLongPressEnabled(true); |
42 mApplication(application) |
42 |
43 { |
43 // Add header area handling widget into layout |
44 NM_FUNCTION; |
44 mHeaderWidget = new NmEditorHeader(documentLoader, this); |
45 |
|
46 // Construct container for the header widgets |
|
47 mHeader = new NmEditorHeader(this, documentLoader); |
45 |
48 |
46 // Get pointer to body text area handling widget |
49 // Get pointer to body text area handling widget |
47 mEditorWidget = qobject_cast<NmEditorTextEdit *>(documentLoader->findWidget(NMUI_EDITOR_BODY)); |
50 mEditorWidget = qobject_cast<NmEditorTextEdit *>(documentLoader->findWidget(NMUI_EDITOR_BODY)); |
48 |
51 |
49 // Set body editor to use NmEditorTextDocument |
52 // Set body editor to use NmEditorTextDocument |
50 NmEditorTextDocument *textDocument = new NmEditorTextDocument(manager); |
53 NmEditorTextDocument *textDocument = new NmEditorTextDocument(manager); |
51 mEditorWidget->setDocument(textDocument); |
54 mEditorWidget->setDocument(textDocument); |
52 textDocument->setParent(mEditorWidget); // ownership changes |
55 textDocument->setParent(mEditorWidget); // ownership changes |
53 |
56 |
54 mEditorWidget->init(mBackgroundScrollArea); |
57 mScrollArea = qobject_cast<NmBaseViewScrollArea *> |
55 // we are interested in the editor widget's height changes |
58 (documentLoader->findWidget(NMUI_EDITOR_SCROLL_AREA)); |
56 connect(mEditorWidget, SIGNAL(editorContentHeightChanged()), this, |
59 mScrollArea->setScrollDirections(Qt::Vertical | Qt::Horizontal); |
57 SLOT(setEditorContentHeight())); |
60 |
58 |
|
59 // Enable style picker menu item. |
61 // Enable style picker menu item. |
60 mEditorWidget->setFormatDialog(new HbFormatDialog()); |
62 mEditorWidget->setFormatDialog(new HbFormatDialog()); |
61 |
63 |
|
64 mScrollAreaContents = |
|
65 qobject_cast<HbWidget *>(documentLoader->findWidget(NMUI_EDITOR_SCROLL_AREA_CONTENTS)); |
|
66 |
62 // Create signal slot connections |
67 // Create signal slot connections |
63 createConnections(); |
68 createConnections(); |
64 } |
69 } |
65 |
70 |
66 /*! |
71 /*! |
67 Destructor |
72 Destructor |
68 */ |
73 */ |
69 NmEditorContent::~NmEditorContent() |
74 NmEditorContent::~NmEditorContent() |
70 { |
75 { |
71 delete mHeaderWidget; |
76 NM_FUNCTION; |
72 } |
77 } |
73 |
78 |
74 /*! |
79 /*! |
75 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 |
76 present, reply header is generated and set to editor. Reply |
81 present, reply header is generated and set to editor. Reply |
77 envelope ownership is not transferred here. |
82 envelope ownership is not transferred here. |
78 */ |
83 */ |
79 void NmEditorContent::setMessageData(const NmMessage &message, |
84 void NmEditorContent::setMessageData(const NmMessage &originalMessage, |
80 NmMessageEnvelope *replyMsgEnvelope) |
85 NmUiEditorStartMode &editorStartMode) |
81 { |
86 { |
82 // Check which part is present. Html or plain text part |
87 NM_FUNCTION; |
83 const NmMessagePart *htmlPart = message.htmlBodyPart(); |
88 |
84 const NmMessagePart *plainPart = message.plainTextBodyPart(); |
89 QString bodyContent; |
85 |
90 |
86 QList<NmMessagePart*> parts; |
91 // Create the "reply" header (also for forward message) |
87 message.attachmentList(parts); |
92 if (editorStartMode==NmUiEditorReply || editorStartMode==NmUiEditorReplyAll || |
88 NmMessagePart* attachmentHtml = NULL; |
93 editorStartMode==NmUiEditorForward) { |
89 |
94 bodyContent.append(NmUtilities::createReplyHeader(originalMessage.envelope())); |
90 foreach(NmMessagePart* part, parts) { |
95 } |
91 if (part->contentDescription().startsWith( NmContentDescrAttachmentHtml )) { |
96 |
92 attachmentHtml = part; |
97 // Check which part is present. Html or plain text part. We use the original message parts. |
93 } |
98 const NmMessagePart *htmlPart = originalMessage.htmlBodyPart(); |
94 } |
99 const NmMessagePart *plainPart = originalMessage.plainTextBodyPart(); |
95 |
100 |
96 if (htmlPart) { |
101 if (htmlPart) { |
97 // Html part was present, set it to HbTextEdit |
102 bodyContent.append(htmlPart->textContent()); |
98 // This will generate contentsChanged() event which is used to |
103 if(editorStartMode==NmUiEditorReply || editorStartMode==NmUiEditorReplyAll ) { |
99 // set new height for the editor widget and content. |
104 removeEmbeddedImages(bodyContent); |
100 if(attachmentHtml){ |
105 } |
101 QString htmlText = htmlPart->textContent() + attachmentHtml->textContent(); |
106 emit setHtml(bodyContent); |
102 emit setHtml(htmlText); |
107 mMessageBodyType = NmHTMLText; |
103 } |
|
104 else{ |
|
105 emit setHtml(htmlPart->textContent()); |
|
106 } |
|
107 mMessageBodyType = HTMLText; |
|
108 } |
108 } |
109 else if (plainPart) { |
109 else if (plainPart) { |
110 // Plain text part was present, set it to HbTextEdit |
110 // Plain text part was present, set it to HbTextEdit |
111 emit setPlainText(plainPart->textContent()); |
111 bodyContent.append(plainPart->textContent()); |
112 mMessageBodyType = PlainText; |
112 emit setPlainText(bodyContent); |
113 } |
113 mMessageBodyType = NmPlainText; |
114 |
|
115 // Original message text to editor content fiel |
|
116 if (replyMsgEnvelope && mEditorWidget) { |
|
117 QTextCursor cursor = mEditorWidget->textCursor(); |
|
118 cursor.setPosition(0); |
|
119 cursor.insertHtml(NmUtilities::createReplyHeader(*replyMsgEnvelope)); |
|
120 } |
114 } |
121 } |
115 } |
122 |
116 |
123 /*! |
117 /*! |
124 This method set new height for the editor content when header or body field |
|
125 height has been changed. |
|
126 */ |
|
127 void NmEditorContent::setEditorContentHeight() |
|
128 { |
|
129 const QSizeF reso = HbDeviceProfile::current().logicalSize(); |
|
130 qreal containerHeight = |
|
131 mEditorWidget->contentHeight() + mHeaderWidget->headerHeight() + HeaderAreaMarginsTotal; |
|
132 if (containerHeight < reso.height()) { |
|
133 //Currently content height is too long because Chrome hiding is not supported. |
|
134 //Fix this when Chrome works. |
|
135 containerHeight = reso.height(); |
|
136 qreal bodyContentHeight = |
|
137 reso.height() - mHeaderWidget->headerHeight() - HeaderAreaMarginsTotal; |
|
138 mEditorWidget->setPreferredHeight(bodyContentHeight); |
|
139 mEditorWidget->setMaximumHeight(bodyContentHeight); |
|
140 } |
|
141 mParentView->scrollAreaContents()->setMinimumHeight(containerHeight); |
|
142 mParentView->scrollAreaContents()->setMaximumHeight(containerHeight); |
|
143 mBackgroundScrollArea->setMaximumHeight(containerHeight); |
|
144 } |
|
145 |
|
146 /*! |
|
147 This method creates all needed signal-slot connections |
118 This method creates all needed signal-slot connections |
148 */ |
119 */ |
149 void NmEditorContent::createConnections() |
120 void NmEditorContent::createConnections() |
150 { |
121 { |
151 // Body edit widget is also interested about bg scroll position change |
122 NM_FUNCTION; |
152 connect(mBackgroundScrollArea, SIGNAL(scrollPositionChanged(QPointF)), |
123 |
153 mEditorWidget, SLOT(updateScrollPosition(QPointF))); |
|
154 // Signal for setting HbTextEdit widgets html content |
124 // Signal for setting HbTextEdit widgets html content |
155 connect(this, SIGNAL(setHtml(QString)), |
125 connect(this, SIGNAL(setHtml(QString)), |
156 mEditorWidget, SLOT(setHtml(QString))); |
126 mEditorWidget, SLOT(setHtml(QString)), Qt::QueuedConnection); |
|
127 |
157 // Signal for setting HbTextEdit widgets plain text content |
128 // Signal for setting HbTextEdit widgets plain text content |
158 connect(this, SIGNAL(setPlainText(QString)), |
129 connect(this, SIGNAL(setPlainText(QString)), |
159 mEditorWidget, SLOT(setPlainText(QString))); |
130 mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection); |
|
131 |
160 // Inform text edit widget that header height has been changed |
132 // Inform text edit widget that header height has been changed |
161 connect(mHeaderWidget, SIGNAL(headerHeightChanged(int)), |
133 connect(mHeader, SIGNAL(headerHeightChanged(int)), this, SLOT(setEditorContentHeight()), |
162 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); |
163 } |
155 } |
164 |
156 |
165 /*! |
157 /*! |
166 Return pointer to the email body text edit widget |
158 Return pointer to the email body text edit widget |
167 */ |
159 */ |
168 NmEditorTextEdit* NmEditorContent::editor() const |
160 NmEditorTextEdit *NmEditorContent::editor() const |
169 { |
161 { |
|
162 NM_FUNCTION; |
|
163 |
170 return mEditorWidget; |
164 return mEditorWidget; |
171 } |
165 } |
172 |
166 |
173 /*! |
167 /*! |
174 Return pointer to the header widget |
168 Return pointer to the header widget |
175 */ |
169 */ |
176 NmEditorHeader* NmEditorContent::header() const |
170 NmEditorHeader *NmEditorContent::header() const |
177 { |
171 { |
178 return mHeaderWidget; |
172 NM_FUNCTION; |
179 } |
173 |
180 |
174 return mHeader; |
|
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 } |