gnumeric.c 10.7 KB
Newer Older
1
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
Morten Welinder's avatar
Morten Welinder committed
2
/*
3 4 5
 * Gnumeric GOffice component
 * gnumeric.c
 *
6
 * Copyright (C) 2006-2010
7 8 9
 *
 * Developed by Jean Bréfort <jean.brefort@normalesup.org>
 *
Morten Welinder's avatar
Morten Welinder committed
10 11
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
12 13 14 15 16 17 18 19 20
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, see <https://www.gnu.org/licenses/>
22
 */
23

24
#include <gnumeric-config.h>
Jean Bréfort's avatar
Jean Bréfort committed
25
#include <application.h>
26
#include <gnumeric.h>
27
#include <gnm-plugin.h>
28
#include <gnumeric-conf.h>
29
#include <gui-file.h>
30
#include <gui-util.h>
31
#include <gutils.h>
32
#include <print-cell.h>
33
#include <print.h>
34
#include <ranges.h>
35
#include <selection.h>
36
#include <sheet.h>
37 38 39
#include <wbc-gtk-impl.h>
#include <workbook-view.h>
#include <workbook.h>
40

41
#include <goffice/goffice.h>
42 43 44 45 46 47 48 49 50 51
#include <goffice/component/goffice-component.h>
#include <goffice/component/go-component-factory.h>
#include <goffice/component/go-component.h>
#include <goffice/app/module-plugin-defs.h>
#include <gsf/gsf-impl-utils.h>
#include <gsf/gsf-input-memory.h>
#include <gsf/gsf-output-memory.h>


#include <glib/gi18n-lib.h>
52 53
#include <cairo.h>
#include <pango/pangocairo.h>
54 55

GOPluginModuleDepend const go_plugin_depends [] = {
56
	{ "goffice", GOFFICE_API_VERSION }
57 58 59 60 61 62 63
};
GOPluginModuleHeader const go_plugin_header =
	{ GOFFICE_MODULE_PLUGIN_MAGIC_NUMBER, G_N_ELEMENTS (go_plugin_depends) };

G_MODULE_EXPORT void go_plugin_init (GOPlugin *plugin, GOCmdContext *cc);
G_MODULE_EXPORT void go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc);

64
typedef struct {
65 66
	GOComponent parent;

Jody Goldberg's avatar
Jody Goldberg committed
67
	WorkbookView	*wv;
68
	Workbook	*wb;
69
	WBCGtk		*edited;
Jody Goldberg's avatar
Jody Goldberg committed
70
	Sheet		*sheet;
71
	int col_start, col_end, row_start, row_end;
72 73 74 75 76
	int width, height;
} GOGnmComponent;

typedef GOComponentClass GOGnmComponentClass;

77 78 79
#define GO_TYPE_GNM_COMPONENT	(go_gnm_component_get_type ())
#define GO_GNM_COMPONENT(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GO_TYPE_GNM_COMPONENT, GOGnmComponent))
#define GO_IS_GNM_COMPONENT(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GO_TYPE_GNM_COMPONENT))
80 81 82 83 84 85 86 87 88 89

GType go_gnm_component_get_type (void);

static GObjectClass *gognm_parent_klass;

static gboolean
go_gnm_component_get_data (GOComponent *component, gpointer *data, int *length,
									void (**clearfunc) (gpointer), gpointer *user_data)
{
	GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
90
	if (gognm->wv) {
91
		GOCmdContext *cc = go_component_get_command_context (component);
92
		GOIOContext *io_context = go_io_context_new (cc);
93
		GsfOutput *output = gsf_output_memory_new ();
94
		GOFileSaver *gfs = workbook_get_file_saver (gognm->wb);
95 96
		if (gfs == NULL)
			gfs = go_file_saver_get_default ();
97 98
		workbook_view_save_to_output (gognm->wv, gfs, output,
					      io_context);
99 100 101 102
		*data = (gpointer) gsf_output_memory_get_bytes (GSF_OUTPUT_MEMORY (output));
		*length = gsf_output_size (output);
		*clearfunc = g_object_unref;
		*user_data = output;
103
		g_object_unref (io_context);
104 105 106 107 108 109
		return TRUE;
	}
	return FALSE;
}

static void
110
go_gnm_component_update_data (GOGnmComponent *gognm)
111
{
112 113 114 115 116 117 118 119 120
	SheetView *sv;
	GnmRange const *range;
	gognm->sheet = wb_view_cur_sheet (gognm->wv);
	sv = sheet_get_view (gognm->sheet, gognm->wv);
	range = selection_first_range (sv, NULL, NULL);
	gognm->col_start = range->start.col;
	gognm->row_start = range->start.row;
	gognm->col_end = range->end.col;
	gognm->row_end = range->end.row;
121
	gognm->width = sheet_col_get_distance_pts (
122
		gognm->sheet, gognm->col_start, gognm->col_end + 1);
123 124
	gognm->parent.width = gognm->width / 72.;
	gognm->parent.descent = 0.;
125
	gognm->height = sheet_row_get_distance_pts (
126
		gognm->sheet, gognm->row_start, gognm->row_end + 1);
127 128 129 130 131 132 133
	gognm->parent.ascent = gognm->parent.height = gognm->height  / 72.;
}

static void
go_gnm_component_set_data (GOComponent *component)
{
	GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
134
	GOCmdContext *cc = go_component_get_command_context (component);
135 136 137 138 139 140 141 142
	GOIOContext *io_context = go_io_context_new (cc);
	GsfInput *input = gsf_input_memory_new (component->data, component->length, FALSE);

	g_object_set (G_OBJECT (io_context), "exec-main-loop", FALSE, NULL);
	if (gognm->wv != NULL) {
		g_object_unref (gognm->wv);
		g_object_unref (gognm->wb);
	}
143
	gognm->wv = workbook_view_new_from_input (input, NULL, NULL, io_context, NULL);
144
	gognm->wb = wb_view_get_workbook (gognm->wv);
Jean Bréfort's avatar
Jean Bréfort committed
145
	gnm_app_workbook_list_remove (gognm->wb);
146 147
	g_object_unref (io_context);
	go_gnm_component_update_data (gognm);
148 149 150
}

static void
151
go_gnm_component_render (GOComponent *component, cairo_t *cr, double width_pixels, double height_pixels)
152 153
{
	GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
Jean Bréfort's avatar
Jean Bréfort committed
154
	GnmRange range;
155

156 157 158
	if (!gognm->sheet)
		go_gnm_component_update_data (gognm);

159
	range_init (&range, gognm->col_start, gognm->row_start, gognm->col_end, gognm->row_end);
160 161
	cairo_save (cr);
	cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
162
	cairo_scale (cr, ((double) width_pixels) / gognm->width, ((double) height_pixels) / gognm->height);
163 164
	cairo_rectangle (cr, 0., 0., gognm->width, gognm->height);
	cairo_clip (cr); /* not sure it is necessary */
165
	gnm_gtk_print_cell_range (cr, gognm->sheet, &range, 0., 0.,
166
				  gognm->sheet->print_info);
167
	/* Now render objects */
168 169
	gnm_print_sheet_objects (cr, gognm->sheet, &range, 0., 0.);
	cairo_restore (cr);
170
}
171

172
static void
173
cb_gognm_save (G_GNUC_UNUSED GtkAction *a, WBCGtk *wbcg)
174
{
175 176 177
	gpointer data = g_object_get_data (G_OBJECT (wbcg), "component");
	if (GO_IS_COMPONENT (data)) {
		GOComponent *component = GO_COMPONENT (data);
178 179
		/* update the component data since not all clients will call set_data */
		GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
Morten Welinder's avatar
Morten Welinder committed
180
		WorkbookView *wv = wb_control_view (GNM_WBC (wbcg));
181 182 183 184 185 186
		if (wv != gognm->wv) {
			if (gognm->wv != NULL) {
				g_object_unref (gognm->wv);
				g_object_unref (gognm->wb);
			}
			gognm->wv = g_object_ref (wv);
Jean Bréfort's avatar
Jean Bréfort committed
187 188
			gognm->wb = wb_view_get_workbook (wv);
			gnm_app_workbook_list_remove (gognm->wb); /* no need to have this one in the list */
189 190 191
		}
		go_doc_set_dirty (GO_DOC (gognm->wb), FALSE);
		go_gnm_component_update_data (gognm);
192 193
		go_component_emit_changed (component);
	} else
Morten Welinder's avatar
Morten Welinder committed
194
		gui_file_save (wbcg, wb_control_view (GNM_WBC (wbcg)));
195 196 197 198
}

static GtkActionEntry const actions[] = {
/* File */
199
	{ "FileSaveEmbed", GNM_N_STOCK_SAVE, NULL,
200
		NULL, N_("Save the embedded workbook"),
201
		G_CALLBACK (cb_gognm_save) }
202 203 204
};

static void
Jody Goldberg's avatar
Jody Goldberg committed
205
cb_editor_destroyed (GOGnmComponent *gognm)
206
{
207 208
	if (gognm->edited && G_OBJECT (gognm->edited)->ref_count > 0)
		g_object_unref (gognm->edited);
209 210 211
	gognm->edited = NULL;
}

212
static GtkWindow*
213 214 215 216 217
go_gnm_component_edit (GOComponent *component)
{
	GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
	WorkbookView *wv;
	if (gognm->edited) {
218 219
		gdk_window_raise (gtk_widget_get_parent_window (GTK_WIDGET (wbcg_toplevel (gognm->edited))));
		return wbcg_toplevel (gognm->edited);
220 221 222 223 224 225 226
	}
	if (!gognm->wv) {
		component->ascent = 0.;
		component->descent = 0.;
		component->width = 0.;
		wv = workbook_view_new (workbook_new_with_sheets (1));
	} else {
227
		GOCmdContext *cc = go_component_get_command_context (component);
228
		GOIOContext *io_context = GO_IS_IO_CONTEXT (cc)? GO_IO_CONTEXT (g_object_ref (cc)): go_io_context_new (cc);
229
		GsfInput *input = gsf_input_memory_new (component->data, component->length, FALSE);
230

231
		g_object_set (G_OBJECT (io_context), "exec-main-loop", FALSE, NULL);
232
		wv = workbook_view_new_from_input (input, NULL, NULL, io_context, NULL);
233 234
		g_object_unref (io_context);
	}
235
	set_uifilename ("Gnumeric-embed.xml", actions, G_N_ELEMENTS (actions));
236
	gognm->edited = wbc_gtk_new (wv, NULL, NULL, NULL);
Jody Goldberg's avatar
Jody Goldberg committed
237

238 239
	g_object_set_data (G_OBJECT (gognm->edited), "component", gognm);
	g_signal_connect_swapped (gognm->edited->toplevel, "destroy",
Jody Goldberg's avatar
Jody Goldberg committed
240
		G_CALLBACK (cb_editor_destroyed), gognm);
241
	return wbcg_toplevel (gognm->edited);
242 243 244 245 246 247 248 249
}

static void
go_gnm_component_finalize (GObject *obj)
{
	GOGnmComponent *gognm = GO_GNM_COMPONENT (obj);
	if (gognm->wv != NULL) {
		g_object_unref (gognm->wv);
250
		g_object_unref (gognm->wb);
251 252 253
		gognm->wv = NULL;
	}
	if (gognm->edited != NULL) {
Morten Welinder's avatar
Morten Welinder committed
254
		g_object_unref (wb_control_view (GNM_WBC (gognm->edited)));
255 256 257 258 259 260 261 262 263 264 265
		gognm->edited = NULL;
	}
	G_OBJECT_CLASS (gognm_parent_klass)->finalize (obj);
}

static void
go_gnm_component_init (GOComponent *component)
{
	GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
	component->resizable = FALSE;
	component->editable = TRUE;
266
	component->snapshot_type = GO_SNAPSHOT_SVG;
267 268
	gognm->row_start = gognm->col_start = 0;
	gognm->sheet = NULL;
269 270 271 272 273 274 275 276 277 278 279 280 281 282
	gognm->row_end = 9;
	gognm->col_end = 4;
}

static void
go_gnm_component_class_init (GOComponentClass *klass)
{
	GObjectClass *obj_klass = (GObjectClass *) klass;
	obj_klass->finalize = go_gnm_component_finalize;

	gognm_parent_klass = (GObjectClass*) g_type_class_peek_parent (klass);

	klass->get_data = go_gnm_component_get_data;
	klass->set_data = go_gnm_component_set_data;
283
	klass->render = go_gnm_component_render;
284 285 286 287 288
	klass->edit = go_gnm_component_edit;
}

GSF_DYNAMIC_CLASS (GOGnmComponent, go_gnm_component,
	go_gnm_component_class_init, go_gnm_component_init,
289
	GO_TYPE_COMPONENT)
290 291 292 293

/*************************************************************************************/

G_MODULE_EXPORT void
294
go_plugin_init (GOPlugin *plugin, G_GNUC_UNUSED GOCmdContext *cc)
295 296 297 298
{
	GTypeModule *module;
	char const *env_var;
	GSList *dir_list;
299 300
	const char *usr_dir = gnm_usr_dir (TRUE);

301 302
	bindtextdomain (GETTEXT_PACKAGE, gnm_locale_dir ());
	bindtextdomain (GETTEXT_PACKAGE "-functions", gnm_locale_dir ());
303 304 305 306 307
#ifdef ENABLE_NLS
	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif
	module = go_plugin_get_type_module (plugin);
	go_gnm_component_register_type (module);
308
	gnm_init ();
309 310
	if (!gnm_sys_data_dir ())
		gutils_init ();
311 312
	dir_list = go_slist_create (
		g_build_filename (gnm_sys_lib_dir (), PLUGIN_SUBDIR, NULL),
313 314
		(usr_dir == NULL ? NULL :
			g_build_filename (usr_dir, PLUGIN_SUBDIR, NULL)),
315
		NULL);
316 317 318
	dir_list = g_slist_concat
		(dir_list,
		 go_string_slist_copy (gnm_conf_get_autoformat_extra_dirs ()));
319 320 321 322 323

	env_var = g_getenv ("GNUMERIC_PLUGIN_PATH");
	if (env_var != NULL)
		GO_SLIST_CONCAT (dir_list, go_strsplit_to_slist (env_var, G_SEARCHPATH_SEPARATOR));

324 325
	go_components_set_mime_suffix ("application/x-gnumeric", "*.gnumeric");

326
	go_plugins_init (go_component_get_command_context (NULL),
327 328 329
			gnm_conf_get_plugins_file_states (),
			gnm_conf_get_plugins_active (),
			dir_list,
330
			gnm_conf_get_plugins_activate_newplugins (),
331
			gnm_plugin_loader_module_get_type ());
332 333 334
}

G_MODULE_EXPORT void
335
go_plugin_shutdown (G_GNUC_UNUSED GOPlugin *plugin,
336
		    G_GNUC_UNUSED GOCmdContext *cc)
337 338
{
}