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 ®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 }