No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Rodrigo Moya <rodrigo@novell.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 /* This is prototype code only, this may, or may not, use undocumented
24 * unstable or private internal function calls. */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <string.h>
31 #include <glib/gi18n.h>
32
33 #include <libevolution-utils/e-alert-dialog.h>
34 #include <e-util/e-plugin.h>
35
36 #include <shell/e-shell-sidebar.h>
37 #include <shell/e-shell-view.h>
38 #include <shell/e-shell-window.h>
39
40 #include "format-handler.h"
41
42 /* Plugin entry points */
43 gboolean calendar_save_as_init (GtkUIManager *ui_manager,
44 EShellView *shell_view);
45 gboolean memo_list_save_as_init (GtkUIManager *ui_manager,
46 EShellView *shell_view);
47 gboolean task_list_save_as_init (GtkUIManager *ui_manager,
48 EShellView *shell_view);
49
50 gint e_plugin_lib_enable (EPlugin *ep, gint enable);
51
52 gint
53 e_plugin_lib_enable (EPlugin *ep,
54 gint enable)
55 {
56 return 0;
57 }
58
59 enum { /* GtkComboBox enum */
60 DEST_NAME_COLUMN,
61 DEST_HANDLER,
62 N_DEST_COLUMNS
63
64 };
65
66 static void
67 extra_widget_foreach_hide (GtkWidget *widget,
68 gpointer data)
69 {
70 if (widget != data)
71 gtk_widget_hide (widget);
72 }
73
74 static void
75 on_type_combobox_changed (GtkComboBox *combobox,
76 gpointer data)
77 {
78 FormatHandler *handler = NULL;
79 GtkWidget *extra_widget = data;
80 GtkTreeIter iter;
81 GtkTreeModel *model = gtk_combo_box_get_model (combobox);
82
83 gtk_container_foreach (
84 GTK_CONTAINER (extra_widget),
85 extra_widget_foreach_hide,
86 g_object_get_data (G_OBJECT (combobox), "format-box"));
87
88 gtk_combo_box_get_active_iter (combobox, &iter);
89
90 gtk_tree_model_get (
91 model, &iter,
92 DEST_HANDLER, &handler, -1);
93
94 if (handler->options_widget)
95 {
96 gtk_widget_show (handler->options_widget);
97 }
98
99 }
100
101 static void
102 format_handlers_foreach_free (gpointer data,
103 gpointer user_data)
104 {
105 FormatHandler *handler = data;
106
107 if (handler->options_widget)
108 gtk_widget_destroy (handler->options_widget);
109
110 if (handler->data)
111 g_free (handler->data);
112
113 g_free (data);
114 }
115
116 static void
117 ask_destination_and_save (ESourceSelector *selector,
118 ECalClientSourceType type)
119 {
120 FormatHandler *handler = NULL;
121
122 GtkWidget *extra_widget = gtk_vbox_new (FALSE, 0);
123 GtkWidget *hbox = gtk_hbox_new (FALSE, 0);
124 GtkLabel *label = GTK_LABEL (gtk_label_new_with_mnemonic (_("_Format:")));
125 GtkComboBox *combo = GTK_COMBO_BOX (gtk_combo_box_new ());
126 GtkTreeModel *model = GTK_TREE_MODEL (gtk_list_store_new
127 (N_DEST_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER));
128 GtkCellRenderer *renderer = NULL;
129 GtkListStore *store = GTK_LIST_STORE (model);
130 GtkTreeIter iter;
131 GtkWidget *dialog = NULL;
132 gchar *dest_uri = NULL;
133
134 GList *format_handlers = NULL;
135
136 /* The available formathandlers */
137 format_handlers = g_list_append (format_handlers,
138 ical_format_handler_new ());
139 format_handlers = g_list_append (format_handlers,
140 csv_format_handler_new ());
141 format_handlers = g_list_append (format_handlers,
142 rdf_format_handler_new ());
143
144 gtk_box_pack_start (GTK_BOX (extra_widget), GTK_WIDGET (hbox), FALSE, FALSE, 0);
145 gtk_label_set_mnemonic_widget (label, GTK_WIDGET (combo));
146
147 gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (label), FALSE, FALSE, 0);
148
149 /* The Type GtkComboBox */
150 gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (combo), TRUE, TRUE, 0);
151 gtk_combo_box_set_model (combo, model);
152
153 gtk_list_store_clear (store);
154 renderer = gtk_cell_renderer_text_new ();
155 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
156 gtk_cell_layout_set_attributes (
157 GTK_CELL_LAYOUT (combo),
158 renderer, "text", DEST_NAME_COLUMN, NULL);
159
160 while (format_handlers) {
161 handler = format_handlers->data;
162 gtk_list_store_append (store, &iter);
163 gtk_list_store_set (
164 store, &iter, DEST_NAME_COLUMN,
165 handler->combo_label, -1);
166 gtk_list_store_set (store, &iter, DEST_HANDLER, handler, -1);
167
168 if (handler->options_widget) {
169 gtk_box_pack_start (
170 GTK_BOX (extra_widget),
171 GTK_WIDGET (handler->options_widget), TRUE, TRUE, 0);
172 gtk_widget_hide (handler->options_widget);
173 }
174
175 if (handler->isdefault) {
176 gtk_combo_box_set_active_iter (combo, &iter);
177 if (handler->options_widget)
178 gtk_widget_show (handler->options_widget);
179 }
180
181 format_handlers = g_list_next (format_handlers);
182 }
183
184 g_signal_connect (
185 combo, "changed",
186 G_CALLBACK (on_type_combobox_changed), extra_widget);
187 g_object_set_data (G_OBJECT (combo), "format-box", hbox);
188
189 dialog = gtk_file_chooser_dialog_new (
190 _("Select destination file"),
191 NULL,
192 GTK_FILE_CHOOSER_ACTION_SAVE,
193 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
194 GTK_STOCK_SAVE_AS, GTK_RESPONSE_OK,
195 NULL);
196
197 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
198 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), extra_widget);
199 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
200 gtk_widget_show (hbox);
201 gtk_widget_show (GTK_WIDGET (label));
202 gtk_widget_show (GTK_WIDGET (combo));
203 gtk_widget_show (extra_widget);
204
205 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
206 gchar *tmp = NULL;
207
208 gtk_combo_box_get_active_iter (combo, &iter);
209 gtk_tree_model_get (
210 model, &iter,
211 DEST_HANDLER, &handler, -1);
212
213 dest_uri = gtk_file_chooser_get_uri
214 (GTK_FILE_CHOOSER (dialog));
215
216 tmp = strstr (dest_uri, handler->filename_ext);
217
218 if (!(tmp && *(tmp + strlen (handler->filename_ext)) == '\0')) {
219
220 gchar *temp;
221 temp = g_strconcat (dest_uri, handler->filename_ext, NULL);
222 g_free (dest_uri);
223 dest_uri = temp;
224 }
225
226 handler->save (handler, selector, type, dest_uri);
227 }
228
229 /* Free the handlers */
230 g_list_foreach (format_handlers, format_handlers_foreach_free, NULL);
231 g_list_free (format_handlers);
232
233 /* Now we can destroy it */
234 gtk_widget_destroy (dialog);
235 g_free (dest_uri);
236
237 }
238
239 /* Returns output stream for the uri, or NULL on any error.
240 * When done with the stream, just g_output_stream_close and g_object_unref it.
241 * It will ask for overwrite if file already exists.
242 */
243 GOutputStream *
244 open_for_writing (GtkWindow *parent,
245 const gchar *uri,
246 GError **error)
247 {
248 GFile *file;
249 GFileOutputStream *fostream;
250 GError *err = NULL;
251
252 g_return_val_if_fail (uri != NULL, NULL);
253
254 file = g_file_new_for_uri (uri);
255
256 g_return_val_if_fail (file != NULL, NULL);
257
258 fostream = g_file_create (file, G_FILE_CREATE_NONE, NULL, &err);
259
260 if (err && err->code == G_IO_ERROR_EXISTS) {
261 gint response;
262 g_clear_error (&err);
263
264 response = e_alert_run_dialog_for_args (
265 parent, E_ALERT_ASK_FILE_EXISTS_OVERWRITE,
266 uri, NULL);
267 if (response == GTK_RESPONSE_OK) {
268 fostream = g_file_replace (
269 file, NULL, FALSE, G_FILE_CREATE_NONE,
270 NULL, &err);
271
272 if (err && fostream) {
273 g_object_unref (fostream);
274 fostream = NULL;
275 }
276 } else if (fostream) {
277 g_object_unref (fostream);
278 fostream = NULL;
279 }
280 }
281
282 g_object_unref (file);
283
284 if (error && err)
285 *error = err;
286 else if (err)
287 g_error_free (err);
288
289 if (fostream)
290 return G_OUTPUT_STREAM (fostream);
291
292 return NULL;
293 }
294
295 static void
296 save_general (EShellView *shell_view,
297 ECalClientSourceType type)
298 {
299 EShellSidebar *shell_sidebar;
300 ESourceSelector *selector = NULL;
301
302 shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
303 g_object_get (shell_sidebar, "selector", &selector, NULL);
304 g_return_if_fail (selector != NULL);
305
306 ask_destination_and_save (selector, type);
307
308 g_object_unref (selector);
309 }
310
311 static void
312 action_calendar_save_as_cb (GtkAction *action,
313 EShellView *shell_view)
314 {
315 save_general (shell_view, E_CAL_CLIENT_SOURCE_TYPE_EVENTS);
316 }
317
318 static void
319 action_memo_list_save_as_cb (GtkAction *action,
320 EShellView *shell_view)
321 {
322 save_general (shell_view, E_CAL_CLIENT_SOURCE_TYPE_MEMOS);
323 }
324
325 static void
326 action_task_list_save_as_cb (GtkAction *action,
327 EShellView *shell_view)
328 {
329 save_general (shell_view, E_CAL_CLIENT_SOURCE_TYPE_TASKS);
330 }
331
332 gboolean
333 calendar_save_as_init (GtkUIManager *ui_manager,
334 EShellView *shell_view)
335 {
336 EShellWindow *shell_window;
337 GtkActionGroup *action_group;
338 GtkAction *action;
339 const gchar *tooltip;
340 const gchar *stock_id;
341 const gchar *name;
342
343 shell_window = e_shell_view_get_shell_window (shell_view);
344
345 name = "calendar-save-as";
346 tooltip = _("Save the selected calendar to disk");
347 stock_id = GTK_STOCK_SAVE_AS;
348 action = gtk_action_new (name, NULL, tooltip, stock_id);
349
350 name = "lockdown-save-to-disk";
351 action_group = e_shell_window_get_action_group (shell_window, name);
352 gtk_action_group_add_action (action_group, action);
353
354 g_signal_connect (
355 action, "activate",
356 G_CALLBACK (action_calendar_save_as_cb), shell_view);
357
358 g_object_unref (action);
359
360 return TRUE;
361 }
362
363 gboolean
364 memo_list_save_as_init (GtkUIManager *ui_manager,
365 EShellView *shell_view)
366 {
367 EShellWindow *shell_window;
368 GtkActionGroup *action_group;
369 GtkAction *action;
370 const gchar *tooltip;
371 const gchar *stock_id;
372 const gchar *name;
373
374 shell_window = e_shell_view_get_shell_window (shell_view);
375
376 name = "memo-list-save-as";
377 tooltip = _("Save the selected memo list to disk");
378 stock_id = GTK_STOCK_SAVE_AS;
379 action = gtk_action_new (name, NULL, tooltip, stock_id);
380
381 name = "lockdown-save-to-disk";
382 action_group = e_shell_window_get_action_group (shell_window, name);
383 gtk_action_group_add_action (action_group, action);
384
385 g_signal_connect (
386 action, "activate",
387 G_CALLBACK (action_memo_list_save_as_cb), shell_view);
388
389 g_object_unref (action);
390
391 return TRUE;
392 }
393
394 gboolean
395 task_list_save_as_init (GtkUIManager *ui_manager,
396 EShellView *shell_view)
397 {
398 EShellWindow *shell_window;
399 GtkActionGroup *action_group;
400 GtkAction *action;
401 const gchar *tooltip;
402 const gchar *stock_id;
403 const gchar *name;
404
405 shell_window = e_shell_view_get_shell_window (shell_view);
406
407 name = "task-list-save-as";
408 tooltip = _("Save the selected task list to disk");
409 stock_id = GTK_STOCK_SAVE_AS;
410 action = gtk_action_new (name, NULL, tooltip, stock_id);
411
412 name = "lockdown-save-to-disk";
413 action_group = e_shell_window_get_action_group (shell_window, name);
414 gtk_action_group_add_action (action_group, action);
415
416 g_signal_connect (
417 action, "activate",
418 G_CALLBACK (action_task_list_save_as_cb), shell_view);
419
420 g_object_unref (action);
421
422 return TRUE;
423 }