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

No issues found

  1 /*
  2  * e-composer-autosave.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 <libebackend/libebackend.h>
 24 
 25 #include <libevolution-utils/e-alert-dialog.h>
 26 #include <composer/e-msg-composer.h>
 27 
 28 #include "e-autosave-utils.h"
 29 
 30 /* Standard GObject macros */
 31 #define E_TYPE_COMPOSER_AUTOSAVE \
 32 	(e_composer_autosave_get_type ())
 33 #define E_COMPOSER_AUTOSAVE(obj) \
 34 	(G_TYPE_CHECK_INSTANCE_CAST \
 35 	((obj), E_TYPE_COMPOSER_AUTOSAVE, EComposerAutosave))
 36 
 37 #define AUTOSAVE_INTERVAL	60 /* seconds */
 38 
 39 typedef struct _EComposerAutosave EComposerAutosave;
 40 typedef struct _EComposerAutosaveClass EComposerAutosaveClass;
 41 
 42 struct _EComposerAutosave {
 43 	EExtension parent;
 44 
 45 	GCancellable *cancellable;
 46 	guint timeout_id;
 47 
 48 	/* Composer contents have changed since
 49 	 * the last auto-save or explicit save. */
 50 	gboolean changed;
 51 
 52 	/* Prevent error dialogs from piling up. */
 53 	gboolean error_shown;
 54 };
 55 
 56 struct _EComposerAutosaveClass {
 57 	EExtensionClass parent_class;
 58 };
 59 
 60 /* Forward Declarations */
 61 GType e_composer_autosave_get_type (void);
 62 void e_composer_autosave_type_register (GTypeModule *type_module);
 63 
 64 G_DEFINE_DYNAMIC_TYPE (
 65 	EComposerAutosave,
 66 	e_composer_autosave,
 67 	E_TYPE_EXTENSION)
 68 
 69 static void
 70 composer_autosave_finished_cb (EMsgComposer *composer,
 71                                GAsyncResult *result,
 72                                EComposerAutosave *autosave)
 73 {
 74 	GFile *snapshot_file;
 75 	GError *error = NULL;
 76 
 77 	snapshot_file = e_composer_get_snapshot_file (composer);
 78 	e_composer_save_snapshot_finish (composer, result, &error);
 79 
 80 	/* Return silently if we were cancelled. */
 81 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 82 		g_error_free (error);
 83 
 84 	else if (error != NULL) {
 85 		gchar *basename;
 86 
 87 		if (G_IS_FILE (snapshot_file))
 88 			basename = g_file_get_basename (snapshot_file);
 89 		else
 90 			basename = g_strdup (" ");
 91 
 92 		/* Only show one error dialog at a time. */
 93 		if (!autosave->error_shown) {
 94 			autosave->error_shown = TRUE;
 95 			e_alert_run_dialog_for_args (
 96 				GTK_WINDOW (composer),
 97 				"mail-composer:no-autosave",
 98 				basename, error->message, NULL);
 99 			autosave->error_shown = FALSE;
100 		} else
101 			g_warning ("%s: %s", basename, error->message);
102 
103 		g_free (basename);
104 		g_error_free (error);
105 	}
106 
107 	g_object_unref (autosave);
108 }
109 
110 static gboolean
111 composer_autosave_timeout_cb (EComposerAutosave *autosave)
112 {
113 	EExtensible *extensible;
114 
115 	extensible = e_extension_get_extensible (E_EXTENSION (autosave));
116 
117 	/* User may have reverted or explicitly saved
118 	 * the changes since the timeout was scheduled. */
119 	if (autosave->changed) {
120 
121 		/* Cancel the previous snapshot if it's still in
122 		 * progress and start a new snapshot operation. */
123 		g_cancellable_cancel (autosave->cancellable);
124 		g_object_unref (autosave->cancellable);
125 		autosave->cancellable = g_cancellable_new ();
126 
127 		e_composer_save_snapshot (
128 			E_MSG_COMPOSER (extensible),
129 			autosave->cancellable,
130 			(GAsyncReadyCallback)
131 			composer_autosave_finished_cb,
132 			g_object_ref (autosave));
133 	}
134 
135 	autosave->timeout_id = 0;
136 	autosave->changed = FALSE;
137 
138 	return FALSE;
139 }
140 
141 static void
142 composer_autosave_changed_cb (EComposerAutosave *autosave)
143 {
144 	GtkhtmlEditor *editor;
145 	EExtensible *extensible;
146 
147 	extensible = e_extension_get_extensible (E_EXTENSION (autosave));
148 
149 	editor = GTKHTML_EDITOR (extensible);
150 	autosave->changed = gtkhtml_editor_get_changed (editor);
151 
152 	if (autosave->changed && autosave->timeout_id == 0)
153 		autosave->timeout_id = g_timeout_add_seconds (
154 			AUTOSAVE_INTERVAL, (GSourceFunc)
155 			composer_autosave_timeout_cb, autosave);
156 }
157 
158 static void
159 composer_autosave_dispose (GObject *object)
160 {
161 	EComposerAutosave *autosave;
162 	GObjectClass *parent_class;
163 
164 	autosave = E_COMPOSER_AUTOSAVE (object);
165 
166 	/* Cancel any snapshots in progress. */
167 	if (autosave->cancellable != NULL) {
168 		g_cancellable_cancel (autosave->cancellable);
169 		g_object_unref (autosave->cancellable);
170 		autosave->cancellable = NULL;
171 	}
172 
173 	if (autosave->timeout_id > 0) {
174 		g_source_remove (autosave->timeout_id);
175 		autosave->timeout_id = 0;
176 	}
177 
178 	/* Chain up to parent's dispose() method. */
179 	parent_class = G_OBJECT_CLASS (e_composer_autosave_parent_class);
180 	parent_class->dispose (object);
181 }
182 
183 static void
184 composer_autosave_constructed (GObject *object)
185 {
186 	EExtensible *extensible;
187 	GObjectClass *parent_class;
188 
189 	/* Chain up to parent's constructed() method. */
190 	parent_class = G_OBJECT_CLASS (e_composer_autosave_parent_class);
191 	parent_class->constructed (object);
192 
193 	extensible = e_extension_get_extensible (E_EXTENSION (object));
194 
195 	g_signal_connect_swapped (
196 		extensible, "notify::changed",
197 		G_CALLBACK (composer_autosave_changed_cb), object);
198 }
199 
200 static void
201 e_composer_autosave_class_init (EComposerAutosaveClass *class)
202 {
203 	GObjectClass *object_class;
204 	EExtensionClass *extension_class;
205 
206 	object_class = G_OBJECT_CLASS (class);
207 	object_class->dispose = composer_autosave_dispose;
208 	object_class->constructed = composer_autosave_constructed;
209 
210 	extension_class = E_EXTENSION_CLASS (class);
211 	extension_class->extensible_type = E_TYPE_MSG_COMPOSER;
212 }
213 
214 static void
215 e_composer_autosave_class_finalize (EComposerAutosaveClass *class)
216 {
217 }
218 
219 static void
220 e_composer_autosave_init (EComposerAutosave *autosave)
221 {
222 	autosave->cancellable = g_cancellable_new ();
223 }
224 
225 void
226 e_composer_autosave_type_register (GTypeModule *type_module)
227 {
228 	/* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
229 	 *     function, so we have to wrap it with a public function in
230 	 *     order to register types from a separate compilation unit. */
231 	e_composer_autosave_register_type (type_module);
232 }