Hi,
I've found out that when one meta contact has more than one contact from
specific
protocol the properties of that contacts aren't saved correctly. To be
precise
for instance if contact A doesn't have prop_QString_firstName and contact
B has it
then on next startup A will have the prop_QString_firstName and B won't.
Attached patch fixes this by saving each contact into one
plugin-contact-data element
instead of merging it.
So
<meta-contact>
<plugin-data plugin-id="ICQProtocol" >
<plugin-data-field key="contactId" >ContactA
ContactB</plugin-data-field>
</plugin-data>
</meta-contact>
will be
<meta-contact>
<plugin-contact-data plugin-id="ICQProtocol" >
<plugin-data-field key="contactId" >ContactA</plugin-data-field>
</plugin-contact-data>
<plugin-contact-data plugin-id="ICQProtocol" >
<plugin-data-field key="contactId" >ContactB</plugin-data-field>
</plugin-contact-data>
</meta-contact>
The patch also calls Protocol::serialize only once per protocol and not
for every contact.
I know that the serialize/deserialize API is really ugly but I don't want
to mess with it
in feature freeze.
Could anybody review this patch and check if I didn't miss anything?
Regards,
Roman
Index: kopete/libkopete/kopeteprotocol.h
===================================================================
--- kopete/libkopete/kopeteprotocol.h (revision 982847)
+++ kopete/libkopete/kopeteprotocol.h (working copy)
@@ -235,6 +235,11 @@
virtual void deserialize( MetaContact *metaContact, const QMap<QString, QString> &serializedData );
/**
+ * @brief Deserialize the plugin data for a meta contact's contacts.
+ */
+ virtual void deserializeContactList( MetaContact *metaContact, const QList< QMap<QString, QString> > &dataList );
+
+ /**
* @brief Deserialize a single contact.
*
* This method is called by @ref deserialize() for each separate contact,
@@ -291,15 +296,15 @@
*/
virtual bool validatePassword( const QString & password ) const;
-public slots:
+public:
/**
- * A meta contact is about to save.
+ * Serialize meta contact into the metacontact's plugin data
* Call serialize() for all contained contacts for this protocol.
* @internal
* it's public because for example, Contact::setMetaContact uses it.
* @todo we probably should think to another way to save the contacltist.
*/
- void slotMetaContactAboutToSave( Kopete::MetaContact *metaContact );
+ void serialize( Kopete::MetaContact *metaContact );
private:
Index: kopete/libkopete/kopetecontactlistelement.cpp
===================================================================
--- kopete/libkopete/kopetecontactlistelement.cpp (revision 982847)
+++ kopete/libkopete/kopetecontactlistelement.cpp (working copy)
@@ -1,3 +1,4 @@
+
/*
kopeteplugindataobject.cpp - Kopete Plugin Data Object
@@ -31,6 +32,7 @@
{
public:
ContactListElement::PluginDataMap pluginData;
+ QMap<QString, ContactListElement::ContactDataList> pluginContactData;
ContactListElement::IconMap icons;
bool useCustomIcon;
bool loading;
@@ -107,6 +109,51 @@
return d->pluginData;
}
+QMap<QString, ContactListElement::ContactDataList > ContactListElement::pluginContactData() const
+{
+ return d->pluginContactData;
+}
+
+ContactListElement::ContactDataList ContactListElement::pluginContactData( Plugin *plugin ) const
+{
+ if ( !d->pluginContactData.contains( plugin->pluginId() ) )
+ return ContactDataList();
+
+ return d->pluginContactData[ plugin->pluginId() ];
+}
+
+void ContactListElement::clearPluginContactData()
+{
+ d->pluginContactData.clear();
+}
+
+void ContactListElement::setPluginContactData( Plugin *plugin, const ContactListElement::ContactDataList &dataList )
+{
+ QString pluginId = plugin->pluginId();
+ if ( dataList.isEmpty() )
+ {
+ d->pluginContactData.remove( pluginId );
+ return;
+ }
+
+ d->pluginContactData[ pluginId ] = dataList;
+
+ emit pluginDataChanged();
+}
+
+void ContactListElement::appendPluginContactData( const QString &pluginId, const ContactData &data )
+{
+ if ( data.isEmpty() )
+ {
+ d->pluginContactData.remove( pluginId );
+ return;
+ }
+
+ d->pluginContactData[ pluginId ].append( data );
+
+ emit pluginDataChanged();
+}
+
const ContactListElement::IconMap ContactListElement::icons() const
{
return d->icons;
Index: kopete/libkopete/kopetepluginmanager.cpp
===================================================================
--- kopete/libkopete/kopetepluginmanager.cpp (revision 982847)
+++ kopete/libkopete/kopetepluginmanager.cpp (working copy)
@@ -43,6 +43,7 @@
#include <kservicetypetrader.h>
#include "kopeteplugin.h"
+#include "kopeteprotocol.h"
#include "kopetecontactlist.h"
#include "kopeteaccountmanager.h"
@@ -387,6 +388,10 @@
kDebug( 14010 ) << "Successfully loaded plugin '" << pluginId << "'";
emit pluginLoaded( plugin );
+
+ Protocol* protocol = dynamic_cast<Protocol*>( plugin );
+ if ( protocol )
+ emit protocolLoaded( protocol );
}
else
{
Index: kopete/libkopete/contactlist/xmlcontactstorage.cpp
===================================================================
--- kopete/libkopete/contactlist/xmlcontactstorage.cpp (revision 982847)
+++ kopete/libkopete/contactlist/xmlcontactstorage.cpp (working copy)
@@ -61,18 +61,19 @@
{
public:
Private()
- : isBusy(false), isValid(false)
+ : isBusy(false), isValid(false), version(0)
{}
bool isBusy;
bool isValid;
QString xmlFilename;
QString errorMessage;
+ uint version;
/**
* Current contact list version * 10 ( i.e. '10' is version '1.0' )
*/
- static const uint ContactListVersion = 11;
+ static const uint ContactListVersion = 12;
};
@@ -140,21 +141,27 @@
QDomElement list = contactList.documentElement();
- QString versionString = list.attribute( QString::fromLatin1( "version" ), QString() );
- uint version = 0;
- if( QRegExp( QString::fromLatin1( "[0-9]+\\.[0-9]" ) ).exactMatch( versionString ) )
- version = versionString.remove( QLatin1Char( '.' ) ).toUInt();
+ d->version = readVersion( list );
+ if( d->version < Private::ContactListVersion )
+ {
+ QFile::copy( filename, filename + QString::fromLatin1(".bak_v%1").arg( d->version ) );
- if( version < Private::ContactListVersion )
- {
bool contactListUpdated = false;
- if ( version == 10 )
- contactListUpdated = updateFrom10( list );
+ if ( d->version == 10 )
+ {
+ contactListUpdated = updateFrom10to11( list );
+ d->version = readVersion( list );
+ }
+ if ( d->version == 11 )
+ {
+ contactListUpdated = updateFrom11to12( list );
+ d->version = readVersion( list );
+ }
- if ( !contactListUpdated )
+ if ( d->version < Private::ContactListVersion )
{
contactListFile.close();
- kWarning(14010) << "The contact list on disk is older than expected."
+ kWarning(14010) << "The contact list on disk is older than expected or cannot be updated!"
<< "No contact list will be loaded";
return;
}
@@ -235,7 +242,7 @@
QDomDocument doc;
doc.appendChild( doc.createElement( QLatin1String("kopete-contact-list") ) );
- doc.documentElement().setAttribute( QLatin1String("version"), QLatin1String("1.1"));
+ doc.documentElement().setAttribute( QLatin1String("version"), QLatin1String("1.2"));
// Save group information. ie: Open/Closed, pehaps later icons? Who knows.
Kopete::Group::List groupList = Kopete::ContactList::self()->groups();
@@ -461,8 +468,10 @@
metaContact->setDisplayNameSource( nameSourcePID, nameSourceAID, nameSourceCID );
// If a plugin is loaded, load data cached
- QObject::connect( Kopete::PluginManager::self(), SIGNAL( pluginLoaded(Kopete::Plugin*) ),
- metaContact, SLOT( slotPluginLoaded(Kopete::Plugin*) ) );
+ QObject::connect( Kopete::PluginManager::self(), SIGNAL(pluginLoaded(Kopete::Plugin*)),
+ metaContact, SLOT(slotPluginLoaded(Kopete::Plugin*)) );
+ QObject::connect( Kopete::PluginManager::self(), SIGNAL(protocolLoaded(Kopete::Protocol*)),
+ metaContact, SLOT(slotProtocolLoaded(Kopete::Protocol*)) );
// All plugins are already loaded, call manually the contact setting slot.
if( Kopete::PluginManager::self()->isAllPluginsLoaded() )
@@ -580,6 +589,24 @@
}
contactListElement->setPluginData( pluginId, pluginData );
}
+ else if ( element.tagName() == QLatin1String( "plugin-contact-data" ) )
+ {
+ QMap<QString, QString> pluginData;
+ QString pluginId = element.attribute( QLatin1String( "plugin-id" ), QString() );
+
+ QDomNode field = element.firstChild();
+ while( !field.isNull() )
+ {
+ QDomElement fieldElement = field.toElement();
+ if ( fieldElement.tagName() == QLatin1String( "plugin-data-field" ) )
+ {
+ pluginData.insert( fieldElement.attribute( QLatin1String( "key" ),
+ QLatin1String( "undefined-key" ) ), fieldElement.text() );
+ }
+ field = field.nextSibling();
+ }
+ contactListElement->appendPluginContactData( pluginId, pluginData );
+ }
else if ( element.tagName() == QLatin1String( "custom-icons" ) )
{
contactListElement->setUseCustomIcon( element.attribute( QLatin1String( "use" ), QLatin1String( "1" ) ) == QLatin1String( "1" ) );
@@ -622,7 +649,7 @@
const QDomElement XmlContactStorage::storeMetaContact( Kopete::MetaContact *metaContact, bool minimal ) const
{
// This causes each Kopete::Protocol subclass to serialise its contacts' data into the metacontact's plugin data and address book data
- metaContact->emitAboutToSave();
+ metaContact->serialize();
QDomDocument metaContactDoc;
metaContactDoc.appendChild( metaContactDoc.createElement( QString::fromUtf8( "meta-contact" ) ) );
@@ -767,6 +794,32 @@
}
}
+ const QMap<QString, Kopete::ContactListElement::ContactDataList > pluginsContactData = contactListElement->pluginContactData();
+ if ( !pluginsContactData.isEmpty() )
+ {
+ QMap<QString, Kopete::ContactListElement::ContactDataList >::ConstIterator pluginIt, pluginItEnd = pluginsContactData.end();
+ for ( pluginIt = pluginsContactData.begin(); pluginIt != pluginItEnd; ++pluginIt )
+ {
+ foreach ( Kopete::ContactListElement::ContactData dataItem, pluginIt.value() )
+ {
+ QDomElement pluginElement = pluginData.createElement( QLatin1String( "plugin-contact-data" ) );
+ pluginElement.setAttribute( QLatin1String( "plugin-id" ), pluginIt.key() );
+
+ QMap<QString, QString>::ConstIterator it;
+ for ( it = dataItem.begin(); it != dataItem.end(); ++it )
+ {
+ QDomElement pluginDataField = pluginData.createElement( QLatin1String( "plugin-data-field" ) );
+ pluginDataField.setAttribute( QLatin1String( "key" ), it.key() );
+ pluginDataField.appendChild( pluginData.createTextNode( it.value() ) );
+ pluginElement.appendChild( pluginDataField );
+ }
+
+ pluginData.documentElement().appendChild( pluginElement );
+ pluginNodes.append( pluginElement );
+ }
+ }
+ }
+
const Kopete::ContactListElement::IconMap icons = contactListElement->icons();
if ( !icons.isEmpty() )
{
@@ -813,7 +866,7 @@
return pluginNodes;
}
-bool XmlContactStorage::updateFrom10( QDomElement &rootElement ) const
+bool XmlContactStorage::updateFrom10to11( QDomElement &rootElement ) const
{
QDomNodeList metaContactElements = rootElement.elementsByTagName( QLatin1String( "meta-contact" ) );
for ( int i = 0; i < metaContactElements.count(); ++i )
@@ -836,6 +889,94 @@
return true;
}
+bool XmlContactStorage::updateFrom11to12( QDomElement &rootElement ) const
+{
+ QDomNodeList metaContactElementList = rootElement.elementsByTagName( QLatin1String( "meta-contact" ) );
+ for ( int i = 0; i < metaContactElementList.count(); ++i )
+ {
+ typedef QMap<QString, QString> PluginData;
+ typedef QPair<QString, PluginData> ProtocolIdDataPair;
+
+ QList<QDomElement> removeList;
+ QList<ProtocolIdDataPair> newList;
+
+ QDomElement metaContactElement = metaContactElementList.at( i ).toElement();
+ QDomNodeList pluginElementList = metaContactElement.elementsByTagName( QLatin1String( "plugin-data" ) );
+ for ( int j = 0; j < pluginElementList.count(); ++j )
+ {
+ QDomElement element = pluginElementList.at( j ).toElement();
+ QString pluginId = element.attribute( QLatin1String( "plugin-id" ), QString() );
+ if ( !pluginId.endsWith( "Protocol" ) )
+ continue;
+
+ QMap<QString, QStringList> serializedData;
+
+ // Read data to serializedData
+ QDomNode field = element.firstChild();
+ while ( !field.isNull() )
+ {
+ QDomElement fieldElement = field.toElement();
+ if ( fieldElement.tagName() == QLatin1String( "plugin-data-field" ) )
+ {
+ QString key = fieldElement.attribute( QLatin1String( "key" ), QLatin1String( "undefined-key" ) );
+ serializedData[key] = fieldElement.text().split( QChar( 0xE000 ), QString::KeepEmptyParts );
+ }
+ field = field.nextSibling();
+ }
+
+ // Split serializedData by contact
+ int count = serializedData[QLatin1String("contactId")].count();
+ for ( int i = 0; i < count ; i++ )
+ {
+ QMap<QString, QString> sd;
+
+ QMap<QString, QStringList>::Iterator it;
+ QMap<QString, QStringList>::Iterator itEnd = serializedData.end();
+ for ( it = serializedData.begin(); it != itEnd; ++it )
+ {
+ QStringList sl = it.value();
+ if( sl.count() > i)
+ sd[it.key()] = sl.value( i );
+ }
+ newList.append( ProtocolIdDataPair( pluginId, sd ) );
+ }
+
+ removeList.append( element );
+ }
+
+ foreach( QDomElement e, removeList )
+ metaContactElement.removeChild( e );
+
+ foreach( ProtocolIdDataPair pdp, newList )
+ {
+ QDomElement pluginElement = metaContactElement.ownerDocument().createElement( QLatin1String( "plugin-contact-data" ) );
+ pluginElement.setAttribute( QLatin1String( "plugin-id" ), pdp.first );
+
+ QMap<QString, QString>::ConstIterator it;
+ for ( it = pdp.second.begin(); it != pdp.second.end(); ++it )
+ {
+ QDomElement pluginDataField = metaContactElement.ownerDocument().createElement( QLatin1String( "plugin-data-field" ) );
+ pluginDataField.setAttribute( QLatin1String( "key" ), it.key() );
+ pluginDataField.appendChild( metaContactElement.ownerDocument().createTextNode( it.value() ) );
+ pluginElement.appendChild( pluginDataField );
+ }
+
+ metaContactElement.appendChild( pluginElement );
+ }
+ }
+ rootElement.setAttribute( QString("version"), "1.2" );
+ return true;
+}
+
+uint XmlContactStorage::readVersion( QDomElement &rootElement ) const
+{
+ QString versionString = rootElement.attribute( QString::fromLatin1( "version" ), QString() );
+ if( QRegExp( QString::fromLatin1( "[0-9]+\\.[0-9]" ) ).exactMatch( versionString ) )
+ return versionString.remove( QLatin1Char( '.' ) ).toUInt();
+ else
+ return 0;
+}
+
QString XmlContactStorage::sourceToString( Kopete::MetaContact::PropertySource source ) const
{
if ( source == Kopete::MetaContact::SourceCustom )
Index: kopete/libkopete/contactlist/xmlcontactstorage.h
===================================================================
--- kopete/libkopete/contactlist/xmlcontactstorage.h (revision 982847)
+++ kopete/libkopete/contactlist/xmlcontactstorage.h (working copy)
@@ -64,8 +64,11 @@
const QDomElement storeGroup( Kopete::Group *group ) const;
const QList<QDomElement> storeContactListElement( Kopete::ContactListElement *contactListElement ) const;
- bool updateFrom10( QDomElement &rootElement ) const;
+ bool updateFrom10to11( QDomElement &rootElement ) const;
+ bool updateFrom11to12( QDomElement &rootElement ) const;
+ uint readVersion( QDomElement &rootElement ) const;
+
private:
/**
* Convert the contact list from an older version
Index: kopete/libkopete/kopetecontactlistelement.h
===================================================================
--- kopete/libkopete/kopetecontactlistelement.h (revision 982847)
+++ kopete/libkopete/kopetecontactlistelement.h (working copy)
@@ -112,7 +112,40 @@
typedef QMap<QString, QMap<QString, QString> > PluginDataMap;
+ typedef QMap<QString, QString> ContactData;
+ typedef QList<ContactData> ContactDataList;
+
/**
+ * Get the settings as stored previously by calls to @ref setPluginContactData()
+ * Note that plugins shouldn't use this method
+ */
+ QMap<QString, ContactDataList > pluginContactData() const;
+
+ /**
+ * Get the settings as stored previously by calls to @ref setPluginContactData() for a @p plugin
+ * Note that plugins shouldn't use this method
+ */
+ ContactDataList pluginContactData( Plugin *plugin ) const;
+
+ /**
+ * Clear all plugin specific data.
+ * Note that plugins shouldn't use this method
+ */
+ void clearPluginContactData();
+
+ /**
+ * Set plugin specific data for each contact.
+ * Note that plugins shouldn't use this method
+ */
+ void setPluginContactData( Plugin *plugin, const ContactDataList &dataList );
+
+ /**
+ * Convenience method to append plugin specific data for single contact
+ * Note that plugins shouldn't use this method
+ */
+ void appendPluginContactData( const QString &pluginId, const ContactData &data );
+
+ /**
* return plugin-specific data for all plugins
*/
const PluginDataMap pluginData() const;
Index: kopete/libkopete/kopeteprotocol.cpp
===================================================================
--- kopete/libkopete/kopeteprotocol.cpp (revision 982847)
+++ kopete/libkopete/kopeteprotocol.cpp (working copy)
@@ -172,14 +172,9 @@
-void Protocol::slotMetaContactAboutToSave( MetaContact *metaContact )
+void Protocol::serialize( MetaContact *metaContact )
{
- QMap<QString, QString> serializedData, sd;
- QMap<QString, QString> addressBookData, ad;
- QMap<QString, QString>::Iterator it;
-
- //kDebug( 14010 ) << "Protocol::metaContactAboutToSave: protocol " << pluginId() << ": serializing " << metaContact->displayName();
-
+ QList< QMap<QString, QString> > serializedDataList;
QListIterator<Contact *> cit(metaContact->contacts());
while ( cit.hasNext() )
{
@@ -187,8 +182,8 @@
if( c->protocol()->pluginId() != pluginId() )
continue;
- sd.clear();
- ad.clear();
+ QMap<QString, QString> sd;
+ QMap<QString, QString> ad;
// Preset the contactId and displayName, if the plugin doesn't want to save
// them, or use its own format, it can call clear() on the provided list
@@ -206,34 +201,14 @@
c->serializeProperties( sd );
c->serialize( sd, ad );
- // Merge the returned fields with what we already (may) have
- for( it = sd.begin(); it != sd.end(); ++it )
- {
- // The Unicode chars E000-F800 are non-printable and reserved for
- // private use in applications. For more details, see also
- // http://www.unicode.org/charts/PDF/UE000.pdf.
- // Inside libkabc the use of QChar( 0xE000 ) has been standardized
- // as separator for the string lists, use this also for the 'normal'
- // serialized data.
- if( serializedData.contains( it.key() ) )
- serializedData[ it.key() ] = serializedData[ it.key() ] + QChar( 0xE000 ) + it.value();
- else
- serializedData[ it.key() ] = it.value();
- }
-
- for( it = ad.begin(); it != ad.end(); ++it )
- {
- if( addressBookData.contains( it.key() ) )
- addressBookData[ it.key() ] = addressBookData[ it.key() ] + QChar( 0xE000 ) + it.value();
- else
- addressBookData[ it.key() ] = it.value();
- }
+ serializedDataList.append( sd );
}
- // Pass all returned fields to the contact list
- //if( !serializedData.isEmpty() ) //even if we are empty, that mean there are no contact, so remove old value
- metaContact->setPluginData( this, serializedData );
+ // Pass all returned fields to the contact list even if empty (will remove the old one)
+ metaContact->setPluginContactData( this, serializedDataList );
+#if 0
+ // FIXME: This isn't used anywhere right now.
for( it = addressBookData.begin(); it != addressBookData.end(); ++it )
{
//kDebug( 14010 ) << "Protocol::metaContactAboutToSave: addressBookData: key: " << it.key() << ", data: " << it.data();
@@ -252,62 +227,20 @@
else
metaContact->setAddressBookField( this, QString::fromLatin1( "kopete" ), it.key(), it.value() );
}
+#endif
}
-void Protocol::deserialize( MetaContact *metaContact, const QMap<QString, QString> &data )
+void Protocol::deserializeContactList( MetaContact *metaContact, const QList< QMap<QString, QString> > &dataList )
{
- /*kDebug( 14010 ) << "Protocol::deserialize: protocol " <<
- pluginId() << ": deserializing " << metaContact->displayName() << endl;*/
-
- QMap<QString, QStringList> serializedData;
- QMap<QString, QStringList::Iterator> serializedDataIterators;
- QMap<QString, QString>::ConstIterator it;
- for( it = data.begin(); it != data.end(); ++it )
+ foreach ( const ContactListElement::ContactData &sd, dataList )
{
- serializedData[ it.key() ] = it.value().split( QChar( 0xE000 ), QString::KeepEmptyParts );
- serializedDataIterators[ it.key() ] = serializedData[ it.key() ].begin();
- }
-
- int count = serializedData[QString::fromLatin1("contactId")].count();
-
- // Prepare the independent entries to pass to the plugin's implementation
- for( int i = 0; i < count ; i++ )
- {
- QMap<QString, QString> sd;
-#ifdef __GNUC__
-#warning write this properly
-#endif
-#if 0
- QMap<QString, QStringList::Iterator>::Iterator serializedDataIt;
- for( serializedDataIt = serializedDataIterators.begin(); serializedDataIt != serializedDataIterators.end(); ++serializedDataIt )
- {
- sd[ serializedDataIt.key() ] = *( serializedDataIt.data() );
- ++( serializedDataIt.data() );
- }
-
-#else
- QMap<QString, QStringList>::Iterator serializedDataIt;
- QMap<QString, QStringList>::Iterator serializedDataItEnd = serializedData.end();
- for( serializedDataIt = serializedData.begin(); serializedDataIt != serializedDataItEnd; ++serializedDataIt )
- {
- QStringList sl=serializedDataIt.value();
- if(sl.count()>i)
- sd[ serializedDataIt.key() ] = sl[i];
- }
-
-
-#endif
-
- const QString& accountId=sd[ QString::fromLatin1( "accountId" ) ];
- // myself was allowed in the contact list in old version of kopete.
- // But if one keep it on the contact list now, it may conflict witht he myself metacontact.
- // So ignore it
+ const QString& accountId = sd[ QString::fromLatin1( "accountId" ) ];
if( !d->canAddMyself && accountId == sd[ QString::fromLatin1( "contactId" ) ] )
{
kDebug( 14010 ) << "Myself contact was on the contactlist.xml for account " << accountId << ". Ignore it";
continue;
}
-
+
// FIXME: This code almost certainly breaks when having more than
// one contact in a meta contact. There are solutions, but
// they are all hacky and the API needs revision anyway (see
@@ -318,8 +251,6 @@
// book data in the deserializer yet, only when serializing.
// - Martijn
QMap<QString, QString> ad;
-
-
#if 0
QStringList kabcFields = addressBookFields();
for( QStringList::Iterator fieldIt = kabcFields.begin(); fieldIt != kabcFields.end(); ++fieldIt )
@@ -347,21 +278,26 @@
else
{
kWarning( 14010 ) <<
- "No account available and account not set in " \
- "contactlist.xml either!" << endl
+ "No account available and account not set in " \
+ "contactlist.xml either!" << endl
<< "Not deserializing this contact." << endl;
return;
}
}
#endif
-
Contact *c = deserializeContact( metaContact, sd, ad );
if (c) // should never be null but I do not like crashes
c->deserializeProperties( sd );
}
}
+void Protocol::deserialize( MetaContact *metaContact, const QMap<QString, QString> &data )
+{
+ Q_UNUSED( metaContact )
+ Q_UNUSED( data )
+}
+
Contact *Protocol::deserializeContact(
MetaContact * metaContact,
const QMap<QString, QString> & serializedData,
Index: kopete/libkopete/kopetemetacontact.cpp
===================================================================
--- kopete/libkopete/kopetemetacontact.cpp (revision 982847)
+++ kopete/libkopete/kopetemetacontact.cpp (working copy)
@@ -557,9 +557,20 @@
contact->sendFile( sourceURL, altFileName, fileSize );
}
-void MetaContact::emitAboutToSave()
+void MetaContact::serialize()
{
- emit aboutToSave( this );
+ clearPluginContactData();
+
+ QSet<Kopete::Protocol*> protocolSet;
+ foreach ( Kopete::Contact* c, contacts() )
+ {
+ Kopete::Protocol* protocol = c->protocol();
+ if ( !protocolSet.contains( protocol ) )
+ {
+ protocolSet.insert( protocol );
+ protocol->serialize( this );
+ }
+ }
}
void MetaContact::slotContactStatusChanged( Contact * c, const OnlineStatus &status, const OnlineStatus &/*oldstatus*/ )
@@ -1040,6 +1051,16 @@
}
}
+void MetaContact::slotProtocolLoaded( Protocol *p )
+{
+ if( !p )
+ return;
+
+ ContactDataList dataList = pluginContactData( p );
+ if ( !dataList.isEmpty() )
+ p->deserializeContactList( this, dataList );
+}
+
void MetaContact::slotAllPluginsLoaded()
{
// Now that the plugins and subcontacts are loaded, set the source contact.
Index: kopete/libkopete/kopetecontact.cpp
===================================================================
--- kopete/libkopete/kopetecontact.cpp (revision 983314)
+++ kopete/libkopete/kopetecontact.cpp (working copy)
@@ -115,12 +115,7 @@
// if alreadyRegistered is true (which mean that this is duplicate contact) we will not add
// parent and the contact will die out on next Kopete restart.
if( !duplicate && parent && protocol() )
- {
- connect( parent, SIGNAL( aboutToSave( Kopete::MetaContact * ) ),
- protocol(), SLOT( slotMetaContactAboutToSave( Kopete::MetaContact * ) ) );
-
parent->addContact( this );
- }
}
Contact::~Contact()
@@ -354,8 +349,6 @@
if( old )
{
old->removeContact( this );
- disconnect( old, SIGNAL( aboutToSave( Kopete::MetaContact * ) ),
- protocol(), SLOT( slotMetaContactAboutToSave( Kopete::MetaContact * ) ) );
if(old->contacts().isEmpty())
{
@@ -366,7 +359,7 @@
{
d->metaContact = m; //i am forced to do that now if i want the next line works
//remove cached data for this protocol which will not be removed since we disconnected
- protocol()->slotMetaContactAboutToSave( old );
+ protocol()->serialize( old );
}
}
@@ -380,8 +373,6 @@
// between adding completely new contacts (which should be written to kabc) and restoring upon restart
// (where no write is needed).
KABCPersistence::self()->write( m );
- connect( d->metaContact, SIGNAL( aboutToSave( Kopete::MetaContact * ) ),
- protocol(), SLOT( slotMetaContactAboutToSave( Kopete::MetaContact * ) ) );
}
sync();
}
Index: kopete/libkopete/kopetepropertycontainer.h
===================================================================
--- kopete/libkopete/kopetepropertycontainer.h (revision 982847)
+++ kopete/libkopete/kopetepropertycontainer.h (working copy)
@@ -63,7 +63,7 @@
/**
* @brief Deserialize the contacts persistent properties
*/
- void deserializeProperties(QMap<QString, QString> &serializedData);
+ void deserializeProperties(const QMap<QString, QString> &serializedData);
/**
* @return A QStringList containing all property keys
Index: kopete/libkopete/kopetemetacontact.h
===================================================================
--- kopete/libkopete/kopetemetacontact.h (revision 982847)
+++ kopete/libkopete/kopetemetacontact.h (working copy)
@@ -421,18 +421,13 @@
unsigned long fileSize = 0L );
/**
- * Emit aboutToSave signal to notify plugins that this metaContact is going to be saved
+ * Serialize this metaContact
+ * This causes each Kopete::Protocol subclass to serialise its contacts' data into the metacontact's plugin data
*/
- void emitAboutToSave();
+ void serialize();
signals:
/**
- * This metaContact is going to be saved to the contact list. Plugins should
- * connect to this signal to update data with setPluginData()
- */
- void aboutToSave( Kopete::MetaContact *metaContact );
-
- /**
* One of the subcontacts' idle status has changed. As with online status,
* this can occur without the metacontact changing idle state
*/
@@ -512,6 +507,11 @@
*/
void slotPluginLoaded( Kopete::Plugin *plugin );
+ /**
+ * If a protocol is loaded, deserialize cached data
+ */
+ void slotProtocolLoaded( Kopete::Protocol *p );
+
signals:
/**
* @brief The MetaContact online status changed
Index: kopete/libkopete/kopetepropertycontainer.cpp
===================================================================
--- kopete/libkopete/kopetepropertycontainer.cpp (revision 982847)
+++ kopete/libkopete/kopetepropertycontainer.cpp (working copy)
@@ -60,8 +60,7 @@
} // end for()
} // end serializeProperties()
-void PropertyContainer::deserializeProperties(
- QMap<QString, QString> &serializedData )
+void PropertyContainer::deserializeProperties( const QMap<QString, QString> &serializedData )
{
QMap<QString, QString>::ConstIterator it;
for ( it=serializedData.constBegin(); it != serializedData.constEnd(); ++it )
Index: kopete/libkopete/kopetepluginmanager.h
===================================================================
--- kopete/libkopete/kopetepluginmanager.h (revision 982847)
+++ kopete/libkopete/kopetepluginmanager.h (working copy)
@@ -29,6 +29,7 @@
{
class Plugin;
+class Protocol;
typedef QList<Plugin*> PluginList;
class PluginManagerPrivate;
@@ -163,6 +164,12 @@
void pluginUnloaded( const QString &pluginName );
/**
+ * @brief Signals a new protocol has just been loaded.
+ * @note pluginLoaded is also emitted before this signal
+ */
+ void protocolLoaded( Kopete::Protocol *protocol );
+
+ /**
* @brief All plugins have been loaded by the plugin manager.
*
* This signal is emitted exactly ONCE, when the plugin manager has emptied
_______________________________________________
kopete-devel mailing list
kopete-devel@kde.org
https://mail.kde.org/mailman/listinfo/kopete-devel