file.c 8.01 KB
Newer Older
Arturo Espinosa's avatar
Arturo Espinosa committed
1
2
3
4
5
6
7
8
9
10
11
/*
 * file.c: File loading and saving routines
 *
 * Author:
 *   Miguel de Icaza (miguel@kernel.org)
 */
#include <config.h>
#include <gnome.h>
#include "gnumeric.h"
#include "dialogs.h"
#include "xml-io.h"
12
13
#include "file.h"

14
15
16
static GList *gnumeric_file_savers = NULL;
static GList *gnumeric_file_openers = NULL;
static FileSaver *current_saver = NULL;
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

static gint
file_priority_sort (gconstpointer a, gconstpointer b)
{
	FileOpener *fa = (FileOpener *)a;
	FileOpener *fb = (FileOpener *)b;

	return fb->priority - fa->priority;
}

/**
 * file_format_register_open:
 * @priority: The priority at which this file open handler is registered
 * @desc: a description of this file format
 * @probe_fn: A routine that would probe if the file is of a given type.
 * @open_fn: A routine that would load the code
 *
 * The priority is used to give it a higher precendence to a format.
 * The higher the priority, the sooner it will be tried, gnumeric registers
 * its XML-based format at priority 50.
 */
void
file_format_register_open (int priority, char *desc, FileFormatProbe probe_fn, FileFormatOpen open_fn)
{
	FileOpener *fo = g_new (FileOpener, 1);

	g_return_if_fail (probe_fn != NULL);
	g_return_if_fail (open_fn != NULL);
	
	fo->priority = priority;
	fo->format_description = desc;
	fo->probe = probe_fn;
	fo->open  = open_fn;

	gnumeric_file_openers = g_list_insert_sorted (gnumeric_file_openers, fo, file_priority_sort);
}

/**
 * file_format_unregister_open:
 * @probe: The routine that was used to probe
 * @open:  The routine that was used to open
 *
 * This function is used to remove a registered format opener from gnumeric
 */
void
file_format_unregister_open (FileFormatProbe probe, FileFormatOpen open)
{
	GList *l;

	for (l = gnumeric_file_openers; l; l = l->next){
		FileOpener *fo = l->data;

		if (fo->probe == probe && fo->open == open){
			gnumeric_file_openers = g_list_remove_link (gnumeric_file_openers, l);
			return;
		}
	}
}

/**
 * file_format_register_save:
 * @extension: An extension that is usually used by this format
 * @format_description: A description of this format
 * @save_fn: A function that should be used to save
 *
 * This routine registers a file format save routine with Gnumeric
 */
void
file_format_register_save (char *extension, char *format_description, FileFormatSave save_fn)
{
	FileSaver *fs = g_new (FileSaver, 1);

	g_return_if_fail (save_fn != NULL);
	
	fs->extension = extension;
	fs->format_description = format_description;
	fs->save = save_fn;

	gnumeric_file_savers = g_list_prepend (gnumeric_file_savers, fs);
}

/**
 * file_format_unregister_save:
 * @probe: The routine that was used to save
 *
 * This function is used to remove a registered format saver from gnumeric
 */
void
file_format_unregister_save (FileFormatSave save)
{
	GList *l;

	for (l = gnumeric_file_savers; l; l = l->next){
		FileSaver *fs = l->data;

		if (fs->save == save){
113
114
115
			if (fs == current_saver)
				current_saver = NULL;
			
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
			gnumeric_file_savers = g_list_remove_link (gnumeric_file_savers, l);
			return;
		}
	}
}

Workbook *
workbook_read (const char *filename)
{
	GList *l;

	g_return_val_if_fail (filename != NULL, NULL);

	for (l = gnumeric_file_openers; l; l = l->next){
		FileOpener *fo = l->data;
		Workbook *w;
		
		if ((*fo->probe) (filename)){
			w = (*fo->open) (filename);

			if (w)
				return w;
		}
	}
	return NULL;
}
Arturo Espinosa's avatar
Arturo Espinosa committed
142
143
144
145
146
147
148
149

static void
set_ok (GtkWidget *widget, gboolean *dialog_result)
{
	*dialog_result = TRUE;
	gtk_main_quit ();
}

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/**
 * saver_activate:
 *
 * Callback routine to choose the current file saver
 */
static void
saver_activate (GtkMenuItem *item, FileSaver *saver)
{
	GList *l;

	for (l = gnumeric_file_savers; l; l = l->next){
		FileSaver *fs = l->data;
		
		if (fs == saver)
			current_saver = saver;
	}
}

/**
 * file_saver_is_default_format:
 *
 * Returns TRUE if @saver is the default file save format
 */
static gboolean
file_saver_is_default_format (FileSaver *saver)
{
	if (current_saver == saver)
		return TRUE;

179
180
181
	if (strcmp (saver->extension, ".gnumeric") == 0){
		if (current_saver == NULL)
			current_saver = saver;
182
		return TRUE;
183
	}
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
	return FALSE;
}

static void
fill_save_menu (GtkOptionMenu *omenu, GtkMenu *menu)
{
	GList *l;
	int i;
	
	for (i = 0, l = gnumeric_file_savers; l; l = l->next, i++){
		GtkWidget *menu_item;
		FileSaver *fs = l->data;

		menu_item = gtk_menu_item_new_with_label (fs->format_description);
		gtk_widget_show (menu_item);
		
		gtk_menu_append (menu, menu_item);

		if (file_saver_is_default_format (fs))
			gtk_option_menu_set_history (omenu, i);

		gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
				    GTK_SIGNAL_FUNC(saver_activate), fs);
	}
}

static GtkWidget *
make_format_chooser (void)
{
	GtkWidget *box, *label;
	GtkWidget *omenu, *menu;

	box = gtk_hbox_new (0, GNOME_PAD);
	label = gtk_label_new (_("File format:"));
	omenu = gtk_option_menu_new ();
	menu = gtk_menu_new ();

	fill_save_menu (GTK_OPTION_MENU (omenu), GTK_MENU (menu));
	
	gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, GNOME_PAD);
	gtk_box_pack_start (GTK_BOX (box), omenu, FALSE, TRUE, GNOME_PAD);
	gtk_widget_show_all (box);

	gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
	
	return box;
}

232
233
234
235
236
237
238
239
240
241
242
static FileSaver *
insure_saver (FileSaver *current)
{
	GList *l;

	if (current)
		return current;

	for (l = gnumeric_file_savers; l; l = l->next){
		return l->data;
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
243
244
	g_assert_not_reached ();
	return NULL;
245
246
}

Arturo Espinosa's avatar
Arturo Espinosa committed
247
248
249
250
251
void
workbook_save_as (Workbook *wb)
{
	GtkFileSelection *fsel;
	gboolean accepted = FALSE;
252
	GtkWidget *format_selector;
Arturo Espinosa's avatar
Arturo Espinosa committed
253
254
255
256
	
	g_return_if_fail (wb != NULL);

	fsel = (GtkFileSelection *)gtk_file_selection_new (_("Save workbook as"));
257
	
258
	gtk_window_set_modal (GTK_WINDOW (fsel), TRUE);
Arturo Espinosa's avatar
Arturo Espinosa committed
259
260
	if (wb->filename)
		gtk_file_selection_set_filename (fsel, wb->filename);
261
262
263
264
265

	/* Choose the format */
	format_selector = make_format_chooser ();
	gtk_box_pack_start (GTK_BOX (fsel->action_area), format_selector,
			    FALSE, TRUE, 0);
266

Arturo Espinosa's avatar
Arturo Espinosa committed
267
268
269
270
271
272
	
	/* Connect the signals for Ok and Cancel */
	gtk_signal_connect (GTK_OBJECT (fsel->ok_button), "clicked",
			    GTK_SIGNAL_FUNC (set_ok), &accepted);
	gtk_signal_connect (GTK_OBJECT (fsel->cancel_button), "clicked",
			    GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
273
	gtk_window_set_position (GTK_WINDOW (fsel), GTK_WIN_POS_MOUSE);
Arturo Espinosa's avatar
Arturo Espinosa committed
274
275
276
277
278
279
280
281
282
283
	
	/* Run the dialog */
	gtk_widget_show (GTK_WIDGET (fsel));
	gtk_grab_add (GTK_WIDGET (fsel));
	gtk_main ();

	if (accepted){
		char *name = gtk_file_selection_get_filename (fsel);

		if (name [strlen (name)-1] != '/'){
Arturo Espinosa's avatar
Arturo Espinosa committed
284
285
			char *base = g_basename (name);
			
286
287
288
			current_saver = insure_saver (current_saver);
			if (!current_saver)
				gnumeric_notice (_("Sorry, there are no file savers loaded, I can not save"));
Arturo Espinosa's avatar
Arturo Espinosa committed
289
290
291
292
293
294
295
296
			else {
				if (strchr (base, '.') == NULL){
					name = g_strconcat (name, current_saver->extension, NULL);
				} else
					name = g_strdup (name);
				
				workbook_set_filename (wb, name);
				
297
				current_saver->save (wb, wb->filename);
Arturo Espinosa's avatar
Arturo Espinosa committed
298
299
300
				
				g_free (name);
			}
Arturo Espinosa's avatar
Arturo Espinosa committed
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
		}
	}
	gtk_widget_destroy (GTK_WIDGET (fsel));
}

void
workbook_save (Workbook *wb)
{
	g_return_if_fail (wb != NULL);
	
	if (!wb->filename){
		workbook_save_as (wb);
		return;
	}

	gnumericWriteXmlWorkbook (wb, wb->filename);
}

char *
320
dialog_query_load_file (Workbook *wb)
Arturo Espinosa's avatar
Arturo Espinosa committed
321
322
323
324
325
326
{
	GtkFileSelection *fsel;
	gboolean accepted;
	char *result;
	
	fsel = (GtkFileSelection *) gtk_file_selection_new (_("Load file"));
327
	gtk_window_set_modal (GTK_WINDOW (fsel), TRUE);
Arturo Espinosa's avatar
Arturo Espinosa committed
328

329
330
	gtk_window_set_transient_for (GTK_WINDOW (fsel), GTK_WINDOW (wb->toplevel));
	
Arturo Espinosa's avatar
Arturo Espinosa committed
331
332
333
334
335
	/* Connect the signals for Ok and Cancel */
	gtk_signal_connect (GTK_OBJECT (fsel->ok_button), "clicked",
			    GTK_SIGNAL_FUNC (set_ok), &accepted);
	gtk_signal_connect (GTK_OBJECT (fsel->cancel_button), "clicked",
			    GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
336
	gtk_window_set_position (GTK_WINDOW (fsel), GTK_WIN_POS_MOUSE);
Arturo Espinosa's avatar
Arturo Espinosa committed
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356

	/* Run the dialog */
	gtk_widget_show (GTK_WIDGET (fsel));
	gtk_grab_add (GTK_WIDGET (fsel));
	gtk_main ();

	if (accepted){
		char *name = gtk_file_selection_get_filename (fsel);

		if (name [strlen (name)-1] == '/')
			result = NULL;
		else
			result = g_strdup (name);
	} else
		result = NULL;

	gtk_widget_destroy (GTK_WIDGET (fsel));

	return result;
}