1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * sheet-object.c: Implements the sheet object manipulation for Gnumeric
7 * Miguel de Icaza (miguel@kernel.org)
8 * Michael Meeks (mmeeks@gnu.org)
9 * Jody Goldberg (jody@gnome.org)
11 #include <gnumeric-config.h>
12 #include <glib/gi18n-lib.h>
14 #include "sheet-object.h"
17 #include "dependent.h"
18 #include "sheet-view.h"
19 #include "sheet-control.h"
20 #include "sheet-control-gui.h"
21 #include "sheet-private.h"
23 #include "sheet-object-impl.h"
29 #include "gnm-pane-impl.h"
30 #include "gnm-so-line.h"
31 #include "gnm-so-filled.h"
32 #include "sheet-control-gui-priv.h"
33 #include "sheet-object-cell-comment.h"
34 #include "sheet-object-widget.h"
35 #include "sheet-object-graph.h"
36 #include "sheet-object-image.h"
37 #include "sheet-filter-combo.h"
38 #include "wbc-gtk-impl.h"
41 #include <goffice/goffice.h>
42 #include "application.h"
45 #include <libxml/globals.h>
46 #include <gsf/gsf-impl-utils.h>
50 /* GType code for SheetObjectAnchor */
51 static SheetObjectAnchor
*
52 sheet_object_anchor_copy (SheetObjectAnchor
* soa
)
54 SheetObjectAnchor
*res
= g_new (SheetObjectAnchor
, 1);
60 sheet_object_anchor_get_type (void)
65 t
= g_boxed_type_register_static ("SheetObjectAnchor",
66 (GBoxedCopyFunc
)sheet_object_anchor_copy
,
67 (GBoxedFreeFunc
)g_free
);
72 /* Returns the class for a SheetObject */
73 #define SO_CLASS(so) SHEET_OBJECT_CLASS(G_OBJECT_GET_CLASS(so))
85 static guint signals
[LAST_SIGNAL
] = { 0 };
86 static GObjectClass
*parent_klass
;
87 static GQuark sov_so_quark
;
88 static GQuark sov_container_quark
;
91 sheet_object_set_print_flag (SheetObject
*so
, gboolean
*print
)
94 so
->flags
= (so
->flags
| SHEET_OBJECT_PRINT
);
96 so
->flags
= (so
->flags
& ~SHEET_OBJECT_PRINT
);
101 cb_so_size_position (SheetObject
*so
, SheetControl
*sc
)
105 g_return_if_fail (IS_SHEET_CONTROL_GUI (sc
));
107 wbcg
= scg_wbcg ((SheetControlGUI
*)sc
);
109 if (wbcg
->edit_line
.guru
!= NULL
) {
110 GtkWidget
*w
= wbcg
->edit_line
.guru
;
111 wbc_gtk_detach_guru (wbcg
);
112 gtk_widget_destroy (w
);
115 dialog_so_size (wbcg
, G_OBJECT (so
));
119 cb_so_snap_to_grid (SheetObject
*so
, SheetControl
*sc
)
121 SheetObjectAnchor
*snapped
=
122 sheet_object_anchor_dup (sheet_object_get_anchor (so
));
123 snapped
->offset
[0] = snapped
->offset
[1] = 0.;
124 snapped
->offset
[2] = snapped
->offset
[3] = 1.;
125 cmd_objects_move (sc_wbc (sc
),
126 g_slist_prepend (NULL
, so
),
127 g_slist_prepend (NULL
, snapped
),
128 FALSE
, _("Snap object to grid"));
131 cb_so_pull_to_front (SheetObject
*so
, SheetControl
*sc
)
133 cmd_object_raise (sc_wbc (sc
), so
, cmd_object_pull_to_front
);
136 cb_so_pull_forward (SheetObject
*so
, SheetControl
*sc
)
138 cmd_object_raise (sc_wbc (sc
), so
, cmd_object_pull_forward
);
141 cb_so_push_backward (SheetObject
*so
, SheetControl
*sc
)
143 cmd_object_raise (sc_wbc (sc
), so
, cmd_object_push_backward
);
146 cb_so_push_to_back (SheetObject
*so
, SheetControl
*sc
)
148 cmd_object_raise (sc_wbc (sc
), so
, cmd_object_push_to_back
);
151 cb_so_delete (SheetObject
*so
, SheetControl
*sc
)
153 cmd_objects_delete (sc_wbc (sc
),
154 go_slist_create (so
, NULL
), NULL
);
157 cb_so_print (SheetObject
*so
, SheetControl
*sc
)
159 GPtrArray
*a
= g_ptr_array_new ();
160 g_ptr_array_add (a
, so
);
161 gnm_print_so (sc_wbc (sc
), a
, NULL
);
162 g_ptr_array_unref (a
);
165 sheet_object_get_editor (SheetObject
*so
, SheetControl
*sc
)
169 g_return_if_fail (IS_SHEET_OBJECT (so
));
170 g_return_if_fail (SO_CLASS (so
));
171 g_return_if_fail (IS_SHEET_CONTROL_GUI (sc
));
173 wbcg
= scg_wbcg ((SheetControlGUI
*)sc
);
175 if (wbcg
->edit_line
.guru
!= NULL
) {
176 GtkWidget
*w
= wbcg
->edit_line
.guru
;
177 wbc_gtk_detach_guru (wbcg
);
178 gtk_widget_destroy (w
);
181 if (SO_CLASS(so
)->user_config
)
182 SO_CLASS(so
)->user_config (so
, sc
);
185 cb_so_cut (SheetObject
*so
, SheetControl
*sc
)
187 gnm_app_clipboard_cut_copy_obj (sc_wbc (sc
), TRUE
, sc_view (sc
),
188 go_slist_create (so
, NULL
));
191 cb_so_copy (SheetObject
*so
, SheetControl
*sc
)
193 gnm_app_clipboard_cut_copy_obj (sc_wbc (sc
), FALSE
, sc_view (sc
),
194 go_slist_create (so
, NULL
));
198 sheet_object_can_print (SheetObject
const *so
)
200 g_return_val_if_fail (IS_SHEET_OBJECT (so
), FALSE
);
201 return (so
->flags
& SHEET_OBJECT_IS_VISIBLE
) &&
202 (so
->flags
& SHEET_OBJECT_PRINT
) &&
203 SO_CLASS (so
)->draw_cairo
!= NULL
;
207 sheet_object_can_resize (SheetObject
const *so
)
209 g_return_val_if_fail (IS_SHEET_OBJECT (so
), FALSE
);
210 return so
->flags
& SHEET_OBJECT_CAN_RESIZE
;
214 sheet_object_can_edit (SheetObject
const *so
)
216 g_return_val_if_fail (IS_SHEET_OBJECT (so
), FALSE
);
217 return so
->flags
& SHEET_OBJECT_CAN_EDIT
;
221 sheet_object_can_prop (SheetObject
const *so
)
223 g_return_val_if_fail (IS_SHEET_OBJECT (so
), FALSE
);
224 return (sheet_object_can_edit (so
) && (SO_CLASS(so
)->user_config
!= NULL
));
228 sheet_object_populate_menu_real (SheetObject
*so
, GPtrArray
*actions
)
231 if (so
->sheet
->sheet_type
== GNM_SHEET_OBJECT
) {
232 static SheetObjectAction
const so_actions
[] = {
233 { "gtk-properties", NULL
, NULL
, 0, sheet_object_get_editor
, sheet_object_can_prop
},
234 { NULL
, NULL
, NULL
, 0, NULL
, NULL
},
235 { "gtk-copy", NULL
, NULL
, 0, cb_so_copy
, NULL
},
237 for (i
= 0 ; i
< G_N_ELEMENTS (so_actions
); i
++)
238 g_ptr_array_add (actions
, (gpointer
) (so_actions
+ i
));
240 static SheetObjectAction
const so_actions
[] = {
241 { GTK_STOCK_PROPERTIES
, NULL
, NULL
, 0, sheet_object_get_editor
, sheet_object_can_prop
},
242 { NULL
, NULL
, NULL
, 0, NULL
, NULL
},
243 { GTK_STOCK_LEAVE_FULLSCREEN
, N_("Size _& Position"), NULL
, 0, cb_so_size_position
, NULL
},
244 { GTK_STOCK_FULLSCREEN
, N_("_Snap to Grid"), NULL
, 0, cb_so_snap_to_grid
, NULL
},
245 { NULL
, N_("_Order"), NULL
, 1, NULL
, NULL
},
246 { NULL
, N_("Pul_l to Front"), NULL
, 0, cb_so_pull_to_front
, NULL
},
247 { NULL
, N_("Pull _Forward"), NULL
, 0, cb_so_pull_forward
, NULL
},
248 { NULL
, N_("Push _Backward"), NULL
, 0, cb_so_push_backward
, NULL
},
249 { NULL
, N_("Pus_h to Back"), NULL
, 0, cb_so_push_to_back
, NULL
},
250 { NULL
, NULL
, NULL
, -1, NULL
, NULL
},
251 { NULL
, NULL
, NULL
, 0, NULL
, NULL
},
252 { GTK_STOCK_CUT
, NULL
, NULL
, 0, cb_so_cut
, NULL
},
253 { GTK_STOCK_COPY
, NULL
, NULL
, 0, cb_so_copy
, NULL
},
254 { GTK_STOCK_DELETE
, NULL
, NULL
, 0, cb_so_delete
, NULL
},
255 { NULL
, NULL
, NULL
, 0, NULL
, NULL
},
256 { GTK_STOCK_PRINT
, NULL
, NULL
, 0, cb_so_print
, sheet_object_can_print
},
258 for (i
= 0; i
< G_N_ELEMENTS (so_actions
); i
++)
259 g_ptr_array_add (actions
, (gpointer
) (so_actions
+ i
));
264 * sheet_object_populate_menu:
266 * @actions: (inout) (transfer full) (element-type SheetObjectAction): #GPtrArray
268 * Get a list of the actions that can be performed on @so
271 sheet_object_populate_menu (SheetObject
*so
, GPtrArray
*actions
)
273 g_return_if_fail (NULL
!= so
);
275 SHEET_OBJECT_CLASS (G_OBJECT_GET_CLASS(so
))->populate_menu (so
, actions
);
279 * sheet_objects_max_extent:
282 * Utility routine to calculate the maximum extent of objects in this sheet.
285 sheet_objects_max_extent (Sheet
*sheet
)
287 GnmCellPos max_pos
= { 0, 0 };
290 for (ptr
= sheet
->sheet_objects
; ptr
!= NULL
; ptr
= ptr
->next
) {
291 SheetObject
*so
= SHEET_OBJECT (ptr
->data
);
293 if (max_pos
.col
< so
->anchor
.cell_bound
.end
.col
)
294 max_pos
.col
= so
->anchor
.cell_bound
.end
.col
;
295 if (max_pos
.row
< so
->anchor
.cell_bound
.end
.row
)
296 max_pos
.row
= so
->anchor
.cell_bound
.end
.row
;
299 if (sheet
->max_object_extent
.col
!= max_pos
.col
||
300 sheet
->max_object_extent
.row
!= max_pos
.row
) {
301 sheet
->max_object_extent
= max_pos
;
302 sheet_scrollbar_config (sheet
);
307 sheet_object_set_name (SheetObject
*so
, const char *name
)
309 if (name
== so
->name
)
313 so
->name
= g_strdup (name
);
315 g_object_notify (G_OBJECT (so
), "name");
319 sheet_object_get_property (GObject
*obj
, guint param_id
,
320 GValue
*value
, GParamSpec
*pspec
)
322 SheetObject
*so
= SHEET_OBJECT (obj
);
326 g_value_set_string (value
, so
->name
);
329 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
335 sheet_object_set_property (GObject
*obj
, guint param_id
,
336 GValue
const *value
, GParamSpec
*pspec
)
338 SheetObject
*so
= SHEET_OBJECT (obj
);
342 sheet_object_set_name (so
, g_value_get_string (value
));
345 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, param_id
, pspec
);
352 sheet_object_finalize (GObject
*object
)
354 SheetObject
*so
= SHEET_OBJECT (object
);
355 if (so
->sheet
!= NULL
)
356 sheet_object_clear_sheet (so
);
358 parent_klass
->finalize (object
);
362 sheet_object_init (GObject
*object
)
365 SheetObject
*so
= SHEET_OBJECT (object
);
368 so
->flags
= SHEET_OBJECT_IS_VISIBLE
| SHEET_OBJECT_PRINT
|
369 SHEET_OBJECT_CAN_RESIZE
| SHEET_OBJECT_CAN_EDIT
|
370 SHEET_OBJECT_MOVE_WITH_CELLS
| SHEET_OBJECT_SIZE_WITH_CELLS
;
372 /* Store the logical position as A1 */
373 so
->anchor
.cell_bound
.start
.col
= so
->anchor
.cell_bound
.start
.row
= 0;
374 so
->anchor
.cell_bound
.end
.col
= so
->anchor
.cell_bound
.end
.row
= 1;
375 so
->anchor
.base
.direction
= GOD_ANCHOR_DIR_UNKNOWN
;
377 for (i
= 4; i
-- > 0 ;)
378 so
->anchor
.offset
[i
] = 0.;
382 so_default_size (G_GNUC_UNUSED SheetObject
const *so
, double *width
, double *height
)
384 /* Provide some defaults (derived classes may want to override) */
390 sheet_object_class_init (GObjectClass
*klass
)
392 SheetObjectClass
*sheet_object_class
= SHEET_OBJECT_CLASS (klass
);
394 parent_klass
= g_type_class_peek_parent (klass
);
396 klass
->finalize
= sheet_object_finalize
;
397 klass
->get_property
= sheet_object_get_property
;
398 klass
->set_property
= sheet_object_set_property
;
400 sheet_object_class
->populate_menu
= sheet_object_populate_menu_real
;
401 sheet_object_class
->user_config
= NULL
;
402 sheet_object_class
->rubber_band_directly
= FALSE
;
403 sheet_object_class
->interactive
= FALSE
;
404 sheet_object_class
->default_size
= so_default_size
;
405 sheet_object_class
->xml_export_name
= NULL
;
406 sheet_object_class
->foreach_dep
= NULL
;
408 g_object_class_install_property
409 (klass
, SO_PROP_NAME
,
410 g_param_spec_string ("name", NULL
, NULL
, NULL
,
411 GSF_PARAM_STATIC
| G_PARAM_READWRITE
));
413 signals
[BOUNDS_CHANGED
] = g_signal_new ("bounds-changed",
416 G_STRUCT_OFFSET (SheetObjectClass
, bounds_changed
),
418 g_cclosure_marshal_VOID__VOID
,
420 signals
[UNREALIZED
] = g_signal_new ("unrealized",
423 G_STRUCT_OFFSET (SheetObjectClass
, unrealized
),
425 g_cclosure_marshal_VOID__VOID
,
429 GSF_CLASS (SheetObject
, sheet_object
,
430 sheet_object_class_init
, sheet_object_init
,
434 * sheet_object_get_view:
436 * @container: #SheetObjectViewContainer
438 * Returns: (transfer none): the found #SheetObjectView or %NULL.
441 sheet_object_get_view (SheetObject
const *so
, SheetObjectViewContainer
*container
)
445 g_return_val_if_fail (IS_SHEET_OBJECT (so
), NULL
);
447 for (l
= so
->realized_list
; l
; l
= l
->next
) {
448 SheetObjectView
*view
= SHEET_OBJECT_VIEW (l
->data
);
449 if (container
== g_object_get_qdata (G_OBJECT (view
), sov_container_quark
))
457 * sheet_object_update_bounds:
458 * @so: The sheet object
459 * @p: An optional position marking the top left of the region
460 * needing relocation (default == A1)
462 * update the bounds of an object that intersects the region whose top left
463 * is @p. This is used when an objects position is anchored to cols/rows
464 * and they change position.
467 sheet_object_update_bounds (SheetObject
*so
, GnmCellPos
const *pos
)
469 gboolean is_hidden
= TRUE
;
472 g_return_if_fail (IS_SHEET_OBJECT (so
));
475 so
->anchor
.cell_bound
.end
.col
< pos
->col
&&
476 so
->anchor
.cell_bound
.end
.row
< pos
->row
)
479 /* Are all cols hidden ? */
480 end
= so
->anchor
.cell_bound
.end
.col
;
481 i
= so
->anchor
.cell_bound
.start
.col
;
482 while (i
<= end
&& is_hidden
)
483 is_hidden
&= sheet_col_is_hidden (so
->sheet
, i
++);
485 /* Are all rows hidden ? */
488 end
= so
->anchor
.cell_bound
.end
.row
;
489 i
= so
->anchor
.cell_bound
.start
.row
;
490 while (i
<= end
&& is_hidden
)
491 is_hidden
&= sheet_row_is_hidden (so
->sheet
, i
++);
492 so
->flags
|= SHEET_OBJECT_IS_VISIBLE
;
494 so
->flags
&= ~SHEET_OBJECT_IS_VISIBLE
;
496 g_signal_emit (so
, signals
[BOUNDS_CHANGED
], 0);
500 * sheet_object_get_sheet:
503 * A small utility to help keep the implementation of SheetObjects modular.
504 * Returns: (transfer none): the #Sheet owning the object.
507 sheet_object_get_sheet (SheetObject
const *so
)
509 g_return_val_if_fail (IS_SHEET_OBJECT (so
), NULL
);
515 cb_create_views (SheetObject
*so
)
517 g_object_set_data (G_OBJECT (so
), "create_view_handler", NULL
);
518 SHEET_FOREACH_CONTROL (so
->sheet
, view
, control
,
519 sc_object_create_view (control
, so
););
524 * sheet_object_set_sheet:
528 * Adds a reference to the object.
530 * Returns TRUE if there was a problem
533 sheet_object_set_sheet (SheetObject
*so
, Sheet
*sheet
)
535 g_return_val_if_fail (IS_SHEET_OBJECT (so
), TRUE
);
536 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
538 if (sheet
== so
->sheet
)
541 g_return_val_if_fail (so
->sheet
== NULL
, TRUE
);
542 g_return_val_if_fail (g_slist_find (sheet
->sheet_objects
, so
) == NULL
, TRUE
);
545 if (SO_CLASS (so
)->assign_to_sheet
&&
546 SO_CLASS (so
)->assign_to_sheet (so
, sheet
)) {
552 sheet
->sheet_objects
= g_slist_prepend (sheet
->sheet_objects
, so
);
553 /* FIXME : add a flag to sheet to have sheet_update do this */
554 sheet_objects_max_extent (sheet
);
556 if (NULL
== g_object_get_data (G_OBJECT (so
), "create_view_handler")) {
557 guint id
= g_idle_add ((GSourceFunc
) cb_create_views
, so
);
558 g_object_set_data (G_OBJECT (so
), "create_view_handler", GUINT_TO_POINTER (id
));
565 * sheet_object_clear_sheet:
568 * Removes @so from its container, unrealizes all views, disconects the
569 * associated data and unrefs the object
572 sheet_object_clear_sheet (SheetObject
*so
)
575 gpointer view_handler
;
577 g_return_if_fail (IS_SHEET_OBJECT (so
));
579 if (so
->sheet
== NULL
) /* already removed */
582 g_return_if_fail (IS_SHEET (so
->sheet
));
584 ptr
= g_slist_find (so
->sheet
->sheet_objects
, so
);
585 g_return_if_fail (ptr
!= NULL
);
587 /* clear any pending attempts to create views */
588 view_handler
= g_object_get_data (G_OBJECT (so
), "create_view_handler");
589 if (NULL
!= view_handler
) {
590 g_source_remove (GPOINTER_TO_UINT (view_handler
));
591 g_object_set_data (G_OBJECT (so
), "create_view_handler", NULL
);
594 while (so
->realized_list
!= NULL
) {
595 g_object_set_qdata (G_OBJECT (so
->realized_list
->data
), sov_so_quark
, NULL
);
596 g_object_unref (so
->realized_list
->data
);
597 so
->realized_list
= g_list_remove (so
->realized_list
, so
->realized_list
->data
);
600 g_signal_emit (so
, signals
[UNREALIZED
], 0);
602 if (SO_CLASS (so
)->remove_from_sheet
&&
603 SO_CLASS (so
)->remove_from_sheet (so
))
606 so
->sheet
->sheet_objects
= g_slist_remove_link (so
->sheet
->sheet_objects
, ptr
);
609 if (so
->anchor
.cell_bound
.end
.col
== so
->sheet
->max_object_extent
.col
&&
610 so
->anchor
.cell_bound
.end
.row
== so
->sheet
->max_object_extent
.row
)
611 sheet_objects_max_extent (so
->sheet
);
618 cb_sheet_object_invalidate_sheet (GnmDependent
*dep
, G_GNUC_UNUSED SheetObject
*so
, gpointer user
)
621 GnmExprRelocateInfo rinfo
;
622 GnmExprTop
const *texpr
;
623 gboolean save_invalidated
= sheet
->being_invalidated
;
624 gboolean dep_sheet_invalidated
= (dep
->sheet
== sheet
);
629 sheet
->being_invalidated
= TRUE
;
630 rinfo
.reloc_type
= GNM_EXPR_RELOCATE_INVALIDATE_SHEET
;
631 texpr
= gnm_expr_top_relocate (dep
->texpr
, &rinfo
, FALSE
);
632 if (!texpr
&& dep_sheet_invalidated
) {
634 gnm_expr_top_ref (texpr
);
637 sheet
->being_invalidated
= save_invalidated
;
640 gboolean was_linked
= dependent_is_linked (dep
);
641 dependent_set_expr (dep
, texpr
);
642 gnm_expr_top_unref (texpr
);
643 if (dep_sheet_invalidated
)
646 dependent_link (dep
);
651 sheet_object_invalidate_sheet (SheetObject
*so
, Sheet
const *sheet
)
653 sheet_object_foreach_dep (so
, cb_sheet_object_invalidate_sheet
,
658 * sheet_object_foreach_dep:
660 * @func: (scope call): #SheetObjectForeachDepFunc
663 * Loops over each dependent contained in a sheet object and call the handler.
666 sheet_object_foreach_dep (SheetObject
*so
,
667 SheetObjectForeachDepFunc func
,
670 if (SO_CLASS (so
)->foreach_dep
)
671 SO_CLASS (so
)->foreach_dep (so
, func
, user
);
675 * sheet_object_new_view:
679 * Asks @so to create a view for @container.
680 * Returns: (transfer none): the new #SheetObjectView.
683 sheet_object_new_view (SheetObject
*so
, SheetObjectViewContainer
*container
)
685 SheetObjectView
*view
;
687 g_return_val_if_fail (IS_SHEET_OBJECT (so
), NULL
);
688 g_return_val_if_fail (NULL
!= container
, NULL
);
690 view
= sheet_object_get_view (so
, container
);
694 view
= SO_CLASS (so
)->new_view (so
, container
);
699 g_return_val_if_fail (IS_SHEET_OBJECT_VIEW (view
), NULL
);
701 /* Store some useful information */
702 g_object_set_qdata (G_OBJECT (view
), sov_so_quark
, so
);
703 g_object_set_qdata (G_OBJECT (view
), sov_container_quark
, container
);
704 so
->realized_list
= g_list_prepend (so
->realized_list
, view
);
705 sheet_object_update_bounds (so
, NULL
);
711 * sheet_object_draw_cairo:
713 * Draw a sheet object using cairo.
716 * We are assuming that the cairo context is set up so that the top
717 * left of the bounds is (0,0). Note that this
718 * is the real top left cell, not necessarily the cell with to which we are
723 sheet_object_draw_cairo (SheetObject
const *so
, cairo_t
*cr
, gboolean rtl
)
725 if (SO_CLASS (so
)->draw_cairo
) {
726 SheetObjectAnchor
const *anchor
;
727 double x
= 0., y
= 0., width
, height
, cell_width
, cell_height
;
728 anchor
= sheet_object_get_anchor (so
);
729 cell_width
= sheet_col_get_distance_pts (so
->sheet
,
730 anchor
->cell_bound
.start
.col
,
731 anchor
->cell_bound
.start
.col
+ 1);
732 cell_height
= sheet_row_get_distance_pts (so
->sheet
,
733 anchor
->cell_bound
.start
.row
,
734 anchor
->cell_bound
.start
.row
+ 1);
735 x
= cell_width
* anchor
->offset
[0];
737 y
= cell_height
* anchor
->offset
[1];
738 cell_width
= sheet_col_get_distance_pts (so
->sheet
,
739 anchor
->cell_bound
.end
.col
,
740 anchor
->cell_bound
.end
.col
+ 1);
741 cell_height
= sheet_row_get_distance_pts (so
->sheet
,
742 anchor
->cell_bound
.end
.row
,
743 anchor
->cell_bound
.end
.row
+ 1);
746 x
= cell_width
* (1 - anchor
->offset
[2]);
748 if (sheet_object_can_resize (so
)) {
749 width
= sheet_col_get_distance_pts (so
->sheet
,
750 anchor
->cell_bound
.start
.col
,
751 anchor
->cell_bound
.end
.col
+ 1);
752 height
= sheet_row_get_distance_pts (so
->sheet
,
753 anchor
->cell_bound
.start
.row
,
754 anchor
->cell_bound
.end
.row
+ 1);
757 width
-= cell_width
* (1. - anchor
->offset
[2]);
758 height
-= cell_height
* (1 - anchor
->offset
[3]);
760 sheet_object_default_size ((SheetObject
*) so
, &width
, &height
);
762 /* we don't need to save/restore cairo, the caller must do it */
763 cairo_translate (cr
, x
, y
);
764 SO_CLASS (so
)->draw_cairo (so
, cr
, width
, height
);
769 sheet_object_draw_cairo_sized (SheetObject
const *so
, cairo_t
*cr
, double width
, double height
)
771 SO_CLASS (so
)->draw_cairo (so
, cr
, width
, height
);
775 sheet_object_get_range (SheetObject
const *so
)
777 g_return_val_if_fail (IS_SHEET_OBJECT (so
), NULL
);
779 return &so
->anchor
.cell_bound
;
783 * sheet_object_get_anchor:
786 * Returns: (transfer none): the #SheetObjectAnchor for @so.
788 SheetObjectAnchor
const *
789 sheet_object_get_anchor (SheetObject
const *so
)
791 g_return_val_if_fail (IS_SHEET_OBJECT (so
), NULL
);
797 sheet_object_set_anchor (SheetObject
*so
, SheetObjectAnchor
const *anchor
)
799 g_return_if_fail (IS_SHEET_OBJECT (so
));
801 so
->anchor
= *anchor
;
802 if (so
->sheet
!= NULL
) {
803 sheet_objects_max_extent (so
->sheet
);
804 sheet_object_update_bounds (so
, NULL
);
809 sheet_object_anchor_dup (SheetObjectAnchor
const *src
)
811 SheetObjectAnchor
*res
= g_memdup (src
, sizeof (SheetObjectAnchor
));
816 cell_offset_calc_pt (Sheet
const *sheet
, int i
, gboolean is_col
, double offset
)
818 ColRowInfo
const *cri
= sheet_colrow_get_info (sheet
, i
, is_col
);
819 return offset
* cri
->size_pts
;
823 * sheet_object_default_size:
824 * @so: The sheet object
825 * @w: a ptr into which to store the default_width.
826 * @h: a ptr into which to store the default_height.
828 * Measurements are in pts.
831 sheet_object_default_size (SheetObject
*so
, double *w
, double *h
)
833 g_return_if_fail (IS_SHEET_OBJECT (so
));
834 g_return_if_fail (w
!= NULL
);
835 g_return_if_fail (h
!= NULL
);
837 SO_CLASS (so
)->default_size (so
, w
, h
);
841 * sheet_object_position_pts_get:
842 * @so: The sheet object
843 * @coords: array of 4 doubles
845 * Calculate the position of the object @so in pts from the logical position in
849 sheet_object_position_pts_get (SheetObject
const *so
, double *coords
)
851 g_return_if_fail (IS_SHEET_OBJECT (so
));
852 sheet_object_anchor_to_pts (&so
->anchor
, so
->sheet
, coords
);
856 sheet_object_anchor_to_pts (SheetObjectAnchor
const *anchor
,
857 Sheet
const *sheet
, double *res_pts
)
861 g_return_if_fail (res_pts
!= NULL
);
863 r
= &anchor
->cell_bound
;
865 res_pts
[0] = sheet_col_get_distance_pts (sheet
, 0,
867 res_pts
[2] = res_pts
[0] + sheet_col_get_distance_pts (sheet
,
868 r
->start
.col
, r
->end
.col
);
869 res_pts
[1] = sheet_row_get_distance_pts (sheet
, 0,
871 res_pts
[3] = res_pts
[1] + sheet_row_get_distance_pts (sheet
,
872 r
->start
.row
, r
->end
.row
);
874 res_pts
[0] += cell_offset_calc_pt (sheet
, r
->start
.col
,
875 TRUE
, anchor
->offset
[0]);
876 res_pts
[1] += cell_offset_calc_pt (sheet
, r
->start
.row
,
877 FALSE
, anchor
->offset
[1]);
878 res_pts
[2] += cell_offset_calc_pt (sheet
, r
->end
.col
,
879 TRUE
, anchor
->offset
[2]);
880 res_pts
[3] += cell_offset_calc_pt (sheet
, r
->end
.row
,
881 FALSE
, anchor
->offset
[3]);
885 sheet_object_anchor_to_offset_pts (SheetObjectAnchor
const *anchor
,
886 Sheet
const *sheet
, double *res_pts
)
890 g_return_if_fail (res_pts
!= NULL
);
892 r
= &anchor
->cell_bound
;
894 res_pts
[0] = cell_offset_calc_pt (sheet
, r
->start
.col
,
895 TRUE
, anchor
->offset
[0]);
896 res_pts
[1] = cell_offset_calc_pt (sheet
, r
->start
.row
,
897 FALSE
, anchor
->offset
[1]);
898 res_pts
[2] = cell_offset_calc_pt (sheet
, r
->end
.col
,
899 TRUE
, anchor
->offset
[2]);
900 res_pts
[3] = cell_offset_calc_pt (sheet
, r
->end
.row
,
901 FALSE
, anchor
->offset
[3]);
905 clear_sheet (SheetObject
*so
, GOUndo
**pundo
)
908 GOUndo
*u
= go_undo_binary_new
911 (GOUndoBinaryFunc
)sheet_object_set_sheet
,
912 (GFreeFunc
) g_object_unref
,
914 *pundo
= go_undo_combine (*pundo
, u
);
917 sheet_object_clear_sheet (so
);
922 * sheet_objects_relocate:
923 * @rinfo: details on what should be moved.
924 * @update: Should we do the bound_update now, or leave it for later.
925 * if FALSE honour the move_with_cells flag.
926 * @pundo: if non-NULL add dropped objects to ::objects
928 * Uses the relocation info and the anchors to decide whether or not, and how
929 * to relocate objects when the grid moves (eg ins/del col/row).
932 sheet_objects_relocate (GnmExprRelocateInfo
const *rinfo
, gboolean update
,
937 gboolean change_sheets
;
939 g_return_if_fail (rinfo
!= NULL
);
940 g_return_if_fail (IS_SHEET (rinfo
->origin_sheet
));
941 g_return_if_fail (IS_SHEET (rinfo
->target_sheet
));
943 dest
= rinfo
->origin
;
944 range_translate (&dest
, rinfo
->target_sheet
,
945 rinfo
->col_offset
, rinfo
->row_offset
);
946 change_sheets
= (rinfo
->origin_sheet
!= rinfo
->target_sheet
);
948 /* Clear the destination range on the target sheet */
950 GSList
*copy
= g_slist_copy (rinfo
->target_sheet
->sheet_objects
);
951 for (ptr
= copy
; ptr
!= NULL
; ptr
= ptr
->next
) {
952 SheetObject
*so
= SHEET_OBJECT (ptr
->data
);
953 GnmRange
const *r
= &so
->anchor
.cell_bound
;
954 if (range_contains (&dest
, r
->start
.col
, r
->start
.row
)) {
955 clear_sheet (so
, pundo
);
961 ptr
= rinfo
->origin_sheet
->sheet_objects
;
962 for (; ptr
!= NULL
; ptr
= next
) {
963 SheetObject
*so
= SHEET_OBJECT (ptr
->data
);
964 GnmRange r
= so
->anchor
.cell_bound
;
967 if (update
&& 0 == (so
->flags
& SHEET_OBJECT_MOVE_WITH_CELLS
))
969 if (range_contains (&rinfo
->origin
, r
.start
.col
, r
.start
.row
)) {
970 /* FIXME : just moving the range is insufficent for all anchor types */
971 /* Toss any objects that would be clipped. */
972 if (range_translate (&r
, rinfo
->origin_sheet
,
973 rinfo
->col_offset
, rinfo
->row_offset
)) {
974 clear_sheet (so
, pundo
);
977 so
->anchor
.cell_bound
= r
;
981 sheet_object_clear_sheet (so
);
982 sheet_object_set_sheet (so
, rinfo
->target_sheet
);
985 sheet_object_update_bounds (so
, NULL
);
986 } else if (!change_sheets
&&
987 range_contains (&dest
, r
.start
.col
, r
.start
.row
)) {
988 clear_sheet (so
, pundo
);
993 sheet_objects_max_extent (rinfo
->origin_sheet
);
995 sheet_objects_max_extent (rinfo
->target_sheet
);
1000 * @sheet: the sheet.
1001 * @r: an optional range to look in
1002 * @t: The type of object to lookup
1004 * Returns: (element-type SheetObject) (transfer container): a list of which
1005 * the caller must free (just the list not the content).
1006 * Containing all objects of exactly the specified type (inheritence does not count)
1007 * that are completely contained by @r.
1010 sheet_objects_get (Sheet
const *sheet
, GnmRange
const *r
, GType t
)
1015 g_return_val_if_fail (IS_SHEET (sheet
), NULL
);
1017 for (ptr
= sheet
->sheet_objects
; ptr
!= NULL
; ptr
= ptr
->next
) {
1018 GObject
*obj
= G_OBJECT (ptr
->data
);
1020 if (t
== G_TYPE_NONE
|| t
== G_OBJECT_TYPE (obj
)) {
1021 SheetObject
*so
= SHEET_OBJECT (obj
);
1022 if (r
== NULL
|| range_contained (&so
->anchor
.cell_bound
, r
))
1023 res
= g_slist_prepend (res
, so
);
1026 return g_slist_reverse (res
);
1030 * sheet_objects_clear:
1031 * @sheet: the sheet.
1032 * @r: an optional range to look in
1034 * removes the objects in the region.
1037 sheet_objects_clear (Sheet
const *sheet
, GnmRange
const *r
, GType t
,
1042 g_return_if_fail (IS_SHEET (sheet
));
1044 for (ptr
= sheet
->sheet_objects
; ptr
!= NULL
; ptr
= next
) {
1045 GObject
*obj
= G_OBJECT (ptr
->data
);
1047 if ((t
== G_TYPE_NONE
&& G_OBJECT_TYPE (obj
) != GNM_FILTER_COMBO_TYPE
)
1048 || t
== G_OBJECT_TYPE (obj
)) {
1049 SheetObject
*so
= SHEET_OBJECT (obj
);
1050 if (r
== NULL
|| range_contained (&so
->anchor
.cell_bound
, r
))
1051 clear_sheet (so
, pundo
);
1058 * @so: a #SheetObject to duplicate
1060 * Returns: (transfer full): A copy of @so that is not attached to a sheet.
1061 * Caller is responsible for the reference.
1064 sheet_object_dup (SheetObject
const *so
)
1066 SheetObject
*new_so
= NULL
;
1068 if (!SO_CLASS (so
)->copy
)
1071 new_so
= g_object_new (G_OBJECT_TYPE (so
), NULL
);
1073 g_return_val_if_fail (new_so
!= NULL
, NULL
);
1075 SO_CLASS (so
)->copy (new_so
, so
);
1076 new_so
->flags
= so
->flags
;
1077 new_so
->anchor
= so
->anchor
;
1083 cb_sheet_objects_dup (GnmDependent
*dep
, SheetObject
*so
, gpointer user
)
1086 Sheet
*dst
= sheet_object_get_sheet (so
);
1087 GnmExprTop
const *texpr
;
1092 texpr
= gnm_expr_top_relocate_sheet (dep
->texpr
, src
, dst
);
1093 if (texpr
!= dep
->texpr
) {
1094 gboolean was_linked
= dependent_is_linked (dep
);
1095 dependent_set_expr (dep
, texpr
);
1097 dependent_link (dep
);
1099 gnm_expr_top_unref (texpr
);
1104 * sheet_objects_dup:
1105 * @src: The source sheet to read the objects from
1106 * @dst: The destination sheet to attach the objects to
1107 * @range: Optionally NULL region of interest
1109 * Clones the objects of the src sheet and attaches them into the dst sheet
1112 sheet_objects_dup (Sheet
const *src
, Sheet
*dst
, GnmRange
*range
)
1116 g_return_if_fail (IS_SHEET (dst
));
1117 g_return_if_fail (dst
->sheet_objects
== NULL
);
1119 for (list
= src
->sheet_objects
; list
!= NULL
; list
= list
->next
) {
1120 SheetObject
*so
= list
->data
;
1121 if (range
== NULL
|| range_overlap (range
, &so
->anchor
.cell_bound
)) {
1122 SheetObject
*new_so
= sheet_object_dup (so
);
1123 if (new_so
!= NULL
) {
1124 sheet_object_set_sheet (new_so
, dst
);
1125 sheet_object_foreach_dep (new_so
, cb_sheet_objects_dup
,
1127 g_object_unref (new_so
);
1132 dst
->sheet_objects
= g_slist_reverse (dst
->sheet_objects
);
1137 * sheet_object_direction_set:
1138 * @so: The sheet object that we are calculating the direction for
1139 * @coords: array of coordinates in L,T,R,B order
1141 * Sets the object direction from the given the new coordinates
1142 * The original coordinates are assumed to be normalized (so that top
1143 * is above bottom and right is at the right of left)
1146 sheet_object_direction_set (SheetObject
*so
, gdouble
const *coords
)
1148 if (so
->anchor
.base
.direction
== GOD_ANCHOR_DIR_UNKNOWN
)
1151 so
->anchor
.base
.direction
= GOD_ANCHOR_DIR_NONE_MASK
;
1153 if (coords
[1] < coords
[3])
1154 so
->anchor
.base
.direction
|= GOD_ANCHOR_DIR_DOWN
;
1155 if (coords
[0] < coords
[2])
1156 so
->anchor
.base
.direction
|= GOD_ANCHOR_DIR_RIGHT
;
1160 * sheet_object_rubber_band_directly:
1163 * Returns TRUE if we should draw the object as we are laying it out on
1164 * an sheet. If FLASE we draw a rectangle where the object is going to go
1169 sheet_object_rubber_band_directly (G_GNUC_UNUSED SheetObject
const *so
)
1175 * sheet_object_anchor_init:
1176 * @anchor: #SheetObjectAnchor
1177 * @cell_bound: #GnmRange
1178 * @offsets: double[4]
1179 * @direction: #GODrawingAnchorDir
1181 * A utility routine to initialize an anchor. Useful in case we change fields
1182 * in the future and want to ensure that everything is initialized.
1185 sheet_object_anchor_init (SheetObjectAnchor
*anchor
,
1186 GnmRange
const *r
, const double *offsets
,
1187 GODrawingAnchorDir direction
)
1192 static GnmRange
const defaultVal
= { { 0, 0 }, { 1, 1 } };
1195 anchor
->cell_bound
= *r
;
1197 if (offsets
== NULL
) {
1198 static double const defaultVal
[4] = { 0., 0., 0., 0. };
1199 offsets
= defaultVal
;
1201 for (i
= 4; i
-- > 0 ; )
1202 anchor
->offset
[i
] = offsets
[i
];
1204 anchor
->base
.direction
= direction
;
1205 /* TODO : add sanity checking to handle offsets past edges of col/row */
1208 /*****************************************************************************/
1211 * sheet_object_get_stacking:
1214 * Returns @so's position in the stack of sheet objects.
1217 sheet_object_get_stacking (SheetObject
*so
)
1222 g_return_val_if_fail (so
!= NULL
, 0);
1223 g_return_val_if_fail (so
->sheet
!= NULL
, 0);
1225 for (ptr
= so
->sheet
->sheet_objects
; ptr
; ptr
= ptr
->next
, pos
++)
1226 if (ptr
->data
== so
)
1229 g_warning ("Object not found??");
1234 sheet_object_adjust_stacking (SheetObject
*so
, gint offset
)
1237 GSList
**ptr
, *node
= NULL
;
1238 int i
, target
, cur
= 0;
1240 g_return_val_if_fail (so
!= NULL
, 0);
1241 g_return_val_if_fail (so
->sheet
!= NULL
, 0);
1243 for (ptr
= &so
->sheet
->sheet_objects
; *ptr
; ptr
= &(*ptr
)->next
, cur
++)
1244 if ((*ptr
)->data
== so
) {
1246 *ptr
= (*ptr
)->next
;
1250 g_return_val_if_fail (node
!= NULL
, 0);
1252 /* Start at the begining when moving things towards the front */
1254 ptr
= &so
->sheet
->sheet_objects
;
1259 for (target
= cur
- offset
; *ptr
&& i
< target
; ptr
= &(*ptr
)->next
)
1265 /* TODO : Move this to the container */
1266 for (l
= so
->realized_list
; l
; l
= l
->next
) {
1267 GocItem
*item
= GOC_ITEM (l
->data
);
1269 goc_item_raise (item
, offset
);
1271 goc_item_lower (item
, - offset
);
1276 /*****************************************************************************/
1278 static GObjectClass
*view_parent_class
;
1281 sheet_object_view_set_bounds (SheetObjectView
*sov
,
1282 double const *coords
, gboolean visible
)
1284 SheetObjectViewClass
*klass
;
1286 g_return_if_fail (IS_SHEET_OBJECT_VIEW (sov
));
1287 klass
= SHEET_OBJECT_VIEW_GET_CLASS (sov
);
1288 if (NULL
!= klass
->set_bounds
)
1289 (klass
->set_bounds
) (sov
, coords
, visible
);
1293 * sheet_object_view_get_so:
1294 * @sov: #SheetObjectView
1296 * Returns: (transfer none): the #SheetObject owning @view.
1299 sheet_object_view_get_so (SheetObjectView
*view
)
1301 return g_object_get_qdata (G_OBJECT (view
), sov_so_quark
);
1305 sheet_object_view_enter_notify (GocItem
*item
, double x
, double y
)
1309 if (IS_GNM_PANE (item
->canvas
) && scg_wbcg (GNM_SIMPLE_CANVAS (item
->canvas
)->scg
)->new_object
) {
1310 GnmItemGrid
*grid
= GNM_PANE (item
->canvas
)->grid
;
1311 return GOC_ITEM_GET_CLASS (grid
)->enter_notify (GOC_ITEM (grid
), x
, y
);
1314 so
= (SheetObject
*) g_object_get_qdata (G_OBJECT (item
), sov_so_quark
);
1315 gnm_widget_set_cursor_type (GTK_WIDGET (item
->canvas
),
1316 (so
->flags
& SHEET_OBJECT_CAN_PRESS
) ? GDK_HAND2
: GDK_ARROW
);
1321 cb_so_menu_activate (GObject
*menu
, GocItem
*view
)
1323 SheetObjectAction
const *a
= g_object_get_data (menu
, "action");
1326 SheetObject
*so
= sheet_object_view_get_so (SHEET_OBJECT_VIEW (view
));
1327 gpointer data
= g_object_get_data (G_OBJECT (view
->canvas
), "sheet-control");
1330 data
= GNM_SIMPLE_CANVAS (view
->canvas
)->scg
;
1332 (a
->func
) (so
, SHEET_CONTROL (data
));
1337 cb_ptr_array_free (GPtrArray
*actions
)
1339 g_ptr_array_free (actions
, TRUE
);
1343 * sheet_object_build_menu:
1344 * @view: #SheetObjectView
1345 * @actions: (element-type SheetObjectAction): array of actions.
1346 * @i: index of first action to add in the array.
1348 * Builds the contextual menu for @view.
1349 * Returns: (transfer full): the newly constructed #GtkMenu.
1352 sheet_object_build_menu (SheetObjectView
*view
,
1353 GPtrArray
const *actions
, unsigned *i
)
1355 SheetObjectAction
const *a
;
1356 GtkWidget
*item
, *menu
= gtk_menu_new ();
1358 while (*i
< actions
->len
) {
1359 a
= g_ptr_array_index (actions
, *i
);
1363 if (a
->icon
!= NULL
) {
1364 if (a
->label
!= NULL
) {
1365 item
= gtk_image_menu_item_new_with_mnemonic (_(a
->label
));
1366 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item
),
1367 gtk_image_new_from_stock (a
->icon
, GTK_ICON_SIZE_MENU
));
1369 item
= gtk_image_menu_item_new_from_stock (a
->icon
, NULL
);
1370 } else if (a
->label
!= NULL
)
1371 item
= gtk_menu_item_new_with_mnemonic (_(a
->label
));
1373 item
= gtk_separator_menu_item_new ();
1375 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item
),
1376 sheet_object_build_menu (view
, actions
, i
));
1377 else if (a
->label
!= NULL
|| a
->icon
!= NULL
) { /* not a separator or menu */
1378 g_object_set_data (G_OBJECT (item
), "action", (gpointer
)a
);
1379 g_signal_connect_object (G_OBJECT (item
), "activate",
1380 G_CALLBACK (cb_so_menu_activate
), view
, 0);
1381 gtk_widget_set_sensitive (item
, a
->enable_func
== NULL
1382 || a
->enable_func (sheet_object_view_get_so (view
)));
1384 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1390 sheet_object_view_button_pressed (GocItem
*item
, int button
, double x
, double y
)
1394 if (IS_GNM_PANE (item
->canvas
)) {
1395 if (scg_wbcg (GNM_SIMPLE_CANVAS (item
->canvas
)->scg
)->new_object
) {
1396 GnmItemGrid
*grid
= GNM_PANE (item
->canvas
)->grid
;
1397 return GOC_ITEM_GET_CLASS (grid
)->button_pressed (GOC_ITEM (grid
), button
, x
, y
);
1403 pane
= GNM_PANE (item
->canvas
);
1404 so
= (SheetObject
*) g_object_get_qdata (G_OBJECT (item
), sov_so_quark
);
1406 x
*= goc_canvas_get_pixels_per_unit (item
->canvas
);
1407 y
*= goc_canvas_get_pixels_per_unit (item
->canvas
);
1408 /* cb_sheet_object_widget_canvas_event calls even if selected */
1409 if (NULL
== g_hash_table_lookup (pane
->drag
.ctrl_pts
, so
)) {
1410 SheetObjectClass
*soc
=
1411 G_TYPE_INSTANCE_GET_CLASS (so
, SHEET_OBJECT_TYPE
, SheetObjectClass
);
1412 GdkEventButton
*event
= (GdkEventButton
*) goc_canvas_get_cur_event (item
->canvas
);
1414 if (soc
->interactive
&& button
!= 3)
1417 if (!(event
->state
& GDK_SHIFT_MASK
))
1418 scg_object_unselect (pane
->simple
.scg
, NULL
);
1419 scg_object_select (pane
->simple
.scg
, so
);
1420 if (NULL
== g_hash_table_lookup (pane
->drag
.ctrl_pts
, so
))
1421 return FALSE
; /* protected ? */
1425 gnm_pane_object_start_resize (pane
, button
, x
, y
, so
, 8, FALSE
);
1427 gnm_pane_display_object_menu (pane
, so
, goc_canvas_get_cur_event (item
->canvas
));
1430 GPtrArray
*actions
= g_ptr_array_new ();
1434 so
= (SheetObject
*) g_object_get_qdata (G_OBJECT (item
), sov_so_quark
);
1435 sheet_object_populate_menu (so
, actions
);
1437 if (actions
->len
== 0) {
1438 g_ptr_array_free (actions
, TRUE
);
1442 menu
= sheet_object_build_menu
1443 (sheet_object_get_view (so
, (SheetObjectViewContainer
*) item
->canvas
),
1445 g_object_set_data_full (G_OBJECT (menu
), "actions", actions
,
1446 (GDestroyNotify
) cb_ptr_array_free
);
1447 gtk_widget_show_all (menu
);
1448 gnumeric_popup_menu (GTK_MENU (menu
),
1449 goc_canvas_get_cur_event (item
->canvas
));
1456 sheet_object_view_button2_pressed (GocItem
*item
, int button
, double x
, double y
)
1458 if (button
== 1 && !IS_GNM_PANE (item
->canvas
)) {
1459 SheetControl
*sc
= SHEET_CONTROL (g_object_get_data (G_OBJECT (item
->canvas
), "sheet-control"));
1460 SheetObject
*so
= (SheetObject
*) g_object_get_qdata (G_OBJECT (item
), sov_so_quark
);
1462 if (sc
&& sheet_object_can_edit (so
))
1463 sheet_object_get_editor (so
, sc
);
1469 sheet_object_view_finalize (GObject
*obj
)
1471 SheetObject
*so
= (SheetObject
*) g_object_get_qdata (obj
, sov_so_quark
);
1473 so
->realized_list
= g_list_remove (so
->realized_list
, obj
);
1474 view_parent_class
->finalize (obj
);
1478 sheet_object_view_class_init (GocItemClass
*item_klass
)
1480 GObjectClass
*obj_klass
= (GObjectClass
*) item_klass
;
1481 view_parent_class
= g_type_class_peek_parent (item_klass
);
1483 obj_klass
->finalize
= sheet_object_view_finalize
;
1485 item_klass
->enter_notify
= sheet_object_view_enter_notify
;
1486 item_klass
->button_pressed
= sheet_object_view_button_pressed
;
1487 item_klass
->button2_pressed
= sheet_object_view_button2_pressed
;
1490 GSF_CLASS (SheetObjectView
, sheet_object_view
,
1491 sheet_object_view_class_init
, NULL
,
1494 /*****************************************************************************/
1497 sheet_object_imageable_get_type (void)
1499 static GType type
= 0;
1502 static GTypeInfo
const type_info
= {
1503 sizeof (SheetObjectImageableIface
), /* class_size */
1504 NULL
, /* base_init */
1505 NULL
, /* base_finalize */
1506 NULL
, NULL
, NULL
, 0, 0, NULL
, NULL
1509 type
= g_type_register_static (G_TYPE_INTERFACE
,
1510 "SheetObjectImageable", &type_info
, 0);
1516 #define SHEET_OBJECT_IMAGEABLE_CLASS(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), SHEET_OBJECT_IMAGEABLE_TYPE, SheetObjectImageableIface))
1519 sheet_object_get_target_list (SheetObject
const *so
)
1521 if (!IS_SHEET_OBJECT_IMAGEABLE (so
))
1524 return SHEET_OBJECT_IMAGEABLE_CLASS (so
)->get_target_list (so
);
1528 sheet_object_write_image (SheetObject
const *so
, char const *format
, double resolution
,
1529 GsfOutput
*output
, GError
**err
)
1531 g_return_if_fail (IS_SHEET_OBJECT_IMAGEABLE (so
));
1533 SHEET_OBJECT_IMAGEABLE_CLASS (so
)->write_image (so
, format
, resolution
,
1538 /*****************************************************************************/
1541 sheet_object_exportable_get_type (void)
1543 static GType type
= 0;
1546 static GTypeInfo
const type_info
= {
1547 sizeof (SheetObjectExportableIface
), /* class_size */
1548 NULL
, /* base_init */
1549 NULL
, /* base_finalize */
1550 NULL
, NULL
, NULL
, 0, 0, NULL
, NULL
1553 type
= g_type_register_static (G_TYPE_INTERFACE
,
1554 "SheetObjectExportable", &type_info
, 0);
1560 #define SHEET_OBJECT_EXPORTABLE_CLASS(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), SHEET_OBJECT_EXPORTABLE_TYPE, SheetObjectExportableIface))
1563 sheet_object_exportable_get_target_list (SheetObject
const *so
)
1565 if (!IS_SHEET_OBJECT_EXPORTABLE (so
))
1568 return SHEET_OBJECT_EXPORTABLE_CLASS (so
)->get_target_list (so
);
1572 sheet_object_write_object (SheetObject
const *so
, char const *format
,
1573 GsfOutput
*output
, GError
**err
,
1574 GnmConventions
const *convs
)
1578 g_return_if_fail (IS_SHEET_OBJECT_EXPORTABLE (so
));
1580 locale
= gnm_push_C_locale ();
1581 SHEET_OBJECT_EXPORTABLE_CLASS (so
)->
1582 write_object (so
, format
, output
, err
, convs
);
1583 gnm_pop_C_locale (locale
);
1587 * sheet_object_move_undo:
1588 * @objects: (element-type SheetObject):
1591 * Returns: (transfer full): the newly allocated #GOUndo.
1594 sheet_object_move_undo (GSList
*objects
, gboolean objects_created
)
1596 GOUndo
*undo
= NULL
;
1597 GSList
*objs
= objects
;
1599 g_return_val_if_fail (NULL
!= objects
, NULL
);
1601 for (; objs
; objs
= objs
->next
) {
1602 SheetObject
*obj
= objs
->data
;
1603 SheetObjectAnchor
*tmp
;
1605 if (objects_created
) {
1606 undo
= go_undo_combine
1609 (g_object_ref (obj
),
1610 (GOUndoUnaryFunc
) sheet_object_clear_sheet
,
1611 (GFreeFunc
) g_object_unref
));
1614 tmp
= g_new (SheetObjectAnchor
, 1);
1615 *tmp
= *sheet_object_get_anchor (obj
);
1616 undo
= go_undo_combine
1617 (undo
, go_undo_binary_new
1618 (g_object_ref (obj
), tmp
,
1619 (GOUndoBinaryFunc
) sheet_object_set_anchor
,
1620 (GFreeFunc
) g_object_unref
,
1621 (GFreeFunc
) g_free
));
1627 * sheet_object_move_do:
1628 * @objects: (element-type SheetObject):
1629 * @anchors: (element-type SheetObjectAnchor):
1632 * Returns: (transfer full): the newly allocated #GOUndo.
1635 sheet_object_move_do (GSList
*objects
, GSList
*anchors
,
1636 gboolean objects_created
)
1638 GOUndo
*undo
= NULL
;
1639 GSList
*objs
= objects
, *anchs
= anchors
;
1641 g_return_val_if_fail (NULL
!= objects
, NULL
);
1642 g_return_val_if_fail (NULL
!= anchors
, NULL
);
1643 g_return_val_if_fail (g_slist_length (objects
)
1644 == g_slist_length (anchors
), NULL
);
1646 for (; objs
&& anchs
; objs
= objs
->next
, anchs
= anchs
->next
) {
1647 SheetObject
*obj
= objs
->data
;
1648 SheetObjectAnchor
*anch
= anchs
->data
;
1649 SheetObjectAnchor
*tmp
;
1651 if (objects_created
) {
1652 undo
= go_undo_combine
1655 (g_object_ref (obj
),
1656 sheet_object_get_sheet (obj
),
1657 (GOUndoBinaryFunc
) sheet_object_set_sheet
,
1658 (GFreeFunc
) g_object_unref
,
1661 tmp
= g_new (SheetObjectAnchor
, 1);
1663 undo
= go_undo_combine
1665 (g_object_ref (obj
), tmp
,
1666 (GOUndoBinaryFunc
) sheet_object_set_anchor
,
1667 (GFreeFunc
) g_object_unref
,
1668 (GFreeFunc
) g_free
), undo
);
1674 /*****************************************************************************/
1677 sheet_objects_init (void)
1681 SHEET_OBJECT_GRAPH_TYPE
;
1682 SHEET_OBJECT_IMAGE_TYPE
;
1683 GNM_GO_DATA_SCALAR_TYPE
;
1684 GNM_GO_DATA_VECTOR_TYPE
;
1685 GNM_GO_DATA_MATRIX_TYPE
;
1688 sheet_object_widget_register ();
1689 sov_so_quark
= g_quark_from_static_string ("SheetObject");
1690 sov_container_quark
= g_quark_from_static_string ("SheetObjectViewContainer");