evolution-3.6.4/modules/composer-autosave/e-composer-registry.c

No issues found

  1 /*
  2  * e-composer-registry.c
  3  *
  4  * This program is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) version 3.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 16  *
 17  */
 18 
 19 #ifdef HAVE_CONFIG_H
 20 #include <config.h>
 21 #endif
 22 
 23 #include <glib/gstdio.h>
 24 #include <libebackend/libebackend.h>
 25 
 26 #include <shell/e-shell.h>
 27 #include <shell/e-shell-window.h>
 28 #include <libevolution-utils/e-alert-dialog.h>
 29 #include <composer/e-msg-composer.h>
 30 
 31 #include "e-autosave-utils.h"
 32 
 33 /* Standard GObject macros */
 34 #define E_TYPE_COMPOSER_REGISTRY \
 35 	(e_composer_registry_get_type ())
 36 #define E_COMPOSER_REGISTRY(obj) \
 37 	(G_TYPE_CHECK_INSTANCE_CAST \
 38 	((obj), E_TYPE_COMPOSER_REGISTRY, EComposerRegistry))
 39 
 40 typedef struct _EComposerRegistry EComposerRegistry;
 41 typedef struct _EComposerRegistryClass EComposerRegistryClass;
 42 
 43 struct _EComposerRegistry {
 44 	EExtension parent;
 45 	GQueue composers;
 46 	gboolean orphans_restored;
 47 };
 48 
 49 struct _EComposerRegistryClass {
 50 	EExtensionClass parent_class;
 51 };
 52 
 53 /* Forward Declarations */
 54 GType e_composer_registry_get_type (void);
 55 void e_composer_registry_type_register (GTypeModule *type_module);
 56 
 57 G_DEFINE_DYNAMIC_TYPE (
 58 	EComposerRegistry,
 59 	e_composer_registry,
 60 	E_TYPE_EXTENSION)
 61 
 62 static void
 63 composer_registry_recovered_cb (EShell *shell,
 64                                 GAsyncResult *result,
 65                                 EComposerRegistry *registry)
 66 {
 67 	EMsgComposer *composer;
 68 	GError *error = NULL;
 69 
 70 	composer = e_composer_load_snapshot_finish (shell, result, &error);
 71 
 72 	if (error != NULL) {
 73 		/* FIXME Show an alert dialog here explaining
 74 		 *       why we could not recover the message.
 75 		 *       Will need a new error XML entry. */
 76 		g_warn_if_fail (composer == NULL);
 77 		g_warning ("%s", error->message);
 78 		g_error_free (error);
 79 		goto exit;
 80 	}
 81 
 82 	gtk_widget_show (GTK_WIDGET (composer));
 83 
 84 	g_object_unref (composer);
 85 
 86 exit:
 87 	g_object_unref (registry);
 88 }
 89 
 90 static gboolean
 91 composer_registry_map_event_cb (GtkWindow *parent,
 92                                 GdkEvent *event,
 93                                 EComposerRegistry *registry)
 94 {
 95 	EExtensible *extensible;
 96 	GList *orphans;
 97 	gint response;
 98 	GError *error = NULL;
 99 
100 	extensible = e_extension_get_extensible (E_EXTENSION (registry));
101 
102 	/* Look for orphaned auto-save files. */
103 	orphans = e_composer_find_orphans (
104 		&registry->composers, &error);
105 	if (orphans == NULL) {
106 		if (error != NULL) {
107 			g_warning ("%s", error->message);
108 			g_error_free (error);
109 		}
110 		goto exit;
111 	}
112 
113 	/* Ask if the user wants to recover the orphaned files. */
114 	response = e_alert_run_dialog_for_args (
115 		parent, "mail-composer:recover-autosave", NULL);
116 
117 	/* Based on the user's reponse, recover or delete them. */
118 	while (orphans != NULL) {
119 		GFile *file = orphans->data;
120 
121 		if (response == GTK_RESPONSE_YES)
122 			e_composer_load_snapshot (
123 				E_SHELL (extensible),
124 				file, NULL, (GAsyncReadyCallback)
125 				composer_registry_recovered_cb,
126 				g_object_ref (registry));
127 		else
128 			g_file_delete (file, NULL, NULL);
129 
130 		g_object_unref (file);
131 
132 		orphans = g_list_delete_link (orphans, orphans);
133 	}
134 
135 exit:
136 	registry->orphans_restored = TRUE;
137 
138 	return FALSE;
139 }
140 
141 static void
142 composer_registry_notify_cb (EComposerRegistry *registry,
143                              GObject *where_the_object_was)
144 {
145 	/* Remove the finalized composer from the registry. */
146 	g_queue_remove (&registry->composers, where_the_object_was);
147 
148 	g_object_unref (registry);
149 }
150 
151 static void
152 composer_registry_window_added_cb (GtkApplication *application,
153                                    GtkWindow *window,
154                                    EComposerRegistry *registry)
155 {
156 	/* Offer to restore any orphaned auto-save files from the
157 	 * previous session once the first EShellWindow is mapped. */
158 	if (E_IS_SHELL_WINDOW (window) && !registry->orphans_restored)
159 		g_signal_connect (
160 			window, "map-event",
161 			G_CALLBACK (composer_registry_map_event_cb),
162 			registry);
163 
164 	/* Track the new composer window. */
165 	else if (E_IS_MSG_COMPOSER (window)) {
166 		g_queue_push_tail (&registry->composers, window);
167 		g_object_weak_ref (
168 			G_OBJECT (window), (GWeakNotify)
169 			composer_registry_notify_cb,
170 			g_object_ref (registry));
171 	}
172 }
173 
174 static void
175 composer_registry_finalize (GObject *object)
176 {
177 	GObjectClass *parent_class;
178 	EComposerRegistry *registry;
179 
180 	registry = E_COMPOSER_REGISTRY (object);
181 
182 	/* All composers should have been finalized by now. */
183 	g_warn_if_fail (g_queue_is_empty (&registry->composers));
184 
185 	/* Chain up to parent's finalize() method. */
186 	parent_class = G_OBJECT_CLASS (e_composer_registry_parent_class);
187 	parent_class->finalize (object);
188 }
189 
190 static void
191 composer_registry_constructed (GObject *object)
192 {
193 	EExtensible *extensible;
194 	GObjectClass *parent_class;
195 
196 	/* Chain up to parent's constructed() method. */
197 	parent_class = G_OBJECT_CLASS (e_composer_registry_parent_class);
198 	parent_class->constructed (object);
199 
200 	extensible = e_extension_get_extensible (E_EXTENSION (object));
201 
202 	/* Listen for new watched windows. */
203 	g_signal_connect (
204 		extensible, "window-added",
205 		G_CALLBACK (composer_registry_window_added_cb),
206 		object);
207 }
208 
209 static void
210 e_composer_registry_class_init (EComposerRegistryClass *class)
211 {
212 	GObjectClass *object_class;
213 	EExtensionClass *extension_class;
214 
215 	object_class = G_OBJECT_CLASS (class);
216 	object_class->finalize = composer_registry_finalize;
217 	object_class->constructed = composer_registry_constructed;
218 
219 	extension_class = E_EXTENSION_CLASS (class);
220 	extension_class->extensible_type = E_TYPE_SHELL;
221 }
222 
223 static void
224 e_composer_registry_class_finalize (EComposerRegistryClass *class)
225 {
226 }
227 
228 static void
229 e_composer_registry_init (EComposerRegistry *registry)
230 {
231 	g_queue_init (&registry->composers);
232 }
233 
234 void
235 e_composer_registry_type_register (GTypeModule *type_module)
236 {
237 	/* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
238 	 *     function, so we have to wrap it with a public function in
239 	 *     order to register types from a separate compilation unit. */
240 	e_composer_registry_register_type (type_module);
241 }