KAlarm Library
alarmtext.cpp
00001 /* 00002 * alarmtext.cpp - text/email alarm text conversion 00003 * This file is part of kalarmcal library, which provides access to KAlarm 00004 * calendar data. 00005 * Copyright © 2004,2005,2007-2012 by David Jarvie <djarvie@kde.org> 00006 * 00007 * This library is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU Library General Public License as published 00009 * by the Free Software Foundation; either version 2 of the License, or (at 00010 * your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, but WITHOUT 00013 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00015 * License for more details. 00016 * 00017 * You should have received a copy of the GNU Library General Public License 00018 * along with this library; see the file COPYING.LIB. If not, write to the 00019 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00020 * MA 02110-1301, USA. 00021 */ 00022 00023 #include "alarmtext.h" 00024 00025 #include "kaevent.h" 00026 00027 #ifdef KALARMCAL_USE_KRESOURCES 00028 #include <kcal/todo.h> 00029 #endif 00030 #include <klocale.h> 00031 #include <kglobal.h> 00032 #include <QStringList> 00033 00034 namespace KAlarmCal 00035 { 00036 00037 class AlarmText::Private 00038 { 00039 public: 00040 enum Type { None, Email, Script, Todo }; 00041 QString displayText() const; 00042 void clear(); 00043 static void initialise(); 00044 static void setUpTranslations(); 00045 static int emailHeaderCount(const QStringList&); 00046 static QString todoTitle(const QString& text); 00047 00048 static QString mFromPrefix; // translated header prefixes 00049 static QString mToPrefix; 00050 static QString mCcPrefix; 00051 static QString mDatePrefix; 00052 static QString mSubjectPrefix; 00053 static QString mTitlePrefix; 00054 static QString mLocnPrefix; 00055 static QString mDuePrefix; 00056 static QString mFromPrefixEn; // untranslated header prefixes 00057 static QString mToPrefixEn; 00058 static QString mCcPrefixEn; 00059 static QString mDatePrefixEn; 00060 static QString mSubjectPrefixEn; 00061 static bool mInitialised; 00062 00063 QString mBody, mFrom, mTo, mCc, mTime, mSubject; 00064 unsigned long mKMailSerialNum; // if email, message's KMail serial number, else 0 00065 Type mType; 00066 bool mIsEmail; 00067 }; 00068 00069 QString AlarmText::Private::mFromPrefix; 00070 QString AlarmText::Private::mToPrefix; 00071 QString AlarmText::Private::mCcPrefix; 00072 QString AlarmText::Private::mDatePrefix; 00073 QString AlarmText::Private::mSubjectPrefix; 00074 QString AlarmText::Private::mTitlePrefix; 00075 QString AlarmText::Private::mLocnPrefix; 00076 QString AlarmText::Private::mDuePrefix; 00077 QString AlarmText::Private::mFromPrefixEn; 00078 QString AlarmText::Private::mToPrefixEn; 00079 QString AlarmText::Private::mCcPrefixEn; 00080 QString AlarmText::Private::mDatePrefixEn; 00081 QString AlarmText::Private::mSubjectPrefixEn; 00082 bool AlarmText::Private::mInitialised = false; 00083 00084 void AlarmText::Private::initialise() 00085 { 00086 if (!mInitialised) 00087 { 00088 mInitialised = true; 00089 mFromPrefixEn = QLatin1String("From:"); 00090 mToPrefixEn = QLatin1String("To:"); 00091 mCcPrefixEn = QLatin1String("Cc:"); 00092 mDatePrefixEn = QLatin1String("Date:"); 00093 mSubjectPrefixEn = QLatin1String("Subject:"); 00094 } 00095 } 00096 00097 AlarmText::AlarmText(const QString& text) 00098 : d(new Private) 00099 { 00100 Private::initialise(); 00101 setText(text); 00102 } 00103 00104 AlarmText::AlarmText(const AlarmText& other) 00105 : d(new Private(*other.d)) 00106 { 00107 } 00108 00109 AlarmText::~AlarmText() 00110 { 00111 delete d; 00112 } 00113 00114 AlarmText& AlarmText::operator=(const AlarmText& other) 00115 { 00116 if (&other != this) 00117 *d = *other.d; 00118 return *this; 00119 } 00120 00121 void AlarmText::setText(const QString& text) 00122 { 00123 d->clear(); 00124 d->mBody = text; 00125 if (text.startsWith(QLatin1String("#!"))) 00126 d->mType = Private::Script; 00127 } 00128 00129 void AlarmText::setScript(const QString& text) 00130 { 00131 setText(text); 00132 d->mType = Private::Script; 00133 } 00134 00135 void AlarmText::setEmail(const QString& to, const QString& from, const QString& cc, const QString& time, 00136 const QString& subject, const QString& body, unsigned long kmailSerialNumber) 00137 { 00138 d->clear(); 00139 d->mType = Private::Email; 00140 d->mTo = to; 00141 d->mFrom = from; 00142 d->mCc = cc; 00143 d->mTime = time; 00144 d->mSubject = subject; 00145 d->mBody = body; 00146 d->mKMailSerialNum = kmailSerialNumber; 00147 } 00148 00149 #ifndef KALARMCAL_USE_KRESOURCES 00150 void AlarmText::setTodo(const KCalCore::Todo::Ptr& todo) 00151 #else 00152 void AlarmText::setTodo(const KCal::Todo* todo) 00153 #endif 00154 { 00155 d->clear(); 00156 d->mType = Private::Todo; 00157 d->mSubject = todo->summary(); 00158 d->mBody = todo->description(); 00159 d->mTo = todo->location(); 00160 if (todo->hasDueDate()) 00161 { 00162 KDateTime due = todo->dtDue(false); // fetch the next due date 00163 if (todo->hasStartDate() && todo->dtStart() != due) 00164 { 00165 d->mTime = todo->allDay() ? KGlobal::locale()->formatDate(due.date(), KLocale::ShortDate) 00166 : KGlobal::locale()->formatDateTime(due.dateTime()); 00167 } 00168 } 00169 } 00170 00171 /****************************************************************************** 00172 * Return the text for a text message alarm, in display format. 00173 */ 00174 QString AlarmText::displayText() const 00175 { 00176 return d->displayText(); 00177 } 00178 00179 QString AlarmText::Private::displayText() const 00180 { 00181 QString text; 00182 switch (mType) 00183 { 00184 case Email: 00185 // Format the email into a text alarm 00186 setUpTranslations(); 00187 text = mFromPrefix + '\t' + mFrom + '\n'; 00188 text += mToPrefix + '\t' + mTo + '\n'; 00189 if (!mCc.isEmpty()) 00190 text += mCcPrefix + '\t' + mCc + '\n'; 00191 if (!mTime.isEmpty()) 00192 text += mDatePrefix + '\t' + mTime + '\n'; 00193 text += mSubjectPrefix + '\t' + mSubject; 00194 if (!mBody.isEmpty()) 00195 { 00196 text += "\n\n"; 00197 text += mBody; 00198 } 00199 break; 00200 case Todo: 00201 // Format the todo into a text alarm 00202 setUpTranslations(); 00203 if (!mSubject.isEmpty()) 00204 text = mTitlePrefix + '\t' + mSubject + '\n'; 00205 if (!mTo.isEmpty()) 00206 text += mLocnPrefix + '\t' + mTo + '\n'; 00207 if (!mTime.isEmpty()) 00208 text += mDuePrefix + '\t' + mTime + '\n'; 00209 if (!mBody.isEmpty()) 00210 { 00211 if (!text.isEmpty()) 00212 text += '\n'; 00213 text += mBody; 00214 } 00215 break; 00216 default: 00217 break; 00218 } 00219 return !text.isEmpty() ? text : mBody; 00220 } 00221 00222 QString AlarmText::to() const 00223 { 00224 return (d->mType == Private::Email) ? d->mTo : QString(); 00225 } 00226 00227 QString AlarmText::from() const 00228 { 00229 return (d->mType == Private::Email) ? d->mFrom : QString(); 00230 } 00231 00232 QString AlarmText::cc() const 00233 { 00234 return (d->mType == Private::Email) ? d->mCc : QString(); 00235 } 00236 00237 QString AlarmText::time() const 00238 { 00239 return (d->mType == Private::Email) ? d->mTime : QString(); 00240 } 00241 00242 QString AlarmText::subject() const 00243 { 00244 return (d->mType == Private::Email) ? d->mSubject : QString(); 00245 } 00246 00247 QString AlarmText::body() const 00248 { 00249 return (d->mType == Private::Email) ? d->mBody : QString(); 00250 } 00251 00252 QString AlarmText::summary() const 00253 { 00254 return (d->mType == Private::Todo) ? d->mSubject : QString(); 00255 } 00256 00257 QString AlarmText::location() const 00258 { 00259 return (d->mType == Private::Todo) ? d->mTo : QString(); 00260 } 00261 00262 QString AlarmText::due() const 00263 { 00264 return (d->mType == Private::Todo) ? d->mTime : QString(); 00265 } 00266 00267 QString AlarmText::description() const 00268 { 00269 return (d->mType == Private::Todo) ? d->mBody : QString(); 00270 } 00271 00272 /****************************************************************************** 00273 * Return whether there is any text. 00274 */ 00275 bool AlarmText::isEmpty() const 00276 { 00277 if (!d->mBody.isEmpty()) 00278 return false; 00279 if (d->mType != Private::Email) 00280 return true; 00281 return d->mFrom.isEmpty() && d->mTo.isEmpty() && d->mCc.isEmpty() && d->mTime.isEmpty() && d->mSubject.isEmpty(); 00282 } 00283 00284 bool AlarmText::isEmail() const 00285 { 00286 return d->mType == Private::Email; 00287 } 00288 00289 bool AlarmText::isScript() const 00290 { 00291 return d->mType == Private::Script; 00292 } 00293 00294 bool AlarmText::isTodo() const 00295 { 00296 return d->mType == Private::Todo; 00297 } 00298 00299 unsigned long AlarmText::kmailSerialNumber() const 00300 { 00301 return d->mKMailSerialNum; 00302 } 00303 00304 /****************************************************************************** 00305 * Return the alarm summary text for either single line or tooltip display. 00306 * The maximum number of line returned is determined by 'maxLines'. 00307 * If 'truncated' is non-null, it will be set true if the text returned has been 00308 * truncated, other than to strip a trailing newline. 00309 */ 00310 QString AlarmText::summary(const KAEvent& event, int maxLines, bool* truncated) 00311 { 00312 static const QRegExp localfile("^file:/+"); 00313 QString text; 00314 switch (event.actionSubType()) 00315 { 00316 case KAEvent::AUDIO: 00317 text = event.audioFile(); 00318 if (localfile.indexIn(text) >= 0) 00319 text = text.mid(localfile.matchedLength() - 1); 00320 break; 00321 case KAEvent::EMAIL: 00322 text = event.emailSubject(); 00323 break; 00324 case KAEvent::COMMAND: 00325 text = event.cleanText(); 00326 if (localfile.indexIn(text) >= 0) 00327 text = text.mid(localfile.matchedLength() - 1); 00328 break; 00329 case KAEvent::FILE: 00330 text = event.cleanText(); 00331 break; 00332 case KAEvent::MESSAGE: 00333 { 00334 text = event.cleanText(); 00335 // If the message is the text of an email, return its headers or just subject line 00336 QString subject = emailHeaders(text, (maxLines <= 1)); 00337 if (!subject.isNull()) 00338 { 00339 if (truncated) 00340 *truncated = true; 00341 return subject; 00342 } 00343 if (maxLines == 1) 00344 { 00345 // If the message is the text of a todo, return either the 00346 // title/description or the whole text. 00347 subject = Private::todoTitle(text); 00348 if (!subject.isEmpty()) 00349 { 00350 if (truncated) 00351 *truncated = true; 00352 return subject; 00353 } 00354 } 00355 break; 00356 } 00357 } 00358 if (truncated) 00359 *truncated = false; 00360 if (text.count('\n') < maxLines) 00361 return text; 00362 int newline = -1; 00363 for (int i = 0; i < maxLines; ++i) 00364 { 00365 newline = text.indexOf('\n', newline + 1); 00366 if (newline < 0) 00367 return text; // not truncated after all !?! 00368 } 00369 if (newline == static_cast<int>(text.length()) - 1) 00370 return text.left(newline); // text ends in newline 00371 if (truncated) 00372 *truncated = true; 00373 return text.left(newline + (maxLines <= 1 ? 0 : 1)) + QLatin1String("..."); 00374 } 00375 00376 /****************************************************************************** 00377 * Check whether a text is an email. 00378 */ 00379 bool AlarmText::checkIfEmail(const QString& text) 00380 { 00381 QStringList lines = text.split('\n', QString::SkipEmptyParts); 00382 return Private::emailHeaderCount(lines); 00383 } 00384 00385 /****************************************************************************** 00386 * Check whether a text is an email, and if so return its headers or optionally 00387 * only its subject line. 00388 * Reply = headers/subject line, or QString() if not the text of an email. 00389 */ 00390 QString AlarmText::emailHeaders(const QString& text, bool subjectOnly) 00391 { 00392 QStringList lines = text.split('\n', QString::SkipEmptyParts); 00393 int n = Private::emailHeaderCount(lines); 00394 if (!n) 00395 return QString(); 00396 if (subjectOnly) 00397 return lines[n-1].mid(Private::mSubjectPrefix.length()).trimmed(); 00398 QString h = lines[0]; 00399 for (int i = 1; i < n; ++i) 00400 { 00401 h += '\n'; 00402 h += lines[i]; 00403 } 00404 return h; 00405 } 00406 00407 /****************************************************************************** 00408 * Translate an alarm calendar text to a display text. 00409 * Translation is needed for email texts, since the alarm calendar stores 00410 * untranslated email prefixes. 00411 * 'email' is set to indicate whether it is an email text. 00412 */ 00413 QString AlarmText::fromCalendarText(const QString& text, bool& email) 00414 { 00415 Private::initialise(); 00416 QStringList lines = text.split('\n', QString::SkipEmptyParts); 00417 int maxn = lines.count(); 00418 if (maxn >= 4 00419 && lines[0].startsWith(Private::mFromPrefixEn) 00420 && lines[1].startsWith(Private::mToPrefixEn)) 00421 { 00422 int n = 2; 00423 if (lines[2].startsWith(Private::mCcPrefixEn)) 00424 ++n; 00425 if (maxn > n + 1 00426 && lines[n].startsWith(Private::mDatePrefixEn) 00427 && lines[n+1].startsWith(Private::mSubjectPrefixEn)) 00428 { 00429 Private::setUpTranslations(); 00430 QString dispText; 00431 dispText = Private::mFromPrefix + lines[0].mid(Private::mFromPrefixEn.length()) + '\n'; 00432 dispText += Private::mToPrefix + lines[1].mid(Private::mToPrefixEn.length()) + '\n'; 00433 if (n == 3) 00434 dispText += Private::mCcPrefix + lines[2].mid(Private::mCcPrefixEn.length()) + '\n'; 00435 dispText += Private::mDatePrefix + lines[n].mid(Private::mDatePrefixEn.length()) + '\n'; 00436 dispText += Private::mSubjectPrefix + lines[n+1].mid(Private::mSubjectPrefixEn.length()); 00437 int i = text.indexOf(Private::mSubjectPrefixEn); 00438 i = text.indexOf('\n', i); 00439 if (i > 0) 00440 dispText += text.mid(i); 00441 email = true; 00442 return dispText; 00443 } 00444 } 00445 email = false; 00446 return text; 00447 } 00448 00449 /****************************************************************************** 00450 * Return the text for a text message alarm, in alarm calendar format. 00451 * (The prefix strings are untranslated in the calendar.) 00452 */ 00453 QString AlarmText::toCalendarText(const QString& text) 00454 { 00455 Private::setUpTranslations(); 00456 QStringList lines = text.split('\n', QString::SkipEmptyParts); 00457 int maxn = lines.count(); 00458 if (maxn >= 4 00459 && lines[0].startsWith(Private::mFromPrefix) 00460 && lines[1].startsWith(Private::mToPrefix)) 00461 { 00462 int n = 2; 00463 if (lines[2].startsWith(Private::mCcPrefix)) 00464 ++n; 00465 if (maxn > n + 1 00466 && lines[n].startsWith(Private::mDatePrefix) 00467 && lines[n+1].startsWith(Private::mSubjectPrefix)) 00468 { 00469 // Format the email into a text alarm 00470 QString calText; 00471 calText = Private::mFromPrefixEn + lines[0].mid(Private::mFromPrefix.length()) + '\n'; 00472 calText += Private::mToPrefixEn + lines[1].mid(Private::mToPrefix.length()) + '\n'; 00473 if (n == 3) 00474 calText += Private::mCcPrefixEn + lines[2].mid(Private::mCcPrefix.length()) + '\n'; 00475 calText += Private::mDatePrefixEn + lines[n].mid(Private::mDatePrefix.length()) + '\n'; 00476 calText += Private::mSubjectPrefixEn + lines[n+1].mid(Private::mSubjectPrefix.length()); 00477 int i = text.indexOf(Private::mSubjectPrefix); 00478 i = text.indexOf('\n', i); 00479 if (i > 0) 00480 calText += text.mid(i); 00481 return calText; 00482 } 00483 } 00484 return text; 00485 } 00486 00487 void AlarmText::Private::clear() 00488 { 00489 mType = None; 00490 mBody.clear(); 00491 mTo.clear(); 00492 mFrom.clear(); 00493 mCc.clear(); 00494 mTime.clear(); 00495 mSubject.clear(); 00496 mKMailSerialNum = 0; 00497 } 00498 00499 /****************************************************************************** 00500 * Set up messages used by executeDropEvent() and emailHeaders(). 00501 */ 00502 void AlarmText::Private::setUpTranslations() 00503 { 00504 initialise(); 00505 if (mFromPrefix.isNull()) 00506 { 00507 mFromPrefix = i18nc("@info/plain 'From' email address", "From:"); 00508 mToPrefix = i18nc("@info/plain Email addressee", "To:"); 00509 mCcPrefix = i18nc("@info/plain Copy-to in email headers", "Cc:"); 00510 mDatePrefix = i18nc("@info/plain", "Date:"); 00511 mSubjectPrefix = i18nc("@info/plain Email subject", "Subject:"); 00512 // Todo prefixes 00513 mTitlePrefix = i18nc("@info/plain Todo calendar item's title field", "To-do:"); 00514 mLocnPrefix = i18nc("@info/plain Todo calendar item's location field", "Location:"); 00515 mDuePrefix = i18nc("@info/plain Todo calendar item's due date/time", "Due:"); 00516 } 00517 } 00518 00519 /****************************************************************************** 00520 * Check whether a text is an email. 00521 * Reply = number of email header lines, or 0 if not an email. 00522 */ 00523 int AlarmText::Private::emailHeaderCount(const QStringList& lines) 00524 { 00525 setUpTranslations(); 00526 int maxn = lines.count(); 00527 if (maxn >= 4 00528 && lines[0].startsWith(mFromPrefix) 00529 && lines[1].startsWith(mToPrefix)) 00530 { 00531 int n = 2; 00532 if (lines[2].startsWith(mCcPrefix)) 00533 ++n; 00534 if (maxn > n + 1 00535 && lines[n].startsWith(mDatePrefix) 00536 && lines[n+1].startsWith(mSubjectPrefix)) 00537 return n+2; 00538 } 00539 return 0; 00540 } 00541 00542 /****************************************************************************** 00543 * Return the Todo title line, if the text is for a Todo. 00544 */ 00545 QString AlarmText::Private::todoTitle(const QString& text) 00546 { 00547 setUpTranslations(); 00548 QStringList lines = text.split('\n', QString::SkipEmptyParts); 00549 int n; 00550 for (n = 0; n < lines.count() && lines[n].contains('\t'); ++n) ; 00551 if (!n || n > 3) 00552 return QString(); 00553 QString title; 00554 int i = 0; 00555 if (lines[i].startsWith(mTitlePrefix + '\t')) 00556 { 00557 title = lines[i].mid(mTitlePrefix.length()).trimmed(); 00558 ++i; 00559 } 00560 if (i < n && lines[i].startsWith(mLocnPrefix + '\t')) 00561 ++i; 00562 if (i < n && lines[i].startsWith(mDuePrefix + '\t')) 00563 ++i; 00564 if (i == n) 00565 { 00566 // It's a Todo text 00567 if (!title.isEmpty()) 00568 return title; 00569 if (n < lines.count()) 00570 return lines[n]; 00571 } 00572 return QString(); 00573 } 00574 00575 } // namespace KAlarmCal 00576 00577 // vim: et sw=4:
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Aug 27 2012 22:10:38 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Aug 27 2012 22:10:38 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.