• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

KAlarm Library

  • kalarmcal
alarmtext.cpp
1 /*
2  * alarmtext.cpp - text/email alarm text conversion
3  * This file is part of kalarmcal library, which provides access to KAlarm
4  * calendar data.
5  * Copyright © 2004,2005,2007-2012 by David Jarvie <djarvie@kde.org>
6  *
7  * This library is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Library General Public License as published
9  * by the Free Software Foundation; either version 2 of the License, or (at
10  * your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15  * License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB. If not, write to the
19  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20  * MA 02110-1301, USA.
21  */
22 
23 #include "alarmtext.h"
24 
25 #include "kaevent.h"
26 
27 #ifdef KALARMCAL_USE_KRESOURCES
28 #include <kcal/todo.h>
29 #endif
30 #include <klocale.h>
31 #include <kglobal.h>
32 #include <QStringList>
33 
34 namespace KAlarmCal
35 {
36 
37 class AlarmText::Private
38 {
39  public:
40  enum Type { None, Email, Script, Todo };
41  QString displayText() const;
42  void clear();
43  static void initialise();
44  static void setUpTranslations();
45  static int emailHeaderCount(const QStringList&);
46  static QString todoTitle(const QString& text);
47 
48  static QString mFromPrefix; // translated header prefixes
49  static QString mToPrefix;
50  static QString mCcPrefix;
51  static QString mDatePrefix;
52  static QString mSubjectPrefix;
53  static QString mTitlePrefix;
54  static QString mLocnPrefix;
55  static QString mDuePrefix;
56  static QString mFromPrefixEn; // untranslated header prefixes
57  static QString mToPrefixEn;
58  static QString mCcPrefixEn;
59  static QString mDatePrefixEn;
60  static QString mSubjectPrefixEn;
61  static bool mInitialised;
62 
63  QString mBody, mFrom, mTo, mCc, mTime, mSubject;
64  unsigned long mKMailSerialNum; // if email, message's KMail serial number, else 0
65  Type mType;
66  bool mIsEmail;
67 };
68 
69 QString AlarmText::Private::mFromPrefix;
70 QString AlarmText::Private::mToPrefix;
71 QString AlarmText::Private::mCcPrefix;
72 QString AlarmText::Private::mDatePrefix;
73 QString AlarmText::Private::mSubjectPrefix;
74 QString AlarmText::Private::mTitlePrefix;
75 QString AlarmText::Private::mLocnPrefix;
76 QString AlarmText::Private::mDuePrefix;
77 QString AlarmText::Private::mFromPrefixEn;
78 QString AlarmText::Private::mToPrefixEn;
79 QString AlarmText::Private::mCcPrefixEn;
80 QString AlarmText::Private::mDatePrefixEn;
81 QString AlarmText::Private::mSubjectPrefixEn;
82 bool AlarmText::Private::mInitialised = false;
83 
84 void AlarmText::Private::initialise()
85 {
86  if (!mInitialised)
87  {
88  mInitialised = true;
89  mFromPrefixEn = QLatin1String("From:");
90  mToPrefixEn = QLatin1String("To:");
91  mCcPrefixEn = QLatin1String("Cc:");
92  mDatePrefixEn = QLatin1String("Date:");
93  mSubjectPrefixEn = QLatin1String("Subject:");
94  }
95 }
96 
97 AlarmText::AlarmText(const QString& text)
98  : d(new Private)
99 {
100  Private::initialise();
101  setText(text);
102 }
103 
104 AlarmText::AlarmText(const AlarmText& other)
105  : d(new Private(*other.d))
106 {
107 }
108 
109 AlarmText::~AlarmText()
110 {
111  delete d;
112 }
113 
114 AlarmText& AlarmText::operator=(const AlarmText& other)
115 {
116  if (&other != this)
117  *d = *other.d;
118  return *this;
119 }
120 
121 void AlarmText::setText(const QString& text)
122 {
123  d->clear();
124  d->mBody = text;
125  if (text.startsWith(QLatin1String("#!")))
126  d->mType = Private::Script;
127 }
128 
129 void AlarmText::setScript(const QString& text)
130 {
131  setText(text);
132  d->mType = Private::Script;
133 }
134 
135 void AlarmText::setEmail(const QString& to, const QString& from, const QString& cc, const QString& time,
136  const QString& subject, const QString& body, unsigned long kmailSerialNumber)
137 {
138  d->clear();
139  d->mType = Private::Email;
140  d->mTo = to;
141  d->mFrom = from;
142  d->mCc = cc;
143  d->mTime = time;
144  d->mSubject = subject;
145  d->mBody = body;
146  d->mKMailSerialNum = kmailSerialNumber;
147 }
148 
149 #ifndef KALARMCAL_USE_KRESOURCES
150 void AlarmText::setTodo(const KCalCore::Todo::Ptr& todo)
151 #else
152 void AlarmText::setTodo(const KCal::Todo* todo)
153 #endif
154 {
155  d->clear();
156  d->mType = Private::Todo;
157  d->mSubject = todo->summary();
158  d->mBody = todo->description();
159  d->mTo = todo->location();
160  if (todo->hasDueDate())
161  {
162  KDateTime due = todo->dtDue(false); // fetch the next due date
163  if (todo->hasStartDate() && todo->dtStart() != due)
164  {
165  d->mTime = todo->allDay() ? KGlobal::locale()->formatDate(due.date(), KLocale::ShortDate)
166  : KGlobal::locale()->formatDateTime(due.dateTime());
167  }
168  }
169 }
170 
171 /******************************************************************************
172 * Return the text for a text message alarm, in display format.
173 */
174 QString AlarmText::displayText() const
175 {
176  return d->displayText();
177 }
178 
179 QString AlarmText::Private::displayText() const
180 {
181  QString text;
182  switch (mType)
183  {
184  case Email:
185  // Format the email into a text alarm
186  setUpTranslations();
187  text = mFromPrefix + '\t' + mFrom + '\n';
188  text += mToPrefix + '\t' + mTo + '\n';
189  if (!mCc.isEmpty())
190  text += mCcPrefix + '\t' + mCc + '\n';
191  if (!mTime.isEmpty())
192  text += mDatePrefix + '\t' + mTime + '\n';
193  text += mSubjectPrefix + '\t' + mSubject;
194  if (!mBody.isEmpty())
195  {
196  text += "\n\n";
197  text += mBody;
198  }
199  break;
200  case Todo:
201  // Format the todo into a text alarm
202  setUpTranslations();
203  if (!mSubject.isEmpty())
204  text = mTitlePrefix + '\t' + mSubject + '\n';
205  if (!mTo.isEmpty())
206  text += mLocnPrefix + '\t' + mTo + '\n';
207  if (!mTime.isEmpty())
208  text += mDuePrefix + '\t' + mTime + '\n';
209  if (!mBody.isEmpty())
210  {
211  if (!text.isEmpty())
212  text += '\n';
213  text += mBody;
214  }
215  break;
216  default:
217  break;
218  }
219  return !text.isEmpty() ? text : mBody;
220 }
221 
222 QString AlarmText::to() const
223 {
224  return (d->mType == Private::Email) ? d->mTo : QString();
225 }
226 
227 QString AlarmText::from() const
228 {
229  return (d->mType == Private::Email) ? d->mFrom : QString();
230 }
231 
232 QString AlarmText::cc() const
233 {
234  return (d->mType == Private::Email) ? d->mCc : QString();
235 }
236 
237 QString AlarmText::time() const
238 {
239  return (d->mType == Private::Email) ? d->mTime : QString();
240 }
241 
242 QString AlarmText::subject() const
243 {
244  return (d->mType == Private::Email) ? d->mSubject : QString();
245 }
246 
247 QString AlarmText::body() const
248 {
249  return (d->mType == Private::Email) ? d->mBody : QString();
250 }
251 
252 QString AlarmText::summary() const
253 {
254  return (d->mType == Private::Todo) ? d->mSubject : QString();
255 }
256 
257 QString AlarmText::location() const
258 {
259  return (d->mType == Private::Todo) ? d->mTo : QString();
260 }
261 
262 QString AlarmText::due() const
263 {
264  return (d->mType == Private::Todo) ? d->mTime : QString();
265 }
266 
267 QString AlarmText::description() const
268 {
269  return (d->mType == Private::Todo) ? d->mBody : QString();
270 }
271 
272 /******************************************************************************
273 * Return whether there is any text.
274 */
275 bool AlarmText::isEmpty() const
276 {
277  if (!d->mBody.isEmpty())
278  return false;
279  if (d->mType != Private::Email)
280  return true;
281  return d->mFrom.isEmpty() && d->mTo.isEmpty() && d->mCc.isEmpty() && d->mTime.isEmpty() && d->mSubject.isEmpty();
282 }
283 
284 bool AlarmText::isEmail() const
285 {
286  return d->mType == Private::Email;
287 }
288 
289 bool AlarmText::isScript() const
290 {
291  return d->mType == Private::Script;
292 }
293 
294 bool AlarmText::isTodo() const
295 {
296  return d->mType == Private::Todo;
297 }
298 
299 unsigned long AlarmText::kmailSerialNumber() const
300 {
301  return d->mKMailSerialNum;
302 }
303 
304 /******************************************************************************
305 * Return the alarm summary text for either single line or tooltip display.
306 * The maximum number of line returned is determined by 'maxLines'.
307 * If 'truncated' is non-null, it will be set true if the text returned has been
308 * truncated, other than to strip a trailing newline.
309 */
310 QString AlarmText::summary(const KAEvent& event, int maxLines, bool* truncated)
311 {
312  static const QRegExp localfile("^file:/+");
313  QString text;
314  switch (event.actionSubType())
315  {
316  case KAEvent::AUDIO:
317  text = event.audioFile();
318  if (localfile.indexIn(text) >= 0)
319  text = text.mid(localfile.matchedLength() - 1);
320  break;
321  case KAEvent::EMAIL:
322  text = event.emailSubject();
323  break;
324  case KAEvent::COMMAND:
325  text = event.cleanText();
326  if (localfile.indexIn(text) >= 0)
327  text = text.mid(localfile.matchedLength() - 1);
328  break;
329  case KAEvent::FILE:
330  text = event.cleanText();
331  break;
332  case KAEvent::MESSAGE:
333  {
334  text = event.cleanText();
335  // If the message is the text of an email, return its headers or just subject line
336  QString subject = emailHeaders(text, (maxLines <= 1));
337  if (!subject.isNull())
338  {
339  if (truncated)
340  *truncated = true;
341  return subject;
342  }
343  if (maxLines == 1)
344  {
345  // If the message is the text of a todo, return either the
346  // title/description or the whole text.
347  subject = Private::todoTitle(text);
348  if (!subject.isEmpty())
349  {
350  if (truncated)
351  *truncated = true;
352  return subject;
353  }
354  }
355  break;
356  }
357  }
358  if (truncated)
359  *truncated = false;
360  if (text.count('\n') < maxLines)
361  return text;
362  int newline = -1;
363  for (int i = 0; i < maxLines; ++i)
364  {
365  newline = text.indexOf('\n', newline + 1);
366  if (newline < 0)
367  return text; // not truncated after all !?!
368  }
369  if (newline == static_cast<int>(text.length()) - 1)
370  return text.left(newline); // text ends in newline
371  if (truncated)
372  *truncated = true;
373  return text.left(newline + (maxLines <= 1 ? 0 : 1)) + QLatin1String("...");
374 }
375 
376 /******************************************************************************
377 * Check whether a text is an email.
378 */
379 bool AlarmText::checkIfEmail(const QString& text)
380 {
381  QStringList lines = text.split('\n', QString::SkipEmptyParts);
382  return Private::emailHeaderCount(lines);
383 }
384 
385 /******************************************************************************
386 * Check whether a text is an email, and if so return its headers or optionally
387 * only its subject line.
388 * Reply = headers/subject line, or QString() if not the text of an email.
389 */
390 QString AlarmText::emailHeaders(const QString& text, bool subjectOnly)
391 {
392  QStringList lines = text.split('\n', QString::SkipEmptyParts);
393  int n = Private::emailHeaderCount(lines);
394  if (!n)
395  return QString();
396  if (subjectOnly)
397  return lines[n-1].mid(Private::mSubjectPrefix.length()).trimmed();
398  QString h = lines[0];
399  for (int i = 1; i < n; ++i)
400  {
401  h += '\n';
402  h += lines[i];
403  }
404  return h;
405 }
406 
407 /******************************************************************************
408 * Translate an alarm calendar text to a display text.
409 * Translation is needed for email texts, since the alarm calendar stores
410 * untranslated email prefixes.
411 * 'email' is set to indicate whether it is an email text.
412 */
413 QString AlarmText::fromCalendarText(const QString& text, bool& email)
414 {
415  Private::initialise();
416  QStringList lines = text.split('\n', QString::SkipEmptyParts);
417  int maxn = lines.count();
418  if (maxn >= 4
419  && lines[0].startsWith(Private::mFromPrefixEn)
420  && lines[1].startsWith(Private::mToPrefixEn))
421  {
422  int n = 2;
423  if (lines[2].startsWith(Private::mCcPrefixEn))
424  ++n;
425  if (maxn > n + 1
426  && lines[n].startsWith(Private::mDatePrefixEn)
427  && lines[n+1].startsWith(Private::mSubjectPrefixEn))
428  {
429  Private::setUpTranslations();
430  QString dispText;
431  dispText = Private::mFromPrefix + lines[0].mid(Private::mFromPrefixEn.length()) + '\n';
432  dispText += Private::mToPrefix + lines[1].mid(Private::mToPrefixEn.length()) + '\n';
433  if (n == 3)
434  dispText += Private::mCcPrefix + lines[2].mid(Private::mCcPrefixEn.length()) + '\n';
435  dispText += Private::mDatePrefix + lines[n].mid(Private::mDatePrefixEn.length()) + '\n';
436  dispText += Private::mSubjectPrefix + lines[n+1].mid(Private::mSubjectPrefixEn.length());
437  int i = text.indexOf(Private::mSubjectPrefixEn);
438  i = text.indexOf('\n', i);
439  if (i > 0)
440  dispText += text.mid(i);
441  email = true;
442  return dispText;
443  }
444  }
445  email = false;
446  return text;
447 }
448 
449 /******************************************************************************
450 * Return the text for a text message alarm, in alarm calendar format.
451 * (The prefix strings are untranslated in the calendar.)
452 */
453 QString AlarmText::toCalendarText(const QString& text)
454 {
455  Private::setUpTranslations();
456  QStringList lines = text.split('\n', QString::SkipEmptyParts);
457  int maxn = lines.count();
458  if (maxn >= 4
459  && lines[0].startsWith(Private::mFromPrefix)
460  && lines[1].startsWith(Private::mToPrefix))
461  {
462  int n = 2;
463  if (lines[2].startsWith(Private::mCcPrefix))
464  ++n;
465  if (maxn > n + 1
466  && lines[n].startsWith(Private::mDatePrefix)
467  && lines[n+1].startsWith(Private::mSubjectPrefix))
468  {
469  // Format the email into a text alarm
470  QString calText;
471  calText = Private::mFromPrefixEn + lines[0].mid(Private::mFromPrefix.length()) + '\n';
472  calText += Private::mToPrefixEn + lines[1].mid(Private::mToPrefix.length()) + '\n';
473  if (n == 3)
474  calText += Private::mCcPrefixEn + lines[2].mid(Private::mCcPrefix.length()) + '\n';
475  calText += Private::mDatePrefixEn + lines[n].mid(Private::mDatePrefix.length()) + '\n';
476  calText += Private::mSubjectPrefixEn + lines[n+1].mid(Private::mSubjectPrefix.length());
477  int i = text.indexOf(Private::mSubjectPrefix);
478  i = text.indexOf('\n', i);
479  if (i > 0)
480  calText += text.mid(i);
481  return calText;
482  }
483  }
484  return text;
485 }
486 
487 void AlarmText::Private::clear()
488 {
489  mType = None;
490  mBody.clear();
491  mTo.clear();
492  mFrom.clear();
493  mCc.clear();
494  mTime.clear();
495  mSubject.clear();
496  mKMailSerialNum = 0;
497 }
498 
499 /******************************************************************************
500 * Set up messages used by executeDropEvent() and emailHeaders().
501 */
502 void AlarmText::Private::setUpTranslations()
503 {
504  initialise();
505  if (mFromPrefix.isNull())
506  {
507  mFromPrefix = i18nc("@info/plain 'From' email address", "From:");
508  mToPrefix = i18nc("@info/plain Email addressee", "To:");
509  mCcPrefix = i18nc("@info/plain Copy-to in email headers", "Cc:");
510  mDatePrefix = i18nc("@info/plain", "Date:");
511  mSubjectPrefix = i18nc("@info/plain Email subject", "Subject:");
512  // Todo prefixes
513  mTitlePrefix = i18nc("@info/plain Todo calendar item's title field", "To-do:");
514  mLocnPrefix = i18nc("@info/plain Todo calendar item's location field", "Location:");
515  mDuePrefix = i18nc("@info/plain Todo calendar item's due date/time", "Due:");
516  }
517 }
518 
519 /******************************************************************************
520 * Check whether a text is an email.
521 * Reply = number of email header lines, or 0 if not an email.
522 */
523 int AlarmText::Private::emailHeaderCount(const QStringList& lines)
524 {
525  setUpTranslations();
526  int maxn = lines.count();
527  if (maxn >= 4
528  && lines[0].startsWith(mFromPrefix)
529  && lines[1].startsWith(mToPrefix))
530  {
531  int n = 2;
532  if (lines[2].startsWith(mCcPrefix))
533  ++n;
534  if (maxn > n + 1
535  && lines[n].startsWith(mDatePrefix)
536  && lines[n+1].startsWith(mSubjectPrefix))
537  return n+2;
538  }
539  return 0;
540 }
541 
542 /******************************************************************************
543 * Return the Todo title line, if the text is for a Todo.
544 */
545 QString AlarmText::Private::todoTitle(const QString& text)
546 {
547  setUpTranslations();
548  QStringList lines = text.split('\n', QString::SkipEmptyParts);
549  int n;
550  for (n = 0; n < lines.count() && lines[n].contains('\t'); ++n) ;
551  if (!n || n > 3)
552  return QString();
553  QString title;
554  int i = 0;
555  if (lines[i].startsWith(mTitlePrefix + '\t'))
556  {
557  title = lines[i].mid(mTitlePrefix.length()).trimmed();
558  ++i;
559  }
560  if (i < n && lines[i].startsWith(mLocnPrefix + '\t'))
561  ++i;
562  if (i < n && lines[i].startsWith(mDuePrefix + '\t'))
563  ++i;
564  if (i == n)
565  {
566  // It's a Todo text
567  if (!title.isEmpty())
568  return title;
569  if (n < lines.count())
570  return lines[n];
571  }
572  return QString();
573 }
574 
575 } // namespace KAlarmCal
576 
577 // vim: et sw=4:
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:30:13 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KAlarm Library

Skip menu "KAlarm Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal