aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2002-03-15 06:22:35 +0800
committerDan Winship <danw@src.gnome.org>2002-03-15 06:22:35 +0800
commit86b700d089bfb9565c3792ff3df1a1ac6cf225c3 (patch)
tree73a4b5104266850b756b8d9e6dbcefc17904f68a
parenteafda9ba48e7f29a9f98792a498eb9c568f81d59 (diff)
downloadgsoc2013-evolution-86b700d089bfb9565c3792ff3df1a1ac6cf225c3.tar.gz
gsoc2013-evolution-86b700d089bfb9565c3792ff3df1a1ac6cf225c3.tar.zst
gsoc2013-evolution-86b700d089bfb9565c3792ff3df1a1ac6cf225c3.zip
Support for delayed filling-in of storages/folders.
* Evolution-Storage.idl (StorageListener): add notifyHasSubfolders, to announce that a folder has currently- unknown subfolders. (Storage): add asyncOpenFolder, to request that previously- announced subfolders be filled in. * evolution-storage.c (impl_Storage_async_open_folder): emit OPEN_FOLDER. (evolution_storage_has_subfolders): Implement by calling notifyHasSubfolders on all of its listeners. * evolution-storage-listener.c (impl_GNOME_Evolution_StorageListener_notifyHasSubfolders): emit HAS_SUBFOLDERS. * e-corba-storage.c (impl_StorageListener_notifyHasSubfolders): Implement by calling e_storage_has_subfolders. (async_open_folder): Implement by calling asyncOpenFolder on the CORBA storage. * e-storage.c (EStoragePrivate, init, destroy): Keep a list of pseudofolders representing un-filled-in subtrees. (impl_async_open_folder): No-op default implementation (e_storage_async_open_folder): New function to request that un-filled-in subtrees be filled in. (e_storage_new_folder): If the new folder's parent has an "un-filled-in children" pseudofolder, remove it. (e_storage_has_subfolders): New function to note that a folder has unknown children. If the folder previously was marked as having real children, remove them, and emit CLOSE_FOLDER to reset it back to an a "unknown subfolders" state. * e-storage-set.c (make_full_path): Make this deal with path being "/", since that case gets used from storage_close_folder_cb sometimes. (storage_close_folder_cb): Proxy EStorage's CLOSE_FOLDER signal. (storage_set_view_folder_opened): Handle EStorageSetView's FOLDER_OPENED signal by calling e_storage_async_open_folder. * e-storage-set-view.c (etree_fill_in_children): If the given node is its parent's first child, emit FOLDER_OPENED for the parent. (close_folder_cb): Handler for EStorageSet's CLOSE_FOLDER signal. Ask the model to close that node. (e_storage_set_view_construct): Set the default expanded state for the tree to FALSE rather than TRUE, to prevent unwanted expansion of delayed nodes. (This only affects the very first time the tree is displayed anyway: after that its state is loaded off disk.) * e-shell.c (e_shell_construct): Register the "noselect" type with the folder type registry, so icon lookups on placeholder folders will work. svn path=/trunk/; revision=16169
-rw-r--r--shell/ChangeLog56
-rw-r--r--shell/Evolution-Storage.idl16
-rw-r--r--shell/e-corba-storage.c40
-rw-r--r--shell/e-shell.c5
-rw-r--r--shell/e-storage-set-view.c58
-rw-r--r--shell/e-storage-set-view.h2
-rw-r--r--shell/e-storage-set.c49
-rw-r--r--shell/e-storage-set.h1
-rw-r--r--shell/e-storage.c110
-rw-r--r--shell/e-storage.h7
-rw-r--r--shell/evolution-storage-listener.c26
-rw-r--r--shell/evolution-storage-listener.h3
-rw-r--r--shell/evolution-storage.c78
-rw-r--r--shell/evolution-storage.h6
14 files changed, 447 insertions, 10 deletions
diff --git a/shell/ChangeLog b/shell/ChangeLog
index c302cd1380..3b869920bd 100644
--- a/shell/ChangeLog
+++ b/shell/ChangeLog
@@ -1,3 +1,59 @@
+2002-03-14 Dan Winship <danw@ximian.com>
+
+ Support for delayed filling-in of storages/folders.
+
+ * Evolution-Storage.idl (StorageListener): add
+ notifyHasSubfolders, to announce that a folder has currently-
+ unknown subfolders.
+ (Storage): add asyncOpenFolder, to request that previously-
+ announced subfolders be filled in.
+
+ * evolution-storage.c (impl_Storage_async_open_folder): emit
+ OPEN_FOLDER.
+ (evolution_storage_has_subfolders): Implement by calling
+ notifyHasSubfolders on all of its listeners.
+
+ * evolution-storage-listener.c
+ (impl_GNOME_Evolution_StorageListener_notifyHasSubfolders): emit
+ HAS_SUBFOLDERS.
+
+ * e-corba-storage.c (impl_StorageListener_notifyHasSubfolders):
+ Implement by calling e_storage_has_subfolders.
+ (async_open_folder): Implement by calling asyncOpenFolder on the
+ CORBA storage.
+
+ * e-storage.c (EStoragePrivate, init, destroy): Keep a list of
+ pseudofolders representing un-filled-in subtrees.
+ (impl_async_open_folder): No-op default implementation
+ (e_storage_async_open_folder): New function to request that
+ un-filled-in subtrees be filled in.
+ (e_storage_new_folder): If the new folder's parent has an
+ "un-filled-in children" pseudofolder, remove it.
+ (e_storage_has_subfolders): New function to note that a folder has
+ unknown children. If the folder previously was marked as having
+ real children, remove them, and emit CLOSE_FOLDER to reset it back
+ to an a "unknown subfolders" state.
+
+ * e-storage-set.c (make_full_path): Make this deal with path being
+ "/", since that case gets used from storage_close_folder_cb
+ sometimes.
+ (storage_close_folder_cb): Proxy EStorage's CLOSE_FOLDER signal.
+ (storage_set_view_folder_opened): Handle EStorageSetView's
+ FOLDER_OPENED signal by calling e_storage_async_open_folder.
+
+ * e-storage-set-view.c (etree_fill_in_children): If the given node
+ is its parent's first child, emit FOLDER_OPENED for the parent.
+ (close_folder_cb): Handler for EStorageSet's CLOSE_FOLDER signal.
+ Ask the model to close that node.
+ (e_storage_set_view_construct): Set the default expanded state for
+ the tree to FALSE rather than TRUE, to prevent unwanted expansion
+ of delayed nodes. (This only affects the very first time the tree
+ is displayed anyway: after that its state is loaded off disk.)
+
+ * e-shell.c (e_shell_construct): Register the "noselect" type with
+ the folder type registry, so icon lookups on placeholder folders
+ will work.
+
2002-03-13 Ettore Perazzoli <ettore@ximian.com>
* e-shell-settings-dialog.c (load_pages): Use
diff --git a/shell/Evolution-Storage.idl b/shell/Evolution-Storage.idl
index 82e93f4d6f..f7d9ad1e7b 100644
--- a/shell/Evolution-Storage.idl
+++ b/shell/Evolution-Storage.idl
@@ -54,6 +54,8 @@ module Evolution {
in boolean remove_source,
in Bonobo::Listener listener);
+ void asyncOpenFolder (in string path);
+
void updateFolder (in string path,
in long unread_count);
@@ -72,15 +74,19 @@ module Evolution {
/* FIXME exceptions don't make much sense here... */
- void notifyFolderCreated (in string path,
- in Folder folder)
+ void notifyFolderCreated (in string path,
+ in Folder folder)
raises (Exists);
- void notifyFolderUpdated (in string path,
- in long unread_count)
+ void notifyFolderUpdated (in string path,
+ in long unread_count)
+ raises (NotFound);
+
+ void notifyFolderRemoved (in string path)
raises (NotFound);
- void notifyFolderRemoved (in string path)
+ void notifyHasSubfolders (in string path,
+ in string message)
raises (NotFound);
};
diff --git a/shell/e-corba-storage.c b/shell/e-corba-storage.c
index 28238b68d6..96a981b859 100644
--- a/shell/e-corba-storage.c
+++ b/shell/e-corba-storage.c
@@ -163,6 +163,27 @@ impl_StorageListener_notifyFolderRemoved (PortableServer_Servant servant,
NULL);
}
+static void
+impl_StorageListener_notifyHasSubfolders (PortableServer_Servant servant,
+ const CORBA_char *path,
+ const CORBA_char *message,
+ CORBA_Environment *ev)
+{
+ StorageListenerServant *storage_listener_servant;
+ EStorage *storage;
+
+ storage_listener_servant = (StorageListenerServant *) servant;
+ storage = storage_listener_servant->storage;
+
+ if (! e_storage_has_subfolders (storage, path, message)) {
+ g_warning ("Cannot register subfolder tree -- %s\n", path);
+ CORBA_exception_set (ev,
+ CORBA_USER_EXCEPTION,
+ ex_GNOME_Evolution_StorageListener_Exists,
+ NULL);
+ }
+}
+
static gboolean
setup_storage_listener (ECorbaStorage *corba_storage)
@@ -433,6 +454,23 @@ async_xfer_folder (EStorage *storage,
CORBA_exception_free (&ev);
}
+static void
+async_open_folder (EStorage *storage,
+ const char *path)
+{
+ ECorbaStorage *corba_storage;
+ ECorbaStoragePrivate *priv;
+ CORBA_Environment ev;
+
+ corba_storage = E_CORBA_STORAGE (storage);
+ priv = corba_storage->priv;
+
+ CORBA_exception_init (&ev);
+ GNOME_Evolution_Storage_asyncOpenFolder (priv->storage_interface,
+ path, &ev);
+ CORBA_exception_free (&ev);
+}
+
static void
corba_class_init (void)
@@ -450,6 +488,7 @@ corba_class_init (void)
epv->notifyFolderCreated = impl_StorageListener_notifyFolderCreated;
epv->notifyFolderUpdated = impl_StorageListener_notifyFolderUpdated;
epv->notifyFolderRemoved = impl_StorageListener_notifyFolderRemoved;
+ epv->notifyHasSubfolders = impl_StorageListener_notifyHasSubfolders;
vepv = &storage_listener_vepv;
vepv->_base_epv = base_epv;
@@ -469,6 +508,7 @@ class_init (ECorbaStorageClass *klass)
storage_class->async_create_folder = async_create_folder;
storage_class->async_remove_folder = async_remove_folder;
storage_class->async_xfer_folder = async_xfer_folder;
+ storage_class->async_open_folder = async_open_folder;
corba_class_init ();
diff --git a/shell/e-shell.c b/shell/e-shell.c
index 29340d41cd..ccab2004d5 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -1097,6 +1097,11 @@ e_shell_construct (EShell *shell,
priv->uri_schema_registry = e_uri_schema_registry_new ();
priv->storage_set = e_storage_set_new (priv->folder_type_registry);
+ e_folder_type_registry_register_type (priv->folder_type_registry,
+ "noselect", "empty.gif",
+ "noselect", "", FALSE,
+ 0, NULL, 0, NULL);
+
/* CORBA storages must be set up before the components, because otherwise components
cannot register their own storages. */
if (! setup_corba_storages (shell))
diff --git a/shell/e-storage-set-view.c b/shell/e-storage-set-view.c
index b6755370c4..7d88ff2897 100644
--- a/shell/e-storage-set-view.c
+++ b/shell/e-storage-set-view.c
@@ -101,6 +101,7 @@ struct _EStorageSetViewPrivate {
enum {
FOLDER_SELECTED,
+ FOLDER_OPENED,
DND_ACTION,
FOLDER_CONTEXT_MENU_POPPING_UP,
FOLDER_CONTEXT_MENU_POPPED_DOWN,
@@ -1474,6 +1475,27 @@ etree_value_at (ETreeModel *etree,
}
static void
+etree_fill_in_children (ETreeModel *etree,
+ ETreePath tree_path,
+ void *model_data)
+{
+ EStorageSetView *storage_set_view;
+ EStorageSet *storage_set;
+ ETreePath *parent;
+ char *path;
+
+ storage_set_view = E_STORAGE_SET_VIEW (model_data);
+ storage_set = storage_set_view->priv->storage_set;
+
+ parent = e_tree_model_node_get_parent (etree, tree_path);
+ path = (char *) e_tree_memory_node_get_data (E_TREE_MEMORY(etree), parent);
+ if (tree_path == e_tree_model_node_get_first_child (etree, parent)) {
+ gtk_signal_emit (GTK_OBJECT (storage_set_view),
+ signals[FOLDER_OPENED], path);
+ }
+}
+
+static void
etree_set_value_at (ETreeModel *etree,
ETreePath path,
int col,
@@ -1699,6 +1721,24 @@ removed_folder_cb (EStorageSet *storage_set,
e_tree_memory_node_remove (E_TREE_MEMORY(etree), node);
}
+static void
+close_folder_cb (EStorageSet *storage_set,
+ const char *path,
+ void *data)
+{
+ EStorageSetView *storage_set_view;
+ EStorageSetViewPrivate *priv;
+ ETreeModel *etree;
+ ETreePath node;
+
+ storage_set_view = E_STORAGE_SET_VIEW (data);
+ priv = storage_set_view->priv;
+ etree = priv->etree_model;
+
+ node = lookup_node_in_hash (storage_set_view, path);
+ e_tree_model_node_request_collapse (priv->etree_model, node);
+}
+
static void
class_init (EStorageSetViewClass *klass)
@@ -1733,6 +1773,15 @@ class_init (EStorageSetViewClass *klass)
GTK_TYPE_NONE, 1,
GTK_TYPE_STRING);
+ signals[FOLDER_OPENED]
+ = gtk_signal_new ("folder_opened",
+ GTK_RUN_FIRST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EStorageSetViewClass, folder_opened),
+ gtk_marshal_NONE__STRING,
+ GTK_TYPE_NONE, 1,
+ GTK_TYPE_STRING);
+
signals[DND_ACTION]
= gtk_signal_new ("dnd_action",
GTK_RUN_FIRST,
@@ -1969,7 +2018,7 @@ e_storage_set_view_construct (EStorageSetView *storage_set_view,
e_tree_memory_set_node_destroy_func (E_TREE_MEMORY (priv->etree_model),
etree_node_destroy_func, storage_set_view);
- e_tree_memory_set_expanded_default (E_TREE_MEMORY (priv->etree_model), TRUE);
+ e_tree_memory_set_expanded_default (E_TREE_MEMORY (priv->etree_model), FALSE);
priv->root_node = e_tree_memory_node_insert (E_TREE_MEMORY(priv->etree_model), NULL, -1,
g_strdup (ROOT_NODE_NAME));
@@ -2008,6 +2057,13 @@ e_storage_set_view_construct (EStorageSetView *storage_set_view,
gtk_signal_connect_while_alive (GTK_OBJECT (storage_set), "removed_folder",
GTK_SIGNAL_FUNC (removed_folder_cb), storage_set_view,
GTK_OBJECT (storage_set_view));
+ gtk_signal_connect_while_alive (GTK_OBJECT (storage_set), "close_folder",
+ GTK_SIGNAL_FUNC (close_folder_cb), storage_set_view,
+ GTK_OBJECT (storage_set_view));
+
+ gtk_signal_connect_while_alive (GTK_OBJECT (priv->etree_model), "fill_in_children",
+ GTK_SIGNAL_FUNC (etree_fill_in_children), storage_set_view,
+ GTK_OBJECT (storage_set_view));
insert_storages (storage_set_view);
}
diff --git a/shell/e-storage-set-view.h b/shell/e-storage-set-view.h
index 0cb2be8a3f..f0913a9558 100644
--- a/shell/e-storage-set-view.h
+++ b/shell/e-storage-set-view.h
@@ -56,6 +56,8 @@ struct _EStorageSetViewClass {
void (* folder_selected) (EStorageSetView *storage_set_view,
const char *path);
+ void (* folder_opened) (EStorageSetView *storage_set_view,
+ const char *path);
void (* dnd_action) (EStorageSetView *storage_set_view,
GdkDragContext *context,
diff --git a/shell/e-storage-set.c b/shell/e-storage-set.c
index bbe9f5a718..0eb7b48014 100644
--- a/shell/e-storage-set.c
+++ b/shell/e-storage-set.c
@@ -61,6 +61,7 @@ enum {
NEW_FOLDER,
UPDATED_FOLDER,
REMOVED_FOLDER,
+ CLOSE_FOLDER,
LAST_SIGNAL
};
@@ -153,7 +154,10 @@ make_full_path (EStorage *storage,
storage_name = e_storage_get_name (storage);
- if (! g_path_is_absolute (path))
+ if (strcmp (path, G_DIR_SEPARATOR_S) == 0)
+ full_path = g_strconcat (G_DIR_SEPARATOR_S, storage_name,
+ NULL);
+ else if (! g_path_is_absolute (path))
full_path = g_strconcat (G_DIR_SEPARATOR_S, storage_name,
G_DIR_SEPARATOR_S, path, NULL);
else
@@ -208,6 +212,21 @@ storage_removed_folder_cb (EStorage *storage,
g_free (full_path);
}
+static void
+storage_close_folder_cb (EStorage *storage,
+ const char *path,
+ void *data)
+{
+ EStorageSet *storage_set;
+ char *full_path;
+
+ storage_set = E_STORAGE_SET (data);
+
+ full_path = make_full_path (storage, path);
+ gtk_signal_emit (GTK_OBJECT (storage_set), signals[CLOSE_FOLDER], full_path);
+ g_free (full_path);
+}
+
static EStorage *
get_storage_for_path (EStorageSet *storage_set,
@@ -355,6 +374,14 @@ class_init (EStorageSetClass *klass)
gtk_marshal_NONE__STRING,
GTK_TYPE_NONE, 1,
GTK_TYPE_STRING);
+ signals[CLOSE_FOLDER] =
+ gtk_signal_new ("close_folder",
+ GTK_RUN_FIRST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EStorageSetClass, close_folder),
+ gtk_marshal_NONE__STRING,
+ GTK_TYPE_NONE, 1,
+ GTK_TYPE_STRING);
gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
}
@@ -456,6 +483,8 @@ e_storage_set_add_storage (EStorageSet *storage_set,
GTK_SIGNAL_FUNC (storage_updated_folder_cb), storage_set);
gtk_signal_connect (GTK_OBJECT (storage), "removed_folder",
GTK_SIGNAL_FUNC (storage_removed_folder_cb), storage_set);
+ gtk_signal_connect (GTK_OBJECT (storage), "close_folder",
+ GTK_SIGNAL_FUNC (storage_close_folder_cb), storage_set);
priv->storages = g_list_append (priv->storages, storage);
@@ -568,6 +597,21 @@ e_storage_set_get_folder (EStorageSet *storage_set,
}
+static void
+storage_set_view_folder_opened (EStorageSetView *storage_set_view,
+ const char *path,
+ EStorageSet *storage_set)
+{
+ EStorage *storage;
+ const char *subpath;
+
+ storage = get_storage_for_path (storage_set, path, &subpath);
+ if (storage == NULL)
+ return;
+
+ e_storage_async_open_folder (storage, subpath);
+}
+
GtkWidget *
e_storage_set_new_view (EStorageSet *storage_set, BonoboUIContainer *container)
{
@@ -577,6 +621,9 @@ e_storage_set_new_view (EStorageSet *storage_set, BonoboUIContainer *container)
g_return_val_if_fail (E_IS_STORAGE_SET (storage_set), NULL);
storage_set_view = e_storage_set_view_new (storage_set, container);
+ gtk_signal_connect (GTK_OBJECT (storage_set_view), "folder_opened",
+ GTK_SIGNAL_FUNC (storage_set_view_folder_opened),
+ storage_set);
return storage_set_view;
}
diff --git a/shell/e-storage-set.h b/shell/e-storage-set.h
index 16e717df16..6bfa1129e5 100644
--- a/shell/e-storage-set.h
+++ b/shell/e-storage-set.h
@@ -65,6 +65,7 @@ struct _EStorageSetClass {
void (* new_folder) (EStorageSet *storage_set, const char *path);
void (* updated_folder) (EStorageSet *storage_set, const char *path);
void (* removed_folder) (EStorageSet *storage_set, const char *path);
+ void (* close_folder) (EStorageSet *storage_set, const char *path);
};
diff --git a/shell/e-storage.c b/shell/e-storage.c
index 4efc069193..fa32203d7f 100644
--- a/shell/e-storage.c
+++ b/shell/e-storage.c
@@ -50,6 +50,9 @@ struct _EStoragePrivate {
/* The set of folders we have in this storage. */
EFolderTree *folder_tree;
+ /* The pseudofolders representing un-filled-in subtrees */
+ GHashTable *pseudofolders;
+
/* Internal name of the storage */
char *name;
};
@@ -58,6 +61,7 @@ enum {
NEW_FOLDER,
UPDATED_FOLDER,
REMOVED_FOLDER,
+ CLOSE_FOLDER,
LAST_SIGNAL
};
@@ -127,6 +131,13 @@ folder_changed_cb (EFolder *folder,
/* GtkObject methods. */
static void
+free_folder (gpointer path, gpointer folder, gpointer user_data)
+{
+ g_free (path);
+ /* folders will have been freed by e_folder_tree_destroy */
+}
+
+static void
destroy (GtkObject *object)
{
EStorage *storage;
@@ -137,6 +148,10 @@ destroy (GtkObject *object)
if (priv->folder_tree != NULL)
e_folder_tree_destroy (priv->folder_tree);
+ if (priv->pseudofolders) {
+ g_hash_table_foreach (priv->pseudofolders, free_folder, NULL);
+ g_hash_table_destroy (priv->pseudofolders);
+ }
g_free (priv->name);
@@ -208,6 +223,13 @@ impl_async_xfer_folder (EStorage *storage,
(* callback) (storage, E_STORAGE_NOTIMPLEMENTED, data);
}
+static void
+impl_async_open_folder (EStorage *storage,
+ const char *path)
+{
+ ;
+}
+
/* Initialization. */
@@ -227,6 +249,7 @@ class_init (EStorageClass *class)
class->async_create_folder = impl_async_create_folder;
class->async_remove_folder = impl_async_remove_folder;
class->async_xfer_folder = impl_async_xfer_folder;
+ class->async_open_folder = impl_async_open_folder;
signals[NEW_FOLDER] =
gtk_signal_new ("new_folder",
@@ -252,6 +275,14 @@ class_init (EStorageClass *class)
gtk_marshal_NONE__STRING,
GTK_TYPE_NONE, 1,
GTK_TYPE_STRING);
+ signals[CLOSE_FOLDER] =
+ gtk_signal_new ("close_folder",
+ GTK_RUN_FIRST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EStorageClass, close_folder),
+ gtk_marshal_NONE__STRING,
+ GTK_TYPE_NONE, 1,
+ GTK_TYPE_STRING);
gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
}
@@ -263,8 +294,9 @@ init (EStorage *storage)
priv = g_new (EStoragePrivate, 1);
- priv->folder_tree = e_folder_tree_new (folder_destroy_notify, NULL);
- priv->name = NULL;
+ priv->folder_tree = e_folder_tree_new (folder_destroy_notify, NULL);
+ priv->pseudofolders = g_hash_table_new (g_str_hash, g_str_equal);
+ priv->name = NULL;
storage->priv = priv;
}
@@ -429,6 +461,21 @@ e_storage_async_xfer_folder (EStorage *storage,
(* ES_CLASS (storage)->async_xfer_folder) (storage, source_path, destination_path, remove_source, callback, data);
}
+void
+e_storage_async_open_folder (EStorage *storage,
+ const char *path)
+{
+ g_return_if_fail (storage != NULL);
+ g_return_if_fail (E_IS_STORAGE (storage));
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (g_path_is_absolute (path));
+
+ if (g_hash_table_lookup (storage->priv->pseudofolders, path) == NULL)
+ return;
+
+ (* ES_CLASS (storage)->async_open_folder) (storage, path);
+}
+
const char *
e_storage_result_to_string (EStorageResult result)
@@ -546,6 +593,8 @@ e_storage_new_folder (EStorage *storage,
EFolder *e_folder)
{
EStoragePrivate *priv;
+ char *parent_path, *p;
+ gpointer stored_path, pseudofolder;
g_return_val_if_fail (storage != NULL, FALSE);
g_return_val_if_fail (E_IS_STORAGE (storage), FALSE);
@@ -559,6 +608,20 @@ e_storage_new_folder (EStorage *storage,
if (! e_folder_tree_add (priv->folder_tree, path, e_folder))
return FALSE;
+ p = strrchr (path, '/');
+ if (p && p != path)
+ parent_path = g_strndup (path, p - path);
+ else
+ parent_path = g_strdup ("/");
+ if (g_hash_table_lookup_extended (priv->pseudofolders, parent_path,
+ &stored_path, &pseudofolder) &&
+ pseudofolder != e_folder) {
+ g_hash_table_remove (priv->pseudofolders, parent_path);
+ g_free (stored_path);
+ e_storage_removed_folder (storage, e_folder_get_physical_uri (pseudofolder));
+ }
+ g_free (parent_path);
+
gtk_signal_connect_while_alive (GTK_OBJECT (e_folder), "changed", folder_changed_cb,
storage, GTK_OBJECT (storage));
@@ -570,6 +633,49 @@ e_storage_new_folder (EStorage *storage,
}
gboolean
+e_storage_has_subfolders (EStorage *storage,
+ const char *path,
+ const char *message)
+{
+ EStoragePrivate *priv;
+ GList *subfolders, *f;
+ EFolder *pseudofolder;
+ char *pseudofolder_path;
+
+ g_return_val_if_fail (storage != NULL, FALSE);
+ g_return_val_if_fail (E_IS_STORAGE (storage), FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+ g_return_val_if_fail (g_path_is_absolute (path), FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+
+ priv = storage->priv;
+
+ gtk_signal_emit (GTK_OBJECT (storage), signals[CLOSE_FOLDER], path);
+
+ if (g_hash_table_lookup (priv->pseudofolders, path))
+ return TRUE;
+
+ subfolders = e_folder_tree_get_subfolders (priv->folder_tree, path);
+ if (subfolders != NULL) {
+ for (f = subfolders; f; f = f->next)
+ e_storage_removed_folder (storage, f->data);
+ g_list_free (subfolders);
+ /* FIXME: close parent */
+ }
+
+ pseudofolder = e_folder_new (message, "noselect", "");
+ if (strcmp (path, "/") == 0)
+ pseudofolder_path = g_strdup_printf ("/%s", message);
+ else
+ pseudofolder_path = g_strdup_printf ("%s/%s", path, message);
+ e_folder_set_physical_uri (pseudofolder, pseudofolder_path);
+
+ g_hash_table_insert (priv->pseudofolders, g_strdup (path), pseudofolder);
+
+ return e_storage_new_folder (storage, pseudofolder_path, pseudofolder);
+}
+
+gboolean
e_storage_removed_folder (EStorage *storage,
const char *path)
{
diff --git a/shell/e-storage.h b/shell/e-storage.h
index 878aabeee5..0213653408 100644
--- a/shell/e-storage.h
+++ b/shell/e-storage.h
@@ -80,6 +80,7 @@ struct _EStorageClass {
void * (* new_folder) (EStorage *storage, const char *path);
void * (* updated_folder) (EStorage *storage, const char *path);
void * (* removed_folder) (EStorage *storage, const char *path);
+ void * (* close_folder) (EStorage *storage, const char *path);
/* Virtual methods. */
@@ -105,6 +106,9 @@ struct _EStorageClass {
const gboolean remove_source,
EStorageResultCallback callback,
void *data);
+
+ void (* async_open_folder) (EStorage *storage,
+ const char *path);
};
@@ -143,6 +147,8 @@ void e_storage_async_xfer_folder (EStorage *storage,
const gboolean remove_source,
EStorageResultCallback callback,
void *data);
+void e_storage_async_open_folder (EStorage *storage,
+ const char *path);
const char *e_storage_result_to_string (EStorageResult result);
@@ -153,6 +159,7 @@ char *e_storage_get_path_for_physical_uri (EStorage *storage,
/* Protected. C++ anyone? */
gboolean e_storage_new_folder (EStorage *storage, const char *path, EFolder *folder);
+gboolean e_storage_has_subfolders (EStorage *storage, const char *path, const char *message);
gboolean e_storage_removed_folder (EStorage *storage, const char *path);
#ifdef __cplusplus
diff --git a/shell/evolution-storage-listener.c b/shell/evolution-storage-listener.c
index ede46a2f2d..1f08f5fff8 100644
--- a/shell/evolution-storage-listener.c
+++ b/shell/evolution-storage-listener.c
@@ -45,6 +45,7 @@ enum {
NEW_FOLDER,
UPDATE_FOLDER,
REMOVED_FOLDER,
+ HAS_SUBFOLDERS,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
@@ -121,6 +122,21 @@ impl_GNOME_Evolution_StorageListener_notifyFolderRemoved (PortableServer_Servant
gtk_signal_emit (GTK_OBJECT (listener), signals[REMOVED_FOLDER], path);
}
+static void
+impl_GNOME_Evolution_StorageListener_notifyHasSubfolders (PortableServer_Servant servant,
+ const CORBA_char *path,
+ const CORBA_char *message,
+ CORBA_Environment *ev)
+{
+ EvolutionStorageListener *listener;
+ EvolutionStorageListenerPrivate *priv;
+
+ listener = gtk_object_from_servant (servant);
+ priv = listener->priv;
+
+ gtk_signal_emit (GTK_OBJECT (listener), signals[HAS_SUBFOLDERS], path, message);
+}
+
static EvolutionStorageListenerServant *
create_servant (EvolutionStorageListener *listener)
{
@@ -224,6 +240,7 @@ corba_class_init (void)
epv->notifyFolderCreated = impl_GNOME_Evolution_StorageListener_notifyFolderCreated;
epv->notifyFolderUpdated = impl_GNOME_Evolution_StorageListener_notifyFolderUpdated;
epv->notifyFolderRemoved = impl_GNOME_Evolution_StorageListener_notifyFolderRemoved;
+ epv->notifyHasSubfolders = impl_GNOME_Evolution_StorageListener_notifyHasSubfolders;
vepv = & my_GNOME_Evolution_StorageListener_vepv;
vepv->_base_epv = base_epv;
@@ -273,6 +290,15 @@ class_init (EvolutionStorageListenerClass *klass)
GTK_TYPE_NONE, 1,
GTK_TYPE_STRING);
+ signals[HAS_SUBFOLDERS] = gtk_signal_new ("has_subfolders",
+ GTK_RUN_FIRST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EvolutionStorageListenerClass, has_subfolders),
+ gtk_marshal_NONE__POINTER_POINTER,
+ GTK_TYPE_NONE, 2,
+ GTK_TYPE_STRING,
+ GTK_TYPE_STRING);
+
gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
corba_class_init ();
diff --git a/shell/evolution-storage-listener.h b/shell/evolution-storage-listener.h
index 5e13435411..8e9bee5df7 100644
--- a/shell/evolution-storage-listener.h
+++ b/shell/evolution-storage-listener.h
@@ -61,6 +61,9 @@ struct _EvolutionStorageListenerClass {
int unread_count);
void (* removed_folder) (EvolutionStorageListener *storage_listener,
const char *path);
+ void (* has_subfolders) (EvolutionStorageListener *storage_listener,
+ const char *path,
+ const char *message);
};
diff --git a/shell/evolution-storage.c b/shell/evolution-storage.c
index 313e4fb2a6..75d6935f1f 100644
--- a/shell/evolution-storage.c
+++ b/shell/evolution-storage.c
@@ -61,8 +61,9 @@ struct _EvolutionStoragePrivate {
enum {
CREATE_FOLDER,
REMOVE_FOLDER,
- UPDATE_FOLDER,
XFER_FOLDER,
+ UPDATE_FOLDER,
+ OPEN_FOLDER,
LAST_SIGNAL
};
@@ -354,6 +355,20 @@ impl_Storage_updateFolder (PortableServer_Servant servant,
}
static void
+impl_Storage_async_open_folder (PortableServer_Servant servant,
+ const CORBA_char *path,
+ CORBA_Environment *ev)
+{
+ BonoboObject *bonobo_object;
+ EvolutionStorage *storage;
+
+ bonobo_object = bonobo_object_from_servant (servant);
+ storage = EVOLUTION_STORAGE (bonobo_object);
+
+ gtk_signal_emit (GTK_OBJECT (storage), signals[OPEN_FOLDER], path);
+}
+
+static void
impl_Storage_add_listener (PortableServer_Servant servant,
const GNOME_Evolution_StorageListener listener,
CORBA_Environment *ev)
@@ -552,6 +567,15 @@ class_init (EvolutionStorageClass *klass)
GTK_TYPE_STRING,
GTK_TYPE_INT);
+ signals[OPEN_FOLDER] = gtk_signal_new ("open_folder",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EvolutionStorageClass,
+ open_folder),
+ gtk_marshal_NONE__POINTER,
+ GTK_TYPE_NONE, 1,
+ GTK_TYPE_STRING);
+
gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
corba_class_init ();
@@ -582,6 +606,7 @@ evolution_storage_get_epv (void)
epv->asyncCreateFolder = impl_Storage_async_create_folder;
epv->asyncRemoveFolder = impl_Storage_async_remove_folder;
epv->asyncXferFolder = impl_Storage_async_xfer_folder;
+ epv->asyncOpenFolder = impl_Storage_async_open_folder;
epv->updateFolder = impl_Storage_updateFolder;
epv->addListener = impl_Storage_add_listener;
epv->removeListener = impl_Storage_remove_listener;
@@ -1008,5 +1033,56 @@ evolution_storage_folder_exists (EvolutionStorage *evolution_storage,
return e_folder_tree_get_folder (priv->folder_tree, path) != NULL;
}
+EvolutionStorageResult
+evolution_storage_has_subfolders (EvolutionStorage *evolution_storage,
+ const char *path,
+ const char *message)
+{
+ EvolutionStorageResult result;
+ EvolutionStoragePrivate *priv;
+ CORBA_Environment ev;
+ GList *p;
+
+ g_return_val_if_fail (evolution_storage != NULL,
+ EVOLUTION_STORAGE_ERROR_INVALIDPARAMETER);
+ g_return_val_if_fail (EVOLUTION_IS_STORAGE (evolution_storage),
+ EVOLUTION_STORAGE_ERROR_INVALIDPARAMETER);
+ g_return_val_if_fail (path != NULL, EVOLUTION_STORAGE_ERROR_INVALIDPARAMETER);
+ g_return_val_if_fail (g_path_is_absolute (path), EVOLUTION_STORAGE_ERROR_INVALIDPARAMETER);
+ g_return_val_if_fail (message != NULL, EVOLUTION_STORAGE_ERROR_INVALIDPARAMETER);
+
+ priv = evolution_storage->priv;
+
+ if (priv->corba_storage_listeners == NULL)
+ return EVOLUTION_STORAGE_ERROR_NOTREGISTERED;
+
+ CORBA_exception_init (&ev);
+
+ result = EVOLUTION_STORAGE_OK;
+
+ for (p = priv->corba_storage_listeners; p != NULL; p = p->next) {
+ GNOME_Evolution_StorageListener listener;
+
+ listener = p->data;
+ GNOME_Evolution_StorageListener_notifyHasSubfolders (listener, path, message, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION)
+ continue;
+ if (ev._major != CORBA_USER_EXCEPTION)
+ result = EVOLUTION_STORAGE_ERROR_CORBA;
+ else if (strcmp (CORBA_exception_id (&ev), ex_GNOME_Evolution_StorageListener_NotFound) == 0)
+ result = EVOLUTION_STORAGE_ERROR_NOTFOUND;
+ else
+ result = EVOLUTION_STORAGE_ERROR_GENERIC;
+
+ break;
+ }
+
+ CORBA_exception_free (&ev);
+
+ return result;
+}
+
+
E_MAKE_TYPE (evolution_storage, "EvolutionStorage", EvolutionStorage, class_init, init, PARENT_TYPE)
diff --git a/shell/evolution-storage.h b/shell/evolution-storage.h
index aec35e15d8..c039a38e64 100644
--- a/shell/evolution-storage.h
+++ b/shell/evolution-storage.h
@@ -99,6 +99,9 @@ struct _EvolutionStorageClass {
const char *destination_path,
gboolean remove_source);
+ void (*open_folder) (EvolutionStorage *storage,
+ const char *path);
+
void (*update_folder) (EvolutionStorage *storage,
const char *path,
int unread_count);
@@ -139,6 +142,9 @@ EvolutionStorageResult evolution_storage_removed_folder (EvolutionStorage
const char *path);
gboolean evolution_storage_folder_exists (EvolutionStorage *evolution_storage,
const char *path);
+EvolutionStorageResult evolution_storage_has_subfolders (EvolutionStorage *evolution_storage,
+ const char *path,
+ const char *message);
#ifdef __cplusplus
}