1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1999 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.
22 #include "object_ops.h"
23 #include "properties.h"
24 #include "connectionpoint_ops.h"
27 #include "preferences.h"
28 #include "diagram_tree_window.h"
31 #define DEBUG_PRINTF(args) printf args
33 #define DEBUG_PRINTF(args)
37 transaction_point_pointer(Change
*change
, Diagram
*dia
)
39 /* Empty function used to track transactionpoints. */
43 is_transactionpoint(Change
*change
)
45 return change
->apply
== transaction_point_pointer
;
49 new_transactionpoint(void)
51 Change
*transaction
= g_new(Change
, 1);
54 transaction
->apply
= transaction_point_pointer
;
55 transaction
->revert
= transaction_point_pointer
;
56 transaction
->free
= NULL
;
63 new_undo_stack(Diagram
*dia
)
68 stack
= g_new(UndoStack
, 1);
71 transaction
= new_transactionpoint();
72 transaction
->next
= transaction
->prev
= NULL
;
73 stack
->last_change
= transaction
;
74 stack
->current_change
= transaction
;
81 undo_destroy(UndoStack
*stack
)
84 g_free(stack
->current_change
); /* Free first transaction point. */
91 undo_remove_redo_info(UndoStack
*stack
)
96 DEBUG_PRINTF(("UNDO: Removing redo info\n"));
98 change
= stack
->current_change
->next
;
99 stack
->current_change
->next
= NULL
;
100 stack
->last_change
= stack
->current_change
;
102 while (change
!= NULL
) {
103 next_change
= change
->next
;
105 (change
->free
)(change
);
107 change
= next_change
;
112 depth(UndoStack
*stack
)
116 change
= stack
->current_change
;
119 while (change
->prev
!= NULL
) {
120 change
= change
->prev
;
127 undo_push_change(UndoStack
*stack
, Change
*change
)
129 if (stack
->current_change
!= stack
->last_change
)
130 undo_remove_redo_info(stack
);
132 DEBUG_PRINTF(("UNDO: Push new change at %d\n", depth(stack
)));
134 change
->prev
= stack
->last_change
;
136 stack
->last_change
->next
= change
;
137 stack
->last_change
= change
;
138 stack
->current_change
= change
;
142 undo_delete_lowest_transaction(UndoStack
*stack
)
147 /* Find the lowest change: */
148 change
= stack
->current_change
;
149 while (change
->prev
!= NULL
) {
150 change
= change
->prev
;
153 /* Remove changes from the bottom until (and including)
154 * the first transactionpoint.
155 * Stop if we reach current_change or NULL.
158 if ( (change
== NULL
) || (change
== stack
->current_change
))
161 next_change
= change
->next
;
162 DEBUG_PRINTF(("freeing one change from the bottom.\n"));
164 (change
->free
)(change
);
166 change
= next_change
;
167 } while (!is_transactionpoint(change
));
169 if (is_transactionpoint(change
)) {
171 DEBUG_PRINTF(("Decreasing stack depth to: %d\n", stack
->depth
));
177 undo_set_transactionpoint(UndoStack
*stack
)
181 if (is_transactionpoint(stack
->current_change
))
184 DEBUG_PRINTF(("UNDO: Push new transactionpoint at %d\n", depth(stack
)));
186 transaction
= new_transactionpoint();
188 undo_push_change(stack
, transaction
);
190 DEBUG_PRINTF(("Increasing stack depth to: %d\n", stack
->depth
));
192 if (prefs
.undo_depth
> 0) {
193 while (stack
->depth
> prefs
.undo_depth
){
194 undo_delete_lowest_transaction(stack
);
200 undo_revert_to_last_tp(UndoStack
*stack
)
205 if (stack
->current_change
->prev
== NULL
)
206 return; /* Can't revert first transactionpoint */
208 change
= stack
->current_change
;
210 prev_change
= change
->prev
;
211 (change
->revert
)(change
, stack
->dia
);
212 change
= prev_change
;
213 } while (!is_transactionpoint(change
));
214 stack
->current_change
= change
;
216 DEBUG_PRINTF(("Decreasing stack depth to: %d\n", stack
->depth
));
220 undo_apply_to_next_tp(UndoStack
*stack
)
225 change
= stack
->current_change
;
227 if (change
->next
== NULL
)
228 return /* Already at top. */;
231 next_change
= change
->next
;
232 (change
->apply
)(change
, stack
->dia
);
233 change
= next_change
;
234 } while ( (change
!= NULL
) &&
235 (!is_transactionpoint(change
)) );
237 change
= stack
->last_change
;
238 stack
->current_change
= change
;
240 DEBUG_PRINTF(("Increasing stack depth to: %d\n", stack
->depth
));
245 undo_clear(UndoStack
*stack
)
249 DEBUG_PRINTF(("undo_clear()\n"));
251 change
= stack
->current_change
;
253 while (change
->prev
!= NULL
) {
254 change
= change
->prev
;
257 stack
->current_change
= change
;
259 undo_remove_redo_info(stack
);
263 /****************************************************************/
264 /****************************************************************/
265 /***************** *********************/
266 /***************** Specific undo functions: *********************/
267 /***************** *********************/
268 /****************************************************************/
269 /****************************************************************/
271 /******** Move object list: */
273 struct MoveObjectsChange
{
282 move_objects_apply(struct MoveObjectsChange
*change
, Diagram
*dia
)
288 object_add_updates_list(change
->obj_list
, dia
);
290 list
= change
->obj_list
;
292 while (list
!= NULL
) {
293 obj
= (Object
*) list
->data
;
295 obj
->ops
->move(obj
, &change
->dest_pos
[i
]);
297 list
= g_list_next(list
); i
++;
300 list
= change
->obj_list
;
302 obj
= (Object
*) list
->data
;
304 diagram_update_connections_object(dia
, obj
, TRUE
);
306 list
= g_list_next(list
);
309 object_add_updates_list(change
->obj_list
, dia
);
313 move_objects_revert(struct MoveObjectsChange
*change
, Diagram
*dia
)
319 object_add_updates_list(change
->obj_list
, dia
);
321 list
= change
->obj_list
;
323 while (list
!= NULL
) {
324 obj
= (Object
*) list
->data
;
326 obj
->ops
->move(obj
, &change
->orig_pos
[i
]);
328 list
= g_list_next(list
); i
++;
331 list
= change
->obj_list
;
333 obj
= (Object
*) list
->data
;
335 diagram_update_connections_object(dia
, obj
, TRUE
);
337 list
= g_list_next(list
);
340 object_add_updates_list(change
->obj_list
, dia
);
344 move_objects_free(struct MoveObjectsChange
*change
)
346 g_free(change
->orig_pos
);
347 g_free(change
->dest_pos
);
348 g_list_free(change
->obj_list
);
352 undo_move_objects(Diagram
*dia
, Point
*orig_pos
, Point
*dest_pos
,
355 struct MoveObjectsChange
*change
;
357 change
= g_new(struct MoveObjectsChange
, 1);
359 change
->change
.apply
= (UndoApplyFunc
) move_objects_apply
;
360 change
->change
.revert
= (UndoRevertFunc
) move_objects_revert
;
361 change
->change
.free
= (UndoFreeFunc
) move_objects_free
;
363 change
->orig_pos
= orig_pos
;
364 change
->dest_pos
= dest_pos
;
365 change
->obj_list
= obj_list
;
367 DEBUG_PRINTF(("UNDO: Push new move objects at %d\n", depth(dia
->undo
)));
368 undo_push_change(dia
->undo
, (Change
*) change
);
369 return (Change
*)change
;
372 /********** Move handle: */
374 struct MoveHandleChange
{
384 move_handle_apply(struct MoveHandleChange
*change
, Diagram
*dia
)
386 object_add_updates(change
->obj
, dia
);
387 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
388 &change
->dest_pos
, NULL
,
389 HANDLE_MOVE_USER_FINAL
, 0);
390 object_add_updates(change
->obj
, dia
);
391 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
395 move_handle_revert(struct MoveHandleChange
*change
, Diagram
*dia
)
397 object_add_updates(change
->obj
, dia
);
398 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
399 &change
->orig_pos
, NULL
,
400 HANDLE_MOVE_USER_FINAL
, 0);
401 object_add_updates(change
->obj
, dia
);
402 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
406 move_handle_free(struct MoveHandleChange
*change
)
412 undo_move_handle(Diagram
*dia
,
413 Handle
*handle
, Object
*obj
,
414 Point orig_pos
, Point dest_pos
)
416 struct MoveHandleChange
*change
;
418 change
= g_new(struct MoveHandleChange
, 1);
420 change
->change
.apply
= (UndoApplyFunc
) move_handle_apply
;
421 change
->change
.revert
= (UndoRevertFunc
) move_handle_revert
;
422 change
->change
.free
= (UndoFreeFunc
) move_handle_free
;
424 change
->orig_pos
= orig_pos
;
425 change
->dest_pos
= dest_pos
;
426 change
->handle
= handle
;
429 DEBUG_PRINTF(("UNDO: Push new move handle at %d\n", depth(dia
->undo
)));
431 undo_push_change(dia
->undo
, (Change
*) change
);
432 return (Change
*)change
;
435 /***************** Connect object: */
437 struct ConnectChange
{
442 ConnectionPoint
*connectionpoint
;
447 connect_apply(struct ConnectChange
*change
, Diagram
*dia
)
449 object_connect(change
->obj
, change
->handle
, change
->connectionpoint
);
451 object_add_updates(change
->obj
, dia
);
452 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
453 &change
->connectionpoint
->pos
,
454 change
->connectionpoint
,
455 HANDLE_MOVE_CONNECTED
, 0);
457 object_add_updates(change
->obj
, dia
);
461 connect_revert(struct ConnectChange
*change
, Diagram
*dia
)
463 object_unconnect(change
->obj
, change
->handle
);
465 object_add_updates(change
->obj
, dia
);
466 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
467 &change
->handle_pos
, NULL
,
468 HANDLE_MOVE_CONNECTED
, 0);
470 object_add_updates(change
->obj
, dia
);
474 connect_free(struct ConnectChange
*change
)
479 undo_connect(Diagram
*dia
, Object
*obj
, Handle
*handle
,
480 ConnectionPoint
*connectionpoint
)
482 struct ConnectChange
*change
;
484 change
= g_new(struct ConnectChange
, 1);
486 change
->change
.apply
= (UndoApplyFunc
) connect_apply
;
487 change
->change
.revert
= (UndoRevertFunc
) connect_revert
;
488 change
->change
.free
= (UndoFreeFunc
) connect_free
;
491 change
->handle
= handle
;
492 change
->handle_pos
= handle
->pos
;
493 change
->connectionpoint
= connectionpoint
;
495 DEBUG_PRINTF(("UNDO: Push new connect at %d\n", depth(dia
->undo
)));
496 undo_push_change(dia
->undo
, (Change
*) change
);
497 return (Change
*)change
;
500 /*************** Unconnect object: */
502 struct UnconnectChange
{
507 ConnectionPoint
*connectionpoint
;
511 unconnect_apply(struct UnconnectChange
*change
, Diagram
*dia
)
513 object_unconnect(change
->obj
, change
->handle
);
515 object_add_updates(change
->obj
, dia
);
519 unconnect_revert(struct UnconnectChange
*change
, Diagram
*dia
)
521 object_connect(change
->obj
, change
->handle
, change
->connectionpoint
);
523 object_add_updates(change
->obj
, dia
);
527 unconnect_free(struct UnconnectChange
*change
)
532 undo_unconnect(Diagram
*dia
, Object
*obj
, Handle
*handle
)
534 struct UnconnectChange
*change
;
536 change
= g_new(struct UnconnectChange
, 1);
538 change
->change
.apply
= (UndoApplyFunc
) unconnect_apply
;
539 change
->change
.revert
= (UndoRevertFunc
) unconnect_revert
;
540 change
->change
.free
= (UndoFreeFunc
) unconnect_free
;
543 change
->handle
= handle
;
544 change
->connectionpoint
= handle
->connected_to
;
546 DEBUG_PRINTF(("UNDO: Push new unconnect at %d\n", depth(dia
->undo
)));
547 undo_push_change(dia
->undo
, (Change
*) change
);
548 return (Change
*)change
;
552 /******** Delete object list: */
554 struct DeleteObjectsChange
{
558 GList
*obj_list
; /* Owning reference when applied */
559 GList
*original_objects
;
564 delete_objects_apply(struct DeleteObjectsChange
*change
, Diagram
*dia
)
568 DEBUG_PRINTF(("delete_objects_apply()\n"));
570 diagram_unselect_objects(dia
, change
->obj_list
);
571 layer_remove_objects(change
->layer
, change
->obj_list
);
572 object_add_updates_list(change
->obj_list
, dia
);
574 list
= change
->obj_list
;
575 while (list
!= NULL
) {
576 Object
*obj
= (Object
*)list
->data
;
578 /* Have to hide any open properties dialog
579 if it contains some object in cut_list */
580 properties_hide_if_shown(dia
, obj
);
582 /* Remove focus if active */
583 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
587 if (obj
->parent
) /* Lose references to deleted object */
588 obj
->parent
->children
= g_list_remove(obj
->parent
->children
, obj
);
590 list
= g_list_next(list
);
593 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
597 delete_objects_revert(struct DeleteObjectsChange
*change
, Diagram
*dia
)
600 DEBUG_PRINTF(("delete_objects_revert()\n"));
602 layer_set_object_list(change
->layer
,
603 g_list_copy(change
->original_objects
));
604 object_add_updates_list(change
->obj_list
, dia
);
606 list
= change
->obj_list
;
609 Object
*obj
= (Object
*) list
->data
;
610 if (obj
->parent
) /* Restore child references */
611 obj
->parent
->children
= g_list_append(obj
->parent
->children
, obj
);
613 list
= g_list_next(list
);
616 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
620 delete_objects_free(struct DeleteObjectsChange
*change
)
622 DEBUG_PRINTF(("delete_objects_free()\n"));
624 destroy_object_list(change
->obj_list
);
626 g_list_free(change
->obj_list
);
627 g_list_free(change
->original_objects
);
631 This function deletes specified objects along with any children
633 undo_delete_objects() only deletes the objects that are specified.
636 undo_delete_objects_children(Diagram
*dia
, GList
*obj_list
)
638 return undo_delete_objects(dia
, parent_list_affected(obj_list
));
642 undo_delete_objects(Diagram
*dia
, GList
*obj_list
)
644 struct DeleteObjectsChange
*change
;
646 change
= g_new(struct DeleteObjectsChange
, 1);
648 change
->change
.apply
= (UndoApplyFunc
) delete_objects_apply
;
649 change
->change
.revert
= (UndoRevertFunc
) delete_objects_revert
;
650 change
->change
.free
= (UndoFreeFunc
) delete_objects_free
;
652 change
->layer
= dia
->data
->active_layer
;
653 change
->obj_list
= obj_list
;
654 change
->original_objects
= g_list_copy(dia
->data
->active_layer
->objects
);
657 DEBUG_PRINTF(("UNDO: Push new delete objects at %d\n", depth(dia
->undo
)));
658 undo_push_change(dia
->undo
, (Change
*) change
);
659 return (Change
*)change
;
662 /******** Insert object list: */
664 struct InsertObjectsChange
{
668 GList
*obj_list
; /* Owning reference when not applied */
673 insert_objects_apply(struct InsertObjectsChange
*change
, Diagram
*dia
)
675 DEBUG_PRINTF(("insert_objects_apply()\n"));
677 layer_add_objects(change
->layer
, g_list_copy(change
->obj_list
));
678 object_add_updates_list(change
->obj_list
, dia
);
679 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
683 insert_objects_revert(struct InsertObjectsChange
*change
, Diagram
*dia
)
687 DEBUG_PRINTF(("insert_objects_revert()\n"));
689 diagram_unselect_objects(dia
, change
->obj_list
);
690 layer_remove_objects(change
->layer
, change
->obj_list
);
691 object_add_updates_list(change
->obj_list
, dia
);
693 list
= change
->obj_list
;
694 while (list
!= NULL
) {
695 Object
*obj
= (Object
*)list
->data
;
697 /* Have to hide any open properties dialog
698 if it contains some object in cut_list */
699 properties_hide_if_shown(dia
, obj
);
701 /* Remove focus if active */
702 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
706 list
= g_list_next(list
);
709 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
713 insert_objects_free(struct InsertObjectsChange
*change
)
715 DEBUG_PRINTF(("insert_objects_free()\n"));
716 if (!change
->applied
)
717 destroy_object_list(change
->obj_list
);
719 g_list_free(change
->obj_list
);
723 undo_insert_objects(Diagram
*dia
, GList
*obj_list
, int applied
)
725 struct InsertObjectsChange
*change
;
727 change
= g_new(struct InsertObjectsChange
, 1);
729 change
->change
.apply
= (UndoApplyFunc
) insert_objects_apply
;
730 change
->change
.revert
= (UndoRevertFunc
) insert_objects_revert
;
731 change
->change
.free
= (UndoFreeFunc
) insert_objects_free
;
733 change
->layer
= dia
->data
->active_layer
;
734 change
->obj_list
= obj_list
;
735 change
->applied
= applied
;
737 DEBUG_PRINTF(("UNDO: Push new insert objects at %d\n", depth(dia
->undo
)));
738 undo_push_change(dia
->undo
, (Change
*) change
);
739 return (Change
*)change
;
742 /******** Reorder object list: */
744 struct ReorderObjectsChange
{
748 GList
*changed_list
; /* Owning reference when applied */
749 GList
*original_objects
;
750 GList
*reordered_objects
;
754 reorder_objects_apply(struct ReorderObjectsChange
*change
, Diagram
*dia
)
756 DEBUG_PRINTF(("reorder_objects_apply()\n"));
757 layer_set_object_list(change
->layer
,
758 g_list_copy(change
->reordered_objects
));
759 object_add_updates_list(change
->changed_list
, dia
);
763 reorder_objects_revert(struct ReorderObjectsChange
*change
, Diagram
*dia
)
765 DEBUG_PRINTF(("reorder_objects_revert()\n"));
766 layer_set_object_list(change
->layer
,
767 g_list_copy(change
->original_objects
));
768 object_add_updates_list(change
->changed_list
, dia
);
772 reorder_objects_free(struct ReorderObjectsChange
*change
)
774 DEBUG_PRINTF(("reorder_objects_free()\n"));
775 g_list_free(change
->changed_list
);
776 g_list_free(change
->original_objects
);
777 g_list_free(change
->reordered_objects
);
781 undo_reorder_objects(Diagram
*dia
, GList
*changed_list
, GList
*orig_list
)
783 struct ReorderObjectsChange
*change
;
785 change
= g_new(struct ReorderObjectsChange
, 1);
787 change
->change
.apply
= (UndoApplyFunc
) reorder_objects_apply
;
788 change
->change
.revert
= (UndoRevertFunc
) reorder_objects_revert
;
789 change
->change
.free
= (UndoFreeFunc
) reorder_objects_free
;
791 change
->layer
= dia
->data
->active_layer
;
792 change
->changed_list
= changed_list
;
793 change
->original_objects
= orig_list
;
794 change
->reordered_objects
= g_list_copy(dia
->data
->active_layer
->objects
);
796 DEBUG_PRINTF(("UNDO: Push new reorder objects at %d\n", depth(dia
->undo
)));
797 undo_push_change(dia
->undo
, (Change
*) change
);
798 return (Change
*)change
;
801 /******** ObjectChange: */
803 struct ObjectChangeChange
{
807 ObjectChange
*obj_change
;
812 object_change_apply(struct ObjectChangeChange
*change
,
815 object_add_updates(change
->obj
, dia
);
816 change
->obj_change
->apply(change
->obj_change
, change
->obj
);
817 { /* Make sure object updates its data: */
818 Point p
= change
->obj
->position
;
819 (change
->obj
->ops
->move
)(change
->obj
,&p
);
821 object_add_updates(change
->obj
, dia
);
823 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
825 properties_update_if_shown(dia
, change
->obj
);
829 object_change_revert(struct ObjectChangeChange
*change
,
832 object_add_updates(change
->obj
, dia
);
833 change
->obj_change
->revert(change
->obj_change
, change
->obj
);
834 { /* Make sure object updates its data: */
835 Point p
= change
->obj
->position
;
836 (change
->obj
->ops
->move
)(change
->obj
,&p
);
838 object_add_updates(change
->obj
, dia
);
840 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
842 properties_update_if_shown(dia
, change
->obj
);
846 object_change_free(struct ObjectChangeChange
*change
)
848 DEBUG_PRINTF(("state_change_free()\n"));
849 if (change
->obj_change
->free
)
850 (*change
->obj_change
->free
)(change
->obj_change
);
851 g_free(change
->obj_change
);
855 undo_object_change(Diagram
*dia
, Object
*obj
,
856 ObjectChange
*obj_change
)
858 struct ObjectChangeChange
*change
;
860 change
= g_new(struct ObjectChangeChange
, 1);
862 change
->change
.apply
= (UndoApplyFunc
) object_change_apply
;
863 change
->change
.revert
= (UndoRevertFunc
) object_change_revert
;
864 change
->change
.free
= (UndoFreeFunc
) object_change_free
;
867 change
->obj_change
= obj_change
;
869 DEBUG_PRINTF(("UNDO: Push new obj_change at %d\n", depth(dia
->undo
)));
870 undo_push_change(dia
->undo
, (Change
*) change
);
871 return (Change
*)change
;
874 /******** Group object list: */
876 /** Grouping and ungrouping are two subtly different changes: While
877 * ungrouping preserves the front/back position, grouping cannot do that,
878 * since the act of grouping destroys positions for the members of the
879 * group, and those positions have to be restored in the undo.
882 struct GroupObjectsChange
{
886 Object
*group
; /* owning reference if not applied */
887 GList
*obj_list
; /* This list is owned by the group. */
888 GList
*orig_list
; /* This list (not the object) is owned */
893 group_objects_apply(struct GroupObjectsChange
*change
, Diagram
*dia
)
897 DEBUG_PRINTF(("group_objects_apply()\n"));
901 diagram_unselect_objects(dia
, change
->obj_list
);
902 layer_remove_objects(change
->layer
, change
->obj_list
);
903 layer_add_object(change
->layer
, change
->group
);
904 object_add_updates(change
->group
, dia
);
906 list
= change
->obj_list
;
907 while (list
!= NULL
) {
908 Object
*obj
= (Object
*)list
->data
;
910 /* Have to hide any open properties dialog
911 if it contains some object in cut_list */
912 properties_hide_if_shown(dia
, obj
);
914 /* Remove focus if active */
915 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
919 list
= g_list_next(list
);
922 diagram_tree_add_object(diagram_tree(), dia
, change
->group
);
923 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
927 group_objects_revert(struct GroupObjectsChange
*change
, Diagram
*dia
)
931 DEBUG_PRINTF(("group_objects_revert()\n"));
934 diagram_unselect_object(dia
, change
->group
);
935 object_add_updates(change
->group
, dia
);
937 old_list
= change
->layer
->objects
;
938 layer_set_object_list(change
->layer
, g_list_copy(change
->orig_list
));
939 g_list_free(old_list
);
941 object_add_updates_list(change
->obj_list
, dia
);
943 properties_hide_if_shown(dia
, change
->group
);
945 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
946 diagram_tree_remove_object(diagram_tree(), change
->group
);
950 group_objects_free(struct GroupObjectsChange
*change
)
952 DEBUG_PRINTF(("group_objects_free()\n"));
953 if (!change
->applied
) {
954 group_destroy_shallow(change
->group
);
955 change
->group
= NULL
;
956 change
->obj_list
= NULL
;
958 g_list_free(change
->orig_list
);
962 undo_group_objects(Diagram
*dia
, GList
*obj_list
, Object
*group
,
965 struct GroupObjectsChange
*change
;
967 change
= g_new(struct GroupObjectsChange
, 1);
969 change
->change
.apply
= (UndoApplyFunc
) group_objects_apply
;
970 change
->change
.revert
= (UndoRevertFunc
) group_objects_revert
;
971 change
->change
.free
= (UndoFreeFunc
) group_objects_free
;
973 change
->layer
= dia
->data
->active_layer
;
974 change
->group
= group
;
975 change
->obj_list
= obj_list
;
976 change
->orig_list
= orig_list
;
979 DEBUG_PRINTF(("UNDO: Push new group objects at %d\n", depth(dia
->undo
)));
980 undo_push_change(dia
->undo
, (Change
*) change
);
981 return (Change
*)change
;
984 /******** Ungroup object list: */
986 struct UngroupObjectsChange
{
990 Object
*group
; /* owning reference if applied */
991 GList
*obj_list
; /* This list is owned by the ungroup. */
997 ungroup_objects_apply(struct UngroupObjectsChange
*change
, Diagram
*dia
)
999 DEBUG_PRINTF(("ungroup_objects_apply()\n"));
1001 change
->applied
= 1;
1003 diagram_unselect_object(dia
, change
->group
);
1004 object_add_updates(change
->group
, dia
);
1005 layer_replace_object_with_list(change
->layer
, change
->group
,
1006 g_list_copy(change
->obj_list
));
1007 object_add_updates_list(change
->obj_list
, dia
);
1009 properties_hide_if_shown(dia
, change
->group
);
1011 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
1012 diagram_tree_remove_object(diagram_tree(), change
->group
);
1016 ungroup_objects_revert(struct UngroupObjectsChange
*change
, Diagram
*dia
)
1020 DEBUG_PRINTF(("ungroup_objects_revert()\n"));
1021 change
->applied
= 0;
1024 diagram_unselect_objects(dia
, change
->obj_list
);
1025 layer_remove_objects(change
->layer
, change
->obj_list
);
1026 layer_add_object_at(change
->layer
, change
->group
, change
->group_index
);
1027 object_add_updates(change
->group
, dia
);
1029 list
= change
->obj_list
;
1030 while (list
!= NULL
) {
1031 Object
*obj
= (Object
*)list
->data
;
1033 /* Have to hide any open properties dialog
1034 if it contains some object in cut_list */
1035 properties_hide_if_shown(dia
, obj
);
1037 /* Remove focus if active */
1038 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
1042 list
= g_list_next(list
);
1045 diagram_tree_add_object(diagram_tree(), dia
, change
->group
);
1046 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
1050 ungroup_objects_free(struct UngroupObjectsChange
*change
)
1052 DEBUG_PRINTF(("ungroup_objects_free()\n"));
1053 if (change
->applied
) {
1054 group_destroy_shallow(change
->group
);
1055 change
->group
= NULL
;
1056 change
->obj_list
= NULL
;
1061 undo_ungroup_objects(Diagram
*dia
, GList
*obj_list
, Object
*group
,
1064 struct UngroupObjectsChange
*change
;
1066 change
= g_new(struct UngroupObjectsChange
, 1);
1068 change
->change
.apply
= (UndoApplyFunc
) ungroup_objects_apply
;
1069 change
->change
.revert
= (UndoRevertFunc
) ungroup_objects_revert
;
1070 change
->change
.free
= (UndoFreeFunc
) ungroup_objects_free
;
1072 change
->layer
= dia
->data
->active_layer
;
1073 change
->group
= group
;
1074 change
->obj_list
= obj_list
;
1075 change
->group_index
= group_index
;
1076 change
->applied
= 1;
1078 DEBUG_PRINTF(("UNDO: Push new ungroup objects at %d\n", depth(dia
->undo
)));
1079 undo_push_change(dia
->undo
, (Change
*) change
);
1080 return (Change
*)change
;
1083 /******* PARENTING */
1085 struct ParentChange
{
1087 Object
*parentobj
, *childobj
;
1091 /** Performs the actual parenting of a child to a parent.
1092 * Since no display changes arise from this, we need call no update. */
1094 parent_object(Diagram
*dia
, Object
*parent
, Object
*child
)
1096 child
->parent
= parent
;
1097 parent
->children
= g_list_prepend(parent
->children
, child
);
1100 /** Performs the actual removal of a child from a parent.
1101 * Since no display changes arise from this, we need call no update. */
1103 unparent_object(Diagram
*dia
, Object
*parent
, Object
*child
)
1105 child
->parent
= NULL
;
1106 parent
->children
= g_list_remove(parent
->children
, child
);
1109 /** Applies the given ParentChange */
1111 parent_change_apply(Change
*change
, Diagram
*dia
)
1113 struct ParentChange
*parentchange
= (struct ParentChange
*)change
;
1114 if (parentchange
->parent
) {
1115 parent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1117 unparent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1121 /** Reverts the given ParentChange */
1123 parent_change_revert(Change
*change
, Diagram
*dia
)
1125 struct ParentChange
*parentchange
= (struct ParentChange
*)change
;
1126 if (!parentchange
->parent
) {
1127 parent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1129 unparent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1133 /** Frees items in the change -- none really */
1135 parent_change_free(Change
*change
)
1139 /** Create a new Change object for parenting/unparenting.
1140 * `parent' is TRUE if applying this change makes childobj a
1141 * child of parentobj.
1144 undo_parenting(Diagram
*dia
, Object
* parentobj
, Object
* childobj
,
1147 struct ParentChange
*parentchange
= g_new0(struct ParentChange
, 1);
1148 Change
*change
= (Change
*)parentchange
;
1149 change
->apply
= parent_change_apply
;
1150 change
->revert
= parent_change_revert
;
1151 change
->free
= parent_change_free
;
1153 parentchange
->parentobj
= parentobj
;
1154 parentchange
->childobj
= childobj
;
1155 parentchange
->parent
= parent
;
1157 DEBUG_PRINTF(("UNDO: Push new obj_change at %d\n", depth(dia
->undo
)));
1158 undo_push_change(dia
->undo
, change
);