[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    KDE/kdepim/kaddressbook/xxport
From:       Allen Winter <winter () kde ! org>
Date:       2009-07-08 13:08:12
Message-ID: 1247058492.589562.9088.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 993311 by winterz:

Refinement of import/export of kaddressbook from/to GMX.
Patch entirely from Urs Joss. Thanks!
Joss, please close the review board request for this as closed.

Remember: we need to also put this into kcontactmanager.

http://reviewboard.kde.org/r/941
CCMAIL: tschenturs@gmx.ch


 M  +238 -40   gmx_xxport.cpp  


--- trunk/KDE/kdepim/kaddressbook/xxport/gmx_xxport.cpp #993310:993311
@@ -33,6 +33,7 @@
 
 #include <QtCore/QFile>
 #include <QtCore/QMap>
+#include <QtCore/QList>
 #include <QtCore/QTextStream>
 
 #include <kcodecs.h>
@@ -48,6 +49,10 @@
 
 #define GMX_FILESELECTION_STRING "*.gmxa|" + i18n( "GMX address book file (*.gmxa)" \
)  
+const int typeHome  = 0;
+const int typeWork  = 1;
+const int typeOther = 2;
+
 GMXXXPort::GMXXXPort( KABC::AddressBook *ab, QWidget *parent, const char *name )
   : KAB::XXPort( ab, parent, name )
 {
@@ -99,10 +104,11 @@
   QStringList strList;
   typedef QMap<QString, KABC::Addressee *> AddressMap;
   AddressMap addrMap;
+  QMap<QString, QString>  catList;
 
   // "Address_id,Nickname,Firstname,Lastname,Title,Birthday,Comments,Change_date,Status,Address_link_id,Categories"
  line = gmxStream.readLine();
-  while (!line.startsWith(QLatin1String("####")) && !gmxStream.atEnd()) {
+  while ( (line!=QLatin1String("####")) && !gmxStream.atEnd() ) {
     while (1) {
        strList = line.split('#', QString::KeepEmptyParts );
        if (strList.count() >= 11)
@@ -115,13 +121,14 @@
     addr->setNickName(strList[1]);
     addr->setGivenName(strList[2]);
     addr->setFamilyName(strList[3]);
-    addr->setTitle(strList[4]);
+    addr->setFormattedName(strList[3] + ", " + strList[2]);
+    addr->setPrefix(strList[4]);
     if (checkDateTime(strList[5],dt)) addr->setBirthday(dt);
     addr->setNote(strList[6]);
     if (checkDateTime(strList[7],dt)) addr->setRevision(dt);
     // addr->setStatus(strList[8]); Status
     // addr->xxx(strList[9]); Address_link_id
-    // addr->setCategory(strList[10]); Categories
+    catList[strList[0]] = strList[10];
     addrMap[strList[0]] = addr;
 
     line = gmxStream.readLine();
@@ -149,25 +156,50 @@
 
     KABC::Addressee *addr = addrMap[strList[0]];
     if (addr) {
-	for ( QStringList::Iterator it = strList.begin(); it != strList.end(); ++it )
-		*it = (*it).simplified();
 	// strList[1] = Record_id (numbered item, ignore here)
-	int id = strList[14].toInt(); // Record_type_id (0=work,1=home,2=other)
-  KABC::Address::Type type = (id==0) ? KABC::Address::Work : KABC::Address::Home;
-	if (!strList[19].isEmpty() && strList[19].toInt()!=0)
-		type |= KABC::Address::Pref; // Preferred address (seems to be bitfield for \
telephone Prefs) +	int id = strList[14].toInt(); // Record_type_id \
(0=home,1=work,2=other) +	KABC::Address::Type type;
+	KABC::PhoneNumber::Type phoneType;
+	switch ( id ) {
+	  case typeHome:
+	    type = KABC::Address::Home;
+	    phoneType = KABC::PhoneNumber::Home;
+	    break;
+	  case typeWork:
+	    type = KABC::Address::Work;
+	    phoneType = KABC::PhoneNumber::Work;
+	    break;
+	  case typeOther:
+	  default:
+	    type = KABC::Address::Intl;
+	    phoneType = KABC::PhoneNumber::Voice;
+	    break;
+	}
         KABC::Address adr = addr->address(type);
 	adr.setStreet(strList[2]);
 	adr.setCountry(strList[3]);
 	adr.setPostalCode(strList[4]);
 	adr.setLocality(strList[5]);
-	addr->insertPhoneNumber( KABC::PhoneNumber(strList[6], KABC::PhoneNumber::Home) );
-	addr->insertPhoneNumber( KABC::PhoneNumber(strList[7], KABC::PhoneNumber::Fax) );
+	if (!strList[6].isEmpty()) {
+	  addr->insertPhoneNumber(
+	    KABC::PhoneNumber(strList[6], phoneType)
+	  );
+	}
+	if (!strList[7].isEmpty())
+	  addr->insertPhoneNumber(
+	    KABC::PhoneNumber(strList[7], KABC::PhoneNumber::Fax)
+	);
   KABC::PhoneNumber::Type celltype = KABC::PhoneNumber::Cell;
 	// strList[9]=Mobile_type // always 0 or -1(default phone).
-	if (strList[9].toInt()) celltype |= KABC::PhoneNumber::Pref;
-	addr->insertPhoneNumber( KABC::PhoneNumber(strList[8], celltype) );
-	addr->insertEmail(strList[10]);
+	//if ( strList[19].toInt() & 4 ) celltype |= KABC::PhoneNumber::Pref;
+	//  avoid duplicates
+	if (!strList[8].isEmpty())
+	  addr->insertPhoneNumber(
+	    KABC::PhoneNumber(strList[8], celltype)
+	);
+	bool preferred = false;
+	if (strList[19].toInt() & 1 ) preferred = true;
+	addr->insertEmail(strList[10], preferred);
 	if (!strList[11].isEmpty()) addr->setUrl(strList[11]);
 	if (!strList[12].isEmpty()) addr->setRole(strList[12]);
 	// strList[13]=Comments
@@ -187,9 +219,39 @@
     line = gmxStream.readLine();
   }
 
+  // read the categories
+  QStringList categories;
+  line = gmxStream.readLine();
+  line2 = gmxStream.readLine();
+  if ( !line.startsWith( QLatin1String( "AB_CATEGORIES:" ) ) ||
+    !line2.startsWith( QLatin1String( "Category_id" ) ) ) {
+    kWarning() <<"Could not find categories records!";
+  } else {
+    while ( !line.startsWith( QLatin1String( "####" ) ) &&
+            !gmxStream.atEnd() ) {
+      while (1) {
+        strList = line.split( '#', QString::KeepEmptyParts );
+        if ( strList.count() >= 3 )
+          break;
+        line.append( '\n' );
+        line.append( gmxStream.readLine() );
+      };
+      categories.append( strList[1] );
+      line = gmxStream.readLine();
+    };
+  }
+
   // now add the addresses to to addrList
   for ( AddressMap::Iterator it = addrMap.begin(); it != addrMap.end(); ++it ) {
      KABC::Addressee *addr = it.value();
+     // Add categories
+     int addrCat = catList[it.key()].toInt();
+     for ( int i=32; i >= 0; --i ) {
+       int cat =  1<<i;
+       if ( cat > addrCat ) continue;
+       if ( cat & addrCat  && categories.count() > i )
+         addr->insertCategory( categories[i] );
+     }
      addrList.append(*addr);
      delete addr;
   }
@@ -252,6 +314,27 @@
   return d;
 }
 
+static const QStringList assignedCategoriesSorted(
+  const KABC::AddresseeList &list )
+{
+  // Walk through the addressees and collect up to 31 categories,
+  // returned sorted alphabetically
+  QStringList catList;
+  KABC::AddresseeList::ConstIterator it;
+  const KABC::Addressee *addr;
+  for ( it = list.begin(); it != list.end() && catList.count() < 32; ++it ) {
+    addr = &(*it);
+    if ( addr->isEmpty() ) continue;
+    const QStringList categories = addr->categories();
+    for ( int i=0; i < categories.count() && catList.count() < 32; ++i ) {
+      if ( !catList.contains( categories[i]) )
+        catList.append( categories[i] );
+    }
+  }
+  catList.sort();
+  return catList;
+}
+
 void GMXXXPort::doExport( QFile *fp, const KABC::AddresseeList &list )
 {
   if (!fp || !list.count())
@@ -269,6 +352,23 @@
   t << "Address_id,Nickname,Firstname,Lastname,Title,Birthday,Comments,"
        "Change_date,Status,Address_link_id,Categories\n";
 
+  // Categories: The gmxa file lists the categories in the last section
+  // and allows multi-category assignment through bitfields.
+  // However, the category definition in GMX is not updated through the
+  // import (only the category assignment of the addressees). The addresses
+  // may point to non-existing or wrong categories after the import.
+  // This implies that the user needs to make sure he/she manually creates
+  // the categories in the GMX UI *in the same sequence* as in the gmxa files.
+  // Of course this is only necessary if the category list has changed since
+  // the last import.
+  // The GMX UI displays the categories alphabetically sorted (thus hiding the
+  // sequence of entering categories. Therefore the easiest is to output the
+  // category list in the gmxa file alphabetically sorted as well. If you need
+  // to enter a new category, you can delete any existing category which sorts
+  // higher than the new one and then enter the new and remaining category.
+  QList<QString> catList;
+  catList.append( assignedCategoriesSorted( list ) );
+
   int no = 0;
   const QChar DELIM('#');
   for ( it = list.begin(); it != list.end(); ++it ) {
@@ -276,15 +376,34 @@
      if (addr->isEmpty())
         continue;
      addrMap[++no] = addr;
+  
+    // Assign categories as bitfield
+    const QStringList categories = addr->categories();
+    long int category = 0;
+    if ( categories.count() > 0 ) {
+      for ( int i=0; i < categories.count(); i++ ) {
+        if ( catList.contains( categories[i] ) )
+          category |= 1 << catList.indexOf( categories[i], 0 ) ;
+      }
+    }
+
+    // GMX sorts by nickname by default - don't leave empty
+    QString nickName = addr->nickName();
+    if ( nickName.isEmpty() )
+      nickName = addr->formattedName();
+
      t << no << DELIM			// Address_id
-	<< addr->nickName() << DELIM	// Nickname
+	<< nickName << DELIM            // Nickname
 	<< addr->givenName() << DELIM	// Firstname
 	<< addr->familyName() << DELIM	// Lastname
-	<< addr->title() << DELIM	// Title
+	<< addr->prefix() << DELIM	// Title - Note: ->title()
+                                        // refers to the professional title
 	<< dateString(addr->birthday()) << DELIM   // Birthday
 	<< addr->note() /*.replace('\n',"\r\n")*/ << DELIM // Comments
 	<< dateString(addr->revision()) << DELIM   // Change_date
-	<< "1##0\n";			// Status, Address_link_id, Categories
+        << "1" << DELIM                 // Status
+        << DELIM                        // Address_link_id
+        << category << endl;            // Categories
   }
 
   t << "####\n";
@@ -295,27 +414,94 @@
 
   no = 1;
   while ( (addr = addrMap[no]) != NULL ) {
+
+    const KABC::PhoneNumber::List cellPhones =
+      addr->phoneNumbers( KABC::PhoneNumber::Cell );
+
+    const QStringList emails = addr->emails();
+
     for (int record_id=0; record_id<3; ++record_id) {
 
 	KABC::Address address;
   	KABC::PhoneNumber phone, fax, cell;
+     
+      // address preference flag:
+      // & 1: preferred email address
+      // & 4: preferred cell phone
+      int prefFlag=0;
 
-	/* record ID == 1: Work address */
-        if (record_id == 1) {
-		address = addr->address(KABC::Address::Work);
-		phone = addr->phoneNumber(KABC::PhoneNumber::Work);
-		fax   = addr->phoneNumber(KABC::PhoneNumber::Fax);
-		cell  = addr->phoneNumber(KABC::PhoneNumber::Work | KABC::PhoneNumber::Cell);
-	} else {
-		address = addr->address(KABC::Address::Home);
-		phone = addr->phoneNumber(KABC::PhoneNumber::Home);
-		cell  = addr->phoneNumber(KABC::PhoneNumber::Cell);
-	}
+      switch (record_id) {
+      // Assign address, phone and cellphone, fax if applicable
+        case typeHome:
+          address = addr->address( KABC::Address::Home );
+          phone   = addr->phoneNumber( KABC::PhoneNumber::Home );
+          if ( cellPhones.count() > 0 ) {
+            cell  = cellPhones.at(0);
+            if ( !cell.isEmpty() )
+              prefFlag |= 4;
+          }
+          break;
+        case typeWork:
+          address = addr->address( KABC::Address::Work );
+          phone   = addr->phoneNumber( KABC::PhoneNumber::Work );
+          if ( cellPhones.count() >= 2 )
+            cell  = cellPhones.at(1);
+          fax     = addr->phoneNumber( KABC::PhoneNumber::Fax );
+          break;
+        case typeOther:
+        default:
+          if ( addr->addresses( KABC::Address::Home ).count() > 1 )
+            address = addr->addresses( KABC::Address::Home ).at(1);
+          if ( ( address.isEmpty() ) &&
+               ( addr->addresses( KABC::Address::Work ).count() > 1 ) )
+            address = addr->addresses( KABC::Address::Work ).at(1);
+          if ( address.isEmpty() )
+            address = addr->address( KABC::Address::Dom );
+          if ( address.isEmpty() )
+            address = addr->address( KABC::Address::Intl );
+          if ( address.isEmpty() )
+            address = addr->address( KABC::Address::Postal );
+          if ( address.isEmpty() )
+            address = addr->address( KABC::Address::Parcel );
 
-	const QStringList emails = addr->emails();
-	QString email;
-	if (emails.count()>record_id) email = emails[record_id];
+          if ( addr->phoneNumbers( KABC::PhoneNumber::Home ).count() > 1 )
+            phone = addr->phoneNumbers( KABC::PhoneNumber::Home ).at(1);
+          if ( ( phone.isEmpty() ) &&
+               ( addr->phoneNumbers( KABC::PhoneNumber::Work ).count() > 1 ) )
+            phone = addr->phoneNumbers( KABC::PhoneNumber::Work ).at(1);
+          if ( phone.isEmpty() )
+            phone = addr->phoneNumber( KABC::PhoneNumber::Voice );
+          if ( phone.isEmpty() )
+            phone = addr->phoneNumber( KABC::PhoneNumber::Msg );
+          if ( phone.isEmpty() )
+            phone = addr->phoneNumber( KABC::PhoneNumber::Isdn );
+          if ( phone.isEmpty() )
+            phone = addr->phoneNumber( KABC::PhoneNumber::Car );
+          if ( phone.isEmpty() )
+            phone = addr->phoneNumber( KABC::PhoneNumber::Pager );
 
+          switch ( cellPhones.count() ) {
+            case 0: break;
+            case 1:
+            case 2:
+              if ( !address.isEmpty() )
+                cell = cellPhones.at(0);
+              break;
+            default:
+              cell = cellPhones.at(2);
+              break;
+          }
+          break;
+      }
+
+      QString email="";
+      if (emails.count()>record_id) {
+        email = emails[record_id];
+        if ( email == addr->preferredEmail() ) prefFlag |= 1;
+      }
+
+      if ( !address.isEmpty() || !phone.isEmpty() ||
+           !cell.isEmpty()    || !email.isEmpty() ) {
 	t << no << DELIM			// Address_id
 	  << record_id << DELIM			// Record_id
 	  << address.street() << DELIM		// Street
@@ -325,25 +511,37 @@
 	  << phone.number() << DELIM		// Phone
 	  << fax.number() << DELIM		// Fax
 	  << cell.number() << DELIM		// Mobile
-	  << ((cell.type()&KABC::PhoneNumber::Pref)?-1:0) << DELIM // Mobile_type
+	  << ((record_id==typeWork)?0:1 ) << DELIM   // Mobile_type
 	  << email << DELIM			// Email
-	  << ((record_id==1)?addr->url().url():QString()) << DELIM // Homepage
-	  << ((record_id==1)?addr->role():QString()) << DELIM	// Position
-	  << DELIM				// Comments
+	  << ((record_id==typeWork)?addr->url().url():QString()) << DELIM // Homepage
+	  << ((record_id==typeWork)?addr->role():QString()) << DELIM // Position
+	  << ((record_id==typeHome)?addr->custom("KADDRESSBOOK", "X-SpousesName"):QString() \
) << DELIM // Comments  << record_id << DELIM			// Record_type_id (0,1,2) - see above
 	  << DELIM				// Record_type (name of this additional record entry)
-	  << ((record_id==1)?addr->organization():QString()) << DELIM // Company
-	  << ((record_id==1)?addr->custom("KADDRESSBOOK", "X-Department"):QString()) << \
DELIM // Department +	  << ((record_id==typeWork)?addr->organization():QString()) << \
DELIM // Company +	  << ((record_id==typeWork)?addr->custom("KADDRESSBOOK", \
"X-Department"):QString() ) << DELIM // Department  << dateString(addr->revision()) \
                << DELIM	// Change_date
-	  << 5 << DELIM				// Preferred
+	  << prefFlag << DELIM			// Preferred:
+	                                        // ( & 1: preferred email,
+	                                        //   & 4: preferred cell phone )
 	  << 1 << endl;				// Status (should always be "1")
+      }
     }
 
     ++no;
   };
 
-  t << "####";
+  t << "####" << endl;
+  t << "AB_CATEGORIES:" << endl;
+  t << "Category_id,Name,Icon_id" << endl;
+
+  //  Write Category List (beware: Category_ID 0 is reserved for none
+  //  Interestingly: The index here is an int sequence and does not
+  //  correspond to the bit reference used above.
+  for ( int i = 0; i < catList.size(); i++ ) {
+    t << ( i + 1 ) << DELIM << catList.at( i ) << DELIM << 0 << endl;
+  }
+  t << "####" << endl;
 }
 
 #include "gmx_xxport.moc"
-


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic