.gnumeric: if we see a shared array formula, fix it.
[gnumeric.git] / component / gnumeric.c
blob40237d74614e07a5812702aa698547010ad02b9d
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Gnumeric GOffice component
4 * gnumeric.c
6 * Copyright (C) 2006-2010
8 * Developed by Jean Bréfort <jean.brefort@normalesup.org>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * 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/>
24 #include <gnumeric-config.h>
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 #include <wbc-gtk-impl.h>
38 #include <workbook-view.h>
39 #include <workbook.h>
41 #include <goffice/goffice.h>
42 #include <goffice/component/goffice-component.h>
43 #include <goffice/component/go-component-factory.h>
44 #include <goffice/component/go-component.h>
45 #include <goffice/app/module-plugin-defs.h>
46 #include <gsf/gsf-impl-utils.h>
47 #include <gsf/gsf-input-memory.h>
48 #include <gsf/gsf-output-memory.h>
50 #include <gtk/gtk.h>
52 #include <glib/gi18n-lib.h>
53 #include <cairo.h>
54 #include <pango/pangocairo.h>
56 GOPluginModuleDepend const go_plugin_depends [] = {
57 { "goffice", GOFFICE_API_VERSION }
59 GOPluginModuleHeader const go_plugin_header =
60 { GOFFICE_MODULE_PLUGIN_MAGIC_NUMBER, G_N_ELEMENTS (go_plugin_depends) };
62 G_MODULE_EXPORT void go_plugin_init (GOPlugin *plugin, GOCmdContext *cc);
63 G_MODULE_EXPORT void go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc);
65 typedef struct {
66 GOComponent parent;
68 WorkbookView *wv;
69 Workbook *wb;
70 WBCGtk *edited;
71 Sheet *sheet;
72 int col_start, col_end, row_start, row_end;
73 int width, height;
74 } GOGnmComponent;
76 typedef GOComponentClass GOGnmComponentClass;
78 #define GO_TYPE_GNM_COMPONENT (go_gnm_component_get_type ())
79 #define GO_GNM_COMPONENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GO_TYPE_GNM_COMPONENT, GOGnmComponent))
80 #define GO_IS_GNM_COMPONENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GO_TYPE_GNM_COMPONENT))
82 GType go_gnm_component_get_type (void);
84 static GObjectClass *gognm_parent_klass;
86 static gboolean
87 go_gnm_component_get_data (GOComponent *component, gpointer *data, int *length,
88 void (**clearfunc) (gpointer), gpointer *user_data)
90 GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
91 if (gognm->wv) {
92 GOCmdContext *cc = go_component_get_command_context (component);
93 GOIOContext *io_context = go_io_context_new (cc);
94 GsfOutput *output = gsf_output_memory_new ();
95 GOFileSaver *gfs = workbook_get_file_saver (gognm->wb);
96 if (gfs == NULL)
97 gfs = go_file_saver_get_default ();
98 workbook_view_save_to_output (gognm->wv, gfs, output,
99 io_context);
100 *data = (gpointer) gsf_output_memory_get_bytes (GSF_OUTPUT_MEMORY (output));
101 *length = gsf_output_size (output);
102 *clearfunc = g_object_unref;
103 *user_data = output;
104 g_object_unref (io_context);
105 return TRUE;
107 return FALSE;
110 static void
111 go_gnm_component_update_data (GOGnmComponent *gognm)
113 SheetView *sv;
114 GnmRange const *range;
115 gognm->sheet = wb_view_cur_sheet (gognm->wv);
116 sv = sheet_get_view (gognm->sheet, gognm->wv);
117 range = selection_first_range (sv, NULL, NULL);
118 gognm->col_start = range->start.col;
119 gognm->row_start = range->start.row;
120 gognm->col_end = range->end.col;
121 gognm->row_end = range->end.row;
122 gognm->width = sheet_col_get_distance_pts (
123 gognm->sheet, gognm->col_start, gognm->col_end + 1);
124 gognm->parent.width = gognm->width / 72.;
125 gognm->parent.descent = 0.;
126 gognm->height = sheet_row_get_distance_pts (
127 gognm->sheet, gognm->row_start, gognm->row_end + 1);
128 gognm->parent.ascent = gognm->parent.height = gognm->height / 72.;
131 static void
132 go_gnm_component_set_data (GOComponent *component)
134 GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
135 GOCmdContext *cc = go_component_get_command_context (component);
136 GOIOContext *io_context = go_io_context_new (cc);
137 GsfInput *input = gsf_input_memory_new (component->data, component->length, FALSE);
139 g_object_set (G_OBJECT (io_context), "exec-main-loop", FALSE, NULL);
140 if (gognm->wv != NULL) {
141 g_object_unref (gognm->wv);
142 g_object_unref (gognm->wb);
144 gognm->wv = workbook_view_new_from_input (input, NULL, NULL, io_context, NULL);
145 gognm->wb = wb_view_get_workbook (gognm->wv);
146 gnm_app_workbook_list_remove (gognm->wb);
147 g_object_unref (io_context);
148 go_gnm_component_update_data (gognm);
151 static void
152 go_gnm_component_render (GOComponent *component, cairo_t *cr, double width_pixels, double height_pixels)
154 GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
155 GnmRange range;
157 if (!gognm->sheet)
158 go_gnm_component_update_data (gognm);
160 range_init (&range, gognm->col_start, gognm->row_start, gognm->col_end, gognm->row_end);
161 cairo_save (cr);
162 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
163 cairo_scale (cr, ((double) width_pixels) / gognm->width, ((double) height_pixels) / gognm->height);
164 cairo_rectangle (cr, 0., 0., gognm->width, gognm->height);
165 cairo_clip (cr); /* not sure it is necessary */
166 gnm_gtk_print_cell_range (cr, gognm->sheet, &range, 0., 0.,
167 gognm->sheet->print_info);
168 /* Now render objects */
169 gnm_print_sheet_objects (cr, gognm->sheet, &range, 0., 0.);
170 cairo_restore (cr);
173 static void
174 cb_gognm_save (G_GNUC_UNUSED GtkAction *a, WBCGtk *wbcg)
176 gpointer data = g_object_get_data (G_OBJECT (wbcg), "component");
177 if (GO_IS_COMPONENT (data)) {
178 GOComponent *component = GO_COMPONENT (data);
179 /* update the component data since not all clients will call set_data */
180 GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
181 WorkbookView *wv = wb_control_view (GNM_WBC (wbcg));
182 if (wv != gognm->wv) {
183 if (gognm->wv != NULL) {
184 g_object_unref (gognm->wv);
185 g_object_unref (gognm->wb);
187 gognm->wv = g_object_ref (wv);
188 gognm->wb = wb_view_get_workbook (wv);
189 gnm_app_workbook_list_remove (gognm->wb); /* no need to have this one in the list */
191 go_doc_set_dirty (GO_DOC (gognm->wb), FALSE);
192 go_gnm_component_update_data (gognm);
193 go_component_emit_changed (component);
194 } else
195 gui_file_save (wbcg, wb_control_view (GNM_WBC (wbcg)));
198 static GtkActionEntry const actions[] = {
199 /* File */
200 { "FileSaveEmbed", GNM_N_STOCK_SAVE, NULL,
201 NULL, N_("Save the embedded workbook"),
202 G_CALLBACK (cb_gognm_save) }
205 static void
206 cb_editor_destroyed (GOGnmComponent *gognm)
208 if (gognm->edited && G_OBJECT (gognm->edited)->ref_count > 0)
209 g_object_unref (gognm->edited);
210 gognm->edited = NULL;
213 static GtkWindow*
214 go_gnm_component_edit (GOComponent *component)
216 GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
217 WorkbookView *wv;
218 if (gognm->edited) {
219 gdk_window_raise (gtk_widget_get_parent_window (GTK_WIDGET (wbcg_toplevel (gognm->edited))));
220 return wbcg_toplevel (gognm->edited);
222 if (!gognm->wv) {
223 component->ascent = 0.;
224 component->descent = 0.;
225 component->width = 0.;
226 wv = workbook_view_new (workbook_new_with_sheets (1));
227 } else {
228 GOCmdContext *cc = go_component_get_command_context (component);
229 GOIOContext *io_context = GO_IS_IO_CONTEXT (cc)? GO_IO_CONTEXT (g_object_ref (cc)): go_io_context_new (cc);
230 GsfInput *input = gsf_input_memory_new (component->data, component->length, FALSE);
232 g_object_set (G_OBJECT (io_context), "exec-main-loop", FALSE, NULL);
233 wv = workbook_view_new_from_input (input, NULL, NULL, io_context, NULL);
234 g_object_unref (io_context);
236 set_uifilename ("Gnumeric-embed.xml", actions, G_N_ELEMENTS (actions));
237 gognm->edited = wbc_gtk_new (wv, NULL, NULL, NULL);
239 g_object_set_data (G_OBJECT (gognm->edited), "component", gognm);
240 g_signal_connect_swapped (gognm->edited->toplevel, "destroy",
241 G_CALLBACK (cb_editor_destroyed), gognm);
242 return wbcg_toplevel (gognm->edited);
245 static void
246 go_gnm_component_finalize (GObject *obj)
248 GOGnmComponent *gognm = GO_GNM_COMPONENT (obj);
249 if (gognm->wv != NULL) {
250 g_object_unref (gognm->wv);
251 g_object_unref (gognm->wb);
252 gognm->wv = NULL;
254 if (gognm->edited != NULL) {
255 g_object_unref (wb_control_view (GNM_WBC (gognm->edited)));
256 gognm->edited = NULL;
258 G_OBJECT_CLASS (gognm_parent_klass)->finalize (obj);
261 static void
262 go_gnm_component_init (GOComponent *component)
264 GOGnmComponent *gognm = GO_GNM_COMPONENT (component);
265 component->resizable = FALSE;
266 component->editable = TRUE;
267 component->snapshot_type = GO_SNAPSHOT_SVG;
268 gognm->row_start = gognm->col_start = 0;
269 gognm->sheet = NULL;
270 gognm->row_end = 9;
271 gognm->col_end = 4;
274 static void
275 go_gnm_component_class_init (GOComponentClass *klass)
277 GObjectClass *obj_klass = (GObjectClass *) klass;
278 obj_klass->finalize = go_gnm_component_finalize;
280 gognm_parent_klass = (GObjectClass*) g_type_class_peek_parent (klass);
282 klass->get_data = go_gnm_component_get_data;
283 klass->set_data = go_gnm_component_set_data;
284 klass->render = go_gnm_component_render;
285 klass->edit = go_gnm_component_edit;
288 GSF_DYNAMIC_CLASS (GOGnmComponent, go_gnm_component,
289 go_gnm_component_class_init, go_gnm_component_init,
290 GO_TYPE_COMPONENT)
292 /*************************************************************************************/
294 G_MODULE_EXPORT void
295 go_plugin_init (GOPlugin *plugin, G_GNUC_UNUSED GOCmdContext *cc)
297 GTypeModule *module;
298 char const *env_var;
299 GSList *dir_list;
300 const char *usr_dir = gnm_usr_dir (TRUE);
302 bindtextdomain (GETTEXT_PACKAGE, gnm_locale_dir ());
303 bindtextdomain (GETTEXT_PACKAGE "-functions", gnm_locale_dir ());
304 #ifdef ENABLE_NLS
305 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
306 #endif
307 module = go_plugin_get_type_module (plugin);
308 go_gnm_component_register_type (module);
309 gnm_init ();
310 if (!gnm_sys_data_dir ())
311 gutils_init ();
312 dir_list = go_slist_create (
313 g_build_filename (gnm_sys_lib_dir (), PLUGIN_SUBDIR, NULL),
314 (usr_dir == NULL ? NULL :
315 g_build_filename (usr_dir, PLUGIN_SUBDIR, NULL)),
316 NULL);
317 dir_list = g_slist_concat
318 (dir_list,
319 go_string_slist_copy (gnm_conf_get_autoformat_extra_dirs ()));
321 env_var = g_getenv ("GNUMERIC_PLUGIN_PATH");
322 if (env_var != NULL)
323 GO_SLIST_CONCAT (dir_list, go_strsplit_to_slist (env_var, G_SEARCHPATH_SEPARATOR));
325 go_components_set_mime_suffix ("application/x-gnumeric", "*.gnumeric");
327 go_plugins_init (go_component_get_command_context (NULL),
328 gnm_conf_get_plugins_file_states (),
329 gnm_conf_get_plugins_active (),
330 dir_list,
331 gnm_conf_get_plugins_activate_newplugins (),
332 gnm_plugin_loader_module_get_type ());
335 G_MODULE_EXPORT void
336 go_plugin_shutdown (G_GNUC_UNUSED GOPlugin *plugin,
337 G_GNUC_UNUSED GOCmdContext *cc)