2 * sheet-object-component.c
4 * Copyright (C) 2008 Jean Bréfort <jean.brefort@normalesup.org>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>
20 #include <gnumeric-config.h>
22 #include <application.h>
24 #include <gnm-pane-impl.h>
26 #include <sheet-control-gui.h>
27 #include <sheet-object-component.h>
28 #include <sheet-object-impl.h>
30 #include <goffice/goffice.h>
31 #include <goffice/component/go-component.h>
32 #include <gsf/gsf-impl-utils.h>
33 #include <gsf/gsf-output-gio.h>
34 #include <glib/gi18n-lib.h>
38 so_component_view_set_bounds (SheetObjectView
*sov
, double const *coords
, gboolean visible
)
40 GocItem
*view
= GOC_ITEM (GOC_GROUP (sov
)->children
->data
);
41 double scale
= goc_canvas_get_pixels_per_unit (view
->canvas
);
44 GOComponent
*component
= sheet_object_component_get_component (sheet_object_view_get_so (sov
));
46 goc_item_set (GOC_ITEM (sov
),
47 "x", MIN (coords
[0], coords
[2]) / scale
,
48 "y", MIN (coords
[3], coords
[1]) / scale
,
50 if (component
&& ! go_component_is_resizable (component
)) {
51 go_component_get_size (component
, &width
, &height
);
54 "width", width
* gnm_app_display_dpi_get (TRUE
),
55 "height", height
* gnm_app_display_dpi_get (FALSE
),
59 "width", (fabs (coords
[2] - coords
[0]) + 1.) / scale
,
60 "height", (fabs (coords
[3] - coords
[1]) + 1.) / scale
,
68 typedef SheetObjectView SOComponentGocView
;
69 typedef SheetObjectViewClass SOComponentGocViewClass
;
72 so_component_goc_view_class_init (SheetObjectViewClass
*sov_klass
)
74 sov_klass
->set_bounds
= so_component_view_set_bounds
;
77 static GSF_CLASS (SOComponentGocView
, so_component_goc_view
,
78 so_component_goc_view_class_init
, NULL
,
82 /****************************************************************************/
83 #define SHEET_OBJECT_CONFIG_KEY "sheet-object-component-key"
85 #define SHEET_OBJECT_COMPONENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNM_SO_COMPONENT_TYPE, SheetObjectComponentClass))
89 GOComponent
*component
;
91 } SheetObjectComponent
;
92 typedef SheetObjectClass SheetObjectComponentClass
;
94 static GObjectClass
*parent_klass
;
97 gnm_soc_finalize (GObject
*obj
)
99 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (obj
);
101 g_object_unref (soc
->component
);
103 parent_klass
->finalize (obj
);
106 static SheetObjectView
*
107 gnm_soc_new_view (SheetObject
*so
, SheetObjectViewContainer
*container
)
109 GnmPane
*pane
= GNM_PANE (container
);
110 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (so
);
111 GocItem
*view
= goc_item_new (pane
->object_views
,
112 so_component_goc_view_get_type (),
114 goc_item_hide (goc_item_new (GOC_GROUP (view
),
116 "object", soc
->component
,
118 return gnm_pane_object_register (so
, view
, TRUE
);
121 static GtkTargetList
*
122 gnm_soc_get_target_list (SheetObject
const *so
)
124 GtkTargetList
*tl
= gtk_target_list_new (NULL
, 0);
125 char *mime_str
= go_image_format_to_mime ("svg");
128 mimes
= go_strsplit_to_slist (mime_str
, ',');
129 for (ptr
= mimes
; ptr
!= NULL
; ptr
= ptr
->next
) {
130 const char *mime
= ptr
->data
;
132 if (mime
!= NULL
&& *mime
!= '\0')
133 gtk_target_list_add (tl
, gdk_atom_intern (mime
, FALSE
),
137 g_slist_free_full (mimes
, g_free
);
138 /* No need to eliminate duplicates. */
139 gtk_target_list_add_image_targets (tl
, 0, TRUE
);
144 static GtkTargetList
*
145 gnm_soc_get_object_target_list (SheetObject
const *so
)
147 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (so
);
148 GtkTargetList
*tl
= gtk_target_list_new (NULL
, 0);
149 if (soc
&& soc
->component
)
150 gtk_target_list_add (tl
,
151 gdk_atom_intern (go_component_get_mime_type (soc
->component
), FALSE
), 0, 0);
156 gnm_soc_write_image (SheetObject
const *so
, char const *format
, double resolution
,
157 GsfOutput
*output
, GError
**err
)
159 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (so
);
160 gboolean res
= FALSE
;
165 sheet_object_position_pts_get (GNM_SO (so
), coords
);
166 w
= fabs (coords
[2] - coords
[0]) + 1.;
167 h
= fabs (coords
[3] - coords
[1]) + 1.;
170 (g_object_get_data (G_OBJECT (so
), "pt-width-at-copy"));
172 (g_object_get_data (G_OBJECT (so
), "pt-height-at-copy"));
175 g_return_if_fail (w
> 0 && h
> 0);
177 res
= go_component_export_image (soc
->component
, go_image_get_format_from_name (format
),
178 output
, resolution
, resolution
);
180 if (!res
&& err
&& *err
== NULL
)
181 *err
= g_error_new (gsf_output_error_id (), 0,
182 _("Unknown failure while saving image"));
186 soc_cb_save_as (SheetObject
*so
, SheetControl
*sc
)
188 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (so
);
189 /* FIXME: This violates model gui barrier */
190 WBCGtk
*wbcg
= scg_wbcg (GNM_SCG (sc
));
191 GtkWidget
*dlg
= gtk_file_chooser_dialog_new (_("Save as"),
192 GTK_WINDOW (wbcg_toplevel (wbcg
)),
193 GTK_FILE_CHOOSER_ACTION_SAVE
,
194 GNM_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
,
195 GNM_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
197 GtkFileFilter
*filter
= gtk_file_filter_new ();
198 gtk_file_filter_add_mime_type (filter
, go_component_get_mime_type (soc
->component
));
199 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg
), filter
);
200 if (gtk_dialog_run (GTK_DIALOG (dlg
)) == GTK_RESPONSE_ACCEPT
) {
201 char *uri
= gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dlg
));
203 GsfOutput
*output
= gsf_output_gio_new_for_uri (uri
, &err
);
205 go_cmd_context_error (GO_CMD_CONTEXT (wbcg
), err
);
209 gpointer user_data
= NULL
;
210 void (*clearfunc
) (gpointer
) = NULL
;
211 go_component_get_data (soc
->component
, (gpointer
) &buf
, &length
, &clearfunc
, &user_data
);
212 gsf_output_write (output
, length
, buf
);
214 clearfunc ((user_data
)? user_data
: buf
);
215 gsf_output_close (output
);
216 g_object_unref (output
);
220 gtk_widget_destroy (dlg
);
224 soc_cb_save_as_image (SheetObject
*so
, SheetControl
*sc
)
231 GOImageFormat selected_format
;
232 GOImageFormatInfo
const *format_info
;
233 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (so
);
236 g_return_if_fail (soc
!= NULL
);
238 /* assuming that components support the same image formats than graphs */
239 l
= gog_graph_get_supported_image_formats ();
240 g_return_if_fail (l
!= NULL
);
241 selected_format
= GPOINTER_TO_UINT (l
->data
);
243 /* FIXME: This violates model gui barrier */
244 wbcg
= scg_wbcg (GNM_SCG (sc
));
245 uri
= go_gui_get_image_save_info (wbcg_toplevel (wbcg
), l
, &selected_format
, &resolution
);
248 output
= go_file_create (uri
, &err
);
251 format_info
= go_image_get_format_info (selected_format
);
252 sheet_object_write_image (so
, format_info
->name
, resolution
, output
, &err
);
253 g_object_unref (output
);
256 go_cmd_context_error (GO_CMD_CONTEXT (wbcg
), err
);
264 gnm_soc_populate_menu (SheetObject
*so
, GPtrArray
*actions
)
266 static SheetObjectAction
const soc_actions
[] = {
267 { "document-save", GNM_N_STOCK_SAVE
, NULL
, 0, soc_cb_save_as
},
268 { "document-save-as", N_("_Save As Image"), NULL
, 0, soc_cb_save_as_image
}
273 GNM_SO_CLASS (parent_klass
)->populate_menu (so
, actions
);
275 for (i
= 0; i
< G_N_ELEMENTS (soc_actions
); i
++)
276 g_ptr_array_insert (actions
, 1 + i
, (gpointer
)(soc_actions
+ i
));
280 gnm_soc_write_object (SheetObject
const *so
, char const *format
,
281 GsfOutput
*output
, GError
**err
,
282 GnmConventions
const *convs
)
284 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (so
);
287 gpointer user_data
= NULL
;
288 void (*clearfunc
) (gpointer
) = NULL
;
289 go_component_get_data (soc
->component
, (gpointer
) &buf
, &length
, &clearfunc
, &user_data
);
290 gsf_output_write (output
, length
, buf
);
292 clearfunc ((user_data
)? user_data
: buf
);
296 gnm_soc_write_xml_sax (SheetObject
const *so
, GsfXMLOut
*output
,
297 GnmConventions
const *convs
)
299 SheetObjectComponent
const *soc
= GNM_SO_COMPONENT (so
);
300 go_component_write_xml_sax (soc
->component
, output
);
304 soc_xml_finish (GOComponent
*component
, SheetObject
*so
)
306 sheet_object_component_set_component (so
, component
);
310 gnm_soc_prep_sax_parser (SheetObject
*so
, GsfXMLIn
*xin
, xmlChar
const **attrs
,
311 GnmConventions
const *convs
)
313 go_component_sax_push_parser (xin
, attrs
,
314 (GOComponentSaxHandler
) soc_xml_finish
, so
);
318 gnm_soc_copy (SheetObject
*dst
, SheetObject
const *src
)
320 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (src
);
321 GOComponent
*component
= go_component_duplicate (soc
->component
);
322 sheet_object_component_set_component (dst
, component
);
323 g_object_unref (component
);
327 gnm_soc_default_size (SheetObject
const *so
, double *w
, double *h
)
329 SheetObjectComponent
const *soc
= GNM_SO_COMPONENT (so
);
330 if (soc
->component
&& !go_component_is_resizable (soc
->component
)) {
331 go_component_get_size (soc
->component
, w
, h
);
332 *w
= GO_IN_TO_PT (*w
);
333 *h
= GO_IN_TO_PT (*h
);
335 *w
= GO_CM_TO_PT ((double)5);
336 *h
= GO_CM_TO_PT ((double)5);
342 WorkbookControl
*wbc
;
343 GOComponent
*component
;
345 } gnm_soc_user_config_t
;
348 component_changed_cb (GOComponent
*component
, gnm_soc_user_config_t
*data
)
350 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (data
->so
);
351 cmd_so_component_config (data
->wbc
, data
->so
, G_OBJECT (component
), G_OBJECT (soc
->component
));
355 destroy_cb ( gnm_soc_user_config_t
*data
)
357 wbcg_edit_finish (WBC_GTK (data
->wbc
), WBC_EDIT_REJECT
, NULL
);
358 go_component_set_command_context (data
->component
, NULL
);
359 g_object_unref (data
->component
);
364 gnm_soc_user_config (SheetObject
*so
, SheetControl
*sc
)
366 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (so
);
368 GOComponent
*new_comp
;
370 g_return_if_fail (soc
&& soc
->component
);
372 go_component_set_command_context (soc
->component
, GO_CMD_CONTEXT (scg_wbcg (GNM_SCG (sc
))));
373 new_comp
= go_component_duplicate (soc
->component
);
374 go_component_set_command_context (new_comp
, GO_CMD_CONTEXT (scg_wbcg (GNM_SCG (sc
))));
375 w
= (GtkWidget
*) go_component_edit (new_comp
);
376 go_component_set_command_context (soc
->component
, NULL
);
378 gnm_soc_user_config_t
*data
= g_new0 (gnm_soc_user_config_t
, 1);
380 data
->component
= new_comp
;
381 data
->wbc
= GNM_WBC (scg_wbcg (GNM_SCG (sc
)));
382 data
->signal
= g_signal_connect (new_comp
, "changed", G_CALLBACK (component_changed_cb
), data
);
383 g_object_set_data_full (G_OBJECT (w
), "editor", data
, (GDestroyNotify
) destroy_cb
);
384 wbc_gtk_attach_guru (scg_wbcg (GNM_SCG (sc
)), w
);
389 gnm_soc_draw_cairo (SheetObject
const *so
, cairo_t
*cr
,
390 double width
, double height
)
392 SheetObjectComponent
*soc
= GNM_SO_COMPONENT (so
);
393 g_return_if_fail (soc
&& soc
->component
);
395 go_component_render (soc
->component
, cr
, width
, height
);
399 gnm_soc_class_init (GObjectClass
*klass
)
401 SheetObjectClass
*so_class
= GNM_SO_CLASS (klass
);
403 parent_klass
= g_type_class_peek_parent (klass
);
405 /* Object class method overrides */
406 klass
->finalize
= gnm_soc_finalize
;
408 /* SheetObject class method overrides */
409 so_class
->new_view
= gnm_soc_new_view
;
410 so_class
->populate_menu
= gnm_soc_populate_menu
;
411 so_class
->write_xml_sax
= gnm_soc_write_xml_sax
;
412 so_class
->prep_sax_parser
= gnm_soc_prep_sax_parser
;
413 so_class
->copy
= gnm_soc_copy
;
414 so_class
->user_config
= gnm_soc_user_config
;
415 so_class
->default_size
= gnm_soc_default_size
;
416 so_class
->draw_cairo
= gnm_soc_draw_cairo
;
418 so_class
->rubber_band_directly
= FALSE
;
422 gnm_soc_init (GObject
*obj
)
424 SheetObject
*so
= GNM_SO (obj
);
425 so
->anchor
.base
.direction
= GOD_ANCHOR_DIR_DOWN_RIGHT
;
429 soc_imageable_init (SheetObjectImageableIface
*soi_iface
)
431 soi_iface
->get_target_list
= gnm_soc_get_target_list
;
432 soi_iface
->write_image
= gnm_soc_write_image
;
436 soc_exportable_init (SheetObjectExportableIface
*soe_iface
)
438 soe_iface
->get_target_list
= gnm_soc_get_object_target_list
;
439 soe_iface
->write_object
= gnm_soc_write_object
;
442 GSF_CLASS_FULL (SheetObjectComponent
, sheet_object_component
,
443 NULL
, NULL
, gnm_soc_class_init
,NULL
,
444 gnm_soc_init
, GNM_SO_TYPE
, 0,
445 GSF_INTERFACE (soc_imageable_init
, GNM_SO_IMAGEABLE_TYPE
) \
446 GSF_INTERFACE (soc_exportable_init
, GNM_SO_EXPORTABLE_TYPE
));
449 * sheet_object_component_new:
450 * @component: #GOComponent
452 * Returns: (transfer full): the newly allocated #SheetObject.
455 sheet_object_component_new (GOComponent
*component
)
457 SheetObjectComponent
*soc
= g_object_new (GNM_SO_COMPONENT_TYPE
, NULL
);
458 sheet_object_component_set_component (GNM_SO (soc
), component
);
463 * sheet_object_component_get_component:
466 * Returns: (transfer none): the embedded #GOComponent or %NULL on error.
469 sheet_object_component_get_component (SheetObject
*soc
)
471 g_return_val_if_fail (GNM_IS_SO_COMPONENT (soc
), NULL
);
473 return ((SheetObjectComponent
*) soc
)->component
;
477 sheet_object_component_set_component (SheetObject
*so
, GOComponent
*component
)
479 SheetObjectComponent
*soc
;
480 GList
*l
= so
->realized_list
;
482 g_return_if_fail (GNM_IS_SO_COMPONENT (so
));
483 soc
= GNM_SO_COMPONENT (so
);
484 if (soc
->component
!= NULL
) {
485 go_component_stop_editing (soc
->component
);
486 g_object_unref (soc
->component
);
489 soc
->component
= component
;
491 for (; l
; l
= l
->next
)
493 GocGroup
*group
= GOC_GROUP (l
->data
);
494 if (group
->children
->data
)
495 g_object_set (group
->children
->data
, "object", component
, NULL
);
498 g_object_ref (component
);
499 go_component_stop_editing (component
);
500 if (go_component_is_resizable (component
))
501 so
->flags
|= SHEET_OBJECT_CAN_RESIZE
;
503 so
->flags
&= ~(SHEET_OBJECT_CAN_RESIZE
| SHEET_OBJECT_SIZE_WITH_CELLS
);
504 so
->anchor
.mode
= GNM_SO_ANCHOR_ONE_CELL
;
506 if (go_component_is_editable (component
))
507 so
->flags
|= SHEET_OBJECT_CAN_EDIT
;
509 so
->flags
&= ~SHEET_OBJECT_CAN_EDIT
;