akonadi/contact
contactviewer.cpp
00001 /* 00002 This file is part of Akonadi Contact. 00003 00004 Copyright (c) 2009 Tobias Koenig <tokoe@kde.org> 00005 00006 This library is free software; you can redistribute it and/or modify it 00007 under the terms of the GNU Library General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or (at your 00009 option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, but WITHOUT 00012 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00013 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00014 License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to the 00018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00019 02110-1301, USA. 00020 */ 00021 00022 #include "contactviewer.h" 00023 00024 #include "contactmetadata_p.h" 00025 #include "contactmetadataattribute_p.h" 00026 #include "customfieldmanager_p.h" 00027 #include "standardcontactformatter.h" 00028 #include "textbrowser_p.h" 00029 00030 #include <akonadi/collection.h> 00031 #include <akonadi/collectionfetchjob.h> 00032 #include <akonadi/entitydisplayattribute.h> 00033 #include <akonadi/item.h> 00034 #include <akonadi/itemfetchscope.h> 00035 #include <kabc/addressee.h> 00036 #include <kcolorscheme.h> 00037 #include <kglobal.h> 00038 #include <kicon.h> 00039 #include <klocale.h> 00040 #include <kstringhandler.h> 00041 00042 #include <QtGui/QVBoxLayout> 00043 00044 #ifdef HAVE_PRISON 00045 #include <prison/QRCodeBarcode> 00046 #include <prison/DataMatrixBarcode> 00047 #include <kabc/vcardconverter.h> 00048 #endif // HAVE_PRISON 00049 00050 using namespace Akonadi; 00051 00052 class ContactViewer::Private 00053 { 00054 public: 00055 Private( ContactViewer *parent ) 00056 : mParent( parent ), mParentCollectionFetchJob( 0 ) 00057 { 00058 mStandardContactFormatter = new StandardContactFormatter; 00059 mContactFormatter = mStandardContactFormatter; 00060 #ifdef HAVE_PRISON 00061 mQRCode = new prison::QRCodeBarcode(); 00062 mDataMatrix = new prison::DataMatrixBarcode(); 00063 #endif // HAVE_PRISON 00064 } 00065 00066 ~Private() 00067 { 00068 delete mStandardContactFormatter; 00069 #ifdef HAVE_PRISON 00070 delete mQRCode; 00071 delete mDataMatrix; 00072 #endif // HAVE_PRISON 00073 } 00074 00075 void updateView( const QVariantList &localCustomFieldDescriptions = QVariantList(), const QString &addressBookName = QString() ) 00076 { 00077 static QPixmap defaultPixmap = KIcon( QLatin1String( "user-identity" ) ).pixmap( QSize( 100, 100 ) ); 00078 00079 mParent->setWindowTitle( i18n( "Contact %1", mCurrentContact.assembledName() ) ); 00080 00081 if ( mCurrentContact.photo().isIntern() ) { 00082 mBrowser->document()->addResource( QTextDocument::ImageResource, 00083 QUrl( QLatin1String( "contact_photo" ) ), 00084 mCurrentContact.photo().data() ); 00085 } else { 00086 mBrowser->document()->addResource( QTextDocument::ImageResource, 00087 QUrl( QLatin1String( "contact_photo" ) ), 00088 defaultPixmap ); 00089 } 00090 00091 mBrowser->document()->addResource( QTextDocument::ImageResource, 00092 QUrl( QLatin1String( "map_icon" ) ), 00093 KIcon( QLatin1String( "document-open-remote" ) ).pixmap( QSize( 16, 16 ) ) ); 00094 00095 #ifdef HAVE_PRISON 00096 { 00097 KABC::VCardConverter converter; 00098 KABC::Addressee addr(mCurrentContact); 00099 addr.setPhoto(KABC::Picture()); 00100 addr.setLogo(KABC::Picture()); 00101 const QString data = QString::fromUtf8( converter.createVCard( addr ) ); 00102 mQRCode->setData( data ); 00103 mDataMatrix->setData( data ); 00104 mBrowser->document()->addResource( QTextDocument::ImageResource, 00105 QUrl( QLatin1String( "qrcode" ) ), 00106 mQRCode->toImage( QSizeF(50,50) ) ); 00107 mBrowser->document()->addResource( QTextDocument::ImageResource, 00108 QUrl( QLatin1String( "datamatrix" ) ), 00109 mDataMatrix->toImage( QSizeF(50,50) ) ); 00110 } 00111 #endif // HAVE_PRISON 00112 00113 // merge local and global custom field descriptions 00114 QList<QVariantMap> customFieldDescriptions; 00115 foreach ( const QVariant &entry, localCustomFieldDescriptions ) 00116 customFieldDescriptions << entry.toMap(); 00117 00118 const CustomField::List globalCustomFields = CustomFieldManager::globalCustomFieldDescriptions(); 00119 foreach ( const CustomField &field, globalCustomFields ) { 00120 QVariantMap description; 00121 description.insert( QLatin1String( "key" ), field.key() ); 00122 description.insert( QLatin1String( "title" ), field.title() ); 00123 00124 customFieldDescriptions << description; 00125 } 00126 00127 KABC::Addressee contact( mCurrentContact ); 00128 if ( !addressBookName.isEmpty() ) { 00129 contact.insertCustom( QLatin1String( "KADDRESSBOOK" ), QLatin1String( "AddressBook" ), addressBookName ); 00130 } 00131 00132 mContactFormatter->setContact( contact ); 00133 mContactFormatter->setCustomFieldDescriptions( customFieldDescriptions ); 00134 00135 mBrowser->setHtml( mContactFormatter->toHtml() ); 00136 } 00137 00138 void slotMailClicked( const QString&, const QString &email ) 00139 { 00140 QString name, address; 00141 00142 // remove the 'mailto:' and split into name and email address 00143 KABC::Addressee::parseEmailAddress( email.mid( 7 ), name, address ); 00144 00145 emit mParent->emailClicked( name, address ); 00146 } 00147 00148 void slotUrlClicked( const QString &urlString ) 00149 { 00150 KUrl url( urlString ); 00151 00152 if ( url.scheme() == QLatin1String( "http" ) || 00153 url.scheme() == QLatin1String( "https" ) ) { 00154 emit mParent->urlClicked( url ); 00155 } else if ( url.scheme() == QLatin1String( "phone" ) ) { 00156 const int pos = url.queryItemValue( QLatin1String( "index" ) ).toInt(); 00157 00158 const KABC::PhoneNumber::List numbers = mCurrentContact.phoneNumbers(); 00159 if ( pos < numbers.count() ) { 00160 emit mParent->phoneNumberClicked( numbers.at( pos ) ); 00161 } 00162 } else if ( url.scheme() == QLatin1String( "sms" ) ) { 00163 const int pos = url.queryItemValue( QLatin1String( "index" ) ).toInt(); 00164 00165 const KABC::PhoneNumber::List numbers = mCurrentContact.phoneNumbers(); 00166 if ( pos < numbers.count() ) { 00167 emit mParent->smsClicked( numbers.at( pos ) ); 00168 } 00169 } else if ( url.scheme() == QLatin1String( "address" ) ) { 00170 const int pos = url.queryItemValue( QLatin1String( "index" ) ).toInt(); 00171 00172 const KABC::Address::List addresses = mCurrentContact.addresses(); 00173 if ( pos < addresses.count() ) { 00174 emit mParent->addressClicked( addresses.at( pos ) ); 00175 } 00176 } 00177 } 00178 00179 void slotParentCollectionFetched( KJob *job ) 00180 { 00181 mParentCollectionFetchJob = 0; 00182 00183 QString addressBookName; 00184 00185 if ( !job->error() ) { 00186 CollectionFetchJob *fetchJob = qobject_cast<CollectionFetchJob*>( job ); 00187 if ( !fetchJob->collections().isEmpty() ) { 00188 const Collection collection = fetchJob->collections().first(); 00189 if ( collection.hasAttribute<EntityDisplayAttribute>() ) 00190 addressBookName = collection.attribute<EntityDisplayAttribute>()->displayName(); 00191 else 00192 addressBookName = collection.name(); 00193 } 00194 } 00195 00196 // load the local meta data of the item 00197 ContactMetaData metaData; 00198 metaData.load( mCurrentItem ); 00199 00200 updateView( metaData.customFieldDescriptions(), addressBookName ); 00201 } 00202 00203 ContactViewer *mParent; 00204 TextBrowser *mBrowser; 00205 KABC::Addressee mCurrentContact; 00206 Item mCurrentItem; 00207 AbstractContactFormatter *mContactFormatter; 00208 AbstractContactFormatter *mStandardContactFormatter; 00209 CollectionFetchJob *mParentCollectionFetchJob; 00210 #ifdef HAVE_PRISON 00211 prison::AbstractBarcode* mQRCode; 00212 prison::AbstractBarcode* mDataMatrix; 00213 #endif // HAVE_PRISON 00214 }; 00215 00216 ContactViewer::ContactViewer( QWidget *parent ) 00217 : QWidget( parent ), d( new Private( this ) ) 00218 { 00219 QVBoxLayout *layout = new QVBoxLayout( this ); 00220 layout->setMargin( 0 ); 00221 00222 d->mBrowser = new TextBrowser; 00223 d->mBrowser->setNotifyClick( true ); 00224 00225 connect( d->mBrowser, SIGNAL( mailClick( const QString&, const QString& ) ), 00226 this, SLOT( slotMailClicked( const QString&, const QString& ) ) ); 00227 connect( d->mBrowser, SIGNAL( urlClick( const QString& ) ), 00228 this, SLOT( slotUrlClicked( const QString& ) ) ); 00229 00230 layout->addWidget( d->mBrowser ); 00231 00232 // always fetch full payload for contacts 00233 fetchScope().fetchFullPayload(); 00234 fetchScope().fetchAttribute<ContactMetaDataAttribute>(); 00235 fetchScope().setAncestorRetrieval( ItemFetchScope::Parent ); 00236 } 00237 00238 ContactViewer::~ContactViewer() 00239 { 00240 delete d; 00241 } 00242 00243 Akonadi::Item ContactViewer::contact() const 00244 { 00245 return ItemMonitor::item(); 00246 } 00247 00248 KABC::Addressee ContactViewer::rawContact() const 00249 { 00250 return d->mCurrentContact; 00251 } 00252 00253 void ContactViewer::setContactFormatter( AbstractContactFormatter *formatter ) 00254 { 00255 if ( formatter == 0 ) 00256 d->mContactFormatter = d->mStandardContactFormatter; 00257 else 00258 d->mContactFormatter = formatter; 00259 } 00260 00261 void ContactViewer::setContact( const Akonadi::Item &contact ) 00262 { 00263 ItemMonitor::setItem( contact ); 00264 } 00265 00266 void ContactViewer::setRawContact( const KABC::Addressee &contact ) 00267 { 00268 d->mCurrentContact = contact; 00269 00270 d->updateView(); 00271 } 00272 00273 void ContactViewer::itemChanged( const Item &contactItem ) 00274 { 00275 if ( !contactItem.hasPayload<KABC::Addressee>() ) 00276 return; 00277 00278 d->mCurrentItem = contactItem; 00279 d->mCurrentContact = contactItem.payload<KABC::Addressee>(); 00280 00281 // stop any running fetch job 00282 if ( d->mParentCollectionFetchJob ) { 00283 disconnect( d->mParentCollectionFetchJob, SIGNAL( result( KJob* ) ), this, SLOT( slotParentCollectionFetched( KJob* ) ) ); 00284 delete d->mParentCollectionFetchJob; 00285 d->mParentCollectionFetchJob = 0; 00286 } 00287 00288 d->mParentCollectionFetchJob = new CollectionFetchJob( contactItem.parentCollection(), CollectionFetchJob::Base, this ); 00289 connect( d->mParentCollectionFetchJob, SIGNAL( result( KJob* ) ), SLOT( slotParentCollectionFetched( KJob* ) ) ); 00290 } 00291 00292 void ContactViewer::itemRemoved() 00293 { 00294 d->mBrowser->clear(); 00295 } 00296 00297 #include "contactviewer.moc"