1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include "object_ops.h"
29 #include "render_eps.h"
33 #include "preferences.h"
34 #include "properties.h"
35 #include "cut_n_paste.h"
36 #include "layer_dialog.h"
37 #include "app_procs.h"
39 #include "load_save.h"
40 #include "recent_files.h"
41 #include "diagram_tree_window.h"
43 #include "dynamic_refresh.h"
45 #include "lib/diamarshal.h"
48 static GList
*open_diagrams
= NULL
;
56 typedef struct _ObjectExtent ObjectExtent
;
58 static gint
diagram_parent_sort_cb(gconstpointer a
, gconstpointer b
);
61 static void diagram_class_init (DiagramClass
*klass
);
62 static gboolean
diagram_init(Diagram
*obj
, const char *filename
);
63 static void diagram_update_for_filename(Diagram
*dia
);
71 static guint diagram_signals
[LAST_SIGNAL
] = { 0, };
72 static gpointer parent_class
= NULL
;
75 diagram_get_type (void)
77 static GType object_type
= 0;
81 static const GTypeInfo object_info
=
83 sizeof (DiagramClass
),
85 (GBaseFinalizeFunc
) NULL
,
86 (GClassInitFunc
) diagram_class_init
,
87 NULL
, /* class_finalize */
88 NULL
, /* class_data */
94 object_type
= g_type_register_static (DIA_TYPE_DIAGRAM_DATA
,
103 diagram_finalize(GObject
*object
)
105 Diagram
*dia
= DIA_DIAGRAM(object
);
107 assert(dia
->displays
==NULL
);
109 open_diagrams
= g_list_remove(open_diagrams
, dia
);
110 layer_dialog_update_diagram_list();
113 undo_destroy(dia
->undo
);
116 diagram_tree_remove(diagram_tree(), dia
);
118 diagram_cleanup_autosave(dia
);
121 g_free(dia
->filename
);
122 dia
->filename
= NULL
;
124 G_OBJECT_CLASS (parent_class
)->finalize (object
);
128 _diagram_removed (Diagram
* dia
)
133 _diagram_selection_changed (Diagram
* dia
, int n
)
138 diagram_class_init (DiagramClass
*klass
)
140 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
142 parent_class
= g_type_class_peek_parent (klass
);
144 diagram_signals
[REMOVED
] =
145 g_signal_new ("removed",
146 G_TYPE_FROM_CLASS (klass
),
148 G_STRUCT_OFFSET (DiagramClass
, removed
),
150 dia_marshal_VOID__VOID
,
153 diagram_signals
[SELECTION_CHANGED
] =
154 g_signal_new ("selection_changed",
155 G_TYPE_FROM_CLASS (klass
),
157 G_STRUCT_OFFSET (DiagramClass
, selection_changed
),
159 dia_marshal_VOID__INT
,
163 klass
->removed
= _diagram_removed
;
164 klass
->selection_changed
= _diagram_selection_changed
;
166 object_class
->finalize
= diagram_finalize
;
170 dia_open_diagrams(void)
172 return open_diagrams
;
175 /** Initializes a diagram with standard info and sets it to be called
177 * Returns TRUE if everything went ok, FALSE otherwise.
178 * Will return FALSE if filename is not a legal string in the current
182 diagram_init(Diagram
*dia
, const char *filename
)
184 gchar
*newfilename
= NULL
;
185 GError
*error
= NULL
;
187 dia
->data
= &dia
->parent_instance
; /* compatibility */
189 dia
->pagebreak_color
= prefs
.new_diagram
.pagebreak_color
;
191 dia
->grid
.width_x
= prefs
.grid
.x
;
192 dia
->grid
.width_y
= prefs
.grid
.y
;
193 dia
->grid
.width_w
= prefs
.grid
.w
;
194 dia
->grid
.hex_size
= 1.0;
195 dia
->grid
.colour
= prefs
.new_diagram
.grid_color
;
196 dia
->grid
.hex
= prefs
.grid
.hex
;
197 dia
->grid
.visible_x
= 1;
198 dia
->grid
.visible_y
= 1;
199 dia
->grid
.dynamic
= prefs
.grid
.dynamic
;
200 dia
->grid
.major_lines
= prefs
.grid
.major_lines
;
202 dia
->guides
.nhguides
= 0;
203 dia
->guides
.hguides
= NULL
;
204 dia
->guides
.nvguides
= 0;
205 dia
->guides
.vguides
= NULL
;
207 if (dia
->filename
!= NULL
)
208 g_free(dia
->filename
);
209 /* Make sure the filename is absolute */
210 if (!g_path_is_absolute(filename
)) {
211 gchar
*pwd
= g_get_current_dir();
213 newfilename
= g_build_filename(pwd
, filename
, NULL
);
215 filename
= newfilename
;
217 /* All Diagram functions assumes filename in filesystem encoding */
219 dia
->filename
= g_filename_to_utf8(filename
, -1, NULL
, NULL
, &error
);
221 message_error(_("Couldn't convert filename '%s' to UTF-8: %s\n"),
222 dia_message_filename(filename
), error
->message
);
224 dia
->filename
= g_strdup(_("Error"));
229 dia
->mollified
= FALSE
;
230 dia
->autosavefilename
= NULL
;
233 undo_destroy(dia
->undo
);
234 dia
->undo
= new_undo_stack(dia
);
236 if (!g_list_find(open_diagrams
, dia
))
237 open_diagrams
= g_list_prepend(open_diagrams
, dia
);
239 if (app_is_interactive())
240 layer_dialog_update_diagram_list();
247 diagram_load_into(Diagram
*diagram
,
248 const char *filename
,
249 DiaImportFilter
*ifilter
)
252 ifilter
= filter_guess_import_filter(filename
);
253 if (!ifilter
) /* default to native format */
254 ifilter
= &dia_import_filter
;
256 if (!diagram_init(diagram
, filename
)) {
260 if (ifilter
->import_func(filename
, diagram
->data
, ifilter
->user_data
)) {
261 diagram
->unsaved
= FALSE
;
262 diagram_set_modified(diagram
, FALSE
);
263 if (app_is_interactive())
264 recent_file_history_add(filename
);
265 diagram_tree_add(diagram_tree(), diagram
);
272 diagram_load(const char *filename
, DiaImportFilter
*ifilter
)
274 Diagram
*diagram
= NULL
;
277 for (diagrams
= open_diagrams
; diagrams
!= NULL
; diagrams
= g_list_next(diagrams
)) {
278 Diagram
*old_diagram
= (Diagram
*)diagrams
->data
;
279 if (old_diagram
->is_default
) {
280 diagram
= old_diagram
;
285 /* TODO: Make diagram not be initialized twice */
286 if (diagram
== NULL
) {
287 diagram
= new_diagram(filename
);
289 if (diagram
== NULL
) return NULL
;
291 if (!diagram_load_into (diagram
, filename
, ifilter
)) {
292 diagram_destroy(diagram
);
295 if (diagram
!= NULL
&& diagram
->is_default
) {
296 diagram_update_for_filename(diagram
);
297 diagram
->is_default
= FALSE
;
303 /** Create a new diagram with the given filename.
304 * If the diagram could not be created, e.g. because the filename is not
305 * a legal string in the current encoding, return NULL.
308 new_diagram(const char *filename
) /* Note: filename is copied */
310 Diagram
*dia
= g_object_new(DIA_TYPE_DIAGRAM
, NULL
);
312 if (diagram_init(dia
, filename
)) {
321 diagram_destroy(Diagram
*dia
)
323 g_signal_emit (dia
, diagram_signals
[REMOVED
], 0);
327 /** Returns true if we consider the diagram modified.
330 diagram_is_modified(Diagram
*dia
)
332 return dia
->mollified
|| !undo_is_saved(dia
->undo
);
335 /** We might just have change the diagrams modified status.
336 * This doesn't set the status, but merely updates the display.
339 diagram_modified(Diagram
*dia
)
342 displays
= dia
->displays
;
343 while (displays
!= NULL
) {
344 DDisplay
*display
= (DDisplay
*) displays
->data
;
345 ddisplay_update_statusbar(display
);
346 displays
= g_slist_next(displays
);
348 if (diagram_is_modified(dia
)) {
349 dia
->autosaved
= FALSE
;
350 dia
->is_default
= FALSE
;
352 /* diagram_set_modified(dia, TRUE);*/
355 /** Set this diagram explicitly modified. This should not be called
356 * by things that change the undo stack, as those modifications are
357 * noticed through changes in the undo stack.
360 diagram_set_modified(Diagram
*dia
, int modified
)
362 if (dia
->mollified
!= modified
)
364 dia
->mollified
= modified
;
366 diagram_modified(dia
);
369 /* ************ Functions that check for menu sensitivity ********* */
371 /* Suggested optimization: The loops take a lot of the time. Collapse them
372 * into one, have them set flags for the things that have been found true.
373 * Harder to maintain.
376 diagram_selected_any_groups(Diagram
*dia
) {
379 for (selected
= dia
->data
->selected
;
380 selected
!= NULL
; selected
= selected
->next
) {
381 DiaObject
*obj
= (DiaObject
*)selected
->data
;
382 if (IS_GROUP(obj
)) return TRUE
;
388 diagram_selected_any_parents(Diagram
*dia
) {
391 for (selected
= dia
->data
->selected
;
392 selected
!= NULL
; selected
= selected
->next
) {
393 DiaObject
*obj
= (DiaObject
*)selected
->data
;
394 if (object_flags_set(obj
, DIA_OBJECT_CAN_PARENT
) && obj
->children
!= NULL
)
401 diagram_selected_any_children(Diagram
*dia
) {
404 for (selected
= dia
->data
->selected
;
405 selected
!= NULL
; selected
= selected
->next
) {
406 DiaObject
*obj
= (DiaObject
*)selected
->data
;
407 if (obj
->parent
!= NULL
) return TRUE
;
412 /** This is slightly more complex -- must see if any non-parented objects
413 * are within a parenting object.
416 diagram_selected_can_parent(Diagram
*dia
) {
418 GList
*parents
= NULL
;
420 for (selected
= dia
->data
->selected
;
421 selected
!= NULL
; selected
= selected
->next
) {
422 DiaObject
*obj
= (DiaObject
*)selected
->data
;
423 if (object_flags_set(obj
, DIA_OBJECT_CAN_PARENT
)) {
424 parents
= g_list_prepend(parents
, obj
);
427 for (selected
= dia
->data
->selected
;
428 selected
!= NULL
; selected
= selected
->next
) {
429 DiaObject
*obj
= (DiaObject
*)selected
->data
;
430 if (obj
->parent
== NULL
) {
432 Rectangle obj_bb
= obj
->bounding_box
;
433 for (parent_tmp
= parents
; parent_tmp
!= NULL
; parent_tmp
= parent_tmp
->next
) {
434 DiaObject
*p
= (DiaObject
*)parent_tmp
->data
;
435 if (p
== obj
) continue;
436 if (obj_bb
.left
> p
->bounding_box
.left
&&
437 obj_bb
.right
< p
->bounding_box
.right
&&
438 obj_bb
.top
> p
->bounding_box
.top
&&
439 obj_bb
.bottom
< p
->bounding_box
.bottom
) {
441 printf("Obj %f, %f x %f, %f inside %f, %f x %f, %f\n",
446 p->bounding_box.left,
448 p->bounding_box.right,
449 p->bounding_box.bottom);
451 g_list_free(parents
);
457 g_list_free(parents
);
462 This is the real implementation of the sensitivity update.
463 TODO: move it to the DDisplay as it belongs to it IMHO
466 diagram_update_menu_sensitivity (Diagram
*dia
, UpdatableMenuItems
*items
)
468 gint selected_count
= g_list_length (dia
->data
->selected
);
470 gtk_action_set_sensitive (items
->copy
, selected_count
> 0);
471 gtk_action_set_sensitive (items
->cut
, selected_count
> 0);
472 gtk_action_set_sensitive (items
->paste
, cnp_exist_stored_objects());
473 gtk_action_set_sensitive (items
->edit_delete
, selected_count
> 0);
474 gtk_action_set_sensitive (items
->edit_duplicate
, selected_count
> 0);
476 gtk_action_set_sensitive (items
->copy_text
, active_focus() != NULL
);
477 gtk_action_set_sensitive (items
->cut_text
, active_focus() != NULL
);
478 gtk_action_set_sensitive (items
->paste_text
, active_focus() != NULL
);
481 gtk_action_set_sensitive (items
->send_to_back
, selected_count
> 0);
482 gtk_action_set_sensitive (items
->bring_to_front
, selected_count
> 0);
483 gtk_action_set_sensitive (items
->send_backwards
, selected_count
> 0);
484 gtk_action_set_sensitive (items
->bring_forwards
, selected_count
> 0);
486 gtk_action_set_sensitive (items
->parent
, diagram_selected_can_parent (dia
));
487 gtk_action_set_sensitive (items
->unparent
,
488 diagram_selected_any_children (dia
));
489 gtk_action_set_sensitive (items
->unparent_children
,
490 diagram_selected_any_parents (dia
));
491 gtk_action_set_sensitive (items
->group
, selected_count
> 1);
492 gtk_action_set_sensitive (items
->ungroup
, diagram_selected_any_groups (dia
));
493 gtk_action_set_sensitive (items
->properties
, selected_count
> 0);
495 /* Objects->Align menu */
496 gtk_action_set_sensitive (items
->align_h_l
, selected_count
> 1);
497 gtk_action_set_sensitive (items
->align_h_c
, selected_count
> 1);
498 gtk_action_set_sensitive (items
->align_h_r
, selected_count
> 1);
499 gtk_action_set_sensitive (items
->align_h_e
, selected_count
> 1);
500 gtk_action_set_sensitive (items
->align_h_a
, selected_count
> 1);
501 gtk_action_set_sensitive (items
->align_v_t
, selected_count
> 1);
502 gtk_action_set_sensitive (items
->align_v_c
, selected_count
> 1);
503 gtk_action_set_sensitive (items
->align_v_b
, selected_count
> 1);
504 gtk_action_set_sensitive (items
->align_v_e
, selected_count
> 1);
505 gtk_action_set_sensitive (items
->align_v_a
, selected_count
> 1);
509 void diagram_update_menubar_sensitivity(Diagram
*dia
, UpdatableMenuItems
*items
)
511 diagram_update_menu_sensitivity (dia
, items
);
515 void diagram_update_popupmenu_sensitivity(Diagram
*dia
)
517 static int initialized
= 0;
518 static UpdatableMenuItems items
;
520 if (initialized
==0) {
521 menus_initialize_updatable_items (&items
, NULL
);
525 diagram_update_menu_sensitivity (dia
, &items
);
529 diagram_add_ddisplay(Diagram
*dia
, DDisplay
*ddisp
)
531 dia
->displays
= g_slist_prepend(dia
->displays
, ddisp
);
532 dia
->display_count
++;
536 diagram_remove_ddisplay(Diagram
*dia
, DDisplay
*ddisp
)
538 dia
->displays
= g_slist_remove(dia
->displays
, ddisp
);
539 dia
->display_count
--;
541 if (dia
->display_count
== 0) {
542 if (!app_is_embedded()) {
543 /* Don't delete embedded diagram when last view is closed */
544 diagram_destroy(dia
);
550 diagram_add_object(Diagram
*dia
, DiaObject
*obj
)
552 layer_add_object(dia
->data
->active_layer
, obj
);
554 diagram_modified(dia
);
556 diagram_tree_add_object(diagram_tree(), dia
, obj
);
560 diagram_add_object_list(Diagram
*dia
, GList
*list
)
562 layer_add_objects(dia
->data
->active_layer
, list
);
564 diagram_modified(dia
);
566 diagram_tree_add_objects(diagram_tree(), dia
, list
);
570 diagram_selected_break_external(Diagram
*dia
)
573 GList
*connected_list
;
575 DiaObject
*other_obj
;
578 list
= dia
->data
->selected
;
579 while (list
!= NULL
) {
580 obj
= (DiaObject
*)list
->data
;
582 /* Break connections between this object and objects not selected: */
583 for (i
=0;i
<obj
->num_handles
;i
++) {
584 ConnectionPoint
*con_point
;
585 con_point
= obj
->handles
[i
]->connected_to
;
587 if ( con_point
== NULL
)
588 break; /* Not connected */
590 other_obj
= con_point
->object
;
591 if (g_list_find(dia
->data
->selected
, other_obj
) == NULL
) {
592 /* other_obj is not selected, break connection */
593 Change
*change
= undo_unconnect(dia
, obj
, obj
->handles
[i
]);
594 (change
->apply
)(change
, dia
);
595 object_add_updates(obj
, dia
);
599 /* Break connections from non selected objects to this object: */
600 for (i
=0;i
<obj
->num_connections
;i
++) {
601 connected_list
= obj
->connections
[i
]->connected
;
603 while (connected_list
!= NULL
) {
604 other_obj
= (DiaObject
*)connected_list
->data
;
606 if (g_list_find(dia
->data
->selected
, other_obj
) == NULL
) {
607 /* other_obj is not in list, break all connections
608 to obj from other_obj */
610 for (j
=0;j
<other_obj
->num_handles
;j
++) {
611 ConnectionPoint
*con_point
;
612 con_point
= other_obj
->handles
[j
]->connected_to
;
614 if (con_point
&& (con_point
->object
== obj
)) {
616 connected_list
= g_list_previous(connected_list
);
617 change
= undo_unconnect(dia
, other_obj
,
618 other_obj
->handles
[j
]);
619 (change
->apply
)(change
, dia
);
620 if (connected_list
== NULL
)
621 connected_list
= obj
->connections
[i
]->connected
;
626 connected_list
= g_list_next(connected_list
);
629 diagram_tree_remove_object(diagram_tree(), obj
);
630 list
= g_list_next(list
);
635 diagram_remove_all_selected(Diagram
*diagram
, int delete_empty
)
637 object_add_updates_list(diagram
->data
->selected
, diagram
);
638 textedit_remove_focus_all(diagram
);
639 data_remove_all_selected(diagram
->data
);
640 g_signal_emit (diagram
, diagram_signals
[SELECTION_CHANGED
], 0, g_list_length (diagram
->data
->selected
));
644 diagram_unselect_object(Diagram
*diagram
, DiaObject
*obj
)
646 object_add_updates(obj
, diagram
);
647 textedit_remove_focus(obj
, diagram
);
648 data_unselect(DIA_DIAGRAM_DATA(diagram
), obj
);
649 g_signal_emit (diagram
, diagram_signals
[SELECTION_CHANGED
], 0,
650 g_list_length (DIA_DIAGRAM_DATA(diagram
)->selected
));
654 diagram_unselect_objects(Diagram
*dia
, GList
*obj_list
)
659 /* otherwise we would signal objects step by step */
660 g_signal_handlers_block_by_func (dia
, _diagram_selection_changed
, NULL
);
662 while (list
!= NULL
) {
663 obj
= (DiaObject
*) list
->data
;
665 if (g_list_find(dia
->data
->selected
, obj
) != NULL
){
666 diagram_unselect_object(dia
, obj
);
669 list
= g_list_next(list
);
671 g_signal_handlers_unblock_by_func (dia
, _diagram_selection_changed
, NULL
);
672 g_signal_emit (dia
, diagram_signals
[SELECTION_CHANGED
], 0, g_list_length (dia
->data
->selected
));
675 /** Make a single object selected.
676 * Note that an object inside a closed group cannot be made selected, nor
677 * can an object in a non-active layer.
678 * @param diagram The diagram that the object belongs to (sorta redundant now)
679 * @param obj The object that should be made selected.
682 diagram_select(Diagram
*diagram
, DiaObject
*obj
)
684 if (dia_object_is_selectable(obj
)) {
685 data_select(diagram
->data
, obj
);
686 obj
->ops
->selectf(obj
, NULL
, NULL
);
687 object_add_updates(obj
, diagram
);
688 g_signal_emit (diagram
, diagram_signals
[SELECTION_CHANGED
], 0,
689 g_list_length (diagram
->data
->selected
));
694 diagram_select_list(Diagram
*dia
, GList
*list
)
696 g_return_if_fail (dia
&& list
);
697 /* otherwise we would signal objects step by step */
698 g_signal_handlers_block_by_func (dia
, _diagram_selection_changed
, NULL
);
699 while (list
!= NULL
) {
700 DiaObject
*obj
= (DiaObject
*)list
->data
;
702 diagram_select(dia
, obj
);
704 list
= g_list_next(list
);
706 if (active_focus() == NULL
) {
707 textedit_activate_first(ddisplay_active());
709 g_signal_handlers_unblock_by_func (dia
, _diagram_selection_changed
, NULL
);
710 g_signal_emit (dia
, diagram_signals
[SELECTION_CHANGED
], 0, g_list_length (dia
->data
->selected
));
714 diagram_is_selected(Diagram
*diagram
, DiaObject
*obj
)
716 return g_list_find(diagram
->data
->selected
, obj
) != NULL
;
725 list
= open_diagrams
;
727 while (list
!= NULL
) {
728 dia
= (Diagram
*) list
->data
;
730 diagram_add_update_all(dia
);
733 list
= g_list_next(list
);
739 diagram_add_update_all(Diagram
*dia
)
746 ddisp
= (DDisplay
*) l
->data
;
748 ddisplay_add_update_all(ddisp
);
755 diagram_add_update(Diagram
*dia
, Rectangle
*update
)
762 ddisp
= (DDisplay
*) l
->data
;
764 ddisplay_add_update(ddisp
, update
);
770 /** Add an update of the given rectangle, but with an additional
771 * border around it. The pixels are added after the rectangle has
772 * been converted to pixel coords.
773 * Currently used for leaving room for highlighting.
776 diagram_add_update_with_border(Diagram
*dia
, Rectangle
*update
,
784 ddisp
= (DDisplay
*) l
->data
;
786 ddisplay_add_update_with_border(ddisp
, update
, pixel_border
);
793 diagram_add_update_pixels(Diagram
*dia
, Point
*point
,
794 int pixel_width
, int pixel_height
)
801 ddisp
= (DDisplay
*) l
->data
;
803 ddisplay_add_update_pixels(ddisp
, point
, pixel_width
, pixel_height
);
810 diagram_flush(Diagram
*dia
)
816 ddisp
= (DDisplay
*) l
->data
;
818 ddisplay_flush(ddisp
);
822 dynobj_refresh_kick();
826 diagram_find_clicked_object(Diagram
*dia
, Point
*pos
,
829 return layer_find_closest_object_except(dia
->data
->active_layer
,
834 diagram_find_clicked_object_except(Diagram
*dia
, Point
*pos
,
835 real maxdist
, GList
*avoid
)
837 return layer_find_closest_object_except(dia
->data
->active_layer
, pos
,
842 * Always returns the last handle in an object that has
843 * the closest distance
846 diagram_find_closest_handle(Diagram
*dia
, Handle
**closest
,
847 DiaObject
**object
, Point
*pos
)
855 mindist
= 1000000.0; /* Realy big value... */
859 l
= dia
->data
->selected
;
861 obj
= (DiaObject
*) l
->data
;
863 for (i
=0;i
<obj
->num_handles
;i
++) {
864 handle
= obj
->handles
[i
];
865 /* Note: Uses manhattan metric for speed... */
866 dist
= distance_point_point_manhattan(pos
, &handle
->pos
);
881 diagram_find_closest_connectionpoint(Diagram
*dia
,
882 ConnectionPoint
**closest
,
886 real dist
= 100000000.0;
888 for (i
=0;i
<dia
->data
->layers
->len
;i
++) {
889 Layer
*layer
= (Layer
*)g_ptr_array_index(dia
->data
->layers
, i
);
890 ConnectionPoint
*this_cp
;
892 if (layer
->connectable
) {
893 this_dist
= layer_find_closest_connectionpoint(layer
,
894 &this_cp
, pos
, notthis
);
895 if (this_dist
< dist
) {
905 diagram_update_extents(Diagram
*dia
)
907 gfloat cur_scale
= dia
->data
->paper
.scaling
;
908 /* anropar update_scrollbars() */
910 if (data_update_extents(dia
->data
)) {
911 /* Update scrollbars because extents were changed: */
917 ddisp
= (DDisplay
*) l
->data
;
919 ddisplay_update_scrollbars(ddisp
);
923 if (cur_scale
!= dia
->data
->paper
.scaling
) {
924 diagram_add_update_all(dia
);
930 /* Remove connections from obj to objects outside created group. */
932 strip_connections(DiaObject
*obj
, GList
*not_strip_list
, Diagram
*dia
)
938 for (i
=0;i
<obj
->num_handles
;i
++) {
939 handle
= obj
->handles
[i
];
940 if ((handle
->connected_to
!= NULL
) &&
941 (g_list_find(not_strip_list
, handle
->connected_to
->object
)==NULL
)) {
942 change
= undo_unconnect(dia
, obj
, handle
);
943 (change
->apply
)(change
, dia
);
951 diagram_parent_sort_cb(gconstpointer _a
, gconstpointer _b
)
953 ObjectExtent
**a
= (ObjectExtent
**)_a
;
954 ObjectExtent
**b
= (ObjectExtent
**)_b
;
956 if ((*a
)->extent
.left
< (*b
)->extent
.left
)
958 else if ((*a
)->extent
.left
> (*b
)->extent
.left
)
961 if ((*a
)->extent
.top
< (*b
)->extent
.top
)
963 else if ((*a
)->extent
.top
> (*b
)->extent
.top
)
970 /* needs faster algorithm -- if we find that parenting is slow.
971 * If it works, don't optimize it until it's a hotspot. */
972 void diagram_parent_selected(Diagram
*dia
)
974 GList
*list
= dia
->data
->selected
;
975 int length
= g_list_length(list
);
978 gboolean any_parented
= FALSE
;
979 GPtrArray
*extents
= g_ptr_array_sized_new(length
);
982 oe
= g_new(ObjectExtent
, 1);
983 oe
->object
= list
->data
;
984 parent_handle_extents(list
->data
, &oe
->extent
);
985 g_ptr_array_add(extents
, oe
);
986 list
= g_list_next(list
);
988 /* sort all the objects by their left position */
989 g_ptr_array_sort(extents
, diagram_parent_sort_cb
);
991 for (idx
= 0; idx
< length
; idx
++)
993 ObjectExtent
*oe1
= g_ptr_array_index(extents
, idx
);
994 if (oe1
->object
->parent
)
997 for (idx2
= idx
+ 1; idx2
< length
; idx2
++)
999 ObjectExtent
*oe2
= g_ptr_array_index(extents
, idx2
);
1000 if (!object_flags_set(oe2
->object
, DIA_OBJECT_CAN_PARENT
))
1003 if (oe1
->extent
.right
<= oe2
->extent
.right
1004 && oe1
->extent
.bottom
<= oe2
->extent
.bottom
)
1007 change
= undo_parenting(dia
, oe2
->object
, oe1
->object
, TRUE
);
1008 (change
->apply
)(change
, dia
);
1009 any_parented
= TRUE
;
1011 oe1->object->parent = oe2->object;
1012 oe2->object->children = g_list_append(oe2->object->children, oe1->object);
1018 g_ptr_array_free(extents
, TRUE
);
1020 diagram_modified(dia
);
1022 undo_set_transactionpoint(dia
->undo
);
1026 /** Remove all selected objects from their parents (if any). */
1027 void diagram_unparent_selected(Diagram
*dia
)
1030 DiaObject
*obj
, *parent
;
1032 gboolean any_unparented
= FALSE
;
1034 for (list
= dia
->data
->selected
; list
!= NULL
; list
= g_list_next(list
))
1036 obj
= (DiaObject
*) list
->data
;
1037 parent
= obj
->parent
;
1042 change
= undo_parenting(dia
, parent
, obj
, FALSE
);
1043 (change
->apply
)(change
, dia
);
1044 any_unparented
= TRUE
;
1046 parent->children = g_list_remove(parent->children, obj);
1050 if (any_unparented
) {
1051 diagram_modified(dia
);
1053 undo_set_transactionpoint(dia
->undo
);
1057 /** Remove all children from the selected parents. */
1058 void diagram_unparent_children_selected(Diagram
*dia
)
1061 DiaObject
*obj
, *child
;
1062 gboolean any_unparented
= FALSE
;
1063 for (list
= dia
->data
->selected
; list
!= NULL
; list
= g_list_next(list
))
1065 obj
= (DiaObject
*) list
->data
;
1066 if (!object_flags_set(obj
, DIA_OBJECT_CAN_PARENT
) || !obj
->children
)
1069 any_unparented
= TRUE
;
1070 /* Yes, this creates a whole bunch of Changes. They're lightweight
1071 * structures, though, and it's easier to assure correctness this
1072 * way. If needed, we can make a parent undo with a list of children.
1074 while (obj
->children
!= NULL
) {
1076 child
= (DiaObject
*) obj
->children
->data
;
1077 change
= undo_parenting(dia
, obj
, child
, FALSE
);
1078 /* This will remove one item from the list, so the while terminates. */
1079 (change
->apply
)(change
, dia
);
1081 if (obj
->children
!= NULL
)
1082 printf("Obj still has %d children\n",
1083 g_list_length(obj
->children
));
1085 if (any_unparented
) {
1086 diagram_modified(dia
);
1088 undo_set_transactionpoint(dia
->undo
);
1092 void diagram_group_selected(Diagram
*dia
)
1102 /* the following is wrong as it screws up the selected list, see bug #153525
1103 * I just don't get what was originally intented so please speak up if you know --hb
1105 dia
->data
->selected
= parent_list_affected(dia
->data
->selected
);
1108 orig_list
= g_list_copy(dia
->data
->active_layer
->objects
);
1110 /* We have to rebuild the selection list so that it is the same
1111 order as in the Diagram list. */
1112 group_list
= diagram_get_sorted_selected_remove(dia
);
1115 while (list
!= NULL
) {
1116 obj
= (DiaObject
*)list
->data
;
1118 /* Remove connections from obj to objects outside created group. */
1119 /* strip_connections sets up its own undo info. */
1120 /* The connections aren't reattached by ungroup. */
1121 strip_connections(obj
, dia
->data
->selected
, dia
);
1123 list
= g_list_next(list
);
1126 /* Remove list of selected objects */
1127 textedit_remove_focus_all(dia
);
1128 data_remove_all_selected(dia
->data
);
1130 group
= group_create(group_list
);
1131 change
= undo_group_objects(dia
, group_list
, group
, orig_list
);
1132 (change
->apply
)(change
, dia
);
1134 /* Select the created group */
1135 diagram_select(dia
, group
);
1137 diagram_modified(dia
);
1140 undo_set_transactionpoint(dia
->undo
);
1143 void diagram_ungroup_selected(Diagram
*dia
)
1147 GList
*selected
, *selection_copy
;
1151 if (g_list_length(dia
->data
->selected
) < 1) {
1152 message_error("Trying to ungroup with no selected objects.");
1156 selection_copy
= g_list_copy(dia
->data
->selected
);
1157 selected
= selection_copy
;
1158 while (selected
!= NULL
) {
1159 group
= (DiaObject
*)selected
->data
;
1161 if (IS_GROUP(group
)) {
1165 diagram_unselect_object(dia
, group
);
1167 group_list
= group_objects(group
);
1168 diagram_select_list(dia
, group_list
);
1170 group_index
= layer_object_index(dia
->data
->active_layer
, group
);
1172 change
= undo_ungroup_objects(dia
, group_list
, group
, group_index
);
1173 (change
->apply
)(change
, dia
);
1177 selected
= g_list_next(selected
);
1179 g_list_free(selection_copy
);
1182 diagram_modified(dia
);
1184 undo_set_transactionpoint(dia
->undo
);
1189 diagram_get_sorted_selected(Diagram
*dia
)
1191 return data_get_sorted_selected(dia
->data
);
1194 /** Remove the currently selected objects from the diagram's object list.
1195 * Returns a newly created list of the selected objects, in order.
1198 diagram_get_sorted_selected_remove(Diagram
*dia
)
1200 diagram_modified(dia
);
1202 return data_get_sorted_selected_remove(dia
->data
);
1206 diagram_place_under_selected(Diagram
*dia
)
1211 if (g_list_length (dia
->data
->selected
) == 0)
1214 orig_list
= g_list_copy(dia
->data
->active_layer
->objects
);
1216 sorted_list
= diagram_get_sorted_selected_remove(dia
);
1217 object_add_updates_list(sorted_list
, dia
);
1218 layer_add_objects_first(dia
->data
->active_layer
, sorted_list
);
1220 undo_reorder_objects(dia
, g_list_copy(sorted_list
), orig_list
);
1222 diagram_modified(dia
);
1224 undo_set_transactionpoint(dia
->undo
);
1228 diagram_place_over_selected(Diagram
*dia
)
1233 if (g_list_length (dia
->data
->selected
) == 0)
1236 orig_list
= g_list_copy(dia
->data
->active_layer
->objects
);
1238 sorted_list
= diagram_get_sorted_selected_remove(dia
);
1239 object_add_updates_list(sorted_list
, dia
);
1240 layer_add_objects(dia
->data
->active_layer
, sorted_list
);
1242 undo_reorder_objects(dia
, g_list_copy(sorted_list
), orig_list
);
1244 diagram_modified(dia
);
1246 undo_set_transactionpoint(dia
->undo
);
1250 diagram_place_up_selected(Diagram
*dia
)
1255 GList
*new_list
= NULL
;
1257 if (g_list_length (dia
->data
->selected
) == 0)
1260 orig_list
= g_list_copy(dia
->data
->active_layer
->objects
);
1262 sorted_list
= diagram_get_sorted_selected(dia
);
1263 object_add_updates_list(orig_list
, dia
);
1265 new_list
= g_list_copy(orig_list
);
1266 stmp
= g_list_last(sorted_list
);
1268 for (tmp
= g_list_last(new_list
);
1270 tmp
= g_list_previous(tmp
)) {
1271 if (stmp
== NULL
) break;
1272 if (tmp
->prev
== NULL
) break;
1273 if (tmp
->data
== stmp
->data
) {
1274 stmp
= g_list_previous(stmp
);
1275 } else if (tmp
->prev
->data
== stmp
->data
) {
1276 void *swap
= tmp
->data
;
1277 tmp
->data
= tmp
->prev
->data
;
1278 tmp
->prev
->data
= swap
;
1279 stmp
= g_list_previous(stmp
);
1283 layer_set_object_list(dia
->data
->active_layer
, new_list
);
1285 undo_reorder_objects(dia
, g_list_copy(sorted_list
), orig_list
);
1287 diagram_modified(dia
);
1289 undo_set_transactionpoint(dia
->undo
);
1293 diagram_place_down_selected(Diagram
*dia
)
1298 GList
*new_list
= NULL
;
1300 if (g_list_length (dia
->data
->selected
) == 0)
1303 orig_list
= g_list_copy(dia
->data
->active_layer
->objects
);
1305 sorted_list
= diagram_get_sorted_selected(dia
);
1306 object_add_updates_list(orig_list
, dia
);
1309 g_assert(g_list_length (dia
->data
->selected
) == g_list_length(sorted_list
));
1311 new_list
= g_list_copy(orig_list
);
1315 for (tmp
= new_list
; tmp
!= NULL
; tmp
= g_list_next(tmp
)) {
1316 if (stmp
== NULL
) break;
1317 if (tmp
->next
== NULL
) break;
1318 if (tmp
->data
== stmp
->data
) {
1319 /* This just takes care of any starting matches */
1320 stmp
= g_list_next(stmp
);
1321 } else if (tmp
->next
->data
== stmp
->data
) {
1322 /* This flips the non-selected element forwards, ala bubblesort */
1323 void *swap
= tmp
->data
;
1324 tmp
->data
= tmp
->next
->data
;
1325 tmp
->next
->data
= swap
;
1326 stmp
= g_list_next(stmp
);
1330 layer_set_object_list(dia
->data
->active_layer
, new_list
);
1332 undo_reorder_objects(dia
, g_list_copy(sorted_list
), orig_list
);
1334 diagram_modified(dia
);
1336 undo_set_transactionpoint(dia
->undo
);
1340 diagram_set_filename(Diagram
*dia
, const char *filename
)
1342 g_free(dia
->filename
);
1343 dia
->filename
= g_filename_to_utf8(filename
, -1, NULL
, NULL
, NULL
);
1345 diagram_update_for_filename(dia
);
1348 /** Update the various areas that require updating when changing filename
1349 * This will ensure that all places that use the filename are updated:
1350 * Window titles, layer dialog, recent files, diagram tree.
1351 * @param dia The diagram whose filename has changed.
1354 diagram_update_for_filename(Diagram
*dia
)
1359 char *filename
= dia
->filename
;
1361 title
= diagram_get_name(dia
);
1365 ddisp
= (DDisplay
*) l
->data
;
1367 ddisplay_set_title(ddisp
, title
);
1369 l
= g_slist_next(l
);
1374 layer_dialog_update_diagram_list();
1375 recent_file_history_add(filename
);
1377 diagram_tree_update_name(diagram_tree(), dia
);
1380 /** Returns a string with a 'sensible' (human-readable) name for the
1381 * diagram. The string should be freed after use.
1382 * This name may or may not be the same as the filename.
1385 diagram_get_name(Diagram
*dia
)
1387 gchar
*title
= strrchr(dia
->filename
, G_DIR_SEPARATOR
);
1389 title
= dia
->filename
;
1394 return g_strdup(title
);
1397 int diagram_modified_exists(void)
1402 list
= open_diagrams
;
1404 while (list
!= NULL
) {
1405 dia
= (Diagram
*) list
->data
;
1407 if (diagram_is_modified(dia
))
1410 list
= g_list_next(list
);
1415 void diagram_object_modified(Diagram
*dia
, DiaObject
*object
)
1417 diagram_tree_update_object(diagram_tree(), dia
, object
);