Re: Category support in adsressbook




----- Original Message -----
From: Nathan Owens
Time: 10-01-07 07:35
> --- Tom Billiet <mouse256 ulyssis org> wrote:
>   
>> ----- Original Message -----
>> From: Tom Billiet
>> Time: 08-01-07 15:54
>>     
>>> Hi,
>>>
>>> I'm currently looking if it's possible to add category support for the
>>> addressbook when syncing with evolution.  As far as I found there is
>>> currently no support for it, so I started looking at the code trying
>>> to hack it myself :-)
>>>       
>
> Great! We need this!
>   
And I think it's finished :-p
>
> compare and prepare are called through GTK signals, as you guessed. These are setup in
> conduit_get_gpilot_conduit(). They are called from the gpilotd itself during a sync. You'll want
> to take a look at the pilot-link syncconduit.sgml documentation file. Also take a look at the
> Tasks and Memos conduits for category syncing. It mostly works in those (there's at least 1 bug I
> know of, though in bug 201167)
>
> See http://bugzilla.gnome.org/show_bug.cgi?id=201167 for how Category Syncing was implemented for
> those two conduits.
>   
I did not notice before the todo and memo conduits had category support
already build in, it would have saved me some trouble :-) I took a look
at the code and it's actually almost full copy-paste. But as the todo
and memo conduits are not working very well here (mostly they don't
sync) I can't test it too much.
>> 2) Evolution has support for adding an item to more than 1 category,
>> palm doesn't have this support. Now I'm only using the first category
>> and ignoring the rest if an item has more categories. I don't see any
>> other solution.
>>     
>
> That's essentially what I decided to do on the Tasks and Memos. The better option would be to have
> a "Pilot Category" setting, and the user would choose which of the categories would be the Pilot
> category. Note also that this would make it much easier to prevent the user from having more than
> 16 different categories that need to be synced to the PDA (each database may have at most 16
> categories). I've yet to figure out how the Outlook plugin does it, but I don't think it works any
> better.
>   
I did improve it a little in the calendar conduit as Matt Davey
mentioned. It only touches the first category from evolution if there
are more categories assigned, thus leaving more category support in
evolution available. As far as I see memo and todo always overwrite the
whole category field in evolution. More about these differences in the
bottom of this mail.
>
> This was solved by the Tasks and Memos components. There's still the problem that you have to
> restart Evolution itself to see the category pop-up in the Category box. This is a limitation of
> the Evolution category API (or was - I haven't tested it since 2.6, and I understand there were
> some improvements to the category API)
>   
This bug is still present.
>   
>> If somebody can help me on this I can fix these problems and send my patch.
>>     
>
> You'll want to add it to the bug I mentioned above, and probably also send it into the
> evolution-patches e-mail list. If you're not already, sign up for the evolution-hackers and
> evolution-patches e-mail lists. They're very useful.
I'm first sending the patch here. So should I file it in the bug report
you mentioned above and also on the evolution-patches mailing list?
> Hope this helps,
> Nathan Owens
>   
It was a great help, thanks


Now for the rest I do have some remarks and questions.
Although this patch works here (for me), I don't think the way of
implementation is very good. There is actually too much code duplication
between the todo/memos and calendar conduits regarding the category's. 
Todo and memo both contain the function "add_category_if_possible" (I
even thought it was not allowed to use exactly the same function name
twice in plain C?) which the calendar conduit also needs.
The rest of the category syncing mainly is written in the 2 functions
"comp_from_remote_record" and "local_record_from_comp" . The code that's
written there for the category support can actually be the same for the
three conduits I think.  The code there is actually (almost) exact the
same for the todo and the memo's conduit. It differs a bit from the
calendar conduit as I made the sync only adapt the first category in
evolution if there is more than 1 assigned, thus keeping the evolution
structure more intact.
What I want to say is I think it would be a better Idea to move the
"add_category_if_possible" somewhere to the gnome-pilot code, and also
add 2 more functions there: "remote_category_to_local" and
"local_category_to_remote" which would contain the category code from
the functions "comp_from_remote_record" and "local_record_from_comp"
respectively. This would make bughunting easier (as the bugs for
category support would become the same for every conduit) and
maintaining easy, as code duplication is a hell.
What are your ideas about this?

And before I forget: my patch is attached :-)
PLEASE NOTE: this diff is made agains the code from evolution 2.8.1.2,
BUT the 90_build_with_new_pisock.patch was applied first for pilot-link
0.12 compatibility. (I got it from my distribution (archlinux), but I
think it originates somewhere from debian:
http://cvs.archlinux.org/cgi-bin/viewcvs.cgi/network/evolution/90_build_with_new_pisock.patch?cvsroot=Extra&only_with_tag=CURRENT
)

Please feel free to test and let me know if it works.

Tom Billiet
--- evolution-2.8.2.1/calendar/conduits/calendar/calendar-conduit.c	2007-01-10 14:36:14.000000000 +0100
+++ edit/calendar/conduits/calendar/calendar-conduit.c	2007-01-10 14:33:34.000000000 +0100
@@ -30,6 +30,7 @@
 #include <libecal/e-cal-time-util.h>
 #include <libedataserver/e-url.h>
 #include <libedataserverui/e-passwords.h>
+#include <libedataserver/e-categories.h>
 #include <pi-source.h>
 #include <pi-socket.h>
 #include <pi-dlp.h>
@@ -42,6 +43,7 @@
 #include <e-pilot-settings.h>
 #include <e-pilot-util.h>
 #include <e-config-listener.h>
+#include <string.h>
 
 GnomePilotConduit * conduit_get_gpilot_conduit (guint32);
 void conduit_destroy_gpilot_conduit (GnomePilotConduit*);
@@ -61,6 +63,7 @@
 #define INFO g_message
 
 #define PILOT_MAX_ADVANCE 99
+#define PILOT_MAX_CATEGORIES 16
 
 typedef struct _ECalLocalRecord ECalLocalRecord;
 typedef struct _ECalConduitCfg ECalConduitCfg;
@@ -868,6 +871,56 @@
 }
 
 /*
+ * Adds a category to the category app info structure (name and ID),
+ * sets category->renamed[i] to true if possible to rename.
+ * 
+ * This will be packed and written to the app info block during post_sync.
+ */
+ 
+static int
+add_category_if_possible2(char *cat_to_add, struct CategoryAppInfo *category)
+{
+	int i, j;
+	int retval = 0; /* 0 is the Unfiled category */
+	LOG(g_message("add_category_if_possible2\n"));
+	
+	for(i=0; i<PILOT_MAX_CATEGORIES; i++){
+		/* if strlen is 0, then the category is empty
+		   the PalmOS doesn't let 0-length strings for
+		   categories */
+		if(strlen(category->name[i]) == 0){
+			int cat_to_add_len;
+			
+			cat_to_add_len = strlen(cat_to_add);
+			retval = i;
+			
+			/* only 15 characters for category, 16th is
+			 * '\0' can't do direct mem transfer due to
+			 * declaration type
+			 */
+			for(j=0; j<cat_to_add_len; j++){
+				category->name[i][j] = cat_to_add[j];
+			}
+
+			for(j=cat_to_add_len; j<16; j++)
+				category->name[i][j] = '\0';
+			
+			//category->ID[i] = lastDesktopUniqueID;
+			//lastDesktopUniqueID++;
+			category->renamed[i] = TRUE;
+			
+			break;
+		}
+	}
+	
+	if(retval == 0){
+		LOG(g_warning( _("*** not adding category - category list already full ***") ));
+	}
+	
+	return retval;
+}
+
+/*
  * converts a ECalComponent object to a ECalLocalRecord
  */
 static void
@@ -875,12 +928,13 @@
 {
 	const char *uid;
 	ECalComponentText summary;
-	GSList *d_list = NULL, *edl = NULL, *l;
+	GSList *d_list = NULL, *edl = NULL, *l, *c_list = NULL;
 	ECalComponentText *description;
 	ECalComponentDateTime dt_start, dt_end;
 	ECalComponentClassification classif;
 	icaltimezone *default_tz = ctxt->timezone;
 	int i;
+	char * category_string;
 	
 	g_return_if_fail (local != NULL);
 	g_return_if_fail (comp != NULL);
@@ -924,6 +978,34 @@
 		}
 		pi_buffer_free(piBuf);
 	}
+	
+	/*Category*/
+	e_cal_component_get_categories_list (comp, &c_list);
+	if (c_list) {
+		//list != 0, so at least 1 category is assigned
+		category_string = (char *) c_list->data;
+		if (c_list->next != 0) {
+			LOG (g_message ("Note: item has more categories in evolution, first chosen"));
+		}
+		i=1; //category 0 == unfiled == no category
+		while (1) {
+			if (strcmp(category_string,ctxt->ai.category.name[i]) == 0) {
+				local->local.category = i;
+				break;
+			}
+			i++;
+			if (i == PILOT_MAX_CATEGORIES) {
+				/*category not available on palm, try to create it*/
+				local->local.category = add_category_if_possible2(category_string,&(ctxt->ai.category));
+				break;
+			}
+		}
+		e_cal_component_free_categories_list(c_list);
+		c_list = NULL;
+	} else {
+		local->local.category = 0;
+	}
+	/*end category*/
 
 	/* STOP: don't replace these with g_strdup, since free_Appointment
 	   uses free to deallocate */
@@ -1169,7 +1251,8 @@
 			 GnomePilotRecord *remote,
 			 ECalComponent *in_comp,
 			 ECal *client,
-			 icaltimezone *timezone)
+			 icaltimezone *timezone,
+			 CategoryAppInfo_t categoryInfo)
 {
 	ECalComponent *comp;
 	struct Appointment appt;
@@ -1178,10 +1261,14 @@
 	ECalComponentText summary = {NULL, NULL};
 	ECalComponentDateTime dt = {NULL, NULL};
 	GSList *edl = NULL;	
+	GSList *new_category = NULL;
+	GSList *c_list = NULL;
 	char *txt;
+	char *category_string;
 	int pos, i;
 	
 	g_return_val_if_fail (remote != NULL, NULL);
+	
 
 	memset (&appt, 0, sizeof (struct Appointment));
 	{
@@ -1205,6 +1292,49 @@
 	summary.value = txt = e_pilot_utf8_from_pchar (appt.description);
 	e_cal_component_set_summary (comp, &summary);
 	free (txt);
+	
+	/*Category*/
+	if (remote->category != 0) {
+		/*pda has category assigned*/
+		LOG(g_message("Category: %s\n",categoryInfo.name[remote->category]));
+		new_category = g_slist_append(new_category, categoryInfo.name[remote->category]); /*put the pda category on the first place*/
+		/* TODO The calendar editor page and search bar are not updated until
+	  	a restart of the evolution client */
+		if(e_categories_exist(categoryInfo.name[remote->category]) == FALSE){
+			/* add if it doesn't exist */
+			LOG(g_message("Category created on pc\n"));
+			e_categories_add(categoryInfo.name[remote->category], NULL, NULL, TRUE);
+		}
+	}
+		
+	/*Add the remaining categories already assigned on the pc*/
+	e_cal_component_get_categories_list (comp, &c_list);
+	if (c_list != 0) {
+		/*there were already categories assigned on the pc*/
+		category_string = (char *) c_list->data;
+		/*Only the first category on the pc is synced with palm, so we only replace this one with the one from the PDA
+		Note that this is NOT foolproof, but it will handle most situations*/
+		
+		/*now add the rest of the categories from the pc (if there are) */
+		c_list = c_list->next;
+		while (c_list != 0) {
+			category_string = (char *) c_list->data;
+			if (strcmp(category_string, categoryInfo.name[remote->category]) != 0) {
+				/*different category from pda, so add it*/
+				new_category = g_slist_append(new_category, category_string);
+			}
+		c_list = c_list->next;
+		}
+	}
+	e_cal_component_free_categories_list(c_list);
+	/*store the data on pc*/
+	if (new_category == 0) {
+		e_cal_component_set_categories (comp, " "); /*note: this space is needed to make shure evolution clears the category*/
+	} 
+	else {
+		e_cal_component_set_categories_list (comp, new_category);
+	}
+	/*end category*/
 
 	/* The iCal description field */
 	if (!appt.note) {
@@ -1584,6 +1714,7 @@
 		return -1;
 	}
 	unpack_AppointmentAppInfo (&(ctxt->ai), piBuf->data, len);
+	unpack_CategoryAppInfo (&(ctxt->ai.category), piBuf->data, len);
 	pi_buffer_free(piBuf);
 
 	check_for_slow_setting (conduit, ctxt);
@@ -1601,8 +1732,28 @@
 {
 	GList *changed;
 	gchar *filename, *change_id;
+	unsigned char *buf;
+	int dlpRetVal, len;
 	
 	LOG (g_message ( "post_sync: Calendar Conduit v.%s", CONDUIT_VERSION ));
+	
+	/* Write AppBlock to PDA - updates categories */
+	buf = (unsigned char*)g_malloc (0xffff);
+	
+	len = pack_AppointmentAppInfo (&(ctxt->ai), buf, 0xffff);
+	
+	dlpRetVal = dlp_WriteAppBlock (dbi->pilot_socket, dbi->db_handle, 
+			      (unsigned char *)buf, len);
+	
+	g_free (buf);
+			      
+	if (dlpRetVal < 0) {
+		WARN (_("Could not write pilot's Calendar application block"));
+		WARN ("dlp_WriteAppBlock(...) = %d", dlpRetVal);
+		gnome_pilot_conduit_error (conduit,
+					   _("Could not write pilot's Calendar application block"));
+		return -1;
+	}
 
 	g_free (ctxt->cfg->last_uri);
 	ctxt->cfg->last_uri = g_strdup (e_cal_get_uri (ctxt->client));
@@ -1801,7 +1952,7 @@
 
 	LOG (g_message ( "add_record: adding %s to desktop\n", print_remote (remote) ));
 
-	comp = comp_from_remote_record (conduit, remote, ctxt->default_comp, ctxt->client, ctxt->timezone);
+	comp = comp_from_remote_record (conduit, remote, ctxt->default_comp, ctxt->client, ctxt->timezone, ctxt->ai.category);
 
 	/* Give it a new UID otherwise it will be the uid of the default comp */
 	uid = e_cal_component_gen_uid ();
@@ -1833,7 +1984,7 @@
 	LOG (g_message ("replace_record: replace %s with %s\n",
 			print_local (local), print_remote (remote)));
 
-	new_comp = comp_from_remote_record (conduit, remote, local->comp, ctxt->client, ctxt->timezone);
+	new_comp = comp_from_remote_record (conduit, remote, local->comp, ctxt->client, ctxt->timezone, ctxt->ai.category);
 	g_object_unref (local->comp);
 	local->comp = new_comp;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]