-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend.h | 70 | ||||
-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend_xml.h | 550 | ||||
-rw-r--r-- | libopie2/opiepim/core/ocontactaccess.cpp | 174 | ||||
-rw-r--r-- | libopie2/opiepim/core/ocontactaccess.h | 197 | ||||
-rw-r--r-- | libopie2/opiepim/ocontact.cpp | 1433 | ||||
-rw-r--r-- | libopie2/opiepim/ocontact.h | 311 |
6 files changed, 2735 insertions, 0 deletions
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend.h b/libopie2/opiepim/backend/ocontactaccessbackend.h new file mode 100644 index 0000000..9469bbc --- a/dev/null +++ b/libopie2/opiepim/backend/ocontactaccessbackend.h @@ -0,0 +1,70 @@ +/** + * The class responsible for managing a backend. + * The implementation of this abstract class contains + * the complete database handling. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; + * either version 2 of the License, or (at your option) any later + * version. + * ===================================================================== + * ToDo: Define enum for query settings + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2002/09/27 17:11:44 eilers + * Added API for accessing the Contact-Database ! It is compiling, but + * please do not expect that anything is working ! + * I will debug that stuff in the next time .. + * Please read README_COMPILE for compiling ! + * + * ===================================================================== + * + */ + +#ifndef _OCONTACTACCESSBACKEND_H_ +#define _OCONTACTACCESSBACKEND_H_ + +#include "opimaccessbackend.h" + +class OContactAccessBackend: public OPimAccessBackend<OContact> { + public: + OContactAccessBackend() {} + virtual ~OContactAccessBackend() {} + + + /** Return if database was changed externally. + * This may just make sense on file based databases like a XML-File. + * It is used to prevent to overwrite the current database content + * if the file was already changed by something else ! + * If this happens, we have to reload before save our data. + * If we use real databases, this should be handled by the database + * management system themselve, therefore this function should always return false in + * this case. It is not our problem to handle this conflict ... + * @return <i>true</i> if the database was changed and if save without reload will + * be dangerous. <i>false</i> if the database was not changed or it is save to write + * in this situation. + */ + virtual bool wasChangedExternally() = 0; + + /** Return all possible settings. + * @return All settings provided by the current backend + * (i.e.: query_WildCards & query_IgnoreCase) + */ + virtual const uint querySettings() = 0; + + /** Check whether settings are correct. + * @return <i>true</i> if the given settings are correct and possible. + */ + virtual bool hasQuerySettings (uint querySettings) const = 0; + + +}; +#endif diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h new file mode 100644 index 0000000..2cdb45b --- a/dev/null +++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h @@ -0,0 +1,550 @@ +/* + * XML Backend for the OPIE-Contact Database. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * ToDo: XML-Backend: Automatic reload if something was changed... + * + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2002/09/27 17:11:44 eilers + * Added API for accessing the Contact-Database ! It is compiling, but + * please do not expect that anything is working ! + * I will debug that stuff in the next time .. + * Please read README_COMPILE for compiling ! + * + * + */ + +#ifndef _OContactAccessBackend_XML_ +#define _OContactAccessBackend_XML_ + +#include <qasciidict.h> +#include <qdatetime.h> +#include <qfile.h> +#include <qregexp.h> +#include <qarray.h> + +#include <opie/xmltree.h> +#include "ocontactaccessbackend.h" + +using namespace Opie; + +/* the default xml implementation */ +class OContactAccessBackend_XML : public OContactAccessBackend { + public: + OContactAccessBackend_XML ( QString appname, QString filename = 0l ) + { + m_appName = appname; + + /* Set journalfile name ... */ + m_journalName = getenv("HOME"); + m_journalName +="/.abjournal" + appname; + + /* Expecting to access the default filename if nothing else is set */ + if ( filename.isEmpty() ){ + m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); + } else + m_fileName = filename; + + /* Load Database now */ + load (); + } + + bool save() { + QString strNewFile = m_fileName + ".new"; + QFile f( strNewFile ); + if ( !f.open( IO_WriteOnly|IO_Raw ) ) + return false; + + int total_written; + QString out; + out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" + " <Groups>\n" + " </Groups>\n" + " <Contacts>\n"; + //QValueList<Contact>::iterator it; + QValueListConstIterator<OContact> it; + for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) { + out += "<Contact "; + (*it).save( out ); + out += "/>\n"; + QCString cstr = out.utf8(); + total_written = f.writeBlock( cstr.data(), cstr.length() ); + if ( total_written != int(cstr.length()) ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + out = ""; + } + out += " </Contacts>\n</AddressBook>\n"; + + QCString cstr = out.utf8(); + total_written = f.writeBlock( cstr.data(), cstr.length() ); + if ( total_written != int( cstr.length() ) ) { + f.close(); + QFile::remove( strNewFile ); + return false; + } + f.close(); + + // move the file over, I'm just going to use the system call + // because, I don't feel like using QDir. + if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { + qWarning( "problem renaming file %s to %s, errno: %d", + strNewFile.latin1(), m_journalName.latin1(), errno ); + // remove the tmp file... + QFile::remove( strNewFile ); + } + + /* The journalfile should be removed now... */ + removeJournal(); + return true; + } + + bool load () { + m_contactList.clear(); + + /* Load XML-File and journal if it exists */ + if ( !load ( m_fileName, false ) ) + return false; + /* The returncode of the journalfile is ignored due to the + * fact that it does not exist when this class is instantiated ! + * But there may such a file exist, if the application crashed. + * Therefore we try to load it to get the changes before the # + * crash happened... + */ + load (m_journalName, true); + + return true; + } + + void clear () { + m_contactList.clear(); + + } + + bool wasChangedExternally() + { + QFileInfo fi( m_fileName ); + + QDateTime lastmod = fi.lastModified (); + + return (lastmod != m_readtime); + } + + QArray<int> allRecords() const { + QArray<int> uid_list( m_contactList.count() ); + + uint counter = 0; + QValueListConstIterator<OContact> it; + for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ + uid_list[counter++] = (*it).uid(); + } + + return ( uid_list ); + } + + OContact find ( int uid ) const + { + bool found = false; + OContact foundContact; //Create empty contact + + QValueListConstIterator<OContact> it; + for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ + if ((*it).uid() == uid){ + found = true; + break; + } + } + if ( found ){ + foundContact = *it; + } + + return ( foundContact ); + } + + QArray<int> queryByExample ( const OContact &query, int settings ){ + + QArray<int> m_currentQuery( m_contactList.count() ); + QValueListConstIterator<OContact> it; + uint arraycounter = 0; + + for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ + /* Search all fields and compare them with query object. Store them into list + * if all fields matches. + */ + bool allcorrect = true; + for ( int i = 0; i < Qtopia::rid; i++ ) { + /* Just compare fields which are not empty in the query object */ + if ( !query.field(i).isEmpty() ){ + switch ( settings & ~OContactAccess::query_IgnoreCase ){ + case OContactAccess::query_RegExp:{ + QRegExp expr ( query.field(i), + !(settings & OContactAccess::query_IgnoreCase), + false ); + if ( expr.find ( (*it).field(i), 0 ) == -1 ) + allcorrect = false; + } + break; + case OContactAccess::query_WildCards:{ + QRegExp expr ( query.field(i), + !(settings & OContactAccess::query_IgnoreCase), + true ); + if ( expr.find ( (*it).field(i), 0 ) == -1 ) + allcorrect = false; + } + break; + case OContactAccess::query_ExactMatch:{ + if (settings & OContactAccess::query_IgnoreCase){ + if ( query.field(i).upper() != + (*it).field(i).upper() ) + allcorrect = false; + }else{ + if ( query.field(i) != (*it).field(i) ) + allcorrect = false; + } + } + break; + } + } + } + if ( allcorrect ){ + m_currentQuery[arraycounter++] = (*it).uid(); + } + } + + // Shrink to fit.. + m_currentQuery.resize(arraycounter); + + return m_currentQuery; + } + + const uint querySettings() + { + return ( OContactAccess::query_WildCards + & OContactAccess::query_IgnoreCase + & OContactAccess::query_RegExp + & OContactAccess::query_ExactMatch ); + } + + bool hasQuerySettings (uint querySettings) const + { + /* OContactAccess::query_IgnoreCase may be added with one + * of the other settings, but never used alone. + * The other settings are just valid alone... + */ + switch ( querySettings & ~OContactAccess::query_IgnoreCase ){ + case OContactAccess::query_RegExp: + return ( true ); + case OContactAccess::query_WildCards: + return ( true ); + case OContactAccess::query_ExactMatch: + return ( true ); + default: + return ( false ); + } + } + + bool add ( const OContact &newcontact ) + { + //qWarning("odefaultbackend: ACTION::ADD"); + updateJournal (newcontact, OContact::ACTION_ADD); + addContact_p( newcontact ); + return true; + } + + bool replace ( const OContact &contact ) + { + bool found = false; + + QValueListIterator<OContact> it; + for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ + if ( (*it).uid() == contact.uid() ){ + found = true; + break; + } + } + if (found) { + updateJournal (contact, OContact::ACTION_REPLACE); + m_contactList.remove (it); + m_contactList.append (contact); + return true; + } else + return false; + } + + bool remove ( int uid ) + { + bool found = false; + QValueListIterator<OContact> it; + for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ + if ((*it).uid() == uid){ + found = true; + break; + } + } + if (found) { + updateJournal ( *it, OContact::ACTION_REMOVE); + m_contactList.remove (it); + return true; + } else + return false; + } + + bool reload(){ + /* Reload is the same as load in this implementation */ + return ( load() ); + } + + private: + void addContact_p( const OContact &newcontact ){ + m_contactList.append (newcontact); + } + + /* This function loads the xml-database and the journalfile */ + bool load( const QString filename, bool isJournal ) { + + /* We use the time of the last read to check if the file was + * changed externally. + */ + if ( !isJournal ){ + QFileInfo fi( filename ); + m_readtime = fi.lastModified (); + } + + const int JOURNALACTION = Qtopia::Notes + 1; + const int JOURNALROW = JOURNALACTION + 1; + + bool foundAction = false; + OContact::journal_action action = OContact::ACTION_ADD; + int journalKey = 0; + QMap<int, QString> contactMap; + QMap<QString, QString> customMap; + QMap<QString, QString>::Iterator customIt; + QAsciiDict<int> dict( 47 ); + + dict.setAutoDelete( TRUE ); + dict.insert( "Uid", new int(Qtopia::AddressUid) ); + dict.insert( "Title", new int(Qtopia::Title) ); + dict.insert( "FirstName", new int(Qtopia::FirstName) ); + dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); + dict.insert( "LastName", new int(Qtopia::LastName) ); + dict.insert( "Suffix", new int(Qtopia::Suffix) ); + dict.insert( "FileAs", new int(Qtopia::FileAs) ); + dict.insert( "Categories", new int(Qtopia::AddressCategory) ); + dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); + dict.insert( "Emails", new int(Qtopia::Emails) ); + dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); + dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); + dict.insert( "HomeState", new int(Qtopia::HomeState) ); + dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); + dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); + dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); + dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); + dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); + dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); + dict.insert( "Company", new int(Qtopia::Company) ); + dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); + dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); + dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); + dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); + dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); + dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); + dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); + dict.insert( "Department", new int(Qtopia::Department) ); + dict.insert( "Office", new int(Qtopia::Office) ); + dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); + dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); + dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); + dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); + dict.insert( "Profession", new int(Qtopia::Profession) ); + dict.insert( "Assistant", new int(Qtopia::Assistant) ); + dict.insert( "Manager", new int(Qtopia::Manager) ); + dict.insert( "Spouse", new int(Qtopia::Spouse) ); + dict.insert( "Children", new int(Qtopia::Children) ); + dict.insert( "Gender", new int(Qtopia::Gender) ); + dict.insert( "Birthday", new int(Qtopia::Birthday) ); + dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); + dict.insert( "Nickname", new int(Qtopia::Nickname) ); + dict.insert( "Notes", new int(Qtopia::Notes) ); + dict.insert( "action", new int(JOURNALACTION) ); + dict.insert( "actionrow", new int(JOURNALROW) ); + + //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); + + XMLElement *root = XMLElement::load( filename ); + if(root != 0l ){ // start parsing + /* Parse all XML-Elements and put the data into the + * Contact-Class + */ + XMLElement *element = root->firstChild(); + //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); + element = element->firstChild(); + + /* Search Tag "Contacts" which is the parent of all Contacts */ + while( element && !isJournal ){ + if( element->tagName() != QString::fromLatin1("Contacts") ){ + //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", + // element->tagName().latin1()); + element = element->nextChild(); + } else { + element = element->firstChild(); + break; + } + } + /* Parse all Contacts and ignore unknown tags */ + while( element ){ + if( element->tagName() != QString::fromLatin1("Contact") ){ + //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", + // element->tagName().latin1()); + element = element->nextChild(); + continue; + } + /* Found alement with tagname "contact", now parse and store all + * attributes contained + */ + //qWarning("OContactDefBack::load element tagName() : %s", + // element->tagName().latin1() ); + QString dummy; + foundAction = false; + + XMLElement::AttributeMap aMap = element->attributes(); + XMLElement::AttributeMap::Iterator it; + contactMap.clear(); + customMap.clear(); + for( it = aMap.begin(); it != aMap.end(); ++it ){ + // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); + + int *find = dict[ it.key() ]; + /* Unknown attributes will be stored as "Custom" elements */ + if ( !find ) { + qWarning("Attribute %s not known.", it.key().latin1()); + //contact.setCustomField(it.key(), it.data()); + customMap.insert( it.key(), it.data() ); + continue; + } + + /* Check if special conversion is needed and add attribute + * into Contact class + */ + switch( *find ) { + /* + case Qtopia::AddressUid: + contact.setUid( it.data().toInt() ); + break; + case Qtopia::AddressCategory: + contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); + break; + */ + case JOURNALACTION: + action = OContact::journal_action(it.data().toInt()); + foundAction = true; + qWarning ("ODefBack(journal)::ACTION found: %d", action); + break; + case JOURNALROW: + journalKey = it.data().toInt(); + break; + default: // no conversion needed add them to the map + contactMap.insert( *find, it.data() ); + break; + } + } + /* now generate the Contact contact */ + OContact contact( contactMap ); + + for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { + contact.setCustomField( customIt.key(), customIt.data() ); + } + + if (foundAction){ + foundAction = false; + switch ( action ) { + case OContact::ACTION_ADD: + addContact_p (contact); + break; + case OContact::ACTION_REMOVE: + if ( !remove (contact.uid()) ) + qWarning ("ODefBack(journal)::Unable to remove uid: %d", + contact.uid() ); + break; + case OContact::ACTION_REPLACE: + if ( !replace ( contact ) ) + qWarning ("ODefBack(journal)::Unable to replace uid: %d", + contact.uid() ); + break; + default: + qWarning ("Unknown action: ignored !"); + break; + } + }else{ + /* Add contact to list */ + addContact_p (contact); + } + + /* Move to next element */ + element = element->nextChild(); + } + }else { + qWarning("ODefBack::could not load"); + } + delete root; + qWarning("returning from loading" ); + return true; + } + + + void updateJournal( const OContact& cnt, + OContact::journal_action action ) { + QFile f( m_journalName ); + bool created = !f.exists(); + if ( !f.open(IO_WriteOnly|IO_Append) ) + return; + + QString buf; + QCString str; + + // if the file was created, we have to set the Tag "<CONTACTS>" to + // get a XML-File which is readable by our parser. + // This is just a cheat, but better than rewrite the parser. + if ( created ){ + buf = "<Contacts>"; + QCString cstr = buf.utf8(); + f.writeBlock( cstr.data(), cstr.length() ); + } + + buf = "<Contact "; + cnt.save( buf ); + buf += " action=\"" + QString::number( (int)action ) + "\" "; + buf += "/>\n"; + QCString cstr = buf.utf8(); + f.writeBlock( cstr.data(), cstr.length() ); + } + + void removeJournal() + { + QFile f ( m_journalName ); + if ( f.exists() ) + f.remove(); + } + + protected: + QString m_journalName; + QString m_fileName; + QString m_appName; + QValueList<OContact> m_contactList; + QDateTime m_readtime; +}; + +#endif diff --git a/libopie2/opiepim/core/ocontactaccess.cpp b/libopie2/opiepim/core/ocontactaccess.cpp new file mode 100644 index 0000000..2d808f7 --- a/dev/null +++ b/libopie2/opiepim/core/ocontactaccess.cpp @@ -0,0 +1,174 @@ +/* + * Class to manage the Contacts. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * Info: This class could just work with a change in the header-file + * of the Contact class ! Therefore our libopie only compiles + * with our version of libqpe + * ===================================================================== + * ToDo: XML-Backend: Automatic reload if something was changed... + * + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2002/09/27 17:11:44 eilers + * Added API for accessing the Contact-Database ! It is compiling, but + * please do not expect that anything is working ! + * I will debug that stuff in the next time .. + * Please read README_COMPILE for compiling ! + * + * + */ + +#include "ocontactaccess.h" + +#include <qasciidict.h> +#include <qdatetime.h> +#include <qfile.h> +#include <qregexp.h> +#include <qlist.h> +#include <qcopchannel_qws.h> + +//#include <qpe/qcopenvelope_qws.h> +#include <qpe/global.h> + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> + +#include "ocontactaccessbackend_xml.h" + + +OContactAccess::OContactAccess ( const QString appname, const QString filename, + OContactAccessBackend* end, bool autosync ): + OPimAccessTemplate<OContact>( end ), + m_changed ( false ) +{ + /* take care of the backend. If there is no one defined, we + * will use the XML-Backend as default (until we have a cute SQL-Backend..). + */ + if( end == 0 ) { + end = new OContactAccessBackend_XML( appname, filename ); + } + m_backEnd = end; + + /* Connect signal of external db change to function */ + QCopChannel *dbchannel = new QCopChannel( "QPE/PIM", this ); + connect( dbchannel, SIGNAL(received(const QCString &, const QByteArray &)), + this, SLOT(copMessage( const QCString &, const QByteArray &)) ); + if ( autosync ){ + QCopChannel *syncchannel = new QCopChannel( "QPE/Sync", this ); + connect( syncchannel, SIGNAL(received(const QCString &, const QByteArray &)), + this, SLOT(copMessage( const QCString &, const QByteArray &)) ); + } + + +} +OContactAccess::~OContactAccess () +{ + /* The user may forget to save the changed database, therefore try to + * do it for him.. + */ + if ( m_changed ) + save(); + delete m_backEnd; +} + +bool OContactAccess::load() +{ + return ( m_backEnd->load() ); +} + +bool OContactAccess::save () +{ + /* If the database was changed externally, we could not save the + * Data. This will remove added items which is unacceptable ! + * Therefore: Reload database and merge the data... + */ + if ( m_backEnd->wasChangedExternally() ) + reload(); + + if ( m_changed ){ + bool status = m_backEnd->save(); + if ( !status ) return false; + + m_changed = false; + /* Now tell everyone that new data is available. + */ + QCopEnvelope e( "QPE/PIM", "addressbookUpdated()" ); + + } + + return true; +} + +const uint OContactAccess::querySettings() +{ + return ( m_backEnd->querySettings() ); +} + +bool OContactAccess::hasQuerySettings ( int querySettings ) const +{ + return ( m_backEnd->hasQuerySettings ( querySettings ) ); +} + +bool OContactAccess::add ( const OContact& newcontact ) +{ + m_changed = true; + return ( m_backEnd->add ( newcontact ) ); +} + +bool OContactAccess::replace ( const OContact& contact ) +{ + m_changed = true; + return ( m_backEnd->replace ( contact ) ); +} + +bool OContactAccess::remove ( const OContact& t ) +{ + m_changed = true; + return ( m_backEnd->remove ( t.uid() ) ); +} + +bool OContactAccess::remove ( int uid ) +{ + m_changed = true; + return ( m_backEnd->remove ( uid ) ); +} + +bool OContactAccess::wasChangedExternally()const +{ + return ( m_backEnd->wasChangedExternally() ); +} + + +bool OContactAccess::reload() +{ + return ( m_backEnd->reload() ); +} + +void OContactAccess::copMessage( const QCString &msg, const QByteArray & ) +{ + if ( msg == "addressbookUpdated()" ){ + qWarning ("OContactAccess: Received addressbokUpdated()"); + emit signalChanged ( this ); + } else if ( msg == "flush()" ) { + qWarning ("OContactAccess: Received flush()"); + save (); + } else if ( msg == "reload()" ) { + qWarning ("OContactAccess: Received reload()"); + reload (); + emit signalChanged ( this ); + } +} diff --git a/libopie2/opiepim/core/ocontactaccess.h b/libopie2/opiepim/core/ocontactaccess.h new file mode 100644 index 0000000..54f7f07 --- a/dev/null +++ b/libopie2/opiepim/core/ocontactaccess.h @@ -0,0 +1,197 @@ +/* + * Class to manage the Contacts. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; + * either version 2 of the License, or (at your option) any later + * version. + * ===================================================================== + * ToDo: Define enum for query settings + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2002/09/27 17:11:44 eilers + * Added API for accessing the Contact-Database ! It is compiling, but + * please do not expect that anything is working ! + * I will debug that stuff in the next time .. + * Please read README_COMPILE for compiling ! + * + * ===================================================================== + */ +#ifndef _OCONTACTACCESS_H +#define _OCONTACTACCESS_H + +#include <qobject.h> + +#include <qpe/qcopenvelope_qws.h> + +#include <qvaluelist.h> +#include <qfileinfo.h> + +#include "ocontact.h" +#include "ocontactaccessbackend.h" +#include "opimaccesstemplate.h" + +/** Class to access the contacts database. + * This is just a frontend for the real database handling which is + * done by the backend. + */ +class OContactAccess: public QObject, public OPimAccessTemplate<OContact> +{ + Q_OBJECT + + + /* class Iterator{ + friend OContactAccess; + public: + Iterator(); + Iterator ( const Iterator& copy ); + + bool operator== ( const Iterator& it ); + bool operator!= ( const Iterator& it ); + Iterator& operator= ( const Iterator& it ); + Iterator& operator++ (); // prefix + Iterator operator++ ( int ); // postfix + Iterator& operator-- (); // prefix + Iterator operator-- ( int ); // postfix + Contact operator*() const; + Contact operator->() const; + + Iterator begin(); + Iterator end(); + + uint count() const; + + private: + QValueList<int> m_uids; + int m_cur_position; + bool m_end_reached; + OContactAccess *m_db; + + }; + + */ + + public: + /** Create Database with contacts (addressbook). + * @param appname Name of application which wants access to the database + * (i.e. "todolist") + * @param filename The name of the database file. If not set, the default one + * is used. + * @param backend Pointer to an alternative Backend. If not set, we will use + * the default backend. + * @param handlesync If <b>true</b> the database stores the current state + * automatically if it receives the signals <i>flush()</i> and <i>reload()</i> + * which are used before and after synchronisation. If the application wants + * to react itself, it should be disabled by setting it to <b>false</b> + * @see OContactBackend + */ + OContactAccess (const QString appname, const QString filename = 0l, + OContactAccessBackend* backend = 0l, bool handlesync = true); + ~OContactAccess (); + + /** Constants for query. + * Use this constants to set the query parameters. + * Note: <i>query_IgnoreCase</i> just make sense with one of the other attributes ! + * @see queryByExample() + * - why not enum - zecke? + * -> Had some implementation problems .. Will use enum soon ! .. (se) + */ + static const int query_WildCards = 0x0001; + static const int query_IgnoreCase = 0x0002; + static const int query_RegExp = 0x0004; + static const int query_ExactMatch = 0x0008; + + /** Return all possible settings. + * @return All settings provided by the current backend + * (i.e.: query_WildCards & query_IgnoreCase) + */ + const uint querySettings(); + + /** Check whether settings are correct. + * @return <i>true</i> if the given settings are correct and possible. + */ + bool hasQuerySettings ( int querySettings ) const; + + /** Add Contact to database. + * @param newcontact The contact to add. + * @return <i>true</i> if added successfully. + */ + bool add (const OContact& newcontact); + + /** Replace contact. + * Replaces given contact with contact with the user id <i>uid</i>. + * @param uid The user ID + * @param contact The new contact + * @return <i>true</i> if successful. + */ + bool replace ( const OContact& contact ); + + /** Remove contact. + * Removes contact with the user id <i>uid</i>. + * @param The contact to remove + * @return <i>true</i> if successful. + */ + bool remove ( const OContact& t ); + + /** Remove contact. + * Removes contact with the user id <i>uid</i>. + * @param The user id of the contact to remove + * @return <i>true</i> if successful. + */ + bool remove ( int uid ); + + /** Load Database * + */ + bool load(); + + /** + * if the resource was changed externally. + * You should use the signal instead of polling possible changes ! + */ + bool wasChangedExternally()const; + + /** Reload database. + * You should execute this function if the external database + * was changed. + * This function will load the external database and afterwards + * rejoin the local changes. Therefore the local database will be set consistent. + */ + bool reload(); + + /** Save contacts database. + * Save is more a "commit". After calling this function, all changes are public available. + * @return true if successful + */ + bool save(); + + signals: + /* Signal is emitted if the database was changed. Therefore + * we may need to reload to stay consistent. + * @param which Pointer to the database who created this event. This pointer + * is useful if an application has to handle multiple databases at the same time. + * @see reload() + */ + void signalChanged ( const OContactAccess *which ); + + + private: + // class OContactAccessPrivate; + // OContactAccessPrivate* d; + OContactAccessBackend *m_backEnd; + bool m_loading:1; + bool m_changed; + + private slots: + void copMessage( const QCString &msg, const QByteArray &data ); + + +}; +#endif diff --git a/libopie2/opiepim/ocontact.cpp b/libopie2/opiepim/ocontact.cpp new file mode 100644 index 0000000..66632f5 --- a/dev/null +++ b/libopie2/opiepim/ocontact.cpp @@ -0,0 +1,1433 @@ +/********************************************************************** +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#define QTOPIA_INTERNAL_CONTACT_MRE + +#include "ocontact.h" +#include "vobject_p.h" +#include "qfiledirect_p.h" + +#include <qpe/stringutil.h> +#include <qpe/timeconversion.h> + +#include <qobject.h> +#include <qregexp.h> +#include <qstylesheet.h> +#include <qfileinfo.h> +#include <qmap.h> + +#include <stdio.h> + +/*! + \class Contact contact.h + \brief The Contact class holds the data of an address book entry. + + This data includes information the name of the person, contact + information, and business information such as deparment and job title. + + \ingroup qtopiaemb + \ingroup qtopiadesktop +*/ + +Qtopia::UidGen OContact::sUidGen( Qtopia::UidGen::Qtopia ); + +/*! + Creates a new, empty contact. +*/ +OContact::OContact() + : OPimRecord(), mMap(), d( 0 ) +{ +} + +/*! + \internal + Creates a new contact. The properties of the contact are + set from \a fromMap. +*/ +OContact::OContact( const QMap<int, QString> &fromMap ) : + OPimRecord(), mMap( fromMap ), d( 0 ) +{ + QString cats = mMap[ Qtopia::AddressCategory ]; + if ( !cats.isEmpty() ) + setCategories( idsFromString( cats ) ); + QString uidStr = find( Qtopia::AddressUid ); + + if ( uidStr.isEmpty() ) + setUid( uidGen().generate() ); + else + setUid( uidStr.toInt() ); + + if ( !uidStr.isEmpty() ) + setUid( uidStr.toInt() ); +} + +/*! + Destroys a contact. +*/ +OContact::~OContact() +{ +} + +/*! \fn void OContact::setTitle( const QString &str ) + Sets the title of the contact to \a str. +*/ + +/*! \fn void OContact::setFirstName( const QString &str ) + Sets the first name of the contact to \a str. +*/ + +/*! \fn void OContact::setMiddleName( const QString &str ) + Sets the middle name of the contact to \a str. +*/ + +/*! \fn void OContact::setLastName( const QString &str ) + Sets the last name of the contact to \a str. +*/ + +/*! \fn void OContact::setSuffix( const QString &str ) + Sets the suffix of the contact to \a str. +*/ + +/*! \fn void OContact::setFileAs( const QString &str ) + Sets the contact to filed as \a str. +*/ + +/*! \fn void OContact::setDefaultEmail( const QString &str ) + Sets the default email of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeStreet( const QString &str ) + Sets the home street address of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeCity( const QString &str ) + Sets the home city of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeState( const QString &str ) + Sets the home state of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeZip( const QString &str ) + Sets the home zip code of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeCountry( const QString &str ) + Sets the home country of the contact to \a str. +*/ + +/*! \fn void OContact::setHomePhone( const QString &str ) + Sets the home phone number of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeFax( const QString &str ) + Sets the home fax number of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeMobile( const QString &str ) + Sets the home mobile phone number of the contact to \a str. +*/ + +/*! \fn void OContact::setHomeWebpage( const QString &str ) + Sets the home webpage of the contact to \a str. +*/ + +/*! \fn void OContact::setCompany( const QString &str ) + Sets the company for contact to \a str. +*/ + +/*! \fn void OContact::setJobTitle( const QString &str ) + Sets the job title of the contact to \a str. +*/ + +/*! \fn void OContact::setDepartment( const QString &str ) + Sets the department for contact to \a str. +*/ + +/*! \fn void OContact::setOffice( const QString &str ) + Sets the office for contact to \a str. +*/ + +/*! \fn void OContact::setBusinessStreet( const QString &str ) + Sets the business street address of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessCity( const QString &str ) + Sets the business city of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessState( const QString &str ) + Sets the business state of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessZip( const QString &str ) + Sets the business zip code of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessCountry( const QString &str ) + Sets the business country of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessPhone( const QString &str ) + Sets the business phone number of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessFax( const QString &str ) + Sets the business fax number of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessMobile( const QString &str ) + Sets the business mobile phone number of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessPager( const QString &str ) + Sets the business pager number of the contact to \a str. +*/ + +/*! \fn void OContact::setBusinessWebpage( const QString &str ) + Sets the business webpage of the contact to \a str. +*/ + +/*! \fn void OContact::setProfession( const QString &str ) + Sets the profession of the contact to \a str. +*/ + +/*! \fn void OContact::setAssistant( const QString &str ) + Sets the assistant of the contact to \a str. +*/ + +/*! \fn void OContact::setManager( const QString &str ) + Sets the manager of the contact to \a str. +*/ + +/*! \fn void OContact::setSpouse( const QString &str ) + Sets the spouse of the contact to \a str. +*/ + +/*! \fn void OContact::setGender( const QString &str ) + Sets the gender of the contact to \a str. +*/ + +/*! \fn void OContact::setBirthday( const QString &str ) + Sets the birthday for the contact to \a str. +*/ + +/*! \fn void OContact::setAnniversary( const QString &str ) + Sets the anniversary of the contact to \a str. +*/ + +/*! \fn void OContact::setNickname( const QString &str ) + Sets the nickname of the contact to \a str. +*/ + +/*! \fn void OContact::setNotes( const QString &str ) + Sets the notes about the contact to \a str. +*/ + +/*! \fn QString OContact::title() const + Returns the title of the contact. +*/ + +/*! \fn QString OContact::firstName() const + Returns the first name of the contact. +*/ + +/*! \fn QString OContact::middleName() const + Returns the middle name of the contact. +*/ + +/*! \fn QString OContact::lastName() const + Returns the last name of the contact. +*/ + +/*! \fn QString OContact::suffix() const + Returns the suffix of the contact. +*/ + +/*! \fn QString OContact::fileAs() const + Returns the string the contact is filed as. +*/ + +/*! \fn QString OContact::defaultEmail() const + Returns the default email address of the contact. +*/ + +/*! \fn QString OContact::emails() const + Returns the list of email address for a contact separated by ';'s in a single + string. +*/ + +/*! \fn QString OContact::homeStreet() const + Returns the home street address of the contact. +*/ + +/*! \fn QString OContact::homeCity() const + Returns the home city of the contact. +*/ + +/*! \fn QString OContact::homeState() const + Returns the home state of the contact. +*/ + +/*! \fn QString OContact::homeZip() const + Returns the home zip of the contact. +*/ + +/*! \fn QString OContact::homeCountry() const + Returns the home country of the contact. +*/ + +/*! \fn QString OContact::homePhone() const + Returns the home phone number of the contact. +*/ + +/*! \fn QString OContact::homeFax() const + Returns the home fax number of the contact. +*/ + +/*! \fn QString OContact::homeMobile() const + Returns the home mobile number of the contact. +*/ + +/*! \fn QString OContact::homeWebpage() const + Returns the home webpage of the contact. +*/ + +/*! \fn QString OContact::company() const + Returns the company for the contact. +*/ + +/*! \fn QString OContact::department() const + Returns the department for the contact. +*/ + +/*! \fn QString OContact::office() const + Returns the office for the contact. +*/ + +/*! \fn QString OContact::jobTitle() const + Returns the job title of the contact. +*/ + +/*! \fn QString OContact::profession() const + Returns the profession of the contact. +*/ + +/*! \fn QString OContact::assistant() const + Returns the assistant of the contact. +*/ + +/*! \fn QString OContact::manager() const + Returns the manager of the contact. +*/ + +/*! \fn QString OContact::businessStreet() const + Returns the business street address of the contact. +*/ + +/*! \fn QString OContact::businessCity() const + Returns the business city of the contact. +*/ + +/*! \fn QString OContact::businessState() const + Returns the business state of the contact. +*/ + +/*! \fn QString OContact::businessZip() const + Returns the business zip of the contact. +*/ + +/*! \fn QString OContact::businessCountry() const + Returns the business country of the contact. +*/ + +/*! \fn QString OContact::businessPhone() const + Returns the business phone number of the contact. +*/ + +/*! \fn QString OContact::businessFax() const + Returns the business fax number of the contact. +*/ + +/*! \fn QString OContact::businessMobile() const + Returns the business mobile number of the contact. +*/ + +/*! \fn QString OContact::businessPager() const + Returns the business pager number of the contact. +*/ + +/*! \fn QString OContact::businessWebpage() const + Returns the business webpage of the contact. +*/ + +/*! \fn QString OContact::spouse() const + Returns the spouse of the contact. +*/ + +/*! \fn QString OContact::gender() const + Returns the gender of the contact. +*/ + +/*! \fn QString OContact::birthday() const + Returns the birthday of the contact. +*/ + +/*! \fn QString OContact::anniversary() const + Returns the anniversary of the contact. +*/ + +/*! \fn QString OContact::nickname() const + Returns the nickname of the contact. +*/ + +/*! \fn QString OContact::children() const + Returns the children of the contact. +*/ + +/*! \fn QString OContact::notes() const + Returns the notes relating to the the contact. +*/ + +/*! \fn QString OContact::groups() const + \internal + Returns the groups for the contact. +*/ + +/*! \fn QStringList OContact::groupList() const + \internal +*/ + +/*! \fn QString OContact::field(int) const + \internal +*/ + +/*! \fn void OContact::saveJournal( journal_action, const QString & = QString::null ) + \internal +*/ + +/*! \fn void OContact::setUid( int id ) + \internal + Sets the uid for this record to \a id. +*/ + +/*! \enum OContact::journal_action + \internal +*/ + +/*! + \internal +*/ +QMap<int, QString> OContact::toMap() const +{ + QMap<int, QString> map = mMap; + QString cats = idsToString( categories() ); + if ( !cats.isEmpty() ) + map.insert( Qtopia::AddressCategory, cats ); + return map; +} + +/*! + Returns a rich text formatted QString representing the contents the contact. +*/ +QString OContact::toRichText() const +{ + QString text; + QString value, comp, state; + + // name, jobtitle and company + if ( !(value = fullName()).isEmpty() ) + text += "<b>" + Qtopia::escapeString(value) + "</b><br>"; + if ( !(value = jobTitle()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + + comp = company(); + if ( !(value = department()).isEmpty() ) { + text += Qtopia::escapeString(value); + if ( comp ) + text += ", "; + else + text += "<br>"; + } + if ( !comp.isEmpty() ) + text += Qtopia::escapeString(comp) + "<br>"; + + // business address + if ( !businessStreet().isEmpty() || !businessCity().isEmpty() || + !businessZip().isEmpty() || !businessCountry().isEmpty() ) { + text += "<br>"; + text += QObject::tr( "<b>Work Address:</b>" ); + text += "<br>"; + } + + if ( !(value = businessStreet()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + state = businessState(); + if ( !(value = businessCity()).isEmpty() ) { + text += Qtopia::escapeString(value); + if ( state ) + text += ", " + Qtopia::escapeString(state); + text += "<br>"; + } else if ( !state.isEmpty() ) + text += Qtopia::escapeString(state) + "<br>"; + if ( !(value = businessZip()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + if ( !(value = businessCountry()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + + // home address + if ( !homeStreet().isEmpty() || !homeCity().isEmpty() || + !homeZip().isEmpty() || !homeCountry().isEmpty() ) { + text += "<br>"; + text += QObject::tr( "<b>Home Address:</b>" ); + text += "<br>"; + } + + if ( !(value = homeStreet()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + state = homeState(); + if ( !(value = homeCity()).isEmpty() ) { + text += Qtopia::escapeString(value); + if ( !state.isEmpty() ) + text += ", " + Qtopia::escapeString(state); + text += "<br>"; + } else if (!state.isEmpty()) + text += Qtopia::escapeString(state) + "<br>"; + if ( !(value = homeZip()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + if ( !(value = homeCountry()).isEmpty() ) + text += Qtopia::escapeString(value) + "<br>"; + + // the others... + QString str; + str = emails(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Email Addresses: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = homePhone(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Home Phone: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = homeFax(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Home Fax: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = homeMobile(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Home Mobile: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = homeWebpage(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Home Web Page: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = businessWebpage(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Business Web Page: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = office(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Office: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = businessPhone(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Business Phone: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = businessFax(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Business Fax: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = businessMobile(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Business Mobile: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = businessPager(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Business Pager: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = profession(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Profession: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = assistant(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Assistant: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = manager(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Manager: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = gender(); + if ( !str.isEmpty() && str.toInt() != 0 ) { + if ( str.toInt() == 1 ) + str = QObject::tr( "Male" ); + else if ( str.toInt() == 2 ) + str = QObject::tr( "Female" ); + text += "<b>" + QObject::tr("Gender: ") + "</b>" + str + "<br>"; + } + str = spouse(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Spouse: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = birthday(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Birthday: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = anniversary(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Anniversary: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + str = nickname(); + if ( !str.isEmpty() ) + text += "<b>" + QObject::tr("Nickname: ") + "</b>" + + Qtopia::escapeString(str) + "<br>"; + + // notes last + if ( (value = notes()) ) { + QRegExp reg("\n"); + + //QString tmp = Qtopia::escapeString(value); + QString tmp = QStyleSheet::convertFromPlainText(value); + //tmp.replace( reg, "<br>" ); + text += "<br>" + tmp + "<br>"; + } + return text; +} + +/*! + \internal +*/ +void OContact::insert( int key, const QString &v ) +{ + QString value = v.stripWhiteSpace(); + if ( value.isEmpty() ) + mMap.remove( key ); + else + mMap.insert( key, value ); +} + +/*! + \internal +*/ +void OContact::replace( int key, const QString & v ) +{ + QString value = v.stripWhiteSpace(); + if ( value.isEmpty() ) + mMap.remove( key ); + else + mMap.replace( key, value ); +} + +/*! + \internal +*/ +QString OContact::find( int key ) const +{ + return mMap[key]; +} + +/*! + \internal +*/ +QString OContact::displayAddress( const QString &street, + const QString &city, + const QString &state, + const QString &zip, + const QString &country ) const +{ + QString s = street; + if ( !street.isEmpty() ) + s+= "\n"; + s += city; + if ( !city.isEmpty() && !state.isEmpty() ) + s += ", "; + s += state; + if ( !state.isEmpty() && !zip.isEmpty() ) + s += " "; + s += zip; + if ( !country.isEmpty() && !s.isEmpty() ) + s += "\n"; + s += country; + return s; +} + +/*! + \internal +*/ +QString OContact::displayBusinessAddress() const +{ + return displayAddress( businessStreet(), businessCity(), + businessState(), businessZip(), + businessCountry() ); +} + +/*! + \internal +*/ +QString OContact::displayHomeAddress() const +{ + return displayAddress( homeStreet(), homeCity(), + homeState(), homeZip(), + homeCountry() ); +} + +/*! + Returns the full name of the contact +*/ +QString OContact::fullName() const +{ + QString title = find( Qtopia::Title ); + QString firstName = find( Qtopia::FirstName ); + QString middleName = find( Qtopia::MiddleName ); + QString lastName = find( Qtopia::LastName ); + QString suffix = find( Qtopia::Suffix ); + + QString name = title; + if ( !firstName.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += firstName; + } + if ( !middleName.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += middleName; + } + if ( !lastName.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += lastName; + } + if ( !suffix.isEmpty() ) { + if ( !name.isEmpty() ) + name += " "; + name += suffix; + } + return name.simplifyWhiteSpace(); +} + +/*! + Returns a list of the names of the children of the contact. +*/ +QStringList OContact::childrenList() const +{ + return QStringList::split( " ", find( Qtopia::Children ) ); +} + +/*! \fn void OContact::insertEmail( const QString &email ) + + Insert \a email into the email list. Ensures \a email can only be added + once. If there is no default email address set, it sets it to the \a email. +*/ + +/*! \fn void OContact::removeEmail( const QString &email ) + + Removes the \a email from the email list. If the default email was \a email, + then the default email address is assigned to the first email in the + email list +*/ + +/*! \fn void OContact::clearEmails() + + Clears the email list. + */ + +/*! \fn void OContact::insertEmails( const QStringList &emailList ) + + Appends the \a emailList to the exiting email list + */ + +/*! + Returns a list of email addresses belonging to the contact, including + the default email address. +*/ +QStringList OContact::emailList() const +{ + QString emailStr = emails(); + + QStringList r; + if ( !emailStr.isEmpty() ) { + qDebug(" emailstr "); + QStringList l = QStringList::split( emailSeparator(), emailStr ); + for ( QStringList::ConstIterator it = l.begin();it != l.end();++it ) + r += (*it).simplifyWhiteSpace(); + } + + return r; +} + +/*! + \overload + + Generates the string for the contact to be filed as from the first, + middle and last name of the contact. +*/ +void OContact::setFileAs() +{ + QString lastName, firstName, middleName, fileas; + + lastName = find( Qtopia::LastName ); + firstName = find( Qtopia::FirstName ); + middleName = find( Qtopia::MiddleName ); + if ( !lastName.isEmpty() && !firstName.isEmpty() + && !middleName.isEmpty() ) + fileas = lastName + ", " + firstName + " " + middleName; + else if ( !lastName.isEmpty() && !firstName.isEmpty() ) + fileas = lastName + ", " + firstName; + else if ( !lastName.isEmpty() || !firstName.isEmpty() || + !middleName.isEmpty() ) + fileas = firstName + ( firstName.isEmpty() ? "" : " " ) + + middleName + ( middleName.isEmpty() ? "" : " " ) + + lastName; + + replace( Qtopia::FileAs, fileas ); +} + +/*! + \internal + Appends the contact information to \a buf. +*/ +void OContact::save( QString &buf ) const +{ + static const QStringList SLFIELDS = fields(); + // I'm expecting "<Contact " in front of this... + for ( QMap<int, QString>::ConstIterator it = mMap.begin(); + it != mMap.end(); ++it ) { + const QString &value = it.data(); + int key = it.key(); + if ( !value.isEmpty() ) { + if ( key == Qtopia::AddressCategory || key == Qtopia::AddressUid) + continue; + + key -= Qtopia::AddressCategory+1; + buf += SLFIELDS[key]; + buf += "=\"" + Qtopia::escapeString(value) + "\" "; + } + } + buf += customToXml(); + if ( categories().count() > 0 ) + buf += "Categories=\"" + idsToString( categories() ) + "\" "; + buf += "Uid=\"" + QString::number( uid() ) + "\" "; + // You need to close this yourself +} + +/*! + \internal + Returns the list of fields belonging to a contact +*/ +QStringList OContact::fields() +{ + QStringList list; + + list.append( "Title" ); // Not Used! + list.append( "FirstName" ); + list.append( "MiddleName" ); + list.append( "LastName" ); + list.append( "Suffix" ); + list.append( "FileAs" ); + + list.append( "JobTitle" ); + list.append( "Department" ); + list.append( "Company" ); + list.append( "BusinessPhone" ); + list.append( "BusinessFax" ); + list.append( "BusinessMobile" ); + + list.append( "DefaultEmail" ); + list.append( "Emails" ); + + list.append( "HomePhone" ); + list.append( "HomeFax" ); + list.append( "HomeMobile" ); + + list.append( "BusinessStreet" ); + list.append( "BusinessCity" ); + list.append( "BusinessState" ); + list.append( "BusinessZip" ); + list.append( "BusinessCountry" ); + list.append( "BusinessPager" ); + list.append( "BusinessWebPage" ); + + list.append( "Office" ); + list.append( "Profession" ); + list.append( "Assistant" ); + list.append( "Manager" ); + + list.append( "HomeStreet" ); + list.append( "HomeCity" ); + list.append( "HomeState" ); + list.append( "HomeZip" ); + list.append( "HomeCountry" ); + list.append( "HomeWebPage" ); + + list.append( "Spouse" ); + list.append( "Gender" ); + list.append( "Birthday" ); + list.append( "Anniversary" ); + list.append( "Nickname" ); + list.append( "Children" ); + + list.append( "Notes" ); + list.append( "Groups" ); + + return list; +} + +/*! + \internal + Returns a translated list of field names for a contact. +*/ +QStringList OContact::trfields() +{ + QStringList list; + + list.append( QObject::tr( "Name Title") ); + list.append( QObject::tr( "First Name" ) ); + list.append( QObject::tr( "Middle Name" ) ); + list.append( QObject::tr( "Last Name" ) ); + list.append( QObject::tr( "Suffix" ) ); + list.append( QObject::tr( "File As" ) ); + + list.append( QObject::tr( "Job Title" ) ); + list.append( QObject::tr( "Department" ) ); + list.append( QObject::tr( "Company" ) ); + list.append( QObject::tr( "Business Phone" ) ); + list.append( QObject::tr( "Business Fax" ) ); + list.append( QObject::tr( "Business Mobile" ) ); + + list.append( QObject::tr( "Default Email" ) ); + list.append( QObject::tr( "Emails" ) ); + + list.append( QObject::tr( "Home Phone" ) ); + list.append( QObject::tr( "Home Fax" ) ); + list.append( QObject::tr( "Home Mobile" ) ); + + list.append( QObject::tr( "Business Street" ) ); + list.append( QObject::tr( "Business City" ) ); + list.append( QObject::tr( "Business State" ) ); + list.append( QObject::tr( "Business Zip" ) ); + list.append( QObject::tr( "Business Country" ) ); + list.append( QObject::tr( "Business Pager" ) ); + list.append( QObject::tr( "Business WebPage" ) ); + + list.append( QObject::tr( "Office" ) ); + list.append( QObject::tr( "Profession" ) ); + list.append( QObject::tr( "Assistant" ) ); + list.append( QObject::tr( "Manager" ) ); + + list.append( QObject::tr( "Home Street" ) ); + list.append( QObject::tr( "Home City" ) ); + list.append( QObject::tr( "Home State" ) ); + list.append( QObject::tr( "Home Zip" ) ); + list.append( QObject::tr( "Home Country" ) ); + list.append( QObject::tr( "Home Web Page" ) ); + + list.append( QObject::tr( "Spouse" ) ); + list.append( QObject::tr( "Gender" ) ); + list.append( QObject::tr( "Birthday" ) ); + list.append( QObject::tr( "Anniversary" ) ); + list.append( QObject::tr( "Nickname" ) ); + list.append( QObject::tr( "Children" ) ); + + list.append( QObject::tr( "Notes" ) ); + list.append( QObject::tr( "Groups" ) ); + + return list; +} + +/*! + Sets the list of email address for contact to those contained in \a str. + Email address should be separated by ';'s. +*/ +void OContact::setEmails( const QString &str ) +{ + replace( Qtopia::Emails, str ); + if ( str.isEmpty() ) + setDefaultEmail( QString::null ); +} + +/*! + Sets the list of children for the contact to those contained in \a str. +*/ +void OContact::setChildren( const QString &str ) +{ + replace( Qtopia::Children, str ); +} + +// vcard conversion code +/*! + \internal +*/ +static inline VObject *safeAddPropValue( VObject *o, const char *prop, const QString &value ) +{ + VObject *ret = 0; + if ( o && !value.isEmpty() ) + ret = addPropValue( o, prop, value.latin1() ); + return ret; +} + +/*! + \internal +*/ +static inline VObject *safeAddProp( VObject *o, const char *prop) +{ + VObject *ret = 0; + if ( o ) + ret = addProp( o, prop ); + return ret; +} + +/*! + \internal +*/ +static VObject *createVObject( const OContact &c ) +{ + VObject *vcard = newVObject( VCCardProp ); + safeAddPropValue( vcard, VCVersionProp, "2.1" ); + safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) ); + safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) ); + + // full name + safeAddPropValue( vcard, VCFullNameProp, c.fullName() ); + + // name properties + VObject *name = safeAddProp( vcard, VCNameProp ); + safeAddPropValue( name, VCFamilyNameProp, c.lastName() ); + safeAddPropValue( name, VCGivenNameProp, c.firstName() ); + safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() ); + safeAddPropValue( name, VCNamePrefixesProp, c.title() ); + safeAddPropValue( name, VCNameSuffixesProp, c.suffix() ); + + // home properties + VObject *home_adr= safeAddProp( vcard, VCAdrProp ); + safeAddProp( home_adr, VCHomeProp ); + safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() ); + safeAddPropValue( home_adr, VCCityProp, c.homeCity() ); + safeAddPropValue( home_adr, VCRegionProp, c.homeState() ); + safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() ); + safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() ); + + VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() ); + safeAddProp( home_phone, VCHomeProp ); + home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() ); + safeAddProp( home_phone, VCHomeProp ); + safeAddProp( home_phone, VCCellularProp ); + home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() ); + safeAddProp( home_phone, VCHomeProp ); + safeAddProp( home_phone, VCFaxProp ); + + VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() ); + safeAddProp( url, VCHomeProp ); + + // work properties + VObject *work_adr= safeAddProp( vcard, VCAdrProp ); + safeAddProp( work_adr, VCWorkProp ); + safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() ); + safeAddPropValue( work_adr, VCCityProp, c.businessCity() ); + safeAddPropValue( work_adr, VCRegionProp, c.businessState() ); + safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() ); + safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() ); + + VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() ); + safeAddProp( work_phone, VCWorkProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCCellularProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCFaxProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCPagerProp ); + + url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() ); + safeAddProp( url, VCWorkProp ); + + VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() ); + safeAddProp( title, VCWorkProp ); + + + QStringList emails = c.emailList(); + emails.prepend( c.defaultEmail() ); + for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) { + VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it ); + safeAddProp( email, VCInternetProp ); + } + + safeAddPropValue( vcard, VCNoteProp, c.notes() ); + + safeAddPropValue( vcard, VCBirthDateProp, c.birthday() ); + + if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) { + VObject *org = safeAddProp( vcard, VCOrgProp ); + safeAddPropValue( org, VCOrgNameProp, c.company() ); + safeAddPropValue( org, VCOrgUnitProp, c.department() ); + safeAddPropValue( org, VCOrgUnit2Prop, c.office() ); + } + + // some values we have to export as custom fields + safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() ); + safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() ); + safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() ); + + safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() ); + safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() ); + safeAddPropValue( vcard, "X-Qtopia-Anniversary", c.anniversary() ); + safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() ); + safeAddPropValue( vcard, "X-Qtopia-Children", c.children() ); + + return vcard; +} + + +/*! + \internal +*/ +static OContact parseVObject( VObject *obj ) +{ + OContact c; + + VObjectIterator it; + initPropIterator( &it, obj ); + while( moreIteration( &it ) ) { + VObject *o = nextVObject( &it ); + QCString name = vObjectName( o ); + QCString value = vObjectStringZValue( o ); + if ( name == VCNameProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCNamePrefixesProp ) + c.setTitle( value ); + else if ( name == VCNameSuffixesProp ) + c.setSuffix( value ); + else if ( name == VCFamilyNameProp ) + c.setLastName( value ); + else if ( name == VCGivenNameProp ) + c.setFirstName( value ); + else if ( name == VCAdditionalNamesProp ) + c.setMiddleName( value ); + } + } + else if ( name == VCAdrProp ) { + bool work = TRUE; // default address is work address + QString street; + QString city; + QString region; + QString postal; + QString country; + + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCHomeProp ) + work = FALSE; + else if ( name == VCWorkProp ) + work = TRUE; + else if ( name == VCStreetAddressProp ) + street = value; + else if ( name == VCCityProp ) + city = value; + else if ( name == VCRegionProp ) + region = value; + else if ( name == VCPostalCodeProp ) + postal = value; + else if ( name == VCCountryNameProp ) + country = value; + } + if ( work ) { + c.setBusinessStreet( street ); + c.setBusinessCity( city ); + c.setBusinessCountry( country ); + c.setBusinessZip( postal ); + c.setBusinessState( region ); + } else { + c.setHomeStreet( street ); + c.setHomeCity( city ); + c.setHomeCountry( country ); + c.setHomeZip( postal ); + c.setHomeState( region ); + } + } + else if ( name == VCTelephoneProp ) { + enum { + HOME = 0x01, + WORK = 0x02, + VOICE = 0x04, + CELL = 0x08, + FAX = 0x10, + PAGER = 0x20, + UNKNOWN = 0x80 + }; + int type = 0; + + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + if ( name == VCHomeProp ) + type |= HOME; + else if ( name == VCWorkProp ) + type |= WORK; + else if ( name == VCVoiceProp ) + type |= VOICE; + else if ( name == VCCellularProp ) + type |= CELL; + else if ( name == VCFaxProp ) + type |= FAX; + else if ( name == VCPagerProp ) + type |= PAGER; + else if ( name == VCPreferredProp ) + ; + else + type |= UNKNOWN; + } + if ( (type & UNKNOWN) != UNKNOWN ) { + if ( ( type & (HOME|WORK) ) == 0 ) // default + type |= HOME; + if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default + type |= VOICE; + + if ( (type & (VOICE|HOME) ) == (VOICE|HOME) ) + c.setHomePhone( value ); + if ( ( type & (FAX|HOME) ) == (FAX|HOME) ) + c.setHomeFax( value ); + if ( ( type & (CELL|HOME) ) == (CELL|HOME) ) + c.setHomeMobile( value ); + if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) ) + c.setBusinessPhone( value ); + if ( ( type & (FAX|WORK) ) == (FAX|WORK) ) + c.setBusinessFax( value ); + if ( ( type & (CELL|WORK) ) == (CELL|WORK) ) + c.setBusinessMobile( value ); + if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) ) + c.setBusinessPager( value ); + } + } + else if ( name == VCEmailAddressProp ) { + QString email = vObjectStringZValue( o ); + bool valid = TRUE; + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + if ( name != VCInternetProp && name != VCHomeProp && + name != VCWorkProp && + name != VCPreferredProp ) + // ### preffered should map to default email + valid = FALSE; + } + if ( valid ) { + c.insertEmail( email ); + } + } + else if ( name == VCURLProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + if ( name == VCHomeProp ) + c.setHomeWebpage( value ); + else if ( name == VCWorkProp ) + c.setBusinessWebpage( value ); + } + } + else if ( name == VCOrgProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCOrgNameProp ) + c.setCompany( value ); + else if ( name == VCOrgUnitProp ) + c.setDepartment( value ); + else if ( name == VCOrgUnit2Prop ) + c.setOffice( value ); + } + } + else if ( name == VCTitleProp ) { + c.setJobTitle( value ); + } + else if ( name == "X-Qtopia-Profession" ) { + c.setProfession( value ); + } + else if ( name == "X-Qtopia-Manager" ) { + c.setManager( value ); + } + else if ( name == "X-Qtopia-Assistant" ) { + c.setAssistant( value ); + } + else if ( name == "X-Qtopia-Spouse" ) { + c.setSpouse( value ); + } + else if ( name == "X-Qtopia-Gender" ) { + c.setGender( value ); + } + else if ( name == "X-Qtopia-Anniversary" ) { + c.setAnniversary( value ); + } + else if ( name == "X-Qtopia-Nickname" ) { + c.setNickname( value ); + } + else if ( name == "X-Qtopia-Children" ) { + c.setChildren( value ); + } + + +#if 0 + else { + printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + printf(" subprop: %s = %s\n", name.data(), value.latin1() ); + } + } +#endif + } + c.setFileAs(); + return c; +} + +/*! + Writes the list of \a contacts as a set of VCards to the file \a filename. +*/ +void OContact::writeVCard( const QString &filename, const QValueList<OContact> &contacts) +{ + QFileDirect f( filename.utf8().data() ); + if ( !f.open( IO_WriteOnly ) ) { + qWarning("Unable to open vcard write"); + return; + } + + QValueList<OContact>::ConstIterator it; + for( it = contacts.begin(); it != contacts.end(); ++it ) { + VObject *obj = createVObject( *it ); + writeVObject(f.directHandle() , obj ); + cleanVObject( obj ); + } + cleanStrTbl(); +} + +/*! + writes \a contact as a VCard to the file \a filename. +*/ +void OContact::writeVCard( const QString &filename, const OContact &contact) +{ + QFileDirect f( filename.utf8().data() ); + if ( !f.open( IO_WriteOnly ) ) { + qWarning("Unable to open vcard write"); + return; + } + + VObject *obj = createVObject( contact ); + writeVObject( f.directHandle() , obj ); + cleanVObject( obj ); + + cleanStrTbl(); +} + +/*! + Returns the set of contacts read as VCards from the file \a filename. +*/ +QValueList<OContact> OContact::readVCard( const QString &filename ) +{ + qDebug("trying to open %s, exists=%d", filename.utf8().data(), QFileInfo( filename.utf8().data() ).size() ); + VObject *obj = Parse_MIME_FromFileName( (char *)filename.utf8().data() ); + + qDebug("vobject = %p", obj ); + + QValueList<OContact> contacts; + + while ( obj ) { + contacts.append( parseVObject( obj ) ); + + VObject *t = obj; + obj = nextVObjectInList(obj); + cleanVObject( t ); + } + + return contacts; +} + +/*! + Returns TRUE if the contact matches the regular expression \a regexp. + Otherwise returns FALSE. +*/ +bool OContact::match( const QString ®exp ) const +{ + return match(QRegExp(regexp)); +} + +/*! + \overload + Returns TRUE if the contact matches the regular expression \a regexp. + Otherwise returns FALSE. +*/ +bool OContact::match( const QRegExp &r ) const +{ + bool match; + match = false; + QMap<int, QString>::ConstIterator it; + for ( it = mMap.begin(); it != mMap.end(); ++it ) { + if ( (*it).find( r ) > -1 ) { + match = true; + break; + } + } + return match; +} + + +// Noch nicht definiert ! :SX +QString OContact::toShortText() const +{ + return ( QString::fromLatin1( "Not defined!") ); +} +QString OContact::type() const +{ + return QString::fromLatin1( "OContact" ); +} + +// Noch nicht definiert ! :SX +QMap<QString,QString> OContact::toExtraMap() const +{ + QMap <QString,QString> useless; + return useless; +} + +// Noch nicht definiert ! :SX +class QString OContact::recordField(int) const +{ + return QString::fromLatin1( "Noch nicht implementiert !" ); +} diff --git a/libopie2/opiepim/ocontact.h b/libopie2/opiepim/ocontact.h new file mode 100644 index 0000000..e0555c8 --- a/dev/null +++ b/libopie2/opiepim/ocontact.h @@ -0,0 +1,311 @@ +/********************************************************************** +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef __OCONTACT_H__ +#define __OCONTACT_H__ + +#include <opie/opimrecord.h> +#include <qpe/recordfields.h> + +#include <qstringlist.h> + +#if defined(QPC_TEMPLATEDLL) +// MOC_SKIP_BEGIN +QPC_TEMPLATEEXTERN template class QPC_EXPORT QMap<int, QString>; +// MOC_SKIP_END +#endif + +class ContactPrivate; // Wozu ist das gut und wo ist das decrariert ? (se) +class QPC_EXPORT OContact : public OPimRecord +{ + friend class DataSet; +public: + OContact(); + OContact( const QMap<int, QString> &fromMap ); + virtual ~OContact(); + + static void writeVCard( const QString &filename, const QValueList<OContact> &contacts); + static void writeVCard( const QString &filename, const OContact &c ); + static QValueList<OContact> readVCard( const QString &filename ); + + enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; + + void setTitle( const QString &v ) { replace( Qtopia::Title, v ); } + void setFirstName( const QString &v ) { replace( Qtopia::FirstName, v ); } + void setMiddleName( const QString &v ) { replace( Qtopia::MiddleName, v ); } + void setLastName( const QString &v ) { replace( Qtopia::LastName, v ); } + void setSuffix( const QString &v ) { replace( Qtopia::Suffix, v ); } + void setFileAs( const QString &v ) { replace( Qtopia::FileAs, v ); } + void setFileAs(); + + // default email address + void setDefaultEmail( const QString &v ); + // inserts email to list and ensure's doesn't already exist + void insertEmail( const QString &v ); + void removeEmail( const QString &v ); + void clearEmails(); + void insertEmails( const QStringList &v ); + + // home + void setHomeStreet( const QString &v ) { replace( Qtopia::HomeStreet, v ); } + void setHomeCity( const QString &v ) { replace( Qtopia::HomeCity, v ); } + void setHomeState( const QString &v ) { replace( Qtopia::HomeState, v ); } + void setHomeZip( const QString &v ) { replace( Qtopia::HomeZip, v ); } + void setHomeCountry( const QString &v ) { replace( Qtopia::HomeCountry, v ); } + void setHomePhone( const QString &v ) { replace( Qtopia::HomePhone, v ); } + void setHomeFax( const QString &v ) { replace( Qtopia::HomeFax, v ); } + void setHomeMobile( const QString &v ) { replace( Qtopia::HomeMobile, v ); } + void setHomeWebpage( const QString &v ) { replace( Qtopia::HomeWebPage, v ); } + + // business + void setCompany( const QString &v ) { replace( Qtopia::Company, v ); } + void setBusinessStreet( const QString &v ) { replace( Qtopia::BusinessStreet, v ); } + void setBusinessCity( const QString &v ) { replace( Qtopia::BusinessCity, v ); } + void setBusinessState( const QString &v ) { replace( Qtopia::BusinessState, v ); } + void setBusinessZip( const QString &v ) { replace( Qtopia::BusinessZip, v ); } + void setBusinessCountry( const QString &v ) { replace( Qtopia::BusinessCountry, v ); } + void setBusinessWebpage( const QString &v ) { replace( Qtopia::BusinessWebPage, v ); } + void setJobTitle( const QString &v ) { replace( Qtopia::JobTitle, v ); } + void setDepartment( const QString &v ) { replace( Qtopia::Department, v ); } + void setOffice( const QString &v ) { replace( Qtopia::Office, v ); } + void setBusinessPhone( const QString &v ) { replace( Qtopia::BusinessPhone, v ); } + void setBusinessFax( const QString &v ) { replace( Qtopia::BusinessFax, v ); } + void setBusinessMobile( const QString &v ) { replace( Qtopia::BusinessMobile, v ); } + void setBusinessPager( const QString &v ) { replace( Qtopia::BusinessPager, v ); } + void setProfession( const QString &v ) { replace( Qtopia::Profession, v ); } + void setAssistant( const QString &v ) { replace( Qtopia::Assistant, v ); } + void setManager( const QString &v ) { replace( Qtopia::Manager, v ); } + + // personal + void setSpouse( const QString &v ) { replace( Qtopia::Spouse, v ); } + void setGender( const QString &v ) { replace( Qtopia::Gender, v ); } + void setBirthday( const QString &v ) { replace( Qtopia::Birthday, v ); } + void setAnniversary( const QString &v ) { replace( Qtopia::Anniversary, v ); } + void setNickname( const QString &v ) { replace( Qtopia::Nickname, v ); } + void setChildren( const QString &v ); + + // other + void setNotes( const QString &v ) { replace( Qtopia::Notes, v); } + + bool match( const QString ®exp ) const; + +// DON'T ATTEMPT TO USE THIS +#ifdef QTOPIA_INTERNAL_CONTACT_MRE + bool match( const QRegExp ®exp ) const; +#endif + +// // custom +// void setCustomField( const QString &key, const QString &v ) +// { replace(Custom- + key, v ); } + + // name + QString fullName() const; + QString title() const { return find( Qtopia::Title ); } + QString firstName() const { return find( Qtopia::FirstName ); } + QString middleName() const { return find( Qtopia::MiddleName ); } + QString lastName() const { return find( Qtopia::LastName ); } + QString suffix() const { return find( Qtopia::Suffix ); } + QString fileAs() const { return find( Qtopia::FileAs ); } + + // email + QString defaultEmail() const { return find( Qtopia::DefaultEmail ); } + QStringList emailList() const; + + // home + QString homeStreet() const { return find( Qtopia::HomeStreet ); } + QString homeCity() const { return find( Qtopia::HomeCity ); } + QString homeState() const { return find( Qtopia::HomeState ); } + QString homeZip() const { return find( Qtopia::HomeZip ); } + QString homeCountry() const { return find( Qtopia::HomeCountry ); } + QString homePhone() const { return find( Qtopia::HomePhone ); } + QString homeFax() const { return find( Qtopia::HomeFax ); } + QString homeMobile() const { return find( Qtopia::HomeMobile ); } + QString homeWebpage() const { return find( Qtopia::HomeWebPage ); } + /** Multi line string containing all non-empty address info in the form + * Street + * City, State Zip + * Country + */ + QString displayHomeAddress() const; + + // business + QString company() const { return find( Qtopia::Company ); } + QString businessStreet() const { return find( Qtopia::BusinessStreet ); } + QString businessCity() const { return find( Qtopia::BusinessCity ); } + QString businessState() const { return find( Qtopia::BusinessState ); } + QString businessZip() const { return find( Qtopia::BusinessZip ); } + QString businessCountry() const { return find( Qtopia::BusinessCountry ); } + QString businessWebpage() const { return find( Qtopia::BusinessWebPage ); } + QString jobTitle() const { return find( Qtopia::JobTitle ); } + QString department() const { return find( Qtopia::Department ); } + QString office() const { return find( Qtopia::Office ); } + QString businessPhone() const { return find( Qtopia::BusinessPhone ); } + QString businessFax() const { return find( Qtopia::BusinessFax ); } + QString businessMobile() const { return find( Qtopia::BusinessMobile ); } + QString businessPager() const { return find( Qtopia::BusinessPager ); } + QString profession() const { return find( Qtopia::Profession ); } + QString assistant() const { return find( Qtopia::Assistant ); } + QString manager() const { return find( Qtopia::Manager ); } + /** Multi line string containing all non-empty address info in the form + * Street + * City, State Zip + * Country + */ + QString displayBusinessAddress() const; + + //personal + QString spouse() const { return find( Qtopia::Spouse ); } + QString gender() const { return find( Qtopia::Gender ); } + QString birthday() const { return find( Qtopia::Birthday ); } + QString anniversary() const { return find( Qtopia::Anniversary ); } + QString nickname() const { return find( Qtopia::Nickname ); } + QString children() const { return find( Qtopia::Children ); } + QStringList childrenList() const; + + // other + QString notes() const { return find( Qtopia::Notes ); } + QString groups() const { return find( Qtopia::Groups ); } + QStringList groupList() const; + +// // custom +// const QString &customField( const QString &key ) +// { return find( Custom- + key ); } + + static QStringList fields(); + static QStringList trfields(); + + QString toRichText() const; + QMap<int, QString> toMap() const; + QString field( int key ) const { return find( key ); } + + + // journaling... + void saveJournal( journal_action action, const QString &key = QString::null ); + void save( QString &buf ) const; + + void setUid( int i ) +{ Record::setUid(i); replace( Qtopia::AddressUid , QString::number(i)); } + + QString toShortText()const; + QString OContact::type()const; + QMap<QString,QString> OContact::toExtraMap() const; + class QString OContact::recordField(int) const; + +private: + friend class AbEditor; + friend class AbTable; + friend class AddressBookAccessPrivate; + friend class XMLIO; + + QString emailSeparator() const { return " "; } + // the emails should be seperated by a comma + void setEmails( const QString &v ); + QString emails() const { return find( Qtopia::Emails ); } + + void insert( int key, const QString &value ); + void replace( int key, const QString &value ); + QString find( int key ) const; + + QString displayAddress( const QString &street, + const QString &city, + const QString &state, + const QString &zip, + const QString &country ) const; + + Qtopia::UidGen &uidGen() { return sUidGen; } + static Qtopia::UidGen sUidGen; + QMap<int, QString> mMap; + ContactPrivate *d; +}; + +// these methods are inlined to keep binary compatability with Qtopia 1.5 +inline void OContact::insertEmail( const QString &v ) +{ + //qDebug("insertEmail %s", v.latin1()); + QString e = v.simplifyWhiteSpace(); + QString def = defaultEmail(); + + // if no default, set it as the default email and don't insert + if ( def.isEmpty() ) { + setDefaultEmail( e ); // will insert into the list for us + return; + } + + // otherwise, insert assuming doesn't already exist + QString emailsStr = find( Qtopia::Emails ); + if ( emailsStr.contains( e )) + return; + if ( !emailsStr.isEmpty() ) + emailsStr += emailSeparator(); + emailsStr += e; + replace( Qtopia::Emails, emailsStr ); +} + +inline void OContact::removeEmail( const QString &v ) +{ + QString e = v.simplifyWhiteSpace(); + QString def = defaultEmail(); + QString emailsStr = find( Qtopia::Emails ); + QStringList emails = emailList(); + + // otherwise, must first contain it + if ( !emailsStr.contains( e ) ) + return; + + // remove it + //qDebug(" removing email from list %s", e.latin1()); + emails.remove( e ); + // reset the string + emailsStr = emails.join(emailSeparator()); // Sharp's brain dead separator + replace( Qtopia::Emails, emailsStr ); + + // if default, then replace the default email with the first one + if ( def == e ) { + //qDebug("removeEmail is default; setting new default"); + if ( !emails.count() ) + clearEmails(); + else // setDefaultEmail will remove e from the list + setDefaultEmail( emails.first() ); + } +} +inline void OContact::clearEmails() +{ + mMap.remove( Qtopia::DefaultEmail ); + mMap.remove( Qtopia::Emails ); +} +inline void OContact::setDefaultEmail( const QString &v ) +{ + QString e = v.simplifyWhiteSpace(); + + //qDebug("OContact::setDefaultEmail %s", e.latin1()); + replace( Qtopia::DefaultEmail, e ); + + if ( !e.isEmpty() ) + insertEmail( e ); + +} + +inline void OContact::insertEmails( const QStringList &v ) +{ + for ( QStringList::ConstIterator it = v.begin(); it != v.end(); ++it ) + insertEmail( *it ); +} + +#endif |