Adds edition for macosx address book contact properties. Avoids concurrent access to contact details. Corrects msoutlook subcategories for email and nickname.

cusax-fix
Vincent Lucas 13 years ago
parent fd097c2eb2
commit a6288b5c35

@ -231,20 +231,45 @@ JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_plugin_addrbook_macosx
NSMutableDictionary *addr;
addr = [NSMutableDictionary dictionary];
for (i = 0; i < propertyCount; i+=2)
data=[[ABMutableMultiValue alloc] init];
NSString *subProp = NULL;
NSString *lastSubProp;
for (i = 0; i < propertyCount; i+=3)
{
jstring value = (jstring) (*jniEnv)->GetObjectArrayElement(jniEnv, arr, i);
jstring label = (jstring) (*jniEnv)->GetObjectArrayElement(jniEnv, arr, i+1);
jstring value
= (jstring) (*jniEnv)->GetObjectArrayElement(jniEnv, arr, i);
jstring label
= (jstring) (*jniEnv)->GetObjectArrayElement(jniEnv, arr, i+1);
jstring tmpLastSubProp
= (jstring) (*jniEnv)->GetObjectArrayElement(jniEnv, arr, i+2);
lastSubProp = JavaStringToNSString(jniEnv, tmpLastSubProp);
// Initiates the first sub-property value.
if(i == 0)
{
subProp = lastSubProp;
}
//NSLog(@"key:%@, value:%@", JavaStringToNSString(jniEnv, label), JavaStringToNSString(jniEnv, value));
// If there is a change in the sub-property, then save the actual
// one to the address property and create a new sub-property list
// (Home, Work).
if(![lastSubProp isEqualToString: subProp])
{
[(ABMutableMultiValue *) data addValue:addr withLabel:subProp];
addr = [NSMutableDictionary dictionary];
// Sets the new current proeperty
subProp = lastSubProp;
}
//NSLog(@"key:%@, value:%@", JavaStringToNSString(jniEnv, label),
//JavaStringToNSString(jniEnv, value));
[addr setObject:JavaStringToNSString(jniEnv, value)
forKey:JavaStringToNSString(jniEnv, label)];
forKey:JavaStringToNSString(jniEnv, label)];
}
// Adds the last sub-property to the address book.
if(i > 0)
{
[(ABMutableMultiValue *) data addValue: addr withLabel: subProp];
}
data=[[ABMutableMultiValue alloc] init];
[(ABMutableMultiValue *) data
addValue:addr
withLabel:JavaStringToNSString(jniEnv, subProperty)];
}
//else if(property == kABOtherDatesProperty)//kABMultiDateProperty
else

@ -0,0 +1,208 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.addrbook.macosx;
import java.util.*;
//import java.util.regex.*;
//import net.java.sip.communicator.plugin.addrbook.*;
import net.java.sip.communicator.service.contactsource.*;
//import net.java.sip.communicator.service.contactsource.ContactDetail.*;
//import net.java.sip.communicator.service.protocol.*;
//import net.java.sip.communicator.util.*;
/**
* The editable detail, change get changed and in addressbook.
*
* @author Lyubomir Marinov
*/
public class MacOSXAddrBookContactDetail
extends EditableContactDetail
{
/**
* The property index for this detail.
*/
private final int property;
/**
* The id of the detail.
*/
private String id;
private String subPropertyLabel;
/**
* Initializes a new <tt>ContactDetail</tt> instance which is to represent a
* specific contact address and which is to be optionally labeled with a
* specific set of labels.
*
* @param contactDetailValue the contact detail value to be represented by
* the new <tt>ContactDetail</tt> instance
* @param category
* @param subCategories the set of sub categories with which the new
* <tt>ContactDetail</tt> instance is to be labeled.
* @param id The id of the detail.
*/
public MacOSXAddrBookContactDetail(
int property,
String contactDetailValue,
Category category,
SubCategory[] subCategories,
String subPropertyLabel,
String id)
{
super(contactDetailValue, category, subCategories);
this.property = property;
this.subPropertyLabel = subPropertyLabel;
this.id = id;
}
/**
* Whether the value for the category are multiline.
* @param category
* @return
*/
public static boolean isMultiline(Category category)
{
switch(category)
{
case Personal:
return false;
case Organization:
return false;
case Email:
return true;
case InstantMessaging:
return true;
case Phone:
return true;
case Address:
return true;
default:
return false;
}
}
/**
* Sets the given detail value.
*
* @param value the new value of the detail
*/
public void setDetail(String value)
{
//let's save in addressbook
if(isMultiline(getCategory()))
{
// get others
EditableSourceContact sourceContact = getSourceContact();
if(sourceContact != null
&& sourceContact instanceof MacOSXAddrBookSourceContact)
{
List<ContactDetail> details =
((MacOSXAddrBookSourceContact) sourceContact)
.getContactDetails(getCategory());
boolean isAddress =
property == MacOSXAddrBookContactQuery.kABAddressProperty;
boolean isHomeAddress = containsSubCategory(SubCategory.Home);
// For an address, we must check that the current detail is the
// modified one. For all other properties than address, this
// boolean must always be true.
boolean isModifiedAddressOrGenericDetail;
// first add existing one
List<String> values = new ArrayList<String>();
for(ContactDetail cd : details)
{
isModifiedAddressOrGenericDetail = true;
if(isAddress)
{
// lets check home and work details
if((isHomeAddress
&& !cd.containsSubCategory(SubCategory.Home)
)
|| (!isHomeAddress
&& !cd.containsSubCategory(SubCategory.Work)
))
{
isModifiedAddressOrGenericDetail = false;
}
}
String det = cd.getDetail();
for(SubCategory sub : cd.getSubCategories())
{
String label
= MacOSXAddrBookContactQuery.
getLabel(property, sub, subPropertyLabel);
if(label != null)
{
if(getSubCategories().contains(sub)
&& isModifiedAddressOrGenericDetail)
values.add(value);
else
values.add(det);
values.add(label);
// For an address adds a third item for the tuple:
// value, label, sub-property label.
if(isAddress
&& cd instanceof MacOSXAddrBookContactDetail
)
{
values.add(
((MacOSXAddrBookContactDetail) cd)
.getSubPropertyLabel());
}
}
}
}
// now the real edit
MacOSXAddrBookContactQuery.setProperty(
id,
MacOSXAddrBookContactQuery.ABPERSON_PROPERTIES[
property],
subPropertyLabel,
values.toArray(new Object[values.size()]));
}
}
else
{
MacOSXAddrBookContactQuery.setProperty(
id,
MacOSXAddrBookContactQuery.ABPERSON_PROPERTIES[
property],
null,
value);
}
super.setDetail(value);
}
/**
* Returns the sub property.
* @return
*/
public String getSubPropertyLabel()
{
return subPropertyLabel;
}
/**
* Returns the property index for this detail.
*
* @return The property index for this detail.
*/
public final int getProperty()
{
return this.property;
}
}

@ -0,0 +1,378 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.addrbook.macosx;
import java.util.*;
//import java.util.regex.*;
//import net.java.sip.communicator.plugin.addrbook.*;
import net.java.sip.communicator.service.contactsource.*;
import net.java.sip.communicator.service.contactsource.ContactDetail.*;
//import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
/**
* Our editable source contact, we store changes in the addressbook.
*
* @author Lyubomir Marinov
*/
public class MacOSXAddrBookSourceContact
extends GenericSourceContact
implements EditableSourceContact
{
/**
* The <tt>Logger</tt> used by the <tt>MacOSXAddrBookSourceContact</tt>
* class and its instances for logging output.
*/
private static final Logger logger
= Logger.getLogger(MacOSXAddrBookSourceContact.class);
/**
* Initializes a new <tt>AddrBookSourceContact</tt> instance.
*
* @param contactSource the <tt>ContactSourceService</tt> which is creating
* the new instance
* @param displayName the display name of the new instance
* @param contactDetails the <tt>ContactDetail</tt>s of the new instance
*/
public MacOSXAddrBookSourceContact(
ContactSourceService contactSource,
String displayName,
List<ContactDetail> contactDetails)
{
super(contactSource, displayName, contactDetails);
// let's save the parent so we can reuse it later when editing
// the detail
for(ContactDetail cd : contactDetails)
{
if(cd instanceof MacOSXAddrBookContactDetail)
{
((MacOSXAddrBookContactDetail)cd).setSourceContact(this);
}
}
}
/**
* Adds a contact detail to the list of contact details.
*
* @param detail the <tt>ContactDetail</tt> to add
*/
public void addContactDetail(ContactDetail detail)
{
synchronized(this.contactDetails)
{
String id = (String)getData(SourceContact.DATA_ID);
if(id == null)
{
logger.warn("No id or wrong ContactDetail " + detail);
return;
}
String subProperty = null;
int property = MacOSXAddrBookContactQuery.getProperty(
detail.getCategory(),
detail.getSubCategories());
if(MacOSXAddrBookContactDetail.isMultiline(detail.getCategory()))
{
if(detail instanceof MacOSXAddrBookContactDetail)
{
subProperty = ((MacOSXAddrBookContactDetail)detail)
.getSubPropertyLabel();
}
if(subProperty == null
&& property
== MacOSXAddrBookContactQuery.kABAddressProperty)
{
if(detail.containsSubCategory(SubCategory.Home))
subProperty
= MacOSXAddrBookContactQuery.kABAddressHomeLabel();
else
subProperty
= MacOSXAddrBookContactQuery.kABAddressWorkLabel();
}
List<String> values
= getValues(detail, property, subProperty, true);
MacOSXAddrBookContactQuery.setProperty(
id,
MacOSXAddrBookContactQuery.ABPERSON_PROPERTIES[
property],
subProperty,
values.toArray(new Object[values.size()]));
}
else
{
MacOSXAddrBookContactQuery.setProperty(
id,
MacOSXAddrBookContactQuery.ABPERSON_PROPERTIES[
property],
null,
detail.getDetail());
}
// make sure we add AddressBookContactDetail
Collection<SubCategory> subCategories
= detail.getSubCategories();
MacOSXAddrBookContactDetail contactDetail
= new MacOSXAddrBookContactDetail(
property,
detail.getDetail(),
detail.getCategory(),
subCategories.toArray(
new SubCategory[
subCategories.size()]),
subProperty,
id);
contactDetail.setSourceContact(this);
// Add the detail at the right index : group multiline properties
// together , such as home/work address fields.
boolean added = false;
int index = 0;
for(ContactDetail cd: contactDetails)
{
if(cd instanceof MacOSXAddrBookContactDetail)
{
MacOSXAddrBookContactDetail macOSXcd
= (MacOSXAddrBookContactDetail) cd;
if(!added
&& contactDetail.getProperty()
== macOSXcd.getProperty()
&& (contactDetail.getSubPropertyLabel() == null
|| contactDetail.getSubPropertyLabel().equals(
macOSXcd.getSubPropertyLabel())))
{
added = true;
}
}
if(!added)
++index;
}
contactDetails.add(index, contactDetail);
}
}
/**
* Returns the list of values that will be saved.
* @param detail the current modified detail
* @param property the property we change
* @param subProperty the subproperty that is changed
* @param addDetail should we add <tt>detail</tt> to the list of values.
* @return the list of values to be saved.
*/
private List<String> getValues(ContactDetail detail,
int property,
String subProperty,
boolean addDetail)
{
// first add existing one
List<String> values = new ArrayList<String>();
List<ContactDetail> details =
getContactDetails(detail.getCategory());
boolean isIM =
(property == MacOSXAddrBookContactQuery.kABICQInstantProperty
|| property == MacOSXAddrBookContactQuery.kABAIMInstantProperty
|| property == MacOSXAddrBookContactQuery.kABYahooInstantProperty
|| property == MacOSXAddrBookContactQuery.kABMSNInstantProperty
|| property == MacOSXAddrBookContactQuery.kABJabberInstantProperty
);
boolean isAddress
= property == MacOSXAddrBookContactQuery.kABAddressProperty;
boolean isHomeAddress =
detail.containsSubCategory(SubCategory.Home);
int lastHomeIndex = 0;
int lastWorkIndex = 0;
for(ContactDetail cd : details)
{
// if the detail exists do not added, in case of add there is
// sense the detail to be added twice. In case of remove
// we miss the detail
if(cd.equals(detail))
continue;
String det = cd.getDetail();
for(SubCategory sub : cd.getSubCategories())
{
// if its an im property check also if the detail
// is the same subcategory (which is icq, yahoo, ...)
if(isIM && !detail.getSubCategories().contains(sub))
continue;
String label =
MacOSXAddrBookContactQuery.
getLabel(property, sub, subProperty);
if(label != null)
{
values.add(det);
values.add(label);
// For an address adds a third item for the tuple:
// value, label, sub-property label.
if(isAddress
&& cd instanceof MacOSXAddrBookContactDetail)
{
String subPropertyLabel
= ((MacOSXAddrBookContactDetail) cd)
.getSubPropertyLabel();
values.add(subPropertyLabel);
if(subPropertyLabel.equals(
MacOSXAddrBookContactQuery
.kABAddressHomeLabel()))
{
lastHomeIndex = values.size();
}
else if(subPropertyLabel.equals(
MacOSXAddrBookContactQuery
.kABAddressWorkLabel()))
{
lastWorkIndex = values.size();
}
}
}
}
}
if(addDetail)
{
// now the new value to add
for(SubCategory sub : detail.getSubCategories())
{
String label =
MacOSXAddrBookContactQuery.
getLabel(property, sub, subProperty);
if(label != null)
{
// For an address adds a third item for the tuple:
// value, label, sub-property label.
if(isAddress)
{
String subPropertyLabel = "";
int index = values.size();
if(isHomeAddress)
{
subPropertyLabel
= MacOSXAddrBookContactQuery
.kABAddressHomeLabel();
index = lastHomeIndex;
if(lastWorkIndex > lastHomeIndex)
{
lastWorkIndex += 3;
}
lastHomeIndex += 3;
}
else
{
subPropertyLabel
= MacOSXAddrBookContactQuery
.kABAddressWorkLabel();
index = lastWorkIndex;
if(lastHomeIndex > lastWorkIndex)
{
lastHomeIndex += 3;
}
lastWorkIndex += 3;
}
values.add(index, detail.getDetail());
values.add(index + 1, label);
values.add(index + 2, subPropertyLabel);
}
else
{
values.add(detail.getDetail());
values.add(label);
}
}
else
logger.warn("Missing label fo prop:" + property
+ " and sub:" + sub);
}
}
return values;
}
/**
* Removes the given <tt>ContactDetail</tt> from the list of details for
* this <tt>SourceContact</tt>.
*
* @param detail the <tt>ContactDetail</tt> to remove
*/
public void removeContactDetail(ContactDetail detail)
{
synchronized(this.contactDetails)
{
//remove the detail from the addressbook
String id = (String)getData(SourceContact.DATA_ID);
if(id != null && detail instanceof MacOSXAddrBookContactDetail)
{
if(MacOSXAddrBookContactDetail.isMultiline(
detail.getCategory()))
{
String subProperty = null;
if(detail instanceof MacOSXAddrBookContactDetail)
{
subProperty = ((MacOSXAddrBookContactDetail)detail)
.getSubPropertyLabel();
}
List<String> values =
getValues(
detail,
((MacOSXAddrBookContactDetail)detail)
.getProperty(),
subProperty,
false);
MacOSXAddrBookContactQuery.setProperty(
id,
MacOSXAddrBookContactQuery.ABPERSON_PROPERTIES[
((MacOSXAddrBookContactDetail) detail)
.getProperty()],
subProperty,
values.toArray(new Object[values.size()]));
}
else
MacOSXAddrBookContactQuery.removeProperty(
id,
MacOSXAddrBookContactQuery.ABPERSON_PROPERTIES[
((MacOSXAddrBookContactDetail) detail)
.getProperty()]);
}
else
logger.warn("No id or wrong ContactDetail " + detail);
contactDetails.remove(detail);
}
}
/**
* Changes the details list with the supplied one.
* @param details the details.
*/
public void setDetails(List<ContactDetail> details)
{
synchronized(this.contactDetails)
{
contactDetails.clear();
contactDetails.addAll(details);
}
}
}

@ -19,11 +19,6 @@
public class MsOutlookAddrBookContactDetail
extends EditableContactDetail
{
/**
* The source contact which contains this contact detail.
*/
private MsOutlookAddrBookSourceContact sourceContact;
/**
* The list of codes used by outlook to identify the property corresponding
* to this contact detail.
@ -53,18 +48,6 @@ public MsOutlookAddrBookContactDetail(
this.outlookPropId = new Vector<Long>(1, 1);
this.outlookPropId.add(new Long(outlookPropId));
this.sourceContact = null;
}
/**
* Sets the source contact that contains this contact detail.
*
* @param sourceContact The source contact that contains this contact
* detail.
*/
public void setSourceContact(MsOutlookAddrBookSourceContact sourceContact)
{
this.sourceContact = sourceContact;
}
/**
@ -78,7 +61,8 @@ public void setSourceContact(MsOutlookAddrBookSourceContact sourceContact)
*/
public boolean match(ContactDetail contactDetail)
{
return (this.getCategory() == contactDetail.getCategory()
return (contactDetail != null
&& this.getCategory() == contactDetail.getCategory()
&& this.getDetail().equals(contactDetail.getDetail()));
}
@ -103,9 +87,11 @@ public void setDetail(String value)
{
super.setDetail(value);
if(this.sourceContact != null)
EditableSourceContact sourceContact = this.getSourceContact();
if(sourceContact != null
&& sourceContact instanceof MsOutlookAddrBookSourceContact)
{
this.sourceContact.save();
((MsOutlookAddrBookSourceContact) sourceContact).save();
}
}
}

@ -381,6 +381,7 @@ private ContactDetail.SubCategory[] getSubCategories(int propIndex)
{
case PR_GIVEN_NAME:
case PR_MIDDLE_NAME:
case PR_COMPANY_NAME:
return
new ContactDetail.SubCategory[]
{
@ -398,9 +399,10 @@ private ContactDetail.SubCategory[] getSubCategories(int propIndex)
{
ContactDetail.SubCategory.Nickname
};
case PR_COMPANY_NAME:
case PR_BUSINESS2_TELEPHONE_NUMBER:
case PR_BUSINESS_TELEPHONE_NUMBER:
case dispidEmail1EmailAddress:
case PR_EMAIL_ADDRESS:
//case dispidWorkAddress:
return
new ContactDetail.SubCategory[]
@ -409,6 +411,7 @@ private ContactDetail.SubCategory[] getSubCategories(int propIndex)
};
case PR_HOME2_TELEPHONE_NUMBER:
case PR_HOME_TELEPHONE_NUMBER:
case dispidEmail2EmailAddress:
//case dispidHomeAddress:
return
new ContactDetail.SubCategory[]
@ -448,6 +451,12 @@ private ContactDetail.SubCategory[] getSubCategories(int propIndex)
// {
// ContactDetail.SubCategory.Other
// };
case dispidEmail3EmailAddress:
return
new ContactDetail.SubCategory[]
{
ContactDetail.SubCategory.Other
};
default:
return null;
}
@ -484,15 +493,21 @@ else if(subCategories.contains(
else
return MAPI_MAILUSER_PROP_IDS[PR_DISPLAY_NAME_PREFIX];
case Organization:
if(subCategories.contains(ContactDetail.SubCategory.Work))
if(subCategories.contains(ContactDetail.SubCategory.Name))
return MAPI_MAILUSER_PROP_IDS[PR_COMPANY_NAME];
else
return MAPI_MAILUSER_PROP_IDS[PR_BUSINESS_HOME_PAGE];
case Email:
return MAPI_MAILUSER_PROP_IDS[dispidEmail1EmailAddress];
//dispidEmail2EmailAddress:
//dispidEmail3EmailAddress:
// PR_EMAIL_ADDRESS:
if(subCategories.contains(ContactDetail.SubCategory.Work))
return MAPI_MAILUSER_PROP_IDS[dispidEmail1EmailAddress];
// PR_EMAIL_ADDRESS:
else if(subCategories.contains(
ContactDetail.SubCategory.Home))
return MAPI_MAILUSER_PROP_IDS[dispidEmail2EmailAddress];
else if(subCategories.contains(
ContactDetail.SubCategory.Other))
return MAPI_MAILUSER_PROP_IDS[dispidEmail3EmailAddress];
break;
case Phone:
if(subCategories.contains(ContactDetail.SubCategory.Fax))
{

@ -14,9 +14,14 @@
*
* @author Yana Stamcheva
*/
public class EditableContactDetail
public abstract class EditableContactDetail
extends ContactDetail
{
/**
* The source contact which contains this contact detail.
*/
private EditableSourceContact sourceContact = null;
/**
* Creates a <tt>ContactDetail</tt> by specifying the contact address,
* corresponding to this detail.
@ -47,6 +52,16 @@ public EditableContactDetail(
super(contactDetailValue, category, subCategories);
}
/**
* Returns the source contact that contains this contact detail.
*
* @return The source contact that contains this contact detail.
*/
public EditableSourceContact getSourceContact()
{
return this.sourceContact;
}
/**
* Sets the given detail value.
*
@ -56,4 +71,15 @@ public void setDetail(String value)
{
contactDetailValue = value;
}
/**
* Sets the source contact that contains this contact detail.
*
* @param sourceContact The source contact that contains this contact
* detail.
*/
public void setSourceContact(EditableSourceContact sourceContact)
{
this.sourceContact = sourceContact;
}
}

@ -35,7 +35,7 @@ public class GenericSourceContact
/**
* The display name of this <tt>SourceContact</tt>.
*/
private final String displayName;
private String displayName;
/**
* The display details of this contact.
@ -122,9 +122,13 @@ public List<ContactDetail> getContactDetails(
for (ContactDetail contactDetail : getContactDetails())
{
ContactDetail.Category detailCategory = contactDetail.getCategory();
if (detailCategory != null && detailCategory.equals(category))
contactDetails.add(contactDetail);
if(contactDetail != null)
{
ContactDetail.Category detailCategory
= contactDetail.getCategory();
if (detailCategory != null && detailCategory.equals(category))
contactDetails.add(contactDetail);
}
}
return contactDetails;
}
@ -174,6 +178,16 @@ public String getDisplayName()
return displayName;
}
/**
* Sets the display name of this <tt>SourceContact</tt>.
*
* @param displayName The display name of this <tt>SourceContact</tt>
*/
public void setDisplayName(String displayName)
{
this.displayName = displayName;
}
/**
* Gets the image/avatar of this <tt>SourceContact</tt>.
*

Loading…
Cancel
Save