[evolution-data-server] I#297 - CalDAV: Support calendar-order property



commit 95a516250405b4ba3ab209bb25618ac97c4456b7
Author: Milan Crha <mcrha redhat com>
Date:   Wed Feb 10 14:57:58 2021 +0100

    I#297 - CalDAV: Support calendar-order property
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/297

 CMakeLists.txt                                  |   4 +-
 src/libebackend/e-webdav-collection-backend.c   |  15 +++-
 src/libedataserver/e-data-server-util.c         |  95 +++++++++++++++++++++
 src/libedataserver/e-data-server-util.h         |   2 +
 src/libedataserver/e-source-address-book.c      | 108 +++++++++++++++++++++++-
 src/libedataserver/e-source-address-book.h      |   4 +
 src/libedataserver/e-source-registry.c          |  32 +------
 src/libedataserver/e-source-selectable.c        |  72 +++++++++++++++-
 src/libedataserver/e-source-selectable.h        |   3 +
 src/libedataserver/e-source-webdav.c            |  70 ++++++++++++++-
 src/libedataserver/e-source-webdav.h            |   3 +
 src/libedataserver/e-webdav-discover.c          |  29 +++++--
 src/libedataserver/e-webdav-discover.h          |   1 +
 src/libedataserver/e-webdav-session.c           |  48 +++++++++--
 src/libedataserver/e-webdav-session.h           |  11 ++-
 src/libedataserverui/e-webdav-discover-widget.c |  10 ++-
 src/libedataserverui/e-webdav-discover-widget.h |   3 +-
 17 files changed, 447 insertions(+), 63 deletions(-)
---
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6c1b9e0ae..e8177fcc9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -56,11 +56,11 @@ set(LIBEBACKEND_CURRENT 10)
 set(LIBEBACKEND_REVISION 0)
 set(LIBEBACKEND_AGE 0)
 
-set(LIBEDATASERVER_CURRENT 25)
+set(LIBEDATASERVER_CURRENT 26)
 set(LIBEDATASERVER_REVISION 0)
 set(LIBEDATASERVER_AGE 0)
 
-set(LIBEDATASERVERUI_CURRENT 2)
+set(LIBEDATASERVERUI_CURRENT 3)
 set(LIBEDATASERVERUI_REVISION 0)
 set(LIBEDATASERVERUI_AGE 0)
 
diff --git a/src/libebackend/e-webdav-collection-backend.c b/src/libebackend/e-webdav-collection-backend.c
index 7f3165244..1a88b1520 100644
--- a/src/libebackend/e-webdav-collection-backend.c
+++ b/src/libebackend/e-webdav-collection-backend.c
@@ -88,6 +88,7 @@ webdav_collection_add_found_source (ECollectionBackend *collection,
                                    SoupURI *uri,
                                    const gchar *display_name,
                                    const gchar *color,
+                                   guint order,
                                    gboolean calendar_auto_schedule,
                                    gboolean is_subscribed_icalendar,
                                    GHashTable *known_sources)
@@ -205,7 +206,12 @@ webdav_collection_add_found_source (ECollectionBackend *collection,
 
                e_source_webdav_set_display_name (webdav_extension, display_name);
 
-               if (source_type != E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS) {
+               if (source_type == E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS) {
+                       if (is_new || e_source_webdav_get_order (webdav_extension) == 
e_source_address_book_get_order (E_SOURCE_ADDRESS_BOOK (backend)))
+                               e_source_address_book_set_order (E_SOURCE_ADDRESS_BOOK (backend), order);
+
+                       e_source_webdav_set_order (webdav_extension, order);
+               } else {
                        /* Also check whether the color format is as expected; cannot
                           use gdk_rgba_parse() here, because it requires gdk/gtk. */
                        if (color && sscanf (color, "#%02x%02x%02x", &rr, &gg, &bb) == 3) {
@@ -222,6 +228,11 @@ webdav_collection_add_found_source (ECollectionBackend *collection,
                                g_free (safe_color);
                        }
 
+                       if (is_new || e_source_webdav_get_order (webdav_extension) == 
e_source_selectable_get_order (E_SOURCE_SELECTABLE (backend)))
+                               e_source_selectable_set_order (E_SOURCE_SELECTABLE (backend), order);
+
+                       e_source_webdav_set_order (webdav_extension, order);
+
                        if (is_new && calendar_auto_schedule)
                                e_source_webdav_set_calendar_auto_schedule (webdav_extension, TRUE);
                }
@@ -259,7 +270,7 @@ webdav_collection_process_discovered_sources (ECollectionBackend *collection,
                for (ii = 0; ii < n_source_types; ii++) {
                        if ((discovered_source->supports & source_types[ii]) == source_types[ii])
                                webdav_collection_add_found_source (collection, source_types[ii], soup_uri,
-                                       discovered_source->display_name, discovered_source->color,
+                                       discovered_source->display_name, discovered_source->color, 
discovered_source->order,
                                        (discovered_source->supports & 
E_WEBDAV_DISCOVER_SUPPORTS_CALENDAR_AUTO_SCHEDULE) != 0,
                                        (discovered_source->supports & 
E_WEBDAV_DISCOVER_SUPPORTS_SUBSCRIBED_ICALENDAR) != 0,
                                        known_sources);
diff --git a/src/libedataserver/e-data-server-util.c b/src/libedataserver/e-data-server-util.c
index ee9851707..5c8116af5 100644
--- a/src/libedataserver/e-data-server-util.c
+++ b/src/libedataserver/e-data-server-util.c
@@ -33,14 +33,18 @@
 #include <glib-object.h>
 
 #include "e-source.h"
+#include "e-source-address-book.h"
 #include "e-source-authentication.h"
 #include "e-source-backend.h"
+#include "e-source-calendar.h"
 #include "e-source-collection.h"
 #include "e-source-enumtypes.h"
 #include "e-source-mail-identity.h"
 #include "e-source-mail-submission.h"
 #include "e-source-mail-transport.h"
+#include "e-source-memo-list.h"
 #include "e-source-registry.h"
+#include "e-source-task-list.h"
 #include "camel/camel.h"
 
 #include "e-data-server-util.h"
@@ -3310,3 +3314,94 @@ e_util_can_use_collection_as_credential_source (ESource *collection_source,
 
        return can_use_collection;
 }
+
+static gboolean
+e_util_source_compare_get_order (ESource *source,
+                                guint *out_order)
+{
+       const gchar *extensions[] = {
+               E_SOURCE_EXTENSION_ADDRESS_BOOK, /* keep it as the first - see below */
+               E_SOURCE_EXTENSION_CALENDAR,
+               E_SOURCE_EXTENSION_MEMO_LIST,
+               E_SOURCE_EXTENSION_TASK_LIST
+       };
+       gint ii;
+
+       for (ii = 0; ii < G_N_ELEMENTS (extensions); ii++) {
+               if (e_source_has_extension (source, extensions[ii])) {
+                       ESourceExtension *extension = e_source_get_extension (source, extensions[ii]);
+
+                       if (ii == 0) /* E_SOURCE_EXTENSION_ADDRESS_BOOK */
+                               *out_order = e_source_address_book_get_order (E_SOURCE_ADDRESS_BOOK 
(extension));
+                       else
+                               *out_order = e_source_selectable_get_order (E_SOURCE_SELECTABLE (extension));
+
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+/**
+ * e_util_source_compare_for_sort:
+ * @source_a: the first #ESource
+ * @source_b: the second #ESource
+ *
+ * Compares two #ESource-s in a way suitable for user interface.
+ * It can be used as a #GCompareFunc.
+ *
+ * This is also used by e_source_registry_build_display_tree().
+ *
+ * Returns: an integer less than, equal to, or greater than zero,
+ *    if @source_a is <, == or > than @source_b.
+ *
+ * Since: 3.40
+ **/
+gint
+e_util_source_compare_for_sort (ESource *source_a,
+                               ESource *source_b)
+{
+       guint order_a = 0, order_b = 0;
+       const gchar *uid_a, *uid_b;
+
+       if (!source_a || !source_b)
+               return (source_a ? 1 : 0) - (source_b ? 1 : 0);
+
+       uid_a = e_source_get_uid (source_a);
+       uid_b = e_source_get_uid (source_b);
+
+       /* Sanity check, with runtime warnings. */
+       if (uid_a == NULL) {
+               g_warn_if_reached ();
+               uid_a = "";
+       }
+       if (uid_b == NULL) {
+               g_warn_if_reached ();
+               uid_b = "";
+       }
+
+       /* The built-in "local-stub" source comes first at depth 1. */
+
+       if (g_strcmp0 (uid_a, "local-stub") == 0)
+               return -1;
+
+       if (g_strcmp0 (uid_b, "local-stub") == 0)
+               return 1;
+
+       /* The built-in "system-*" sources come first at depth 2. */
+
+       if (g_str_has_prefix (uid_a, "system-"))
+               return -1;
+
+       if (g_str_has_prefix (uid_b, "system-"))
+               return 1;
+
+       if (e_util_source_compare_get_order (source_a, &order_a) &&
+           e_util_source_compare_get_order (source_b, &order_b)) {
+               if (order_a != order_b)
+                       return order_a < order_b ? -1 : 1;
+       }
+
+       return e_source_compare_by_display_name (source_a, source_b);
+}
diff --git a/src/libedataserver/e-data-server-util.h b/src/libedataserver/e-data-server-util.h
index bfddb2399..526d8a542 100644
--- a/src/libedataserver/e-data-server-util.h
+++ b/src/libedataserver/e-data-server-util.h
@@ -293,6 +293,8 @@ gboolean    e_util_identity_can_send        (struct _ESourceRegistry *registry,
 gboolean       e_util_can_use_collection_as_credential_source
                                                (struct _ESource *collection_source,
                                                 struct _ESource *child_source);
+gint           e_util_source_compare_for_sort  (struct _ESource *source_a,
+                                                struct _ESource *source_b);
 
 G_END_DECLS
 
diff --git a/src/libedataserver/e-source-address-book.c b/src/libedataserver/e-source-address-book.c
index 9a2be6e81..a3e0d671b 100644
--- a/src/libedataserver/e-source-address-book.c
+++ b/src/libedataserver/e-source-address-book.c
@@ -38,21 +38,121 @@
 
 #include <libedataserver/e-data-server-util.h>
 
-G_DEFINE_TYPE (
-       ESourceAddressBook,
-       e_source_address_book,
-       E_TYPE_SOURCE_BACKEND)
+struct _ESourceAddressBookPrivate {
+       guint order;
+};
+
+enum {
+       PROP_0,
+       PROP_ORDER
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (ESourceAddressBook, e_source_address_book, E_TYPE_SOURCE_BACKEND)
+
+static void
+source_address_book_set_property (GObject *object,
+                                 guint property_id,
+                                 const GValue *value,
+                                 GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_ORDER:
+                       e_source_address_book_set_order (
+                               E_SOURCE_ADDRESS_BOOK (object),
+                               g_value_get_uint (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_address_book_get_property (GObject *object,
+                                 guint property_id,
+                                 GValue *value,
+                                 GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_ORDER:
+                       g_value_set_uint (
+                               value,
+                               e_source_address_book_get_order (
+                               E_SOURCE_ADDRESS_BOOK (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
 
 static void
 e_source_address_book_class_init (ESourceAddressBookClass *class)
 {
+       GObjectClass *object_class;
        ESourceExtensionClass *extension_class;
 
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = source_address_book_set_property;
+       object_class->get_property = source_address_book_get_property;
+
        extension_class = E_SOURCE_EXTENSION_CLASS (class);
        extension_class->name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_ORDER,
+               g_param_spec_uint (
+                       "order",
+                       "Order",
+                       "A sorting order of the source",
+                       0, G_MAXUINT, 0,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_EXPLICIT_NOTIFY |
+                       G_PARAM_STATIC_STRINGS |
+                       E_SOURCE_PARAM_SETTING));
 }
 
 static void
 e_source_address_book_init (ESourceAddressBook *extension)
 {
+       extension->priv = e_source_address_book_get_instance_private (extension);
+}
+
+/**
+ * e_source_address_book_get_order:
+ * @extension: an #ESourceAddressBook
+ *
+ * Returns: the sorting order of the source, if known. Zero is the default.
+ *
+ * Since: 3.40
+ **/
+guint
+e_source_address_book_get_order (ESourceAddressBook *extension)
+{
+       g_return_val_if_fail (E_IS_SOURCE_ADDRESS_BOOK (extension), 0);
+
+       return extension->priv->order;
+}
+
+/**
+ * e_source_address_book_set_order:
+ * @extension: an #ESourceAddressBook
+ * @order: a sorting order
+ *
+ * Set the sorting order of the source.
+ *
+ * Since: 3.40
+ **/
+void
+e_source_address_book_set_order (ESourceAddressBook *extension,
+                                guint order)
+{
+       g_return_if_fail (E_IS_SOURCE_ADDRESS_BOOK (extension));
+
+       if (extension->priv->order == order)
+               return;
+
+       extension->priv->order = order;
+
+       g_object_notify (G_OBJECT (extension), "order");
 }
diff --git a/src/libedataserver/e-source-address-book.h b/src/libedataserver/e-source-address-book.h
index 8960470f4..9d5963f34 100644
--- a/src/libedataserver/e-source-address-book.h
+++ b/src/libedataserver/e-source-address-book.h
@@ -79,6 +79,10 @@ struct _ESourceAddressBookClass {
 
 GType          e_source_address_book_get_type  (void) G_GNUC_CONST;
 
+guint          e_source_address_book_get_order (ESourceAddressBook *extension);
+void           e_source_address_book_set_order (ESourceAddressBook *extension,
+                                                guint order);
+
 G_END_DECLS
 
 #endif /* E_SOURCE_ADDRESS_BOOK_H */
diff --git a/src/libedataserver/e-source-registry.c b/src/libedataserver/e-source-registry.c
index 9664bccf4..3d61eb802 100644
--- a/src/libedataserver/e-source-registry.c
+++ b/src/libedataserver/e-source-registry.c
@@ -2714,38 +2714,8 @@ source_registry_compare_nodes (GNode *node_a,
 {
        ESource *source_a = E_SOURCE (node_a->data);
        ESource *source_b = E_SOURCE (node_b->data);
-       const gchar *uid_a, *uid_b;
 
-       uid_a = e_source_get_uid (source_a);
-       uid_b = e_source_get_uid (source_b);
-
-       /* Sanity check, with runtime warnings. */
-       if (uid_a == NULL) {
-               g_warn_if_reached ();
-               uid_a = "";
-       }
-       if (uid_b == NULL) {
-               g_warn_if_reached ();
-               uid_b = "";
-       }
-
-       /* The built-in "local-stub" source comes first at depth 1. */
-
-       if (g_strcmp0 (uid_a, "local-stub") == 0)
-               return -1;
-
-       if (g_strcmp0 (uid_b, "local-stub") == 0)
-               return 1;
-
-       /* The built-in "system-*" sources come first at depth 2. */
-
-       if (g_str_has_prefix (uid_a, "system-"))
-               return -1;
-
-       if (g_str_has_prefix (uid_b, "system-"))
-               return 1;
-
-       return e_source_compare_by_display_name (source_a, source_b);
+       return e_util_source_compare_for_sort (source_a, source_b);
 }
 
 /* Helper for e_source_registry_build_display_tree() */
diff --git a/src/libedataserver/e-source-selectable.c b/src/libedataserver/e-source-selectable.c
index ef089c68b..ddff58a91 100644
--- a/src/libedataserver/e-source-selectable.c
+++ b/src/libedataserver/e-source-selectable.c
@@ -32,12 +32,14 @@
 struct _ESourceSelectablePrivate {
        gchar *color;
        gboolean selected;
+       guint order;
 };
 
 enum {
        PROP_0,
        PROP_COLOR,
-       PROP_SELECTED
+       PROP_SELECTED,
+       PROP_ORDER
 };
 
 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (
@@ -63,6 +65,12 @@ source_selectable_set_property (GObject *object,
                                E_SOURCE_SELECTABLE (object),
                                g_value_get_boolean (value));
                        return;
+
+               case PROP_ORDER:
+                       e_source_selectable_set_order (
+                               E_SOURCE_SELECTABLE (object),
+                               g_value_get_uint (value));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -88,6 +96,13 @@ source_selectable_get_property (GObject *object,
                                e_source_selectable_get_selected (
                                E_SOURCE_SELECTABLE (object)));
                        return;
+
+               case PROP_ORDER:
+                       g_value_set_uint (
+                               value,
+                               e_source_selectable_get_order (
+                               E_SOURCE_SELECTABLE (object)));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -146,6 +161,20 @@ e_source_selectable_class_init (ESourceSelectableClass *class)
                        G_PARAM_EXPLICIT_NOTIFY |
                        G_PARAM_STATIC_STRINGS |
                        E_SOURCE_PARAM_SETTING));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_ORDER,
+               g_param_spec_uint (
+                       "order",
+                       "Order",
+                       "Preferred sorting order",
+                       0, G_MAXUINT, 0,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_EXPLICIT_NOTIFY |
+                       G_PARAM_STATIC_STRINGS |
+                       E_SOURCE_PARAM_SETTING));
 }
 
 static void
@@ -288,3 +317,44 @@ e_source_selectable_set_selected (ESourceSelectable *extension,
        g_object_notify (G_OBJECT (extension), "selected");
 }
 
+/**
+ * e_source_selectable_get_order:
+ * @extension: an #ESourceSelectable
+ *
+ * Returns the preferred sorting order for the #ESource
+ * to which @extension belongs. Default is 0.
+ *
+ * Returns: the preferred sorting order for the #ESource
+ *
+ * Since: 3.40
+ **/
+guint
+e_source_selectable_get_order (ESourceSelectable *extension)
+{
+       g_return_val_if_fail (E_IS_SOURCE_SELECTABLE (extension), 0);
+
+       return extension->priv->order;
+}
+
+/**
+ * e_source_selectable_set_order:
+ * @extension: an #ESourceSelectable
+ * @selected: selected state
+ *
+ * Sets the sorting order for the #ESource to which @extension belongs.
+ *
+ * Since: 3.40
+ **/
+void
+e_source_selectable_set_order (ESourceSelectable *extension,
+                              guint order)
+{
+       g_return_if_fail (E_IS_SOURCE_SELECTABLE (extension));
+
+       if (extension->priv->order == order)
+               return;
+
+       extension->priv->order = order;
+
+       g_object_notify (G_OBJECT (extension), "order");
+}
diff --git a/src/libedataserver/e-source-selectable.h b/src/libedataserver/e-source-selectable.h
index df418bf09..33dea25dd 100644
--- a/src/libedataserver/e-source-selectable.h
+++ b/src/libedataserver/e-source-selectable.h
@@ -77,6 +77,9 @@ gboolean      e_source_selectable_get_selected
 void           e_source_selectable_set_selected
                                                (ESourceSelectable *extension,
                                                 gboolean selected);
+guint          e_source_selectable_get_order   (ESourceSelectable *extension);
+void           e_source_selectable_set_order   (ESourceSelectable *extension,
+                                                guint order);
 
 G_END_DECLS
 
diff --git a/src/libedataserver/e-source-webdav.c b/src/libedataserver/e-source-webdav.c
index b3432ff4d..91f9ac564 100644
--- a/src/libedataserver/e-source-webdav.c
+++ b/src/libedataserver/e-source-webdav.c
@@ -68,6 +68,7 @@ struct _ESourceWebdavPrivate {
        gboolean avoid_ifmatch;
        gboolean calendar_auto_schedule;
        SoupURI *soup_uri;
+       guint order;
 };
 
 enum {
@@ -80,7 +81,8 @@ enum {
        PROP_RESOURCE_PATH,
        PROP_RESOURCE_QUERY,
        PROP_SOUP_URI,
-       PROP_SSL_TRUST
+       PROP_SSL_TRUST,
+       PROP_ORDER
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (
@@ -322,6 +324,12 @@ source_webdav_set_property (GObject *object,
                                E_SOURCE_WEBDAV (object),
                                g_value_get_string (value));
                        return;
+
+               case PROP_ORDER:
+                       e_source_webdav_set_order (
+                               E_SOURCE_WEBDAV (object),
+                               g_value_get_uint (value));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -396,6 +404,13 @@ source_webdav_get_property (GObject *object,
                                e_source_webdav_dup_ssl_trust (
                                E_SOURCE_WEBDAV (object)));
                        return;
+
+               case PROP_ORDER:
+                       g_value_set_uint (
+                               value,
+                               e_source_webdav_get_order (
+                               E_SOURCE_WEBDAV (object)));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -621,6 +636,20 @@ e_source_webdav_class_init (ESourceWebdavClass *class)
                        G_PARAM_EXPLICIT_NOTIFY |
                        G_PARAM_STATIC_STRINGS |
                        E_SOURCE_PARAM_SETTING));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_ORDER,
+               g_param_spec_uint (
+                       "order",
+                       "Order",
+                       "A sorting order of the resource",
+                       0, G_MAXUINT, 0,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_EXPLICIT_NOTIFY |
+                       G_PARAM_STATIC_STRINGS |
+                       E_SOURCE_PARAM_SETTING));
 }
 
 static void
@@ -1586,3 +1615,42 @@ e_source_webdav_set_ssl_trust_response (ESourceWebdav *extension,
        g_free (host);
        g_free (hash);
 }
+
+/**
+ * e_source_webdav_get_order:
+ * @extension: an #ESourceWebdav
+ *
+ * Returns: the sorting order of the resource, if known. Zero is the default.
+ *
+ * Since: 3.40
+ **/
+guint
+e_source_webdav_get_order (ESourceWebdav *extension)
+{
+       g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), 0);
+
+       return extension->priv->order;
+}
+
+/**
+ * e_source_webdav_set_order:
+ * @extension: an #ESourceWebdav
+ * @order: a sorting order
+ *
+ * Set the sorting order of the resource.
+ *
+ * Since: 3.40
+ **/
+void
+e_source_webdav_set_order (ESourceWebdav *extension,
+                          guint order)
+{
+       g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
+
+       if (extension->priv->order == order)
+               return;
+
+       extension->priv->order = order;
+
+       g_object_notify (G_OBJECT (extension), "order");
+}
diff --git a/src/libedataserver/e-source-webdav.h b/src/libedataserver/e-source-webdav.h
index f1c8da856..e72e553f4 100644
--- a/src/libedataserver/e-source-webdav.h
+++ b/src/libedataserver/e-source-webdav.h
@@ -153,6 +153,9 @@ ETrustPromptResponse
 void           e_source_webdav_set_ssl_trust_response
                                                (ESourceWebdav *extension,
                                                 ETrustPromptResponse response);
+guint          e_source_webdav_get_order       (ESourceWebdav *extension);
+void           e_source_webdav_set_order       (ESourceWebdav *extension,
+                                                guint order);
 
 G_END_DECLS
 
diff --git a/src/libedataserver/e-webdav-discover.c b/src/libedataserver/e-webdav-discover.c
index 0aefa5aae..bad613a2b 100644
--- a/src/libedataserver/e-webdav-discover.c
+++ b/src/libedataserver/e-webdav-discover.c
@@ -91,6 +91,7 @@ e_webdav_discover_split_resources (WebDAVDiscoverData *wdd,
                        discovered->display_name = g_strdup (resource->display_name);
                        discovered->description = g_strdup (resource->description);
                        discovered->color = g_strdup (resource->color);
+                       discovered->order = resource->order;
 
                        if (resource->kind == E_WEBDAV_RESOURCE_KIND_ADDRESSBOOK) {
                                wdd->addressbooks = g_slist_prepend (wdd->addressbooks, discovered);
@@ -146,8 +147,7 @@ e_webdav_discover_traverse_propfind_response_cb (EWebDAVSession *webdav,
 
                        if (full_href && *full_href && GPOINTER_TO_INT (g_hash_table_contains 
(wdd->covered_hrefs, full_href)) != 2 &&
                            e_webdav_session_list_sync (webdav, full_href, E_WEBDAV_DEPTH_THIS_AND_CHILDREN,
-                               E_WEBDAV_LIST_SUPPORTS | E_WEBDAV_LIST_DISPLAY_NAME | 
E_WEBDAV_LIST_DESCRIPTION |
-                               E_WEBDAV_LIST_COLOR | E_WEBDAV_LIST_ONLY_ADDRESSBOOK | E_WEBDAV_LIST_ALL,
+                               E_WEBDAV_LIST_ONLY_ADDRESSBOOK | E_WEBDAV_LIST_ALL,
                                &resources, wdd->cancellable, &local_error)) {
                                e_webdav_discover_split_resources (wdd, resources);
                                g_slist_free_full (resources, e_webdav_resource_free);
@@ -183,8 +183,7 @@ e_webdav_discover_traverse_propfind_response_cb (EWebDAVSession *webdav,
 
                        if (full_href && *full_href && GPOINTER_TO_INT (g_hash_table_contains 
(wdd->covered_hrefs, full_href)) != 2 &&
                            e_webdav_session_list_sync (webdav, full_href, E_WEBDAV_DEPTH_THIS_AND_CHILDREN,
-                               E_WEBDAV_LIST_SUPPORTS | E_WEBDAV_LIST_DISPLAY_NAME | 
E_WEBDAV_LIST_DESCRIPTION |
-                               E_WEBDAV_LIST_COLOR | E_WEBDAV_LIST_ONLY_CALENDAR | E_WEBDAV_LIST_ALL,
+                               E_WEBDAV_LIST_ONLY_CALENDAR | E_WEBDAV_LIST_ALL,
                                &resources, wdd->cancellable, &local_error)) {
                                e_webdav_discover_split_resources (wdd, resources);
                                g_slist_free_full (resources, e_webdav_resource_free);
@@ -269,7 +268,6 @@ e_webdav_discover_traverse_propfind_response_cb (EWebDAVSession *webdav,
                if (GPOINTER_TO_INT (g_hash_table_contains (wdd->covered_hrefs, href)) != 2 &&
                    !g_cancellable_is_cancelled (wdd->cancellable) &&
                    e_webdav_session_list_sync (webdav, href, E_WEBDAV_DEPTH_THIS,
-                       E_WEBDAV_LIST_SUPPORTS | E_WEBDAV_LIST_DISPLAY_NAME | E_WEBDAV_LIST_DESCRIPTION | 
E_WEBDAV_LIST_COLOR |
                        (is_calendar ? E_WEBDAV_LIST_ONLY_CALENDAR : 0) | (is_addressbook ? 
E_WEBDAV_LIST_ONLY_ADDRESSBOOK : 0) | E_WEBDAV_LIST_ALL,
                        &resources, wdd->cancellable, &local_error)) {
                        e_webdav_discover_split_resources (wdd, resources);
@@ -295,7 +293,7 @@ e_webdav_discover_traverse_propfind_response_cb (EWebDAVSession *webdav,
                        e_webdav_resource_new (E_WEBDAV_RESOURCE_KIND_WEBDAV_NOTES,
                                E_WEBDAV_RESOURCE_SUPPORTS_WEBDAV_NOTES, href, NULL,
                                _("Notes"),
-                               NULL, 0, 0, 0, NULL, NULL));
+                               NULL, 0, 0, 0, NULL, NULL, 0));
 
                e_webdav_discover_split_resources (wdd, resources);
 
@@ -760,6 +758,22 @@ e_webdav_discover_sources_sync (ESource *source,
                out_certificate_pem, out_certificate_errors, out_discovered_sources, 
out_calendar_user_addresses, cancellable, error);
 }
 
+static gint
+e_webdav_discover_cmp_sources (gconstpointer ptr1,
+                              gconstpointer ptr2)
+{
+       const EWebDAVDiscoveredSource *source1 = ptr1;
+       const EWebDAVDiscoveredSource *source2 = ptr2;
+
+       if (!source1 || !source2)
+               return (source1 ? 1 : 0) - (source2 ? 1 : 0);
+
+       if (source1->order != source2->order)
+               return source1->order < source2->order ? -1 : 1;
+
+       return g_strcmp0 (source1->display_name, source2->display_name);
+}
+
 /**
  * e_webdav_discover_sources_full_sync:
  * @source: an #ESource from which to take connection details
@@ -1017,7 +1031,7 @@ e_webdav_discover_sources_full_sync (ESource *source,
                        *out_calendar_user_addresses = g_slist_reverse (*out_calendar_user_addresses);
 
                if (out_discovered_sources && *out_discovered_sources)
-                       *out_discovered_sources = g_slist_reverse (*out_discovered_sources);
+                       *out_discovered_sources = g_slist_sort (*out_discovered_sources, 
e_webdav_discover_cmp_sources);
 
                g_hash_table_destroy (wdd.covered_hrefs);
        } else {
@@ -1056,6 +1070,7 @@ e_webdav_discovered_source_copy (EWebDAVDiscoveredSource *discovered_source)
        copy->display_name = g_strdup (discovered_source->display_name);
        copy->description = g_strdup (discovered_source->description);
        copy->color = g_strdup (discovered_source->color);
+       copy->order = discovered_source->order;
 
        return copy;
 }
diff --git a/src/libedataserver/e-webdav-discover.h b/src/libedataserver/e-webdav-discover.h
index 8b6966826..028d3c6e9 100644
--- a/src/libedataserver/e-webdav-discover.h
+++ b/src/libedataserver/e-webdav-discover.h
@@ -48,6 +48,7 @@ typedef struct _EWebDAVDiscoveredSource {
        gchar *display_name;
        gchar *description;
        gchar *color;
+       guint order;
 } EWebDAVDiscoveredSource;
 
 void           e_webdav_discover_free_discovered_sources
diff --git a/src/libedataserver/e-webdav-session.c b/src/libedataserver/e-webdav-session.c
index fbf8a0acb..0976510ff 100644
--- a/src/libedataserver/e-webdav-session.c
+++ b/src/libedataserver/e-webdav-session.c
@@ -66,6 +66,7 @@ G_DEFINE_BOXED_TYPE (EWebDAVAccessControlEntry, e_webdav_access_control_entry, e
  * @last_modified: optional last modified time of the resource, or 0
  * @description: (nullable): optional description of the resource, or %NULL
  * @color: (nullable): optional color of the resource, or %NULL
+ * @order: sort order of the resource, or 0
  *
  * Some values of the resource are not always valid, depending on the @kind,
  * but also whether server stores such values and whether it had been asked
@@ -89,7 +90,8 @@ e_webdav_resource_new (EWebDAVResourceKind kind,
                       glong creation_date,
                       glong last_modified,
                       const gchar *description,
-                      const gchar *color)
+                      const gchar *color,
+                      guint order)
 {
        EWebDAVResource *resource;
 
@@ -105,6 +107,7 @@ e_webdav_resource_new (EWebDAVResourceKind kind,
        resource->last_modified = last_modified;
        resource->description = g_strdup (description);
        resource->color = g_strdup (color);
+       resource->order = order;
 
        return resource;
 }
@@ -135,7 +138,8 @@ e_webdav_resource_copy (const EWebDAVResource *src)
                src->creation_date,
                src->last_modified,
                src->description,
-               src->color);
+               src->color,
+               src->order);
 }
 
 /**
@@ -3569,6 +3573,27 @@ e_webdav_session_extract_content_length (xmlNodePtr parent)
        return length;
 }
 
+static guint
+e_webdav_session_extract_uint (xmlNodePtr parent,
+                              const gchar *prop_ns_href,
+                              const gchar *prop_name)
+{
+       gchar *value_str;
+       guint64 value;
+
+       g_return_val_if_fail (parent != NULL, 0);
+
+       value_str = e_webdav_session_extract_nonempty (parent, prop_ns_href, prop_name, NULL, NULL);
+       if (!value_str)
+               return 0;
+
+       value = g_ascii_strtoull (value_str, NULL, 10);
+
+       g_free (value_str);
+
+       return (guint) value;
+}
+
 static glong
 e_webdav_session_extract_datetime (xmlNodePtr parent,
                                   const gchar *ns_href,
@@ -3622,6 +3647,7 @@ e_webdav_session_list_cb (EWebDAVSession *webdav,
                gchar *description;
                gchar *color;
                gchar *source_href = NULL;
+               guint order;
 
                kind = e_webdav_session_extract_kind (prop_node);
                if (kind == E_WEBDAV_RESOURCE_KIND_UNKNOWN)
@@ -3655,6 +3681,7 @@ e_webdav_session_list_cb (EWebDAVSession *webdav,
                description = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_CALDAV, 
"calendar-description",
                        E_WEBDAV_NS_CARDDAV, "addressbook-description");
                color = e_webdav_session_extract_nonempty (prop_node, E_WEBDAV_NS_ICAL, "calendar-color", 
NULL, NULL);
+               order = e_webdav_session_extract_uint (prop_node, E_WEBDAV_NS_ICAL, "calendar-order");
 
                resource = e_webdav_resource_new (kind, supports,
                        source_href ? source_href : href,
@@ -3665,7 +3692,8 @@ e_webdav_session_list_cb (EWebDAVSession *webdav,
                        creation_date,
                        last_modified,
                        NULL, /* description */
-                       NULL); /* color */
+                       NULL, /* color */
+                       order);
                resource->etag = etag;
                resource->display_name = display_name;
                resource->content_type = content_type;
@@ -3745,8 +3773,7 @@ e_webdav_session_list_sync (EWebDAVSession *webdav,
 
        if (calendar_props && (
            (flags & E_WEBDAV_LIST_SUPPORTS) != 0 ||
-           (flags & E_WEBDAV_LIST_DESCRIPTION) != 0 ||
-           (flags & E_WEBDAV_LIST_COLOR) != 0)) {
+           (flags & E_WEBDAV_LIST_DESCRIPTION) != 0)) {
                e_xml_document_add_namespaces (xml, "C", E_WEBDAV_NS_CALDAV, NULL);
        }
 
@@ -3792,10 +3819,14 @@ e_webdav_session_list_sync (EWebDAVSession *webdav,
                }
        }
 
-       if (calendar_props && (flags & E_WEBDAV_LIST_COLOR) != 0) {
+       if (calendar_props && ((flags & E_WEBDAV_LIST_COLOR) != 0 || (flags & E_WEBDAV_LIST_ORDER) != 0)) {
                e_xml_document_add_namespaces (xml, "IC", E_WEBDAV_NS_ICAL, NULL);
 
-               e_xml_document_add_empty_element (xml, E_WEBDAV_NS_ICAL, "calendar-color");
+               if ((flags & E_WEBDAV_LIST_COLOR) != 0)
+                       e_xml_document_add_empty_element (xml, E_WEBDAV_NS_ICAL, "calendar-color");
+
+               if ((flags & E_WEBDAV_LIST_ORDER) != 0)
+                       e_xml_document_add_empty_element (xml, E_WEBDAV_NS_ICAL, "calendar-order");
        }
 
        e_xml_document_end_element (xml); /* prop */
@@ -4981,7 +5012,8 @@ e_webdav_session_principal_property_search_cb (EWebDAVSession *webdav,
                0, /* creation_date */
                0, /* last_modified */
                NULL, /* description */
-               NULL); /* color */
+               NULL, /* color */
+               0); /* order */
        resource->display_name = display_name;
 
        *out_principals = g_slist_prepend (*out_principals, resource);
diff --git a/src/libedataserver/e-webdav-session.h b/src/libedataserver/e-webdav-session.h
index a9f6f5b0a..fd9050daf 100644
--- a/src/libedataserver/e-webdav-session.h
+++ b/src/libedataserver/e-webdav-session.h
@@ -116,6 +116,7 @@ typedef struct _EWebDAVResource {
        glong last_modified;
        gchar *description;
        gchar *color;
+       guint order;
 } EWebDAVResource;
 
 GType          e_webdav_resource_get_type              (void) G_GNUC_CONST;
@@ -130,13 +131,14 @@ EWebDAVResource *
                                                         glong creation_date,
                                                         glong last_modified,
                                                         const gchar *description,
-                                                        const gchar *color);
+                                                        const gchar *color,
+                                                        guint order);
 EWebDAVResource *
                e_webdav_resource_copy                  (const EWebDAVResource *src);
 void           e_webdav_resource_free                  (gpointer ptr /* EWebDAVResource * */);
 
 typedef enum {
-       E_WEBDAV_LIST_ALL               = 0xFFFFFFFF,
+       E_WEBDAV_LIST_ALL               = 0x00FFFFFF,
        E_WEBDAV_LIST_NONE              = 0,
        E_WEBDAV_LIST_SUPPORTS          = 1 << 0,
        E_WEBDAV_LIST_ETAG              = 1 << 1,
@@ -147,8 +149,9 @@ typedef enum {
        E_WEBDAV_LIST_LAST_MODIFIED     = 1 << 6,
        E_WEBDAV_LIST_DESCRIPTION       = 1 << 7,
        E_WEBDAV_LIST_COLOR             = 1 << 8,
-       E_WEBDAV_LIST_ONLY_CALENDAR     = 1 << 9,
-       E_WEBDAV_LIST_ONLY_ADDRESSBOOK  = 1 << 10
+       E_WEBDAV_LIST_ORDER             = 1 << 9,
+       E_WEBDAV_LIST_ONLY_CALENDAR     = 1 << 28,
+       E_WEBDAV_LIST_ONLY_ADDRESSBOOK  = 1 << 29
 } EWebDAVListFlags;
 
 /**
diff --git a/src/libedataserverui/e-webdav-discover-widget.c b/src/libedataserverui/e-webdav-discover-widget.c
index dbb1d4a7e..7bbb7db99 100644
--- a/src/libedataserverui/e-webdav-discover-widget.c
+++ b/src/libedataserverui/e-webdav-discover-widget.c
@@ -62,6 +62,7 @@ enum {
        COL_SUPPORTS_STRING,
        COL_COLOR_GDKRGBA,
        COL_SHOW_COLOR_BOOLEAN,
+       COL_ORDER_UINT,
        N_COLUMNS
 };
 
@@ -151,7 +152,8 @@ e_webdav_discover_content_new (ECredentialsPrompter *credentials_prompter,
                                         G_TYPE_STRING, /* COL_DESCRIPTION_STRING */
                                         G_TYPE_STRING, /* COL_SUPPORTS_STRING */
                                         GDK_TYPE_RGBA, /* COL_COLOR_GDKRGBA */
-                                        G_TYPE_BOOLEAN); /* COL_SHOW_COLOR_BOOLEAN */
+                                        G_TYPE_BOOLEAN,/* COL_SHOW_COLOR_BOOLEAN */
+                                        G_TYPE_UINT);  /* COL_ORDER_UINT */
 
        tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
        g_object_unref (list_store);
@@ -359,6 +361,7 @@ e_webdav_discover_content_get_base_url (GtkWidget *content)
  * @out_display_name: (out): an output location of the sources display name
  * @out_color: (out): an output location of the string representation of the color
  *    for the source, as set on the server
+ * @out_order: (out): an output location of the preferred sorting order
  *
  * Returns information about selected source at index @index. The function can be called
  * multiple times, with the index starting at zero and as long as it doesn't return %FALSE.
@@ -377,7 +380,8 @@ e_webdav_discover_content_get_selected (GtkWidget *content,
                                        gchar **out_href,
                                        guint *out_supports,
                                        gchar **out_display_name,
-                                       gchar **out_color)
+                                       gchar **out_color,
+                                       guint *out_order)
 {
        EWebDAVDiscoverContent *self;
        GtkTreeSelection *selection;
@@ -413,6 +417,7 @@ e_webdav_discover_content_get_selected (GtkWidget *content,
                                        COL_SUPPORTS_UINT, out_supports,
                                        COL_DISPLAY_NAME_STRING, out_display_name,
                                        COL_COLOR_STRING, out_color,
+                                       COL_ORDER_UINT, out_order,
                                        -1);
                        }
                }
@@ -547,6 +552,7 @@ e_webdav_discover_content_fill_discovered_sources (GtkTreeView *tree_view,
                        COL_SUPPORTS_UINT, source->supports,
                        COL_DISPLAY_NAME_STRING, source->display_name,
                        COL_COLOR_STRING, colorstr,
+                       COL_ORDER_UINT, source->order,
                        COL_DESCRIPTION_STRING, description_markup,
                        COL_SUPPORTS_STRING, supports->str,
                        COL_COLOR_GDKRGBA, show_color ? &rgba : NULL,
diff --git a/src/libedataserverui/e-webdav-discover-widget.h b/src/libedataserverui/e-webdav-discover-widget.h
index 5d44d58df..5e91e9501 100644
--- a/src/libedataserverui/e-webdav-discover-widget.h
+++ b/src/libedataserverui/e-webdav-discover-widget.h
@@ -57,7 +57,8 @@ gboolean      e_webdav_discover_content_get_selected  (GtkWidget *content,
                                                         gchar **out_href,
                                                         guint *out_supports,
                                                         gchar **out_display_name,
-                                                        gchar **out_color);
+                                                        gchar **out_color,
+                                                        guint *out_order);
 gchar *                e_webdav_discover_content_get_user_address
                                                        (GtkWidget *content);
 void           e_webdav_discover_content_refresh       (GtkWidget *content,


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