9 * Initial Contributors: |
9 * Initial Contributors: |
10 * Nokia Corporation - initial contribution. |
10 * Nokia Corporation - initial contribution. |
11 * |
11 * |
12 * Contributors: |
12 * Contributors: |
13 * |
13 * |
14 * Description: nmrecipientlineedit.cpp |
14 * Description: implementation of recipient field (to, cc, bcc) line editor |
15 * |
15 * |
16 */ |
16 */ |
17 |
17 |
18 #include "nmailuiwidgetsheaders.h" |
18 #include "nmailuiwidgetsheaders.h" |
19 |
19 |
20 static const QString Semicolon(";"); |
20 static const QString NmRecipientLineEditSemicolon(";"); |
21 static const QString Delimiter("; "); |
21 static const QString NmRecipientLineEditDelimiter("; "); |
22 static const QRegExp CommaOrSemicolon("[,;]"); |
22 static const QRegExp NmRecipientLineEditCommaOrSemicolon("[,;]"); |
23 |
23 |
24 |
24 static const int NmRecipientLineEditFadedAlpha(125); |
|
25 |
|
26 static const int NmRecipientLineEditForegroundZValue(200); |
|
27 static const int NmRecipientLineEditBackgroundZValue(0); |
|
28 |
|
29 static const QString FILE_PATH_WIDGETML = ":nmrecipientlineedit.widgetml"; |
|
30 static const QString FILE_PATH_CSS = ":nmrecipientlineedit.css"; |
|
31 static const QString FILE_PATH_AUTOFILL_DOCML = ":nmautofilllistview.docml"; |
|
32 static const QString FILE_PATH_AUTOFILLITEM_WIDGETML = ":nmautofilllistviewitem.widgetml"; |
|
33 static const QString FILE_PATH_AUTOFILLITEM_CSS = ":nmautofilllistviewitem.css"; |
25 /*! |
34 /*! |
26 Constructor |
35 Constructor |
27 */ |
36 */ |
28 NmRecipientLineEdit::NmRecipientLineEdit(QGraphicsItem *parent) |
37 NmRecipientLineEdit::NmRecipientLineEdit(QGraphicsItem *parent) |
29 : NmHtmlLineEdit(parent), |
38 : NmHtmlLineEdit(parent), |
30 mNeedToGenerateEmailAddressList(true) |
39 mNeedToGenerateEmailAddressList(true), |
31 { |
40 mContactHistoryModel(NULL), |
32 NM_FUNCTION; |
41 mAutoFillPopup(NULL), |
33 |
42 mAutofillListView(NULL), |
|
43 mAutofillListViewItem(NULL), |
|
44 mPopupBackground(NULL) |
|
45 { |
|
46 NM_FUNCTION; |
|
47 |
|
48 HbStyleLoader::registerFilePath(FILE_PATH_WIDGETML); |
|
49 HbStyleLoader::registerFilePath(FILE_PATH_CSS); |
|
50 HbStyleLoader::registerFilePath(FILE_PATH_AUTOFILLITEM_WIDGETML); |
|
51 HbStyleLoader::registerFilePath(FILE_PATH_AUTOFILLITEM_CSS); |
|
52 |
|
53 createAutofillComponents(); |
|
54 |
34 connect(this, SIGNAL(textChanged(QString)), this, SLOT(handleTextChanged(QString))); |
55 connect(this, SIGNAL(textChanged(QString)), this, SLOT(handleTextChanged(QString))); |
35 } |
56 } |
36 |
57 |
37 |
|
38 /*! |
58 /*! |
39 Destructor |
59 Destructor |
40 */ |
60 */ |
41 NmRecipientLineEdit::~NmRecipientLineEdit() |
61 NmRecipientLineEdit::~NmRecipientLineEdit() |
42 { |
62 { |
43 NM_FUNCTION; |
63 NM_FUNCTION; |
44 } |
64 delete mPopupBackground; |
45 |
65 delete mContactHistoryModel; |
|
66 delete mAutofillListView; |
|
67 |
|
68 HbStyleLoader::unregisterFilePath(FILE_PATH_WIDGETML); |
|
69 HbStyleLoader::unregisterFilePath(FILE_PATH_CSS); |
|
70 HbStyleLoader::unregisterFilePath(FILE_PATH_AUTOFILLITEM_WIDGETML); |
|
71 HbStyleLoader::unregisterFilePath(FILE_PATH_AUTOFILLITEM_CSS); |
|
72 } |
46 |
73 |
47 /*! |
74 /*! |
48 Get the emailaddress list generated from the content of the lineedit. |
75 Get the emailaddress list generated from the content of the lineedit. |
49 */ |
76 */ |
50 QList<NmAddress> NmRecipientLineEdit::emailAddressList() |
77 QList<NmAddress> NmRecipientLineEdit::emailAddressList() |
51 { |
78 { |
52 NM_FUNCTION; |
79 NM_FUNCTION; |
53 |
80 |
54 if (mNeedToGenerateEmailAddressList) { |
81 if (mNeedToGenerateEmailAddressList) { |
55 // Empty mEmailAddressList. |
82 // Empty mEmailAddressList. |
56 mEmailAddressList.clear(); |
83 mEmailAddressList.clear(); |
57 // Generate mEmailAddressList from the lineedit content. |
84 // Generate mEmailAddressList from the lineedit content. |
58 generateEmailAddressList(); |
85 generateEmailAddressList(); |
59 mNeedToGenerateEmailAddressList = false; |
86 mNeedToGenerateEmailAddressList = false; |
60 } |
87 } |
61 |
88 |
62 return mEmailAddressList; |
89 return mEmailAddressList; |
63 } |
90 } |
64 |
91 |
65 |
92 /*! |
66 #ifdef Q_OS_SYMBIAN |
93 This Slot appends the selected contacts to the end of the lineedit content. |
67 /*! |
|
68 This Slot appends the selected contacts to the end of the lineedit content. |
|
69 */ |
94 */ |
70 void NmRecipientLineEdit::addSelectedContacts(const QVariant &selectedContacts) |
95 void NmRecipientLineEdit::addSelectedContacts(const QVariant &selectedContacts) |
71 { |
96 { |
72 NM_FUNCTION; |
97 NM_FUNCTION; |
73 |
98 |
74 // If user selected contact |
99 // If user selected contact |
75 if (!selectedContacts.isNull()) { |
100 if (!selectedContacts.isNull()) { |
76 |
101 |
77 // If the lineedit is not empty and if there is no ";" or "; " at the end, |
102 // If the lineedit is not empty and if there is no ";" or "; " at the end, |
78 // add a delimiter("; ") at the end. |
103 // add a delimiter("; ") at the end. |
79 if (this->text().length() != 0 && !(this->text().endsWith(Semicolon)) && |
104 if (text().length() != 0 && !(text().endsWith(NmRecipientLineEditSemicolon)) && |
80 !(this->text().endsWith(Delimiter))){ |
105 !(text().endsWith(NmRecipientLineEditDelimiter))){ |
81 |
106 |
82 // Move cursor to the end of the lineedit. |
107 // Move cursor to the end of the lineedit. |
83 this->setCursorPosition(this->text().length()); |
108 setCursorPosition(text().length()); |
84 QTextCursor textCursor(this->textCursor()); |
109 QTextCursor textCursor(this->textCursor()); |
85 // Append delimiter("; ") to the end of the lineedit |
110 // Append delimiter("; ") to the end of the lineedit |
86 textCursor.insertText(Delimiter); |
111 textCursor.insertText(NmRecipientLineEditDelimiter); |
87 } |
112 } |
88 |
113 |
89 CntServicesContactList contactList = qVariantValue<CntServicesContactList>(selectedContacts); |
114 CntServicesContactList contactList = qVariantValue<CntServicesContactList>(selectedContacts); |
90 |
115 |
91 // Loop through all the selected contacts. |
116 // Loop through all the selected contacts. |
92 for (int i = 0; i < contactList.count(); ++i) { |
117 for (int i = 0; i < contactList.count(); ++i) { |
93 QString contactName = contactList[i].mDisplayName; |
118 QString contactName = contactList[i].mDisplayName; |
94 QString contactEmailAddress = contactList[i].mEmailAddress; |
119 QString contactEmailAddress = contactList[i].mEmailAddress; |
95 |
120 |
96 // If this contact has no name, use it's emailaddress as the display name |
121 // If this contact has no name, use it's emailaddress as the display name |
97 if(contactName.isEmpty()) { |
122 if (contactName.isEmpty()) { |
98 // Move cursor to the end of the lineedit. |
123 // Move cursor to the end of the lineedit. |
99 this->setCursorPosition(this->text().length()); |
124 setCursorPosition(text().length()); |
100 QTextCursor textCursor(this->textCursor()); |
125 insertContactText(contactEmailAddress); |
101 // Append contactEmailAddress to the end of the lineedit |
|
102 textCursor.insertText(contactEmailAddress); |
|
103 } |
126 } |
104 // If this contact has name, use the name as the display name |
127 // If this contact has name, use the name as the display name |
105 else { |
128 else { |
106 // Handle a rare case: there are contacts has same name but different emailaddress. |
129 // Handle a rare case: there are contacts has same name but different emailaddress. |
107 for (int i = 0; i != mRecipientsAddedFromContacts.count(); ++i) { |
130 for (int i = 0; i != mRecipientsAddedFromContacts.count(); ++i) { |
111 contactName.append("<"); |
134 contactName.append("<"); |
112 contactName.append(contactEmailAddress); |
135 contactName.append(contactEmailAddress); |
113 contactName.append(">"); |
136 contactName.append(">"); |
114 } |
137 } |
115 } |
138 } |
116 |
139 |
117 // Move cursor to the end of the lineedit. |
140 // Move cursor to the end of the lineedit. |
118 this->setCursorPosition(this->text().length()); |
141 setCursorPosition(text().length()); |
119 QTextCursor textCursor(this->textCursor()); |
142 insertContactText(contactName); |
120 // Append contactName to the end of the lineedit |
143 } |
121 textCursor.insertText(contactName); |
144 |
122 } |
145 // Form the contact into NmAddress format. |
123 |
|
124 QTextCursor textCursor(this->textCursor()); |
|
125 // Append delimiter("; ") |
|
126 textCursor.insertText(Delimiter); |
|
127 |
|
128 // Form the contact into Qmail NmAddress format. |
|
129 NmAddress contact; |
146 NmAddress contact; |
130 contact.setAddress(contactEmailAddress); |
147 contact.setAddress(contactEmailAddress); |
131 contact.setDisplayName(contactName); |
148 contact.setDisplayName(contactName); |
132 |
149 |
133 // Add this NmAddress formated contact into mRecipientsAddedFromContacts. |
150 // Add this NmAddress formated contact into mRecipientsAddedFromContacts. |
134 mRecipientsAddedFromContacts.append(contact); |
151 mRecipientsAddedFromContacts.append(contact); |
135 } |
152 } |
136 } |
153 } |
137 else { |
154 else { |
138 //Request returned NULL |
155 //Request returned NULL |
139 NM_COMMENT("ContactsPicker request returned NULL."); |
156 NM_COMMENT("ContactsPicker request returned NULL."); |
140 } |
157 } |
141 |
|
142 } |
158 } |
143 |
159 |
144 Q_IMPLEMENT_USER_METATYPE(CntServicesContact) |
160 Q_IMPLEMENT_USER_METATYPE(CntServicesContact) |
145 Q_IMPLEMENT_USER_METATYPE_NO_OPERATORS(CntServicesContactList) |
161 Q_IMPLEMENT_USER_METATYPE_NO_OPERATORS(CntServicesContactList) |
146 #endif // Q_OS_SYMBIAN |
162 |
147 |
163 /*! |
148 |
164 keyPressEvent handles different keypress events, and reacts to them |
149 /*! |
|
150 keyPressEvent handles replacing user inputs "," or ";" from physical keyboard with "; " |
|
151 P.S. keyPressEvent can only catch QKeyEvent "," or ";" typed from physical keyboard, |
|
152 inputMethodEvent method handles user inputs "," or ";" from virtual keyboard. |
|
153 */ |
165 */ |
154 void NmRecipientLineEdit::keyPressEvent(QKeyEvent *keyEvent) |
166 void NmRecipientLineEdit::keyPressEvent(QKeyEvent *keyEvent) |
155 { |
167 { |
156 NM_FUNCTION; |
168 NM_FUNCTION; |
157 |
169 |
158 bool eventHandled = false; |
|
159 |
|
160 if (keyEvent) { |
170 if (keyEvent) { |
161 switch (keyEvent->key()) { |
171 switch (keyEvent->key()) { |
162 case Qt::Key_Comma: |
172 case Qt::Key_Comma: |
163 case Qt::Key_Semicolon: |
173 case Qt::Key_Semicolon: |
164 { |
174 keyPressEventSemicolon(keyEvent); |
165 QString textBeforeCursor = (this->text()).left(this->cursorPosition()); |
175 break; |
166 |
176 |
167 // No action when the lineedit is empty or cursor is after a Delimiter("; ") |
177 case Qt::Key_Backspace: |
168 // or a Semicolon (";"). |
178 case Qt::Key_Delete: |
169 if ((this->text()).isEmpty() || textBeforeCursor.endsWith(Delimiter) |
179 keyPressEventDelete(keyEvent); |
170 || textBeforeCursor.endsWith(Semicolon)) { |
180 break; |
171 keyEvent->ignore(); |
181 |
172 eventHandled = true; |
182 case Qt::Key_Left: |
173 } |
183 keyPressEventLeft(keyEvent); |
174 else { |
184 break; |
175 // Generate custom keyevent for Delimiter("; ") and |
185 |
176 // forward to the base class to handle. |
186 case Qt::Key_Right: |
177 QKeyEvent delimiterKeyEvent(keyEvent->type(), keyEvent->key(), |
187 keyPressEventRight(keyEvent); |
178 keyEvent->modifiers(), Delimiter); |
|
179 NmHtmlLineEdit::keyPressEvent(&delimiterKeyEvent); |
|
180 eventHandled = true; |
|
181 } |
|
182 } |
|
183 break; |
188 break; |
184 |
189 |
185 default: |
190 default: |
186 NmHtmlLineEdit::keyPressEvent(keyEvent); |
191 NmHtmlLineEdit::keyPressEvent(keyEvent); |
187 eventHandled = true; |
192 break; |
188 break; |
193 } // switch |
189 } |
194 keyEvent->accept(); |
190 } |
195 } |
191 |
196 } |
192 // If event is not handled, forward to the base class to handle. |
197 |
193 if (!eventHandled) { |
198 /*! |
194 NmHtmlLineEdit::keyPressEvent(keyEvent); |
199 * subroutine of keyPressEvent that handles semicolon and comma key presses |
195 } |
200 */ |
196 } |
201 void NmRecipientLineEdit::keyPressEventSemicolon(QKeyEvent *event) |
197 |
202 { |
|
203 NM_FUNCTION; |
|
204 QString textBeforeCursor = (text()).left(cursorPosition()); |
|
205 |
|
206 // No action when the lineedit is empty or cursor is after a Delimiter("; ") |
|
207 // or a Semicolon (";"). |
|
208 if ((text()).isEmpty() || textBeforeCursor.endsWith(NmRecipientLineEditDelimiter) |
|
209 || textBeforeCursor.endsWith(NmRecipientLineEditSemicolon)) { |
|
210 event->ignore(); |
|
211 } |
|
212 else { |
|
213 // Generate custom keyevent for Delimiter("; ") and |
|
214 // forward to the base class to handle. |
|
215 QKeyEvent delimiterKeyEvent(event->type(), event->key(), |
|
216 event->modifiers(), NmRecipientLineEditDelimiter); |
|
217 NmHtmlLineEdit::keyPressEvent(&delimiterKeyEvent); |
|
218 } |
|
219 } |
|
220 |
|
221 /*! |
|
222 * subroutine of keyPressEvent that handles delete and backspace key presses |
|
223 */ |
|
224 void NmRecipientLineEdit::keyPressEventDelete(QKeyEvent *event) |
|
225 { |
|
226 NM_FUNCTION; |
|
227 int pos = cursorPosition(); |
|
228 |
|
229 // 1) if selection exists, delete it |
|
230 if (hasSelectedText()) { |
|
231 // if already selected delete it |
|
232 disconnect(this, SIGNAL(textChanged(QString)), |
|
233 this, SLOT(handleTextChanged(QString))); |
|
234 QKeyEvent eve(event->type(), Qt::Key_Delete, Qt::NoModifier); |
|
235 HbLineEdit::keyPressEvent(&eve); |
|
236 connect(this, SIGNAL(textChanged(QString)), |
|
237 this, SLOT(handleTextChanged(QString))); |
|
238 setCursorPosition(text().length()); |
|
239 handleTextChanged(text()); |
|
240 } else { // no selection.. |
|
241 // peek if earlier chars are underlined |
|
242 setCursorPosition(pos-2); |
|
243 bool isContact(textCursor().charFormat().fontUnderline()); |
|
244 setCursorPosition(pos); |
|
245 if (isContact) { |
|
246 // contact |
|
247 setCursorPosition(pos-3); |
|
248 setHighlight(pos-3); // creates a selection for the current contact |
|
249 } else { |
|
250 // plain text |
|
251 HbLineEdit::keyPressEvent(event); |
|
252 } |
|
253 } |
|
254 } |
|
255 |
|
256 /*! |
|
257 * subroutine of keyPressEvent that handles left key presses |
|
258 */ |
|
259 void NmRecipientLineEdit::keyPressEventLeft(QKeyEvent *event) |
|
260 { |
|
261 NM_FUNCTION; |
|
262 //look ahead left. |
|
263 int pos = cursorPosition(); |
|
264 QString text = this->text(); |
|
265 text = text.left(pos); |
|
266 |
|
267 //look for next seperator while going left. |
|
268 int semicolonPos = text.lastIndexOf(NmRecipientLineEditSemicolon); |
|
269 bool selectedText = hasSelectedText(); |
|
270 |
|
271 if (selectedText) { |
|
272 int selectionStart = textCursor().selectionStart(); |
|
273 if (selectionStart>=2) { |
|
274 setCursorPosition(selectionStart-2); |
|
275 } |
|
276 else { |
|
277 setCursorPosition(0); |
|
278 } |
|
279 textCursor().clearSelection(); |
|
280 } |
|
281 else { // not selected |
|
282 |
|
283 setCursorPosition(pos-2); |
|
284 bool isContact = textCursor().charFormat().fontUnderline(); |
|
285 setCursorPosition(pos); |
|
286 |
|
287 if (isContact) { |
|
288 setHighlight(pos-3); |
|
289 } |
|
290 else { |
|
291 if (pos-2 == semicolonPos) { |
|
292 setCursorPosition(pos-1); // jump over one extra char |
|
293 } |
|
294 HbLineEdit::keyPressEvent(event); |
|
295 } |
|
296 } |
|
297 } |
|
298 |
|
299 /*! |
|
300 * subroutine of keyPressEvent that handles right key presses |
|
301 */ |
|
302 void NmRecipientLineEdit::keyPressEventRight(QKeyEvent *event) |
|
303 { |
|
304 NM_FUNCTION; |
|
305 bool selectedText = hasSelectedText(); |
|
306 |
|
307 if (selectedText) { |
|
308 int selectionEnd = textCursor().selectionEnd(); |
|
309 setCursorPosition(selectionEnd+1); |
|
310 textCursor().clearSelection(); |
|
311 } |
|
312 else { |
|
313 int pos = cursorPosition(); |
|
314 |
|
315 //look ahead |
|
316 setCursorPosition(pos+3); |
|
317 bool isContact = textCursor().charFormat().fontUnderline(); |
|
318 setCursorPosition(pos); |
|
319 |
|
320 if (isContact) { |
|
321 setHighlight(pos+3); |
|
322 } |
|
323 else { |
|
324 int nextSemicolon = text().indexOf(NmRecipientLineEditSemicolon,pos); |
|
325 if (nextSemicolon==pos) { |
|
326 setCursorPosition(pos+1); // jump over one extra char |
|
327 } |
|
328 HbLineEdit::keyPressEvent(event); |
|
329 } |
|
330 } |
|
331 } |
198 |
332 |
199 /*! |
333 /*! |
200 inputMethodEvent handles replacing user inputs "," or ";" from virtual keyboard with "; ". |
334 inputMethodEvent handles replacing user inputs "," or ";" from virtual keyboard with "; ". |
201 P.S. keyPressEvent can only catch QKeyEvent "," or ";" typed from physical keyboard |
335 P.S. keyPressEvent can only catch QKeyEvent "," or ";" typed from physical keyboard |
202 */ |
336 */ |
203 void NmRecipientLineEdit::inputMethodEvent(QInputMethodEvent *event) |
337 void NmRecipientLineEdit::inputMethodEvent(QInputMethodEvent *event) |
204 { |
338 { |
205 NM_FUNCTION; |
339 NM_FUNCTION; |
206 |
340 |
207 bool eventHandled = false; |
341 bool eventHandled(false); |
208 |
342 |
209 if (event) { |
343 if (event) { |
210 QString eventText = event->commitString(); |
344 QString eventText = event->commitString(); |
211 |
345 |
212 if (!eventText.isEmpty() || event->replacementLength()) { |
346 if (!eventText.isEmpty() || event->replacementLength()) { |
213 // If typed charater from virtual keyboard is "," or ";" |
347 // If typed charater from virtual keyboard is "," or ";" |
214 if (eventText.contains(CommaOrSemicolon)) { |
348 if (eventText.contains(NmRecipientLineEditCommaOrSemicolon)) { |
215 QString textBeforeCursor = (this->text()).left(this->cursorPosition()); |
349 QString textBeforeCursor = text().left(cursorPosition()); |
216 |
350 |
217 // No action when the lineedit is empty or cursor is after a Delimiter("; ") |
351 // No action when the lineedit is empty or cursor is after a Delimiter("; ") |
218 // or Semicolon (";"). |
352 // or Semicolon (";"). |
219 if ((this->text()).isEmpty() || textBeforeCursor.endsWith(Delimiter) |
353 if (text().isEmpty() || textBeforeCursor.endsWith(NmRecipientLineEditDelimiter) || textBeforeCursor.endsWith(NmRecipientLineEditSemicolon)) { |
220 || textBeforeCursor.endsWith(Semicolon)) { |
|
221 event->ignore(); |
354 event->ignore(); |
222 eventHandled = true; |
355 eventHandled = true; |
223 } |
356 } |
224 else { |
357 else { |
225 // Modify event with Delimiter("; ") and forward to the base class to handle. |
358 // Modify event with Delimiter("; ") and forward to the base class to handle. |
226 event->setCommitString(Delimiter, event->replacementStart(), |
359 event->setCommitString(NmRecipientLineEditDelimiter, event->replacementStart(), |
227 event->replacementLength()); |
360 event->replacementLength()); |
228 NmHtmlLineEdit::inputMethodEvent(event); |
361 NmHtmlLineEdit::inputMethodEvent(event); |
229 eventHandled = true; |
362 eventHandled = true; |
230 } |
363 } |
231 } |
364 } |
232 } |
365 } |
236 if (!eventHandled) { |
369 if (!eventHandled) { |
237 NmHtmlLineEdit::inputMethodEvent(event); |
370 NmHtmlLineEdit::inputMethodEvent(event); |
238 } |
371 } |
239 } |
372 } |
240 |
373 |
241 |
374 /*! |
|
375 signal received from user screen input |
|
376 */ |
|
377 void NmRecipientLineEdit::gestureEvent(QGestureEvent* event) |
|
378 { |
|
379 //passing gesture event to base class. |
|
380 HbLineEdit::gestureEvent(event); |
|
381 |
|
382 if (HbTapGesture *tap = qobject_cast<HbTapGesture*>(event->gesture(Qt::TapGesture))) { |
|
383 //capturing gesture position, and map to local co-ordinates. |
|
384 QPointF pos = mapFromScene(tap->scenePosition()); |
|
385 |
|
386 switch (tap->state()) { |
|
387 case Qt::GestureFinished: |
|
388 if (HbTapGesture::Tap == tap->tapStyleHint()) { |
|
389 handleTap(); |
|
390 } |
|
391 break; |
|
392 default: |
|
393 break; |
|
394 } |
|
395 event->accept(); |
|
396 } |
|
397 else { |
|
398 event->ignore(); |
|
399 } |
|
400 } |
|
401 |
|
402 /*! |
|
403 user has tapped the recipient field on the screen |
|
404 */ |
|
405 void NmRecipientLineEdit::handleTap() |
|
406 { |
|
407 int currentPos = cursorPosition(); |
|
408 QString txt = text(); |
|
409 |
|
410 QString leftTxt = txt.left(currentPos+2); |
|
411 int previousSemicolonIndex = leftTxt.lastIndexOf(NmRecipientLineEditSemicolon,currentPos); |
|
412 if ((currentPos>0) && |
|
413 (currentPos==previousSemicolonIndex || currentPos==previousSemicolonIndex+1)) { |
|
414 //pressed just on seperator |
|
415 setCursorPosition(previousSemicolonIndex+2); |
|
416 } |
|
417 else |
|
418 { |
|
419 // pressed in middle of an address |
|
420 setCursorPosition(currentPos); |
|
421 if (textCursor().charFormat().fontUnderline()) { |
|
422 // This entry is a "contact" |
|
423 setHighlight(currentPos); |
|
424 } |
|
425 } |
|
426 update(); |
|
427 } |
|
428 |
242 /*! |
429 /*! |
243 Generate a list of all the email addresses from the content of the lineedit. |
430 Generate a list of all the email addresses from the content of the lineedit. |
244 */ |
431 */ |
245 void NmRecipientLineEdit::generateEmailAddressList() |
432 void NmRecipientLineEdit::generateEmailAddressList() |
246 { |
433 { |
247 NM_FUNCTION; |
434 NM_FUNCTION; |
248 |
435 |
249 // Remove whitespace from the start and the end of the lineedit content. |
436 // Remove whitespace from the start and the end of the lineedit content. |
250 QString contentOfLineedit = (this->text()).trimmed(); |
437 QString contentOfLineedit = text().trimmed(); |
251 |
438 |
252 // Split the lineedit content by semicolon(";"). |
439 // Split the lineedit content by semicolon(";"). |
253 QStringList itemsOfLineeditContent = contentOfLineedit.split(Semicolon, QString::SkipEmptyParts); |
440 QStringList itemsOfLineeditContent = contentOfLineedit.split(NmRecipientLineEditSemicolon, QString::SkipEmptyParts); |
254 |
441 |
255 // Loop through all the items of the lineedit content. |
442 // Loop through all the items of the lineedit content. |
256 for (int i = 0; i != itemsOfLineeditContent.count(); ++i) { |
443 for (int i = 0; i != itemsOfLineeditContent.count(); ++i) { |
257 // Remove whitespace from the start and the end of the item. |
444 // Remove whitespace from the start and the end of the item. |
258 QString itemInLineedit = itemsOfLineeditContent.at(i).trimmed(); |
445 QString itemInLineedit = itemsOfLineeditContent.at(i).trimmed(); |
259 |
446 |
260 // Get the count of the recipients added from Contacts. |
447 // Get the count of the recipients added from Contacts. |
261 int countOfRecipientsAddedFromContacts = mRecipientsAddedFromContacts.count(); |
448 int countOfRecipientsAddedFromContacts = mRecipientsAddedFromContacts.count(); |
262 |
449 |
263 // If there is recipient added from Contacts. |
450 // If there is recipient added from Contacts. |
264 if (countOfRecipientsAddedFromContacts > 0) { |
451 if (countOfRecipientsAddedFromContacts > 0) { |
265 QStringList listOfAddedContactsName; |
452 QStringList listOfAddedContactsName; |
266 QStringList listOfAddedContactsAddress; |
453 QStringList listOfAddedContactsAddress; |
267 |
454 |
268 // Loop through all the recipients added from Contacts. |
455 // Loop through all the recipients added from Contacts. |
269 for (int j = 0; j != countOfRecipientsAddedFromContacts; ++j) { |
456 for (int j = 0; j != countOfRecipientsAddedFromContacts; ++j) { |
270 NmAddress contact = mRecipientsAddedFromContacts.at(j); |
457 NmAddress contact = mRecipientsAddedFromContacts.at(j); |
271 listOfAddedContactsName.append(contact.displayName()); |
458 listOfAddedContactsName.append(contact.displayName()); |
272 listOfAddedContactsAddress.append(contact.address()); |
459 listOfAddedContactsAddress.append(contact.address()); |
273 } |
460 } |
274 |
461 |
275 int indexInAddedContactsName = listOfAddedContactsName.indexOf(itemInLineedit); |
462 int indexInAddedContactsName = listOfAddedContactsName.indexOf(itemInLineedit); |
276 int indexInAddedContactsAddress = listOfAddedContactsAddress.indexOf(itemInLineedit); |
463 int indexInAddedContactsAddress = listOfAddedContactsAddress.indexOf(itemInLineedit); |
277 |
464 |
278 // If this itemInLineedit matches the name of one added contact. |
465 // If this itemInLineedit matches the name of one added contact. |
279 if (indexInAddedContactsName >= 0) { |
466 if (indexInAddedContactsName >= 0) { |
280 // Add the recipient into mEmailAddressList. |
467 // Add the recipient into mEmailAddressList. |
281 mEmailAddressList.append(mRecipientsAddedFromContacts.at(indexInAddedContactsName)); |
468 mEmailAddressList.append(mRecipientsAddedFromContacts.at(indexInAddedContactsName)); |
282 } |
469 } |
283 // If this itemInLineedit matches the emailaddress of one added contact. |
470 // If this itemInLineedit matches the emailaddress of one added contact. |
284 else if (indexInAddedContactsAddress >= 0) { |
471 else if (indexInAddedContactsAddress >= 0) { |
285 // Add the recipient into mEmailAddressList. |
472 // Add the recipient into mEmailAddressList. |
286 mEmailAddressList.append(mRecipientsAddedFromContacts.at(indexInAddedContactsAddress)); |
473 mEmailAddressList.append(mRecipientsAddedFromContacts.at(indexInAddedContactsAddress)); |
287 } |
474 } |
288 // This itemInLineedit is not added from Contacts |
475 // This itemInLineedit is not added from Contacts |
289 else { |
476 else { |
290 // Form the item into NmAddress format. |
477 // Form the item into NmAddress format. |
291 NmAddress recipient; |
478 NmAddress recipient; |
292 recipient.setAddress(itemInLineedit); |
479 recipient.setAddress(itemInLineedit); |
293 // There is no display name info available, so leave display name empty. |
480 // There is no display name info available, so leave display name empty. |
294 recipient.setDisplayName(QString()); |
481 recipient.setDisplayName(QString()); |
295 // Add this NmAddress formated lineedit item into mEmailAddressList. |
482 // Add this NmAddress formated lineedit item into mEmailAddressList. |
296 mEmailAddressList.append(recipient); |
483 mEmailAddressList.append(recipient); |
297 } |
484 } |
298 } |
485 } |
299 else { // There is no recipient is added from Contacts |
486 else { // There is no recipient is added from Contacts |
300 // Form the item into NmAddress format. |
487 // Form the item into NmAddress format. |
301 NmAddress recipient; |
488 NmAddress recipient; |
302 recipient.setAddress(itemInLineedit); |
489 recipient.setAddress(itemInLineedit); |
303 // There is no display name info available, so leave display name emapty. |
490 // There is no display name info available, so leave display name emapty. |
304 recipient.setDisplayName(QString()); |
491 recipient.setDisplayName(QString()); |
305 // Add this NmAddress formated lineedit item into mEmailAddressList. |
492 // Add this NmAddress formated lineedit item into mEmailAddressList. |
306 mEmailAddressList.append(recipient); |
493 mEmailAddressList.append(recipient); |
307 } |
494 } |
308 } |
495 } |
309 } |
496 } |
310 |
497 |
311 |
498 |
313 This Slot is called when the lineedit text changes. |
500 This Slot is called when the lineedit text changes. |
314 */ |
501 */ |
315 void NmRecipientLineEdit::handleTextChanged(const QString &text) |
502 void NmRecipientLineEdit::handleTextChanged(const QString &text) |
316 { |
503 { |
317 NM_FUNCTION; |
504 NM_FUNCTION; |
318 |
505 |
319 Q_UNUSED(text); |
|
320 mNeedToGenerateEmailAddressList = true; |
506 mNeedToGenerateEmailAddressList = true; |
321 } |
507 |
322 |
508 //if there is no text, hide popup already |
323 /* |
509 if (document()->isEmpty()) { |
324 * If recipient is added from Contacts by Contacts, we need to add it to the list. |
510 hideAutofillPopup(); |
|
511 } |
|
512 |
|
513 if (mContactHistoryModel) { |
|
514 int startPos(-1), length(-1); |
|
515 currentTextPart(startPos, length); |
|
516 QString t = text.mid(startPos, length); |
|
517 if (t.length()) { |
|
518 mContactHistoryModel->query(t); |
|
519 } |
|
520 } |
|
521 } |
|
522 |
|
523 /*! |
|
524 If recipient is added from Contacts by Contacts, we need to add it to the list. |
325 */ |
525 */ |
326 void NmRecipientLineEdit::addContacts(QList<NmAddress *> contacts) |
526 void NmRecipientLineEdit::addContacts(QList<NmAddress *> contacts) |
327 { |
527 { |
328 foreach (NmAddress *nmContact,contacts) { |
528 foreach (NmAddress *nmContact,contacts) { |
329 if (nmContact && nmContact->displayName().length() > 0) { |
529 if (nmContact && nmContact->displayName().length() > 0) { |
330 mRecipientsAddedFromContacts.append(*nmContact); |
530 mRecipientsAddedFromContacts.append(*nmContact); |
331 mNeedToGenerateEmailAddressList = true; |
531 mNeedToGenerateEmailAddressList = true; |
332 } |
532 } |
333 } |
533 } |
334 } |
534 } |
|
535 |
|
536 /*! |
|
537 This Slot appends the selected contact to the end of the lineedit content. |
|
538 */ |
|
539 void NmRecipientLineEdit::addSelectedContactFromHistory(const QModelIndex &modelIndex) |
|
540 { |
|
541 NM_FUNCTION; |
|
542 |
|
543 // ignore text changes during handling of text |
|
544 disconnect(this, SIGNAL(textChanged(QString)), |
|
545 this, SLOT(handleTextChanged(QString))); |
|
546 |
|
547 // Get address from contact history model |
|
548 NmAddress contact; |
|
549 getChosenAddressFromModel(modelIndex, contact); |
|
550 |
|
551 if (!contact.address().isEmpty()) { |
|
552 // Add the recipient to internal list of addresses |
|
553 mRecipientsAddedFromContacts.append(contact); |
|
554 |
|
555 // Find the text part to be replaced |
|
556 int startPos(-1), length(-1); |
|
557 currentTextPart(startPos, length); |
|
558 |
|
559 // delete currently entered characters before adding replacement |
|
560 QTextCursor cursor(textCursor()); |
|
561 cursor.setPosition(startPos); |
|
562 for(int i=0; i<length; i++) { |
|
563 cursor.deleteChar(); |
|
564 } |
|
565 |
|
566 // Insert replacement text |
|
567 if (contact.displayName().isEmpty()) { |
|
568 insertContactText(contact.address()); |
|
569 } |
|
570 else { |
|
571 insertContactText(contact.displayName()); |
|
572 } |
|
573 } |
|
574 // Continue accepting text changes.. |
|
575 connect(this, SIGNAL(textChanged(QString)), |
|
576 this, SLOT(handleTextChanged(QString))); |
|
577 |
|
578 //hide popup |
|
579 hideAutofillPopup(); |
|
580 } |
|
581 /*! |
|
582 reads the chosen data from contact history model |
|
583 */ |
|
584 void NmRecipientLineEdit::getChosenAddressFromModel(const QModelIndex &modelIndex, NmAddress &address) |
|
585 { |
|
586 NM_FUNCTION; |
|
587 // Dig out the chosen contact data |
|
588 // Get the activated item with given modelIndex |
|
589 NmContactHistoryModelItem item = mContactHistoryModel->data(modelIndex, Qt::DisplayRole).value<NmContactHistoryModelItem>(); |
|
590 if (item.subItemCount()) { |
|
591 QList<NmContactHistoryModelSubItem> itemlist = item.subEntries(); |
|
592 if (itemlist.count() == 2) { |
|
593 address.setDisplayName(itemlist[0].mItemText); |
|
594 address.setAddress(itemlist[1].mItemText); |
|
595 } else if (itemlist.count() == 1) { |
|
596 // only emailaddress found (no display name) |
|
597 address.setAddress(itemlist[0].mItemText); |
|
598 } |
|
599 } |
|
600 } |
|
601 |
|
602 /*! |
|
603 finds the current "entry" (startindex+length) based on current cursor position. |
|
604 Excludes possible trailing delimiter |
|
605 */ |
|
606 void NmRecipientLineEdit::currentTextPart(int &startIndex, int &length) |
|
607 { |
|
608 NM_FUNCTION; |
|
609 |
|
610 // Get current cursor position in the text |
|
611 int currentPos = textCursor().position(); |
|
612 |
|
613 QString tmp_debug = text(); |
|
614 startIndex = qMax(text().lastIndexOf(NmRecipientLineEditSemicolon,currentPos-1), 0); |
|
615 if (startIndex>0) { |
|
616 startIndex+=2; // in case entry is not the first, advance the start index by amount of "; ". |
|
617 } |
|
618 |
|
619 |
|
620 int nextDelimiterIndex=text().indexOf(NmRecipientLineEditDelimiter,currentPos); |
|
621 if (nextDelimiterIndex==-1) { |
|
622 // no delim after current pos |
|
623 length=text().length()-startIndex; |
|
624 } |
|
625 else { |
|
626 // delim after current pos found |
|
627 length=nextDelimiterIndex-startIndex; |
|
628 } |
|
629 } |
|
630 |
|
631 /*! |
|
632 Helper function for creating autofill component. |
|
633 */ |
|
634 void NmRecipientLineEdit::createAutofillComponents() |
|
635 { |
|
636 NM_FUNCTION; |
|
637 |
|
638 //create model |
|
639 mContactHistoryModel = new NmContactHistoryModel(EmailAddressModel); |
|
640 connect(mContactHistoryModel,SIGNAL(modelCompleted(int)),this,SLOT(modelCompleted(int))); |
|
641 |
|
642 //create popup list components |
|
643 HbDocumentLoader loader; |
|
644 bool loadingOk(false); |
|
645 loader.load(FILE_PATH_AUTOFILL_DOCML, &loadingOk); |
|
646 if (loadingOk){ |
|
647 mAutofillListView = dynamic_cast<HbListView*>(loader.findWidget("listview")); |
|
648 } |
|
649 else { |
|
650 NM_COMMENT("mAutofillListView loading from docML failed."); |
|
651 return; |
|
652 } |
|
653 |
|
654 connect(mAutofillListView, SIGNAL(activated(const QModelIndex &)), |
|
655 this, SLOT(addSelectedContactFromHistory(const QModelIndex &))); |
|
656 |
|
657 mAutofillListViewItem = new NmAutoFillListViewItem(); |
|
658 mAutofillListView->setModel(static_cast<QAbstractListModel*>(mContactHistoryModel),mAutofillListViewItem); |
|
659 |
|
660 //create popup |
|
661 createAutoFillPopup(); |
|
662 |
|
663 //set layout for popup |
|
664 QGraphicsLinearLayout *linLayout = new QGraphicsLinearLayout(Qt::Horizontal, |
|
665 mAutoFillPopup); |
|
666 linLayout->addItem(mAutofillListView); |
|
667 |
|
668 } |
|
669 |
|
670 /*! |
|
671 Helper function for creating popup component. |
|
672 */ |
|
673 void NmRecipientLineEdit::createAutoFillPopup() |
|
674 { |
|
675 NM_FUNCTION; |
|
676 mAutoFillPopup = new HbPopup(this); |
|
677 mAutoFillPopup->setVisible(false); |
|
678 mAutoFillPopup->setFlag(QGraphicsItem::ItemIsPanel, true); |
|
679 mAutoFillPopup->setActive(false); |
|
680 mAutoFillPopup->setFocusPolicy(Qt::NoFocus); |
|
681 mAutoFillPopup->setBackgroundFaded(false); |
|
682 mAutoFillPopup->setDismissPolicy(HbPopup::TapOutside); |
|
683 mAutoFillPopup->setTimeout(HbPopup::NoTimeout); |
|
684 mAutoFillPopup->setFrameType(HbPopup::Weak); //uses qtg_fr_popup_secondary graphics |
|
685 HbStyle::setItemName(mAutoFillPopup, QString("autoFillPopup")); |
|
686 |
|
687 mPopupBackground = new NmPopupBackground(mAutoFillPopup, this); |
|
688 mPopupBackground->setVisible(false); |
|
689 mPopupBackground->setZValue(mAutoFillPopup->zValue() - 1); |
|
690 } |
|
691 |
|
692 /*! |
|
693 Helper function for showing autofill popup. |
|
694 */ |
|
695 void NmRecipientLineEdit::showAutofillPopup() |
|
696 { |
|
697 NM_FUNCTION; |
|
698 if (!mAutoFillPopup->isVisible()) { |
|
699 parentItem()->setZValue(NmRecipientLineEditForegroundZValue); |
|
700 mAutoFillPopup->show(); |
|
701 mPopupBackground->setVisible(true); |
|
702 } |
|
703 } |
|
704 |
|
705 /*! |
|
706 Helper function for hiding autofill popup. |
|
707 */ |
|
708 void NmRecipientLineEdit::hideAutofillPopup() |
|
709 { |
|
710 NM_FUNCTION; |
|
711 if (mAutoFillPopup->isVisible()) { |
|
712 mPopupBackground->setVisible(false); |
|
713 parentItem()->setZValue(NmRecipientLineEditBackgroundZValue); |
|
714 mAutoFillPopup->hide(); |
|
715 } |
|
716 } |
|
717 |
|
718 /*! |
|
719 Slot for listening when model is ready with a new data. |
|
720 */ |
|
721 void NmRecipientLineEdit::modelCompleted(int err) |
|
722 { |
|
723 NM_FUNCTION; |
|
724 if (err == 0) { |
|
725 //show model if there was findings |
|
726 int count = mContactHistoryModel->rowCount(QModelIndex()); |
|
727 |
|
728 if (count > 0) { |
|
729 showAutofillPopup(); |
|
730 } else { |
|
731 hideAutofillPopup(); |
|
732 } |
|
733 } |
|
734 } |
|
735 |
|
736 /*! |
|
737 finds the current "entry" in the editor field based on current cursor position and creates a selection of it. |
|
738 Includes possible trailing delimiter |
|
739 */ |
|
740 void NmRecipientLineEdit::setHighlight(int currentPos) |
|
741 { |
|
742 QString txt = text(); |
|
743 |
|
744 int startPos = qMax(txt.lastIndexOf(NmRecipientLineEditDelimiter,currentPos), 0); |
|
745 if (startPos) { |
|
746 startPos+=2; // in case entry is not the first, advance the start index by amount of "; " |
|
747 } |
|
748 int endPos = qMax(txt.indexOf(NmRecipientLineEditDelimiter,currentPos), currentPos); |
|
749 |
|
750 if (startPos >= 0 && endPos >= 0 && startPos != endPos) { |
|
751 setSelection(startPos, endPos - startPos + 2); |
|
752 } |
|
753 else { |
|
754 deselect(); |
|
755 } |
|
756 |
|
757 update(); |
|
758 } |
|
759 |
|
760 /*! |
|
761 inserts a new contact text (underlined) + trailing delimiter to current cursor position in editor field |
|
762 */ |
|
763 void NmRecipientLineEdit::insertContactText(const QString &text) |
|
764 { |
|
765 NM_FUNCTION; |
|
766 |
|
767 // Insert contact text as underlined |
|
768 QTextCharFormat colorFormat(textCursor().charFormat()); |
|
769 QColor fgColor = colorFormat.foreground().color(); |
|
770 fgColor.setAlpha(NmRecipientLineEditFadedAlpha); |
|
771 colorFormat.setUnderlineColor(fgColor); |
|
772 colorFormat.setFontUnderline(true); |
|
773 textCursor().insertText(text, colorFormat); |
|
774 |
|
775 // Insert delimiter (not underlined) |
|
776 colorFormat.setFontUnderline(false); |
|
777 textCursor().insertText(NmRecipientLineEditDelimiter,colorFormat); |
|
778 } |
|
779 |
|
780 /*! |
|
781 Popup's background item. Used to close properly popup if clicked to outside of the popup. |
|
782 */ |
|
783 NmPopupBackground::NmPopupBackground(HbPopup * popup, QGraphicsItem *parent) : |
|
784 QGraphicsItem(parent), |
|
785 mPopup(popup) |
|
786 { |
|
787 // This is needed to be able to block moving the focus to items behind background item by |
|
788 // clicking on them. |
|
789 setFlag(QGraphicsItem::ItemIsFocusable); |
|
790 setFlag(QGraphicsItem::ItemIsPanel); |
|
791 } |
|
792 |
|
793 /*! |
|
794 Paint. Not used but since this is pure virtual it must be here. |
|
795 */ |
|
796 void NmPopupBackground::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget ) |
|
797 { |
|
798 Q_UNUSED(option) |
|
799 Q_UNUSED(widget); |
|
800 Q_UNUSED(painter); |
|
801 } |
|
802 |
|
803 /*! |
|
804 Mouse press events are checked here. If background is clicked, popup must be closed. |
|
805 */ |
|
806 bool NmPopupBackground::sceneEvent(QEvent *event) |
|
807 { |
|
808 if (event->type() == QEvent::GraphicsSceneMousePress) { |
|
809 mPopup->close(); |
|
810 setVisible(false); |
|
811 event->accept(); |
|
812 return true; |
|
813 } |
|
814 else { |
|
815 event->ignore(); |
|
816 return QGraphicsItem::sceneEvent(event); |
|
817 } |
|
818 } |