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

akonadi

  • sources
  • kde-4.12
  • kdepimlibs
  • akonadi
  • contact
standardcontactformatter.cpp
1 /*
2  This file is part of Akonadi Contact.
3 
4  Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
5 
6  This library is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Library General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or (at your
9  option) any later version.
10 
11  This library is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14  License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301, USA.
20 */
21 
22 #include "standardcontactformatter.h"
23 
24 #include <akonadi/item.h>
25 #include <kabc/addressee.h>
26 #include <kcolorscheme.h>
27 #include <kconfiggroup.h>
28 #include <kglobal.h>
29 #include <klocale.h>
30 #include <klocalizedstring.h>
31 #include <kstringhandler.h>
32 
33 #include <QtCore/QSet>
34 #include <QTextDocument>
35 
36 using namespace Akonadi;
37 
38 class StandardContactFormatter::Private
39 {
40 public:
41  Private()
42  :displayQRcode(true)
43  {
44 
45  }
46 
47  bool displayQRcode;
48 };
49 
50 StandardContactFormatter::StandardContactFormatter()
51  : d( new Private() )
52 {
53 }
54 
55 StandardContactFormatter::~StandardContactFormatter()
56 {
57  delete d;
58 }
59 
60 static int contactAge( const QDate &date )
61 {
62  QDate now = QDate::currentDate();
63  int age = now.year() - date.year();
64  if ( date > now.addYears( -age ) ) {
65  age--;
66  }
67  return age;
68 }
69 
70 QString StandardContactFormatter::toHtml( HtmlForm form ) const
71 {
72  KABC::Addressee rawContact;
73  const Akonadi::Item localItem = item();
74  if ( localItem.isValid() && localItem.hasPayload<KABC::Addressee>() ) {
75  rawContact = localItem.payload<KABC::Addressee>();
76  } else {
77  rawContact = contact();
78  }
79 
80  if ( rawContact.isEmpty() ) {
81  return QString();
82  }
83 
84  // We'll be building a table to display the vCard in.
85  // Each row of the table will be built using one of these strings for its HTML.
86 
87  // single data item:
88  // %1 is the item name
89  // %2 is the item value
90  QString rowFmtStr1 = QString::fromLatin1(
91  "<tr valign=\"top\">"
92  "<td align=\"right\" valign=\"top\" width=\"30%\"><b><font color=\"grey\">%1</font></b></td>\n"
93  "<td colspan=\"2\" align=\"left\" valign=\"top\" width=\"70%\"><font>%2</font></td>\n"
94  "</tr>\n"
95  );
96 
97  // data item plus additional icon(s):
98  // %1 is the item name
99  // %2 is the item value
100  // %3 is the icon(s), each as a HTML <a><img> tag
101  QString rowFmtStr2 = QString::fromLatin1(
102  "<tr valign=\"top\">"
103  "<td align=\"right\" valign=\"top\" width=\"30%\"><b><font color=\"grey\">%1</font></b></td>\n"
104  "<td align=\"left\" valign=\"top\"><font>%2</font></td>\n"
105  "<td align=\"left\" valign=\"top\">%3</td>\n"
106  "</tr>\n"
107  );
108 
109  // Build the table's rows here
110  QString dynamicPart;
111 
112  // Birthday
113  const QDate date = rawContact.birthday().date();
114  const int years = contactAge( date );
115 
116  if ( date.isValid() ) {
117  dynamicPart += rowFmtStr1
118  .arg( KABC::Addressee::birthdayLabel() )
119  .arg( KGlobal::locale()->formatDate( date ) +
120  QLatin1String( "&nbsp;&nbsp;" ) + i18np( "(One year old)", "(%1 years old)", years ) );
121  }
122 
123  // Phone Numbers
124  int counter = 0;
125  foreach ( const KABC::PhoneNumber &number, rawContact.phoneNumbers() ) {
126 
127  QString dispLabel = number.typeLabel().replace( QLatin1String( " " ), QLatin1String( "&nbsp;" ) );
128  QString dispValue = QString::fromLatin1( "<a href=\"phone:?index=%1\">%2</a>" ).arg( counter ).arg( Qt::escape( number.number() ) );
129  if ( number.type() & KABC::PhoneNumber::Cell ) {
130  QString dispIcon = QString::fromLatin1( "<a href=\"sms:?index=%1\" title=\"%2\"><img src=\"sms_icon\" align=\"top\"/>")
131  .arg( counter )
132  .arg( i18nc( "@info:tooltip", "Send SMS" ) );
133  dynamicPart += rowFmtStr2
134  .arg( dispLabel )
135  .arg( dispValue )
136  .arg( dispIcon );
137  } else {
138  dynamicPart += rowFmtStr1
139  .arg( dispLabel )
140  .arg( dispValue );
141  }
142 
143  ++counter;
144  }
145 
146  // EMails
147  foreach ( const QString &email, rawContact.emails() ) {
148  const QString type = i18nc( "a contact's email address", "Email" );
149 
150  const QString fullEmail = QString::fromLatin1( KUrl::toPercentEncoding( rawContact.fullEmail( email ) ) );
151 
152  dynamicPart += rowFmtStr1.arg( type )
153  .arg( QString::fromLatin1( "<a href=\"mailto:%1\">%2</a>" )
154  .arg( fullEmail, email ) );
155  }
156 
157  // Homepage
158  if ( rawContact.url().isValid() ) {
159  QString url = rawContact.url().url();
160  if ( !url.startsWith( QLatin1String( "http://" ) ) && !url.startsWith( QLatin1String( "https://" ) ) ) {
161  url = QLatin1String( "http://" ) + url;
162  }
163 
164  url = KStringHandler::tagUrls( Qt::escape( url ) );
165  dynamicPart += rowFmtStr1.arg( i18n( "Homepage" ) ).arg( url );
166  }
167 
168  // Blog Feed
169  const QString blog = rawContact.custom( QLatin1String( "KADDRESSBOOK" ), QLatin1String( "BlogFeed" ) );
170  if ( !blog.isEmpty() ) {
171  dynamicPart += rowFmtStr1.arg( i18n( "Blog Feed" ) ).arg( KStringHandler::tagUrls( Qt::escape( blog ) ) );
172  }
173 
174  // Addresses
175  counter = 0;
176  foreach ( const KABC::Address &address, rawContact.addresses() ) {
177  QString formattedAddress;
178 
179  if ( address.label().isEmpty() ) {
180  formattedAddress = Qt::escape( address.formattedAddress().trimmed() );
181  } else {
182  formattedAddress = Qt::escape( address.label() );
183  }
184 
185  formattedAddress = formattedAddress.replace( QRegExp( QLatin1String( "\n+" ) ), QLatin1String( "<br>" ) );
186 
187  const QString url = QString::fromLatin1( "<a href=\"address:?index=%1\" title=\"%2\"><img src=\"map_icon\" alt=\"%2\"/></a>" )
188  .arg( counter )
189  .arg( i18nc( "@info:tooltip", "Show address on map" ) );
190  counter++;
191 
192  dynamicPart += rowFmtStr2
193  .arg( KABC::Address::typeLabel( address.type() ) )
194  .arg( formattedAddress )
195  .arg( url );
196  }
197 
198  // Note
199  QString notes;
200  if ( !rawContact.note().isEmpty() ) {
201  notes = rowFmtStr1.arg( i18n( "Notes" ) ).arg( Qt::escape( rawContact.note() ).replace( QLatin1Char( '\n' ), QLatin1String( "<br>" ) ) ) ;
202  }
203 
204  // Custom Data
205  QString customData;
206  static QMap<QString, QString> titleMap;
207  if ( titleMap.isEmpty() ) {
208  titleMap.insert( QLatin1String( "Department" ), i18n( "Department" ) );
209  titleMap.insert( QLatin1String( "Profession" ), i18n( "Profession" ) );
210  titleMap.insert( QLatin1String( "AssistantsName" ), i18n( "Assistant's Name" ) );
211  titleMap.insert( QLatin1String( "ManagersName" ), i18n( "Manager's Name" ) );
212  titleMap.insert( QLatin1String( "SpousesName" ), i18nc( "Wife/Husband/...", "Partner's Name" ) );
213  titleMap.insert( QLatin1String( "Office" ), i18n( "Office" ) );
214  titleMap.insert( QLatin1String( "IMAddress" ), i18n( "IM Address" ) );
215  titleMap.insert( QLatin1String( "Anniversary" ), i18n( "Anniversary" ) );
216  titleMap.insert( QLatin1String( "AddressBook" ), i18n( "Address Book" ) );
217  }
218 
219  static QSet<QString> blacklistedKeys;
220  if ( blacklistedKeys.isEmpty() ) {
221  blacklistedKeys.insert( QLatin1String( "CRYPTOPROTOPREF" ) );
222  blacklistedKeys.insert( QLatin1String( "OPENPGPFP" ) );
223  blacklistedKeys.insert( QLatin1String( "SMIMEFP" ) );
224  blacklistedKeys.insert( QLatin1String( "CRYPTOSIGNPREF" ) );
225  blacklistedKeys.insert( QLatin1String( "CRYPTOENCRYPTPREF" ) );
226  blacklistedKeys.insert( QLatin1String( "MailPreferedFormatting" ) );
227  blacklistedKeys.insert( QLatin1String( "MailAllowToRemoteContent" ) );
228  }
229 
230  if ( !rawContact.customs().empty() ) {
231  const QStringList customs = rawContact.customs();
232  foreach ( QString custom, customs ) { //krazy:exclude=foreach
233  if ( custom.startsWith( QLatin1String( "KADDRESSBOOK-" ) ) ) {
234  custom.remove( QLatin1String( "KADDRESSBOOK-X-" ) );
235  custom.remove( QLatin1String( "KADDRESSBOOK-" ) );
236 
237  int pos = custom.indexOf( QLatin1Char( ':' ) );
238  QString key = custom.left( pos );
239  QString value = custom.mid( pos + 1 );
240 
241  // convert anniversary correctly
242  if ( key == QLatin1String( "Anniversary" ) || key == QLatin1String( "ANNIVERSARY" ) ) {
243  const QDateTime dateTime = QDateTime::fromString( value, Qt::ISODate );
244  value = KGlobal::locale()->formatDate( dateTime.date() );
245  } else if ( key == QLatin1String( "BlogFeed" ) ) { // blog is handled separated
246  continue;
247  } else if ( blacklistedKeys.contains( key ) ) {
248  continue;
249  }
250 
251  // check whether we have a mapping for the title
252  const QMap<QString, QString>::ConstIterator keyIt = titleMap.constFind( key );
253  bool needToEscape = true;
254  if ( keyIt != titleMap.constEnd() ) {
255  key = keyIt.value();
256  } else {
257  // check whether it is a custom local field
258  foreach ( const QVariantMap &description, customFieldDescriptions() ) {
259  if ( description.value( QLatin1String( "key" ) ).toString() == key ) {
260  key = description.value( QLatin1String( "title" ) ).toString();
261  const QString descriptionType = description.value( QLatin1String( "type" ) ).toString();
262  if ( descriptionType == QLatin1String( "boolean" ) ) {
263  if ( value == QLatin1String( "true" ) ) {
264  value = i18nc( "Boolean value", "yes" );
265  } else {
266  value = i18nc( "Boolean value", "no" );
267  }
268  } else if ( descriptionType == QLatin1String( "date" ) ) {
269  const QDate date = QDate::fromString( value, Qt::ISODate );
270  value = KGlobal::locale()->formatDate( date, KLocale::ShortDate );
271  } else if ( descriptionType == QLatin1String( "time" ) ) {
272  const QTime time = QTime::fromString( value, Qt::ISODate );
273  value = KGlobal::locale()->formatTime( time );
274  } else if ( descriptionType == QLatin1String( "datetime" ) ) {
275  const QDateTime dateTime = QDateTime::fromString( value, Qt::ISODate );
276  value = KGlobal::locale()->formatDateTime( dateTime, KLocale::ShortDate );
277  } else if ( descriptionType == QLatin1String("url") ) {
278  value = KStringHandler::tagUrls( Qt::escape(value) );
279  needToEscape = false;
280  }
281 
282  break;
283  }
284  }
285  }
286  if (needToEscape)
287  value = Qt::escape( value );
288  customData += rowFmtStr1.arg( key ).arg( value );
289  }
290  }
291  }
292 
293  // Assemble all parts
294  QString role = rawContact.title();
295  if ( role.isEmpty() ) {
296  role = rawContact.role();
297  }
298  if ( role.isEmpty() ) {
299  role = rawContact.custom( QLatin1String( "KADDRESSBOOK" ), QLatin1String( "X-Profession" ) );
300  }
301 
302  QString strAddr = QString::fromLatin1(
303  "<div align=\"center\">"
304  "<table cellpadding=\"3\" cellspacing=\"1\">"
305  "<tr>"
306  "<td align=\"right\" valign=\"top\" width=\"30%\" rowspan=\"3\">"
307  "<img src=\"%1\" width=\"100\" vspace=\"1\">" // image
308  "</td>"
309  "<td colspan=\"2\" align=\"left\" width=\"70%\"><font size=\"+2\"><b>%2</b></font></td>" // name
310  "</tr>"
311  "<tr>"
312  "<td colspan=\"2\" align=\"left\" width=\"70%\">%3</td>" // role
313  "</tr>"
314  "<tr>"
315  "<td colspan=\"2\" align=\"left\" width=\"70%\">%4</td>" // organization
316  "</tr>")
317  .arg( QLatin1String( "contact_photo" ) )
318  .arg( Qt::escape( rawContact.realName() ) )
319  .arg( Qt::escape( role ) )
320  .arg( Qt::escape( rawContact.organization() ) );
321 
322  strAddr.append( dynamicPart );
323  strAddr.append( notes );
324  strAddr.append( customData );
325  strAddr.append( QString::fromLatin1( "</table>" ) );
326 
327 #ifdef HAVE_PRISON
328  if (d->displayQRcode) {
329  KConfig config( QLatin1String( "akonadi_contactrc" ) );
330  KConfigGroup group( &config, QLatin1String( "View" ) );
331  if ( group.readEntry( "QRCodes", true ) ) {
332  strAddr.append( QString::fromLatin1(
333  "<p align=\"center\">"
334  "<img src=\"%1\" vspace=\"1\">"
335  "<img src=\"%2\" vspace=\"1\">"
336  "</p>"
337  )
338  .arg( QLatin1String( "datamatrix" ) )
339  .arg( QLatin1String( "qrcode" ) ) );
340  }
341  }
342 #endif // HAVE_PRISON
343 
344  strAddr.append( QString::fromLatin1( "</div>\n" ) );
345 
346  if ( form == EmbeddableForm ) {
347  return strAddr;
348  }
349 
350  const QString document = QString::fromLatin1(
351  "<html>"
352  "<head>"
353  " <style type=\"text/css\">"
354  " a {text-decoration:none; color:%1}"
355  " </style>"
356  "</head>"
357  "<body text=\"%1\" bgcolor=\"%2\">" // text and background color
358  "%3" // contact part
359  "</body>"
360  "</html>" )
361  .arg( KColorScheme( QPalette::Active, KColorScheme::View ).foreground().color().name() )
362  .arg( KColorScheme( QPalette::Active, KColorScheme::View ).background().color().name() )
363  .arg( strAddr );
364 
365  return document;
366 }
367 
368 void StandardContactFormatter::setDisplayQRCode( bool show )
369 {
370  d->displayQRcode = show;
371 }
372 
373 bool StandardContactFormatter::displayQRCode() const
374 {
375  return d->displayQRcode;
376 }
377 
Akonadi::AbstractContactFormatter::HtmlForm
HtmlForm
Describes the form of the HTML that is created.
Definition: abstractcontactformatter.h:52
Akonadi::AbstractContactFormatter::EmbeddableForm
Creates a div HTML element that can be embedded.
Definition: abstractcontactformatter.h:54
Akonadi::StandardContactFormatter::~StandardContactFormatter
virtual ~StandardContactFormatter()
Destroys the standard contact formatter.
Definition: standardcontactformatter.cpp:55
Akonadi::AbstractContactFormatter::customFieldDescriptions
QList< QVariantMap > customFieldDescriptions() const
Returns the custom field descriptions that will be used.
Definition: abstractcontactformatter.cpp:72
Akonadi::AbstractContactFormatter::contact
KABC::Addressee contact() const
Returns the contact that will be formatted.
Definition: abstractcontactformatter.cpp:52
Akonadi::StandardContactFormatter::toHtml
virtual QString toHtml(HtmlForm form=SelfcontainedForm) const
Returns the contact formatted as HTML.
Definition: standardcontactformatter.cpp:70
Akonadi::StandardContactFormatter::StandardContactFormatter
StandardContactFormatter()
Creates a new standard contact formatter.
Definition: standardcontactformatter.cpp:50
Akonadi::AbstractContactFormatter::item
Akonadi::Item item() const
Returns the item who's payload will be formatted.
Definition: abstractcontactformatter.cpp:62
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:00:28 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

Search



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