r7037 - in dumbhippo/trunk/client: common/ddm common/hippo linux/src



Author: otaylor
Date: 2007-12-12 09:59:21 -0600 (Wed, 12 Dec 2007)
New Revision: 7037

Modified:
   dumbhippo/trunk/client/common/ddm/ddm-condition.c
   dumbhippo/trunk/client/common/ddm/ddm-data-query.c
   dumbhippo/trunk/client/common/ddm/ddm-data-resource.c
   dumbhippo/trunk/client/common/ddm/ddm-data-resource.h
   dumbhippo/trunk/client/common/ddm/ddm-feed.h
   dumbhippo/trunk/client/common/ddm/ddm-work-item.c
   dumbhippo/trunk/client/common/hippo/hippo-connection.c
   dumbhippo/trunk/client/common/hippo/hippo-disk-cache.c
   dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.c
Log:
ddm-data-resource.[ch]: Add new value type DDM_DATA_FEED, add
  ddm_data_resource_update_feed_property()

ddm-data-resource.c: Fix bug where a long value of ' ' was parsed without
  error as 0.
  
ddm-data-query.c ddm-work-item.c: Handle recursion into feed-valued properties

ddm-condition.c: Handle feed-valued properties (not really tested, probably not
 very useful, but easy enough to do)

hippo-connection.c: Parse m:ts propreties, call 
 ddm_data_resource_update_feed_property() as appropriate

hippo-disk-cache.c: Add an itemTimestamp column to Property (using the migration
 framework for the first time), fill it in and read for it for
 feed properties.

hippo-dbus-model-client.c: Add feed properties to the d-bus protocol by
  using a string-long pair as the variant value


Modified: dumbhippo/trunk/client/common/ddm/ddm-condition.c
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-condition.c	2007-12-12 15:49:24 UTC (rev 7036)
+++ dumbhippo/trunk/client/common/ddm/ddm-condition.c	2007-12-12 15:59:21 UTC (rev 7037)
@@ -2,6 +2,7 @@
 
 #include <string.h>
 
+#include "ddm-feed.h"
 #include "ddm-rule.h"
 
 static DDMCondition true_condition = {
@@ -244,6 +245,7 @@
             return FALSE;
     case DDM_DATA_FLOAT:
     case DDM_DATA_NONE:
+    case DDM_DATA_FEED:
     case DDM_DATA_LIST:
         break;
     }
@@ -259,15 +261,33 @@
     GSList *l;
     gboolean empty;
 
-    g_return_val_if_fail(list_value->type == DDM_DATA_NONE || DDM_DATA_IS_LIST(list_value->type), FALSE);
-    
-    empty = list_value->type == DDM_DATA_NONE || list_value->u.list == NULL;
+    if (DDM_DATA_IS_LIST(list_value->type))
+        empty = list_value->u.list == NULL;
+    else if (list_value->type == DDM_DATA_FEED)
+        empty = list_value->u.feed == NULL || ddm_feed_is_empty(list_value->u.feed);
+    else if (list_value->type == DDM_DATA_NONE)
+        empty = TRUE;
+    else {
+        g_assert_not_reached();
+        empty = TRUE;
+    }
 
     if (scalar_value->type == DDM_DATA_BOOLEAN)
         return !empty == !!scalar_value->type;
     else if (empty)
         return FALSE;
-    else {
+    else if (list_value->type == DDM_DATA_FEED) {
+        DDMFeedIter iter;
+        DDMDataValue element;
+
+        element.type = DDM_DATA_RESOURCE;
+
+        ddm_feed_iter_init(&iter, list_value->u.feed);
+        while (ddm_feed_iter_next(&iter, &element.u.resource, NULL)) {
+            if (compare_properties_1_1(&element, scalar_value))
+                return TRUE;
+        }
+    } else {
         for (l = list_value->u.list; l; l = l->next) {
             DDMDataValue element;
             
@@ -322,7 +342,7 @@
         g_warning("Refusing to compare properties of type float");
         return FALSE;
     }
-    
+
     if (left_cardinality == DDM_DATA_CARDINALITY_N &&
         right_cardinality == DDM_DATA_CARDINALITY_N) {
         g_warning("Don't know how compare two list-valued properties");
@@ -370,8 +390,8 @@
             return FALSE;
     case DDM_DATA_FLOAT:
         return FALSE;
+    case DDM_DATA_FEED:
     case DDM_DATA_NONE:
-        break;
     case DDM_DATA_LIST:
         break;
     }
@@ -387,14 +407,32 @@
     GSList *l;
     gboolean empty;
 
-    g_return_val_if_fail(list_value->type == DDM_DATA_NONE || DDM_DATA_IS_LIST(list_value->type), FALSE);
+    if (DDM_DATA_IS_LIST(list_value->type))
+        empty = list_value->u.list == NULL;
+    else if (list_value->type == DDM_DATA_FEED)
+        empty = list_value->u.feed == NULL || ddm_feed_is_empty(list_value->u.feed);
+    else if (list_value->type == DDM_DATA_NONE)
+        empty = TRUE;
+    else {
+        g_assert_not_reached();
+        empty = TRUE;
+    }
 
-    empty = list_value->type == DDM_DATA_NONE || list_value->u.list == NULL;
-    
     if (literal->type == DDM_CONDITION_VALUE_BOOLEAN) {
         return !empty == !!literal->u.boolean;
     } else if (empty) {
         return FALSE;
+    } else if (list_value->type == DDM_DATA_FEED) {
+        DDMFeedIter iter;
+        DDMDataValue element;
+
+        element.type = DDM_DATA_RESOURCE;
+
+        ddm_feed_iter_init(&iter, list_value->u.feed);
+        while (ddm_feed_iter_next(&iter, &element.u.resource, NULL)) {
+            if (compare_property_literal_1_1(&element, literal))
+                return TRUE;
+        }
     } else {
         for (l = list_value->u.list; l; l = l->next) {
             DDMDataValue element;

Modified: dumbhippo/trunk/client/common/ddm/ddm-data-query.c
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-data-query.c	2007-12-12 15:49:24 UTC (rev 7036)
+++ dumbhippo/trunk/client/common/ddm/ddm-data-query.c	2007-12-12 15:59:21 UTC (rev 7037)
@@ -3,6 +3,7 @@
 #include "ddm-data-query-internal.h"
 #include "ddm-data-model-internal.h"
 #include "ddm-data-resource-internal.h"
+#include "ddm-feed.h"
 
 typedef enum {
     HANDLER_NONE,
@@ -276,6 +277,15 @@
                 } else {
                     mark_received_fetches(value.u.resource, children, local);
                 }
+            } else if (value.type == DDM_DATA_FEED) {
+                if (value.u.feed != NULL) {
+                    DDMFeedIter feed_iter;
+                    DDMDataResource *item_resource;
+
+                    ddm_feed_iter_init(&feed_iter, value.u.feed);
+                    while (ddm_feed_iter_next(&feed_iter, &item_resource, NULL))
+                        mark_received_fetches(item_resource, children, local);
+                }
             }
         }
     }

Modified: dumbhippo/trunk/client/common/ddm/ddm-data-resource.c
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-data-resource.c	2007-12-12 15:49:24 UTC (rev 7036)
+++ dumbhippo/trunk/client/common/ddm/ddm-data-resource.c	2007-12-12 15:59:21 UTC (rev 7037)
@@ -5,6 +5,7 @@
 #include <stdlib.h>
 
 #include "ddm-data-fetch.h"
+#include "ddm-feed.h"
 #include "ddm-data-model-internal.h"
 #include "ddm-data-resource-internal.h"
 #include "ddm-rule.h"
@@ -120,6 +121,7 @@
         element->u.string  = (char *)node->data;
         return;
     case DDM_DATA_NONE:
+    case DDM_DATA_FEED:
     case DDM_DATA_LIST:
         break;
     }
@@ -144,6 +146,7 @@
         return;
     case DDM_DATA_RESOURCE:
     case DDM_DATA_NONE:
+    case DDM_DATA_FEED:
     case DDM_DATA_LIST:
         return;
     }
@@ -298,22 +301,36 @@
 {
     DDMDataProperty *property = data;
 
-    if (DDM_DATA_BASE(property->value.type) != DDM_DATA_RESOURCE)
-        return FALSE;
+    if (DDM_DATA_BASE(property->value.type) == DDM_DATA_RESOURCE) {
+        property->rule_sources = slist_foreach_remove(property->rule_sources, reset_resource_rule_source_foreach, property);
 
-    property->rule_sources = slist_foreach_remove(property->rule_sources, reset_resource_rule_source_foreach, property);
-
-    if (DDM_DATA_IS_LIST(property->value.type)) {
-        property->value.u.list = slist_foreach_remove(property->value.u.list, reset_resource_value_foreach, NULL);
-        reset_resource_value_foreach(data, user_data);
+        if (DDM_DATA_IS_LIST(property->value.type)) {
+            property->value.u.list = slist_foreach_remove(property->value.u.list, reset_resource_value_foreach, NULL);
+            reset_resource_value_foreach(data, user_data);
+            return FALSE;
+        } else {
+            if (!property->value.u.resource->local) {
+                ddm_data_property_free(property);
+                return TRUE;
+            } else {
+                return FALSE;
+            }
+        }
+    } else if (property->value.type == DDM_DATA_FEED) {
+        if (property->value.u.feed) {
+            DDMFeedIter iter;
+            DDMDataResource *resource;
+            
+            ddm_feed_iter_init(&iter, property->value.u.feed);
+            while (ddm_feed_iter_next(&iter, &resource, NULL)) {
+                if (!resource->local)
+                    ddm_feed_iter_remove(&iter);
+            }
+        }
+            
         return FALSE;
     } else {
-        if (!property->value.u.resource->local) {
-            ddm_data_property_free(property);
-            return TRUE;
-        } else {
-            return FALSE;
-        }
+        return FALSE;
     }
 }
 
@@ -451,12 +468,16 @@
 static void
 set_value(DDMDataType   type,
           DDMDataValue *value,
-          void           *location)
+          void         *location)
 {
     if (DDM_DATA_IS_LIST(type)) {
         *((GSList **)location) = value->u.list;
+    } else if (type == DDM_DATA_FEED) {
+        *((DDMFeed **)location) = value->u.feed;
     } else {
         switch (DDM_DATA_BASE(type)) {
+        case DDM_DATA_LIST:
+        case DDM_DATA_FEED:
         case DDM_DATA_NONE:
             break;
         case DDM_DATA_BOOLEAN:
@@ -491,6 +512,8 @@
 {
     if (DDM_DATA_IS_LIST(type)) {
         *((GSList **)location) = NULL;
+    } else if (type == DDM_DATA_FEED) {
+        *((DDMFeed **)location) = NULL;
     } else {
         switch (type) {
         case DDM_DATA_BOOLEAN:
@@ -515,6 +538,7 @@
             *((const char **)location) = NULL;
             break;
         case DDM_DATA_LIST:
+        case DDM_DATA_FEED:
         case DDM_DATA_NONE:
             break;
         }
@@ -551,6 +575,9 @@
     case DDM_DATA_URL:
         result = "list:url";
         break;
+    case DDM_DATA_FEED:
+        result = "xxxx:feed";
+        break;
     default:
         result = "list:<unknown>";
         break;
@@ -829,10 +856,16 @@
         case DDM_DATA_RESOURCE:
         case DDM_DATA_NONE:
         case DDM_DATA_LIST:
+        case DDM_DATA_FEED:
             break;
         }
 
         g_slist_free(value->u.list);
+    } else if (value->type == DDM_DATA_FEED) {
+        if (value->u.feed) {
+            ddm_feed_clear(value->u.feed);
+            g_object_unref(value->u.feed);
+        }
     } else {
         switch (value->type) {
         case DDM_DATA_NONE:
@@ -842,6 +875,7 @@
         case DDM_DATA_FLOAT:
         case DDM_DATA_RESOURCE:
         case DDM_DATA_LIST:
+        case DDM_DATA_FEED:
             break;
         case DDM_DATA_STRING:
         case DDM_DATA_URL:
@@ -899,6 +933,7 @@
     case DDM_DATA_URL:
         return strcmp(value_a->u.string, value_b->u.string) == 0;
     case DDM_DATA_LIST:
+    case DDM_DATA_FEED:
         break;
     }
 
@@ -917,6 +952,11 @@
         g_warning("data_property_set() called with a list type");
         return FALSE;
     }
+    
+    if (property->value.type == DDM_DATA_FEED) {
+        g_warning("data_property_set() called with a feed type");
+        return FALSE;
+    }
 
     if (data_value_matches(&property->value, value))
         return FALSE;
@@ -971,6 +1011,7 @@
         property->value.u.list = g_slist_prepend(property->value.u.list, g_strdup(value->u.string));
         return;
     case DDM_DATA_NONE:
+    case DDM_DATA_FEED:
     case DDM_DATA_LIST:
         break;
     }
@@ -1063,12 +1104,23 @@
     GSList *l;
     gboolean changed;
 
+    if (value != NULL) {
+        if (DDM_DATA_IS_LIST(value->type)) {
+            g_critical("ddm_data_resource_update_property called with a list value");
+            return FALSE;
+        }
+        if (value->type == DDM_DATA_FEED) {
+            g_critical("ddm_data_resource_update_property called with a feed value");
+            return FALSE;
+        }
+    }
+
 #if 0
     g_debug("updating resource '%s' property %s update %d new value %s",
             resource->resource_id, property_id->name, update,
             value ? ddm_data_value_to_string(value) : "NULL" ); /* leak! FIXME remove from production */
-#endif       
-    
+#endif
+
     /* it's important to only ever set this to TRUE,
      * never assign it a value that could be FALSE,
      * or you could unset an earlier TRUE. If making
@@ -1209,6 +1261,139 @@
     return changed;
 }
 
+/* We make things a bit more difficult for ourselves, by representing
+ * an empty feed property with:
+ *
+ *  - NULL, before anything is ever added to the feed
+ *  - a DDMFeed, after that
+ *
+ * The initial NULL is important because a feed that starts empty and stays
+ * empty is a common case and shouldn't require creating a DDMFeed object
+ * (think of recent messages on a block in the Mugshot stacker)
+ *
+ * Keeping the DMFeed around after that makes things a little easier for
+ * someone who wants to connect to signals on the DDFeed (though patterns
+ * to deal with the initially-NULL state probably handle transitions back
+ * to NULL OK as well.)
+ */
+static DDMDataProperty *
+add_feed_property(DDMDataResource *resource,
+                  DDMQName        *property_id)
+{
+    DDMDataProperty *property = add_property(resource, property_id, DDM_DATA_CARDINALITY_N);
+    
+    property->value.type = DDM_DATA_FEED;
+    property->value.u.feed = NULL;
+
+    return property;
+}
+
+static gboolean
+add_feed_property_item(DDMDataProperty *property,
+                       DDMDataResource *item_resource,
+                       gint64           item_timestamp)
+{
+    if (property->value.u.feed == NULL)
+        property->value.u.feed = ddm_feed_new();
+
+    return ddm_feed_add_item(property->value.u.feed, item_resource, item_timestamp);
+}
+
+static void
+clear_feed_property(DDMDataProperty *property)
+{
+    if (property->value.u.feed != NULL)
+        ddm_feed_clear(property->value.u.feed);
+}
+
+/* return value is whether something changed (we need to emit notification) */
+gboolean
+ddm_data_resource_update_feed_property(DDMDataResource    *resource,
+                                       DDMQName           *property_id,
+                                       DDMDataUpdate       update,
+                                       gboolean            default_include,
+                                       const char         *default_children,
+                                       DDMDataResource    *item_resource,
+                                       gint64              item_timestamp)
+{
+    DDMDataProperty *property = NULL;
+    GSList *l;
+    gboolean changed;
+
+#if 0
+    g_debug("updating feed resource '%s' property %s update %d new value %s timestamp " G_GINT64_FORMAT,
+            resource->resource_id, property_id->name, update,
+            item_resource ? item_resource->resource_id : "NULL",
+            item_timestamp);
+#endif       
+    
+    changed = FALSE;
+    
+    for (l = resource->properties; l; l = l->next) {
+        if (((DDMDataProperty *)l->data)->qname == property_id) {
+            property = l->data;
+            break;
+        }
+    }
+
+    if (update == DDM_DATA_UPDATE_DELETE && property == NULL) {
+        g_warning("Remove of a property we don't have %s#%s", property_id->uri, property_id->name);
+        return FALSE;
+    }
+
+    if (property != NULL && DDM_DATA_BASE(property->value.type) != DDM_DATA_FEED) {
+        g_warning("Previous cardinality of not compatible with new property, discarding old values %s#%s", property_id->uri, property_id->name);
+        remove_property(resource, property);
+        changed = TRUE;
+    }
+
+    switch (update) {
+    case DDM_DATA_UPDATE_ADD:
+        if (property == NULL) {
+            property = add_feed_property(resource, property_id);
+        }
+        changed = changed || add_feed_property_item(property, item_resource, item_timestamp);
+        break;
+    case DDM_DATA_UPDATE_REPLACE:
+        if (property != NULL) {
+            clear_feed_property(property);
+        } else {
+            property = add_feed_property(resource, property_id);
+        }
+        add_feed_property_item(property, item_resource, item_timestamp);
+        changed = TRUE;
+        break;
+    case DDM_DATA_UPDATE_DELETE:
+        if (property != NULL && property->value.u.feed != NULL &&
+            ddm_feed_remove_item(property->value.u.feed, item_resource))
+        {
+            changed = TRUE;
+        } else {
+            g_warning("remove of a property value not there %s#%s", property_id->uri, property_id->name);
+        }
+        break;
+    case DDM_DATA_UPDATE_CLEAR:
+        if (property != NULL) {
+            clear_feed_property(property);
+        } else {
+            property = add_feed_property(resource, property_id);
+        }
+        changed = TRUE;
+        break;
+    }
+
+    if (property != NULL) {
+        property->default_include = default_include;
+        if (default_children && !property->default_children)
+            property->default_children = ddm_data_fetch_from_string(default_children);
+    }
+
+    if (changed)
+        mark_property_changed(resource, property);
+
+    return changed;
+}
+
 void
 _ddm_data_resource_send_local_notifications (DDMDataResource *resource,
                                              GSList          *changed_properties)
@@ -1325,6 +1510,9 @@
     case 'u':
         *type = DDM_DATA_URL;
         break;
+    case 'F':
+        *type = DDM_DATA_FEED;
+        break;
     default:
         g_warning("Can't understand type string '%s'", type_string);
         return FALSE;
@@ -1384,6 +1572,32 @@
 
         return g_string_free(str, FALSE);
     }
+
+    if (value->type == DDM_DATA_FEED) {
+        GString *str = g_string_new(NULL);
+        DDMFeedIter iter;
+        DDMDataResource *resource;
+        gint64 timestamp;
+
+        g_string_append(str, "[");
+        if (value->u.feed) {
+            ddm_feed_iter_init(&iter, value->u.feed);
+
+            while (ddm_feed_iter_next(&iter, &resource, &timestamp)) {
+                if (str->len > 1)
+                    g_string_append(str, ", ");
+                g_string_append(str, "(");
+                g_string_append(str, resource->resource_id);
+                g_string_append(str, ", ");
+                g_string_append_printf(str, "%" G_GINT64_FORMAT, timestamp);
+                g_string_append(str, ")");
+            }
+        
+            g_string_append(str, "]");
+        }
+
+        return g_string_free(str, FALSE);
+    }
     
     switch (value->type) {
     case DDM_DATA_NONE:
@@ -1393,7 +1607,7 @@
     case DDM_DATA_INTEGER:
         return g_strdup_printf("%d", value->u.integer);
     case DDM_DATA_LONG:
-        return g_strdup_printf("%" G_GINT64_FORMAT "\n", value->u.long_);
+        return g_strdup_printf("%" G_GINT64_FORMAT, value->u.long_);
     case DDM_DATA_FLOAT:
         return g_strdup_printf("%f", value->u.float_);
     case DDM_DATA_STRING:
@@ -1454,7 +1668,7 @@
         {
             char *end;
             long v = strtol(str_stripped, &end, 10);
-            if (*str == '\0' || *end != '\0') {
+            if (*str_stripped == '\0' || *end != '\0') {
                 g_set_error(error,
                             DDM_DATA_ERROR,
                             DDM_DATA_ERROR_BAD_REPLY,
@@ -1468,7 +1682,7 @@
         {
             char *end;
             value->u.long_ = g_ascii_strtoll(str_stripped, &end, 10);
-            if (*str == '\0' || *end != '\0') {
+            if (*str_stripped == '\0' || *end != '\0') {
                 g_set_error(error,
                             DDM_DATA_ERROR,
                             DDM_DATA_ERROR_BAD_REPLY,
@@ -1481,7 +1695,7 @@
         {
             char *end;
             value->u.float_ = g_ascii_strtod(str_stripped, &end);
-            if (*str == '\0' || *end != '\0') {
+            if (*str_stripped == '\0' || *end != '\0') {
                 g_set_error(error,
                             DDM_DATA_ERROR,
                             DDM_DATA_ERROR_BAD_REPLY,
@@ -1498,14 +1712,17 @@
         if (value->u.string == NULL)
             goto error;
         goto success;
+    case DDM_DATA_FEED:
+        g_critical("Data type DDM_DATA_FEED invalid in ddm_data_value_from_string()");
+        goto error;
     case DDM_DATA_RESOURCE:
         g_critical("Data type DDM_DATA_RESOURCE invalid in ddm_data_value_from_string()");
         goto error;
     case DDM_DATA_NONE:
-        g_critical("Data type DDM_DATA_RESOURCE invalid in ddm_data_value_from_string()");
+        g_critical("Data type DDM_DATA_NONE invalid in ddm_data_value_from_string()");
         goto error;
     case DDM_DATA_LIST:
-        g_critical("Data type DDM_DATA_RESOURCE invalid in ddm_data_value_from_string()");
+        g_critical("Data type DDM_DATA_LIST invalid in ddm_data_value_from_string()");
         goto error;
     }
 

Modified: dumbhippo/trunk/client/common/ddm/ddm-data-resource.h
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-data-resource.h	2007-12-12 15:49:24 UTC (rev 7036)
+++ dumbhippo/trunk/client/common/ddm/ddm-data-resource.h	2007-12-12 15:59:21 UTC (rev 7037)
@@ -48,6 +48,7 @@
     DDM_DATA_STRING     = 5,
     DDM_DATA_RESOURCE   = 6,
     DDM_DATA_URL        = 7,
+    DDM_DATA_FEED       = 8,
     DDM_DATA_LIST       = 0x10
 } DDMDataType;
 
@@ -66,6 +67,7 @@
 typedef struct _DDMDataResource      DDMDataResource;
 
 typedef struct _DDMClient            DDMClient;    /* Avoid circular include */
+typedef struct _DDMFeed              DDMFeed;
 
 
 typedef void (*DDMDataFunction) (DDMDataResource *resource,
@@ -82,6 +84,7 @@
         double float_;
         char *string;
         DDMDataResource *resource;
+        DDMFeed *feed;
         GSList *list;
     } u;
 };
@@ -135,6 +138,14 @@
                                                             gboolean            default_include,
                                                             const char         *default_children,
                                                             DDMDataValue       *value);
+gboolean           ddm_data_resource_update_feed_property  (DDMDataResource    *resource,
+                                                            DDMQName           *property_id,
+                                                            DDMDataUpdate       update,
+                                                            gboolean            default_include,
+                                                            const char         *default_children,
+                                                            DDMDataResource    *item_resource,
+                                                            gint64              item_timestamp);
+
 DDMDataProperty *  ddm_data_resource_get_property          (DDMDataResource    *resource,
                                                             const char         *name);
 DDMDataProperty *  ddm_data_resource_get_property_by_qname (DDMDataResource    *resource,

Modified: dumbhippo/trunk/client/common/ddm/ddm-feed.h
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-feed.h	2007-12-12 15:49:24 UTC (rev 7036)
+++ dumbhippo/trunk/client/common/ddm/ddm-feed.h	2007-12-12 15:59:21 UTC (rev 7037)
@@ -25,7 +25,6 @@
  * most recent item.
  */
 
-typedef struct _DDMFeed      DDMFeed;
 typedef struct _DDMFeedClass DDMFeedClass;
 typedef struct _DDMFeedIter  DDMFeedIter;
 

Modified: dumbhippo/trunk/client/common/ddm/ddm-work-item.c
===================================================================
--- dumbhippo/trunk/client/common/ddm/ddm-work-item.c	2007-12-12 15:49:24 UTC (rev 7036)
+++ dumbhippo/trunk/client/common/ddm/ddm-work-item.c	2007-12-12 15:59:21 UTC (rev 7037)
@@ -4,6 +4,7 @@
 #include "ddm-data-model-internal.h"
 #include "ddm-data-query-internal.h"
 #include "ddm-data-resource-internal.h"
+#include "ddm-feed.h"
 
 typedef struct {
     DDMDataResource *resource;
@@ -251,6 +252,17 @@
                     if (!item_fetch_additional(item, value.u.resource, children))
                         all_satisfied = FALSE;
                 }
+            } else if (value.type == DDM_DATA_FEED) {
+                if (value.u.feed != NULL) {
+                    DDMFeedIter feed_iter;
+                    DDMDataResource *item_resource;
+
+                    ddm_feed_iter_init(&feed_iter, value.u.feed);
+                    while (ddm_feed_iter_next(&feed_iter, &item_resource, NULL)) {
+                        if (!item_fetch_additional(item, item_resource, children))
+                            all_satisfied = FALSE;
+                    }
+                }
             }
         }
     }

Modified: dumbhippo/trunk/client/common/hippo/hippo-connection.c
===================================================================
--- dumbhippo/trunk/client/common/hippo/hippo-connection.c	2007-12-12 15:49:24 UTC (rev 7036)
+++ dumbhippo/trunk/client/common/hippo/hippo-connection.c	2007-12-12 15:59:21 UTC (rev 7037)
@@ -4744,6 +4744,31 @@
     return ddm_data_parse_type(type_attr, type, cardinality, default_include);
 }
 
+static gint64
+dm_context_get_ts(DMContext *context)
+{
+    const char *ts_attr = dm_context_get_system_attribute(context, "ts");
+    if (ts_attr == NULL) {
+        return -1;
+    } else {
+        char *str_stripped;
+        char *end;
+        gint64 result;
+        
+        str_stripped = g_strdup(ts_attr);
+        g_strstrip(str_stripped);
+        
+        result = g_ascii_strtoll(str_stripped, &end, 10);
+        if (*str_stripped == '\0' || *end != '\0') {
+            g_warning("Invalid m:ts attribute '%s'", ts_attr);
+            result = -1;
+        }
+
+        g_free(str_stripped);
+        return result;
+    }
+}
+
 static gboolean
 dm_context_get_value(DMContext       *context,
                      DDMDataType      type,
@@ -4835,19 +4860,37 @@
         default_children = dm_context_get_system_attribute(context, "defaultChildren");
     else
         default_children = NULL;
-    
-    if (update == DDM_DATA_UPDATE_CLEAR) {
-        changed = ddm_data_resource_update_property(resource, property_qname, update, cardinality,
-                                                     default_include, default_children,
-                                                     NULL);
+
+    if (type == DDM_DATA_FEED) {
+        if (update == DDM_DATA_UPDATE_CLEAR) {
+            changed = ddm_data_resource_update_feed_property(resource, property_qname, update,
+                                                             default_include, default_children,
+                                                             NULL, -1);
+        } else {
+            DDMDataValue value;
+            gint64 ts = dm_context_get_ts(context);
+            
+            if (dm_context_get_value(context, DDM_DATA_RESOURCE, &value)) {
+                changed = ddm_data_resource_update_feed_property(resource, property_qname, update,
+                                                                 default_include, default_children,
+                                                                 value.u.resource, ts);
+                ddm_data_value_clear(&value);
+            }
+        }
     } else {
-        DDMDataValue value;
-        
-        if (dm_context_get_value(context, type, &value)) {
+        if (update == DDM_DATA_UPDATE_CLEAR) {
             changed = ddm_data_resource_update_property(resource, property_qname, update, cardinality,
                                                         default_include, default_children,
-                                                        &value);
-            ddm_data_value_clear(&value);
+                                                        NULL);
+        } else {
+            DDMDataValue value;
+            
+            if (dm_context_get_value(context, type, &value)) {
+                changed = ddm_data_resource_update_property(resource, property_qname, update, cardinality,
+                                                            default_include, default_children,
+                                                            &value);
+                ddm_data_value_clear(&value);
+            }
         }
     }
 

Modified: dumbhippo/trunk/client/common/hippo/hippo-disk-cache.c
===================================================================
--- dumbhippo/trunk/client/common/hippo/hippo-disk-cache.c	2007-12-12 15:49:24 UTC (rev 7036)
+++ dumbhippo/trunk/client/common/hippo/hippo-disk-cache.c	2007-12-12 15:59:21 UTC (rev 7037)
@@ -21,7 +21,7 @@
 
 /* Database schema version, used to know when to run upgrade steps
  */
-#define SCHEMA_VERSION 0
+#define SCHEMA_VERSION 1
 
 static void      hippo_disk_cache_init                (HippoDiskCache       *model);
 static void      hippo_disk_cache_class_init          (HippoDiskCacheClass  *klass);
@@ -349,6 +349,23 @@
     }
 }
 
+static gboolean
+run_migration_0_1(HippoDiskCache *cache)
+{
+    int i;
+    
+    static const char *statements[] = {
+        "ALTER TABLE Property ADD COLUMN itemTimestamp INTEGER DEFAULT -1"
+    };
+    
+    for (i = 0; statements[i]; i++) {
+        if (!execute_sql(cache, statements[i], NULL))
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
 static void
 open_database(HippoDiskCache *cache)
 {
@@ -366,7 +383,7 @@
         "   DELETE FROM QueryResult WHERE query = old.id; "
         "  END ",
         "CREATE TABLE IF NOT EXISTS QueryResult (query INTEGER, resourceId TEXT)",
-        "CREATE TABLE IF NOT EXISTS Property (session INTEGER, timestamp INTEGER, resourceId TEXT, propertyId TEXT, type TEXT, defaultChildren TEXT, value)",
+        "CREATE TABLE IF NOT EXISTS Property (session INTEGER, timestamp INTEGER, resourceId TEXT, propertyId TEXT, type TEXT, defaultChildren TEXT, value, itemTimestamp INTEGER DEFAULT -1)",
         NULL
     };
 
@@ -404,13 +421,9 @@
             g_warning("Database version %d newer than we understand", old_version);
             goto error;
         } else if (old_version < SCHEMA_VERSION) {
-            /* Migration steps go here
-             * 
-             * if (old_version < 1)
-             *     run_migration_01(cache);
-             * if (old_version < 2)
-             *     run_migration_12(cache);
-              */
+            if (old_version < 1)
+                if (!run_migration_0_1(cache))
+                    goto error;
         }
     }
 
@@ -509,6 +522,9 @@
     case DDM_DATA_URL:
         *(p++) = 'u';
         break;
+    case DDM_DATA_FEED:
+        *(p++) = 'F';
+        break;
     case DDM_DATA_NONE:
         *(p++) = 's'; /* Used only for empty lists, tpye doesn't matter */
         break;
@@ -618,6 +634,7 @@
         value_string = value->u.string;
         break;
     case DDM_DATA_LIST:
+    case DDM_DATA_FEED:
     case DDM_DATA_NONE:
         g_assert_not_reached();
         break;
@@ -661,12 +678,39 @@
                     NULL);
 }
 
+static void
+save_feed_property_value_to_disk(HippoDiskCache    *cache,
+                                 const char        *resource_id,
+                                 const char        *property_id,
+                                 DDMDataProperty   *property,
+                                 DDMDataResource   *resource,
+                                 gint64             item_timestamp,
+                                 const char        *type,
+                                 const char        *default_children,
+                                 gint64             timestamp)
+{
+    execute_sql(cache,
+                "INSERT INTO Property (session, timestamp, resourceId, propertyId, type, defaultChildren,  value, itemTimestamp)"
+                " VALUES (:session, :timestamp, :resourceId, :propertyId, :type, :defaultChildren, :value, :itemTimestamp)",
+                "l:session", cache->db_session,
+                "l:timestamp", timestamp,
+                "s:resourceId", resource_id,
+                "s:propertyId", property_id,
+                "s:type", type,
+                "s:defaultChildren", default_children,
+                "s:value", ddm_data_resource_get_resource_id(resource),
+                "l:itemTimestamp", item_timestamp,
+                NULL);
+}
+
 typedef struct {
     DDMDataResource *resource;
     DDMQName *property_qname;
     DDMDataCardinality cardinality;
     gboolean default_include;
     char *default_children;
+    gboolean is_feed;
+    gint64 item_timestamp;
 } QueuedResourceProperty;
 
 typedef struct {
@@ -684,8 +728,10 @@
 queued_resource_property_new(DDMDataResource   *resource,
                              DDMQName          *property_qname,
                              DDMDataCardinality cardinality,
-                             gboolean             default_include,
-                             const char          *default_children)
+                             gboolean           default_include,
+                             const char        *default_children,
+                             gboolean           is_feed,
+                             gint64             item_timestamp)
 {
     QueuedResourceProperty *queued_property = g_new0(QueuedResourceProperty, 1);
 
@@ -694,6 +740,8 @@
     queued_property->cardinality = cardinality;
     queued_property->default_include = default_include;
     queued_property->default_children = g_strdup(default_children);
+    queued_property->is_feed = is_feed;
+    queued_property->item_timestamp = item_timestamp;
 
     return queued_property;
 }
@@ -783,7 +831,7 @@
     DDMQName *class_id_qname = ddm_qname_get("http://mugshot.org/p/system";, "classId");
 
     stmt  = prepare_sql(cache,
-                        "SELECT propertyId, type,defaultChildren, value FROM Property WHERE resourceId = :resourceId",
+                        "SELECT propertyId, type ,defaultChildren, value, itemTimestamp FROM Property WHERE resourceId = :resourceId",
                         "s:resourceId", resource_id,
                         NULL);
     
@@ -811,6 +859,8 @@
         gboolean is_string = FALSE;
         char *value_string = NULL;
 
+        gint64 item_timestamp;
+
         int sql_result;
 
         sql_result = sqlite3_step(stmt);
@@ -843,6 +893,7 @@
             break;
         case DDM_DATA_STRING:
         case DDM_DATA_RESOURCE:
+        case DDM_DATA_FEED:
         case DDM_DATA_URL:
             is_string = TRUE;
             break;
@@ -863,36 +914,53 @@
             g_assert_not_reached();
         }
 
+        item_timestamp = sqlite3_column_int64(stmt, 4);
+
         if (cardinality == DDM_DATA_CARDINALITY_N) {
             if (g_hash_table_lookup(seen_properties, property_qname) == NULL) {
                 g_hash_table_insert(seen_properties, property_qname, property_qname);
-                
-                ddm_data_resource_update_property(resource, property_qname,
-                                                     DDM_DATA_UPDATE_CLEAR,
-                                                     cardinality,
-                                                     default_include, default_children,
-                                                     NULL);
+
+                if (type == DDM_DATA_FEED)
+                    ddm_data_resource_update_feed_property(resource, property_qname,
+                                                           DDM_DATA_UPDATE_CLEAR,
+                                                           default_include, default_children,
+                                                           NULL, -1);
+                else
+                    ddm_data_resource_update_property(resource, property_qname,
+                                                      DDM_DATA_UPDATE_CLEAR,
+                                                      cardinality,
+                                                      default_include, default_children,
+                                                      NULL);
             }
         }
 
-        if (type == DDM_DATA_RESOURCE) {
+        if (type == DDM_DATA_RESOURCE || type == DDM_DATA_FEED) {
             DDMDataResource *referenced_resource;
             referenced_resource = resource_tracking_lookup_resource(tracking, value_string);
             if (referenced_resource) {
-                DDMDataValue value;
-
-                value.type = type;
-                value.u.resource = referenced_resource;
-                
-                ddm_data_resource_update_property(resource, property_qname,
-                                                     (cardinality == DDM_DATA_CARDINALITY_N) ? DDM_DATA_UPDATE_ADD : DDM_DATA_UPDATE_REPLACE,
-                                                     cardinality,
-                                                     default_include, default_children,
-                                                     &value);
+                if (type == DDM_DATA_FEED) {
+                    ddm_data_resource_update_feed_property(resource, property_qname,
+                                                           (cardinality == DDM_DATA_CARDINALITY_N) ? DDM_DATA_UPDATE_ADD : DDM_DATA_UPDATE_REPLACE,
+                                                           default_include, default_children,
+                                                           referenced_resource, item_timestamp);
+                } else {
+                    DDMDataValue value;
+                    
+                    value.type = type;
+                    value.u.resource = referenced_resource;
+                    
+                    ddm_data_resource_update_property(resource, property_qname,
+                                                      (cardinality == DDM_DATA_CARDINALITY_N) ? DDM_DATA_UPDATE_ADD : DDM_DATA_UPDATE_REPLACE,
+                                                      cardinality,
+                                                      default_include, default_children,
+                                                      &value);
+                }
             } else {
                 QueuedResourceProperty *property = queued_resource_property_new(resource, property_qname,
                                                                                 cardinality,
-                                                                                default_include, default_children);
+                                                                                default_include, default_children,
+                                                                                type == DDM_DATA_FEED,
+                                                                                item_timestamp);
                 resource_tracking_queue_resource(tracking, value_string, property);
             }
         } else {
@@ -919,6 +987,7 @@
                 break;
             case DDM_DATA_RESOURCE:
             case DDM_DATA_LIST:
+            case DDM_DATA_FEED:
             case DDM_DATA_NONE:
                 g_assert_not_reached();
                 break;
@@ -1001,16 +1070,25 @@
 
                 for (properties = queued->properties; properties; properties = properties->next) {
                     QueuedResourceProperty *queued_property = properties->data;
-                    DDMDataValue value;
-                    
-                    value.type = DDM_DATA_RESOURCE;
-                    value.u.resource = resource;
 
-                    ddm_data_resource_update_property(queued_property->resource, queued_property->property_qname,
-                                                         (queued_property->cardinality == DDM_DATA_CARDINALITY_N) ? DDM_DATA_UPDATE_ADD : DDM_DATA_UPDATE_REPLACE,
-                                                         queued_property->cardinality,
-                                                         queued_property->default_include, queued_property->default_children,
-                                                         &value);
+                    if (queued_property->is_feed) {
+                        ddm_data_resource_update_feed_property(queued_property->resource, queued_property->property_qname,
+                                                               DDM_DATA_UPDATE_ADD,
+                                                               queued_property->default_include, queued_property->default_children,
+                                                               resource, queued_property->item_timestamp);
+                        
+                    } else {
+                        DDMDataValue value;
+                        
+                        value.type = DDM_DATA_RESOURCE;
+                        value.u.resource = resource;
+                        
+                        ddm_data_resource_update_property(queued_property->resource, queued_property->property_qname,
+                                                          (queued_property->cardinality == DDM_DATA_CARDINALITY_N) ? DDM_DATA_UPDATE_ADD : DDM_DATA_UPDATE_REPLACE,
+                                                          queued_property->cardinality,
+                                                          queued_property->default_include, queued_property->default_children,
+                                                          &value);
+                    }
                 }
                     
                 g_hash_table_insert(tracking->fetched_resources, g_strdup(queued->resource_id), resource);
@@ -1215,8 +1293,22 @@
             char *default_children = make_default_children_string(property);
 
             ddm_data_property_get_value(property, &value);
-            
-            if (ddm_data_property_get_cardinality(property) == DDM_DATA_CARDINALITY_N) {
+
+            if (value.type == DDM_DATA_FEED) {
+                if (value.u.feed != NULL) {
+                    DDMFeedIter iter;
+                    DDMDataResource *item_resource;
+                    gint64 item_timestamp;
+
+                    ddm_feed_iter_init(&iter, value.u.feed);
+                    while (ddm_feed_iter_next(&iter, &item_resource, &item_timestamp)) {
+                        save_feed_property_value_to_disk(cache, resource_id, property_id,
+                                                         property,
+                                                         item_resource, item_timestamp,
+                                                         type, default_children, timestamp);
+                    }
+                }
+            } else if (DDM_DATA_IS_LIST(value.type)) {
                 GSList *ll;
 
                 for (ll = value.u.list; ll; ll = ll->next) {
@@ -1227,7 +1319,7 @@
                     save_property_value_to_disk(cache, resource_id, property_id,
                                                 property, &element, type, default_children, timestamp);
                 }
-            } else {
+            } else if (value.type != DDM_DATA_NONE) {
                 save_property_value_to_disk(cache, resource_id, property_id,
                                             property, &value, type, default_children, timestamp);
             }

Modified: dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.c
===================================================================
--- dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.c	2007-12-12 15:49:24 UTC (rev 7036)
+++ dumbhippo/trunk/client/linux/src/hippo-dbus-model-client.c	2007-12-12 15:59:21 UTC (rev 7037)
@@ -179,6 +179,7 @@
         value_signature = "s";
         break;
     case DDM_DATA_LIST:
+    case DDM_DATA_FEED:
         break;
     }
 
@@ -240,6 +241,7 @@
         }
         break;
     case DDM_DATA_LIST:
+    case DDM_DATA_FEED:
         break;
     }
     
@@ -248,6 +250,59 @@
 }
 
 static void
+add_feed_property_value_to_message(DBusMessageIter    *property_array_iter,
+                                   DDMQName           *property_qname,
+                                   DDMDataUpdate       update,
+                                   DDMDataResource    *item_resource,
+                                   gint64              item_timestamp)
+{
+    DBusMessageIter property_iter;
+    DBusMessageIter value_iter;
+    DBusMessageIter item_struct_iter;
+    char update_byte;
+    char type_byte;
+    char cardinality_byte;
+    const char *value_signature = NULL;
+    const char *item_resource_id = ddm_data_resource_get_resource_id(item_resource);
+    
+    switch (update) {
+    case DDM_DATA_UPDATE_ADD:
+        update_byte = 'a';
+        break;
+    case DDM_DATA_UPDATE_REPLACE:
+        update_byte = 'r';
+        break;
+    case DDM_DATA_UPDATE_DELETE:
+        update_byte = 'd';
+        break;
+    case DDM_DATA_UPDATE_CLEAR:
+        update_byte = 'c';
+        break;
+    }
+
+    type_byte = 'F';
+    value_signature = "(sx)";
+    cardinality_byte = '*';
+    
+    dbus_message_iter_open_container(property_array_iter, DBUS_TYPE_STRUCT, NULL, &property_iter);
+    dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_STRING, &property_qname->uri);
+    dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_STRING, &property_qname->name);
+    dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_BYTE, &update_byte);
+    dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_BYTE, &type_byte);
+    dbus_message_iter_append_basic(&property_iter, DBUS_TYPE_BYTE, &cardinality_byte);
+
+    dbus_message_iter_open_container(&property_iter, DBUS_TYPE_VARIANT, value_signature, &value_iter);
+    
+    dbus_message_iter_open_container(&value_iter, DBUS_TYPE_STRUCT, NULL, &item_struct_iter);
+    dbus_message_iter_append_basic(&item_struct_iter, DBUS_TYPE_STRING, &item_resource_id);
+    dbus_message_iter_append_basic(&item_struct_iter, DBUS_TYPE_INT64, &item_timestamp);
+    dbus_message_iter_close_container(&value_iter, &item_struct_iter);
+    
+    dbus_message_iter_close_container(&property_iter, &value_iter);
+    dbus_message_iter_close_container(property_array_iter, &property_iter);
+}
+
+static void
 add_property_children_to_message(HippoDBusModelClient *client,
                                  DBusMessageIter      *resource_array_iter,
                                  DDMDataProperty      *property,
@@ -263,11 +318,19 @@
         GSList *l;
         for (l = value.u.list; l; l = l->next)
             add_resource_to_message(client, resource_array_iter, l->data, children, TRUE, FALSE, NULL);
+    } else if (value.type == DDM_DATA_FEED && value.u.feed != NULL) {
+        DDMFeedIter feed_iter;
+        DDMDataResource *item_resource;
+
+        ddm_feed_iter_init(&feed_iter, value.u.feed);
+        while (ddm_feed_iter_next(&feed_iter, &item_resource, NULL)) {
+            add_resource_to_message(client, resource_array_iter, item_resource, children, TRUE, FALSE, NULL);
+        }
     }
 }
 
 static void
-add_property_to_message(DBusMessageIter   *property_array_iter,
+add_property_to_message(DBusMessageIter *property_array_iter,
                         DDMDataProperty *property)
 {
     DDMDataCardinality cardinality;
@@ -293,6 +356,22 @@
                                           l == value.u.list ? DDM_DATA_UPDATE_REPLACE : DDM_DATA_UPDATE_ADD,
                                           &element, cardinality);
         }
+    } else if (value.type == DDM_DATA_FEED) {
+        if (value.u.feed != NULL) {
+            DDMFeedIter feed_iter;
+            DDMDataResource *item_resource;
+            gint64 item_timestamp;
+            gboolean first;
+
+            ddm_feed_iter_init(&feed_iter, value.u.feed);
+            first = TRUE;
+            while (ddm_feed_iter_next(&feed_iter, &item_resource, &item_timestamp)) {
+                add_feed_property_value_to_message(property_array_iter, property_qname,
+                                                   first ? DDM_DATA_UPDATE_REPLACE : DDM_DATA_UPDATE_ADD,
+                                                   item_resource, item_timestamp);
+                first = FALSE;
+            }
+        }
     } else {
         add_property_value_to_message(property_array_iter, property_qname,
                                       DDM_DATA_UPDATE_REPLACE,



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