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"
32 #define DEBUG_PRINTF(args) printf args
34 #define DEBUG_PRINTF(args)
38 transaction_point_pointer(Change
*change
, Diagram
*dia
)
40 /* Empty function used to track transactionpoints. */
44 is_transactionpoint(Change
*change
)
46 return change
->apply
== transaction_point_pointer
;
50 new_transactionpoint(void)
52 Change
*transaction
= g_new0(Change
, 1);
55 transaction
->apply
= transaction_point_pointer
;
56 transaction
->revert
= transaction_point_pointer
;
57 transaction
->free
= NULL
;
64 new_undo_stack(Diagram
*dia
)
69 stack
= g_new(UndoStack
, 1);
72 transaction
= new_transactionpoint();
73 transaction
->next
= transaction
->prev
= NULL
;
74 stack
->last_change
= transaction
;
75 stack
->current_change
= transaction
;
76 stack
->last_save
= transaction
;
83 undo_destroy(UndoStack
*stack
)
86 g_free(stack
->current_change
); /* Free first transaction point. */
93 undo_remove_redo_info(UndoStack
*stack
)
98 DEBUG_PRINTF(("UNDO: Removing redo info\n"));
100 change
= stack
->current_change
->next
;
101 stack
->current_change
->next
= NULL
;
102 stack
->last_change
= stack
->current_change
;
104 while (change
!= NULL
) {
105 next_change
= change
->next
;
107 (change
->free
)(change
);
109 change
= next_change
;
114 undo_push_change(UndoStack
*stack
, Change
*change
)
116 if (stack
->current_change
!= stack
->last_change
)
117 undo_remove_redo_info(stack
);
119 DEBUG_PRINTF(("UNDO: Push new change at %d\n", depth(stack
)));
121 change
->prev
= stack
->last_change
;
123 stack
->last_change
->next
= change
;
124 stack
->last_change
= change
;
125 stack
->current_change
= change
;
129 undo_delete_lowest_transaction(UndoStack
*stack
)
134 /* Find the lowest change: */
135 change
= stack
->current_change
;
136 while (change
->prev
!= NULL
) {
137 change
= change
->prev
;
140 /* Remove changes from the bottom until (and including)
141 * the first transactionpoint.
142 * Stop if we reach current_change or NULL.
145 if ( (change
== NULL
) || (change
== stack
->current_change
))
148 next_change
= change
->next
;
149 DEBUG_PRINTF(("freeing one change from the bottom.\n"));
151 (change
->free
)(change
);
153 change
= next_change
;
154 } while (!is_transactionpoint(change
));
156 if (is_transactionpoint(change
)) {
158 DEBUG_PRINTF(("Decreasing stack depth to: %d\n", stack
->depth
));
164 undo_set_transactionpoint(UndoStack
*stack
)
168 if (is_transactionpoint(stack
->current_change
))
171 DEBUG_PRINTF(("UNDO: Push new transactionpoint at %d\n", depth(stack
)));
173 transaction
= new_transactionpoint();
175 undo_push_change(stack
, transaction
);
177 DEBUG_PRINTF(("Increasing stack depth to: %d\n", stack
->depth
));
179 if (prefs
.undo_depth
> 0) {
180 while (stack
->depth
> prefs
.undo_depth
){
181 undo_delete_lowest_transaction(stack
);
187 undo_revert_to_last_tp(UndoStack
*stack
)
192 if (stack
->current_change
->prev
== NULL
)
193 return; /* Can't revert first transactionpoint */
195 change
= stack
->current_change
;
197 prev_change
= change
->prev
;
198 (change
->revert
)(change
, stack
->dia
);
199 change
= prev_change
;
200 } while (!is_transactionpoint(change
));
201 stack
->current_change
= change
;
203 DEBUG_PRINTF(("Decreasing stack depth to: %d\n", stack
->depth
));
207 undo_apply_to_next_tp(UndoStack
*stack
)
212 change
= stack
->current_change
;
214 if (change
->next
== NULL
)
215 return /* Already at top. */;
218 next_change
= change
->next
;
219 (change
->apply
)(change
, stack
->dia
);
220 change
= next_change
;
221 } while ( (change
!= NULL
) &&
222 (!is_transactionpoint(change
)) );
224 change
= stack
->last_change
;
225 stack
->current_change
= change
;
227 DEBUG_PRINTF(("Increasing stack depth to: %d\n", stack
->depth
));
232 undo_clear(UndoStack
*stack
)
236 DEBUG_PRINTF(("undo_clear()\n"));
238 change
= stack
->current_change
;
240 while (change
->prev
!= NULL
) {
241 change
= change
->prev
;
244 stack
->current_change
= change
;
246 undo_remove_redo_info(stack
);
249 /** Marks the undo stack at the time of a save.
252 undo_mark_save(UndoStack
*stack
)
254 stack
->last_save
= stack
->current_change
;
257 /** Returns true if the diagram is undo-wise in the same state as at
258 * last save, i.e. the current change is the same as it was at last save.
261 undo_is_saved(UndoStack
*stack
)
263 return stack
->last_save
== stack
->current_change
;
268 /****************************************************************/
269 /****************************************************************/
270 /***************** *********************/
271 /***************** Specific undo functions: *********************/
272 /***************** *********************/
273 /****************************************************************/
274 /****************************************************************/
276 /******** Move object list: */
278 struct MoveObjectsChange
{
287 move_objects_apply(struct MoveObjectsChange
*change
, Diagram
*dia
)
293 object_add_updates_list(change
->obj_list
, dia
);
295 list
= change
->obj_list
;
297 while (list
!= NULL
) {
298 obj
= (DiaObject
*) list
->data
;
300 obj
->ops
->move(obj
, &change
->dest_pos
[i
]);
302 list
= g_list_next(list
); i
++;
305 list
= change
->obj_list
;
307 obj
= (DiaObject
*) list
->data
;
309 diagram_update_connections_object(dia
, obj
, TRUE
);
311 list
= g_list_next(list
);
314 object_add_updates_list(change
->obj_list
, dia
);
318 move_objects_revert(struct MoveObjectsChange
*change
, Diagram
*dia
)
324 object_add_updates_list(change
->obj_list
, dia
);
326 list
= change
->obj_list
;
328 while (list
!= NULL
) {
329 obj
= (DiaObject
*) list
->data
;
331 obj
->ops
->move(obj
, &change
->orig_pos
[i
]);
333 list
= g_list_next(list
); i
++;
336 list
= change
->obj_list
;
338 obj
= (DiaObject
*) list
->data
;
340 diagram_update_connections_object(dia
, obj
, TRUE
);
342 list
= g_list_next(list
);
345 object_add_updates_list(change
->obj_list
, dia
);
349 move_objects_free(struct MoveObjectsChange
*change
)
351 g_free(change
->orig_pos
);
352 g_free(change
->dest_pos
);
353 g_list_free(change
->obj_list
);
357 undo_move_objects(Diagram
*dia
, Point
*orig_pos
, Point
*dest_pos
,
360 struct MoveObjectsChange
*change
;
362 change
= g_new0(struct MoveObjectsChange
, 1);
364 change
->change
.apply
= (UndoApplyFunc
) move_objects_apply
;
365 change
->change
.revert
= (UndoRevertFunc
) move_objects_revert
;
366 change
->change
.free
= (UndoFreeFunc
) move_objects_free
;
368 change
->orig_pos
= orig_pos
;
369 change
->dest_pos
= dest_pos
;
370 change
->obj_list
= obj_list
;
372 DEBUG_PRINTF(("UNDO: Push new move objects at %d\n", depth(dia
->undo
)));
373 undo_push_change(dia
->undo
, (Change
*) change
);
374 return (Change
*)change
;
377 /********** Move handle: */
379 struct MoveHandleChange
{
389 move_handle_apply(struct MoveHandleChange
*change
, Diagram
*dia
)
391 object_add_updates(change
->obj
, dia
);
392 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
393 &change
->dest_pos
, NULL
,
394 HANDLE_MOVE_USER_FINAL
, 0);
395 object_add_updates(change
->obj
, dia
);
396 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
400 move_handle_revert(struct MoveHandleChange
*change
, Diagram
*dia
)
402 object_add_updates(change
->obj
, dia
);
403 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
404 &change
->orig_pos
, NULL
,
405 HANDLE_MOVE_USER_FINAL
, 0);
406 object_add_updates(change
->obj
, dia
);
407 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
411 move_handle_free(struct MoveHandleChange
*change
)
417 undo_move_handle(Diagram
*dia
,
418 Handle
*handle
, DiaObject
*obj
,
419 Point orig_pos
, Point dest_pos
)
421 struct MoveHandleChange
*change
;
423 change
= g_new0(struct MoveHandleChange
, 1);
425 change
->change
.apply
= (UndoApplyFunc
) move_handle_apply
;
426 change
->change
.revert
= (UndoRevertFunc
) move_handle_revert
;
427 change
->change
.free
= (UndoFreeFunc
) move_handle_free
;
429 change
->orig_pos
= orig_pos
;
430 change
->dest_pos
= dest_pos
;
431 change
->handle
= handle
;
434 DEBUG_PRINTF(("UNDO: Push new move handle at %d\n", depth(dia
->undo
)));
436 undo_push_change(dia
->undo
, (Change
*) change
);
437 return (Change
*)change
;
440 /***************** Connect object: */
442 struct ConnectChange
{
447 ConnectionPoint
*connectionpoint
;
452 connect_apply(struct ConnectChange
*change
, Diagram
*dia
)
454 object_connect(change
->obj
, change
->handle
, change
->connectionpoint
);
456 object_add_updates(change
->obj
, dia
);
457 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
458 &change
->connectionpoint
->pos
,
459 change
->connectionpoint
,
460 HANDLE_MOVE_CONNECTED
, 0);
462 object_add_updates(change
->obj
, dia
);
466 connect_revert(struct ConnectChange
*change
, Diagram
*dia
)
468 object_unconnect(change
->obj
, change
->handle
);
470 object_add_updates(change
->obj
, dia
);
471 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
472 &change
->handle_pos
, NULL
,
473 HANDLE_MOVE_CONNECTED
, 0);
475 object_add_updates(change
->obj
, dia
);
479 connect_free(struct ConnectChange
*change
)
484 undo_connect(Diagram
*dia
, DiaObject
*obj
, Handle
*handle
,
485 ConnectionPoint
*connectionpoint
)
487 struct ConnectChange
*change
;
489 change
= g_new0(struct ConnectChange
, 1);
491 change
->change
.apply
= (UndoApplyFunc
) connect_apply
;
492 change
->change
.revert
= (UndoRevertFunc
) connect_revert
;
493 change
->change
.free
= (UndoFreeFunc
) connect_free
;
496 change
->handle
= handle
;
497 change
->handle_pos
= handle
->pos
;
498 change
->connectionpoint
= connectionpoint
;
500 DEBUG_PRINTF(("UNDO: Push new connect at %d\n", depth(dia
->undo
)));
501 undo_push_change(dia
->undo
, (Change
*) change
);
502 return (Change
*)change
;
505 /*************** Unconnect object: */
507 struct UnconnectChange
{
512 ConnectionPoint
*connectionpoint
;
516 unconnect_apply(struct UnconnectChange
*change
, Diagram
*dia
)
518 object_unconnect(change
->obj
, change
->handle
);
520 object_add_updates(change
->obj
, dia
);
524 unconnect_revert(struct UnconnectChange
*change
, Diagram
*dia
)
526 object_connect(change
->obj
, change
->handle
, change
->connectionpoint
);
528 object_add_updates(change
->obj
, dia
);
532 unconnect_free(struct UnconnectChange
*change
)
537 undo_unconnect(Diagram
*dia
, DiaObject
*obj
, Handle
*handle
)
539 struct UnconnectChange
*change
;
541 change
= g_new0(struct UnconnectChange
, 1);
543 change
->change
.apply
= (UndoApplyFunc
) unconnect_apply
;
544 change
->change
.revert
= (UndoRevertFunc
) unconnect_revert
;
545 change
->change
.free
= (UndoFreeFunc
) unconnect_free
;
548 change
->handle
= handle
;
549 change
->connectionpoint
= handle
->connected_to
;
551 DEBUG_PRINTF(("UNDO: Push new unconnect at %d\n", depth(dia
->undo
)));
552 undo_push_change(dia
->undo
, (Change
*) change
);
553 return (Change
*)change
;
557 /******** Delete object list: */
559 struct DeleteObjectsChange
{
563 GList
*obj_list
; /* Owning reference when applied */
564 GList
*original_objects
;
569 delete_objects_apply(struct DeleteObjectsChange
*change
, Diagram
*dia
)
573 DEBUG_PRINTF(("delete_objects_apply()\n"));
575 diagram_unselect_objects(dia
, change
->obj_list
);
576 layer_remove_objects(change
->layer
, change
->obj_list
);
577 object_add_updates_list(change
->obj_list
, dia
);
579 list
= change
->obj_list
;
580 while (list
!= NULL
) {
581 DiaObject
*obj
= (DiaObject
*)list
->data
;
583 /* Have to hide any open properties dialog
584 if it contains some object in cut_list */
585 properties_hide_if_shown(dia
, 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 DiaObject
*obj
= (DiaObject
*) 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_new0(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 DiaObject
*obj
= (DiaObject
*)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 list
= g_list_next(list
);
704 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
708 insert_objects_free(struct InsertObjectsChange
*change
)
710 DEBUG_PRINTF(("insert_objects_free()\n"));
711 if (!change
->applied
)
712 destroy_object_list(change
->obj_list
);
714 g_list_free(change
->obj_list
);
718 undo_insert_objects(Diagram
*dia
, GList
*obj_list
, int applied
)
720 struct InsertObjectsChange
*change
;
722 change
= g_new0(struct InsertObjectsChange
, 1);
724 change
->change
.apply
= (UndoApplyFunc
) insert_objects_apply
;
725 change
->change
.revert
= (UndoRevertFunc
) insert_objects_revert
;
726 change
->change
.free
= (UndoFreeFunc
) insert_objects_free
;
728 change
->layer
= dia
->data
->active_layer
;
729 change
->obj_list
= obj_list
;
730 change
->applied
= applied
;
732 DEBUG_PRINTF(("UNDO: Push new insert objects at %d\n", depth(dia
->undo
)));
733 undo_push_change(dia
->undo
, (Change
*) change
);
734 return (Change
*)change
;
737 /******** Reorder object list: */
739 struct ReorderObjectsChange
{
743 GList
*changed_list
; /* Owning reference when applied */
744 GList
*original_objects
;
745 GList
*reordered_objects
;
749 reorder_objects_apply(struct ReorderObjectsChange
*change
, Diagram
*dia
)
751 DEBUG_PRINTF(("reorder_objects_apply()\n"));
752 layer_set_object_list(change
->layer
,
753 g_list_copy(change
->reordered_objects
));
754 object_add_updates_list(change
->changed_list
, dia
);
758 reorder_objects_revert(struct ReorderObjectsChange
*change
, Diagram
*dia
)
760 DEBUG_PRINTF(("reorder_objects_revert()\n"));
761 layer_set_object_list(change
->layer
,
762 g_list_copy(change
->original_objects
));
763 object_add_updates_list(change
->changed_list
, dia
);
767 reorder_objects_free(struct ReorderObjectsChange
*change
)
769 DEBUG_PRINTF(("reorder_objects_free()\n"));
770 g_list_free(change
->changed_list
);
771 g_list_free(change
->original_objects
);
772 g_list_free(change
->reordered_objects
);
776 undo_reorder_objects(Diagram
*dia
, GList
*changed_list
, GList
*orig_list
)
778 struct ReorderObjectsChange
*change
;
780 change
= g_new0(struct ReorderObjectsChange
, 1);
782 change
->change
.apply
= (UndoApplyFunc
) reorder_objects_apply
;
783 change
->change
.revert
= (UndoRevertFunc
) reorder_objects_revert
;
784 change
->change
.free
= (UndoFreeFunc
) reorder_objects_free
;
786 change
->layer
= dia
->data
->active_layer
;
787 change
->changed_list
= changed_list
;
788 change
->original_objects
= orig_list
;
789 change
->reordered_objects
= g_list_copy(dia
->data
->active_layer
->objects
);
791 DEBUG_PRINTF(("UNDO: Push new reorder objects at %d\n", depth(dia
->undo
)));
792 undo_push_change(dia
->undo
, (Change
*) change
);
793 return (Change
*)change
;
796 /******** ObjectChange: */
798 struct ObjectChangeChange
{
802 ObjectChange
*obj_change
;
807 object_change_apply(struct ObjectChangeChange
*change
,
810 object_add_updates(change
->obj
, dia
);
811 change
->obj_change
->apply(change
->obj_change
, change
->obj
);
812 { /* Make sure object updates its data: */
813 Point p
= change
->obj
->position
;
814 (change
->obj
->ops
->move
)(change
->obj
,&p
);
816 object_add_updates(change
->obj
, dia
);
818 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
820 properties_update_if_shown(dia
, change
->obj
);
824 object_change_revert(struct ObjectChangeChange
*change
,
827 object_add_updates(change
->obj
, dia
);
828 change
->obj_change
->revert(change
->obj_change
, change
->obj
);
829 { /* Make sure object updates its data: */
830 Point p
= change
->obj
->position
;
831 (change
->obj
->ops
->move
)(change
->obj
,&p
);
833 object_add_updates(change
->obj
, dia
);
835 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
837 properties_update_if_shown(dia
, change
->obj
);
841 object_change_free(struct ObjectChangeChange
*change
)
843 DEBUG_PRINTF(("state_change_free()\n"));
844 if (change
->obj_change
->free
)
845 (*change
->obj_change
->free
)(change
->obj_change
);
846 g_free(change
->obj_change
);
850 undo_object_change(Diagram
*dia
, DiaObject
*obj
,
851 ObjectChange
*obj_change
)
853 struct ObjectChangeChange
*change
;
855 change
= g_new0(struct ObjectChangeChange
, 1);
857 change
->change
.apply
= (UndoApplyFunc
) object_change_apply
;
858 change
->change
.revert
= (UndoRevertFunc
) object_change_revert
;
859 change
->change
.free
= (UndoFreeFunc
) object_change_free
;
862 change
->obj_change
= obj_change
;
864 DEBUG_PRINTF(("UNDO: Push new obj_change at %d\n", depth(dia
->undo
)));
865 undo_push_change(dia
->undo
, (Change
*) change
);
866 return (Change
*)change
;
869 /******** Group object list: */
871 /** Grouping and ungrouping are two subtly different changes: While
872 * ungrouping preserves the front/back position, grouping cannot do that,
873 * since the act of grouping destroys positions for the members of the
874 * group, and those positions have to be restored in the undo.
877 struct GroupObjectsChange
{
881 DiaObject
*group
; /* owning reference if not applied */
882 GList
*obj_list
; /* The list of objects in this group. Owned by the
884 GList
*orig_list
; /* A copy of the original list of all objects,
885 from before the group was created. Owned by
891 group_objects_apply(struct GroupObjectsChange
*change
, Diagram
*dia
)
895 DEBUG_PRINTF(("group_objects_apply()\n"));
899 diagram_unselect_objects(dia
, change
->obj_list
);
900 layer_remove_objects(change
->layer
, change
->obj_list
);
901 layer_add_object(change
->layer
, change
->group
);
902 object_add_updates(change
->group
, dia
);
904 list
= change
->obj_list
;
905 while (list
!= NULL
) {
906 DiaObject
*obj
= (DiaObject
*)list
->data
;
908 /* Have to hide any open properties dialog
909 if it contains some object in cut_list */
910 properties_hide_if_shown(dia
, obj
);
912 object_add_updates(obj
, dia
);
914 list
= g_list_next(list
);
917 diagram_tree_add_object(diagram_tree(), dia
, change
->group
);
918 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
922 group_objects_revert(struct GroupObjectsChange
*change
, Diagram
*dia
)
924 DEBUG_PRINTF(("group_objects_revert()\n"));
927 diagram_unselect_object(dia
, change
->group
);
928 object_add_updates(change
->group
, dia
);
930 layer_set_object_list(change
->layer
, g_list_copy(change
->orig_list
));
932 object_add_updates_list(change
->obj_list
, dia
);
934 properties_hide_if_shown(dia
, change
->group
);
936 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
937 diagram_tree_remove_object(diagram_tree(), change
->group
);
941 group_objects_free(struct GroupObjectsChange
*change
)
943 DEBUG_PRINTF(("group_objects_free()\n"));
944 if (!change
->applied
) {
945 group_destroy_shallow(change
->group
);
946 change
->group
= NULL
;
947 change
->obj_list
= NULL
;
950 g_list_free(change
->orig_list
);
954 undo_group_objects(Diagram
*dia
, GList
*obj_list
, DiaObject
*group
,
957 struct GroupObjectsChange
*change
;
959 change
= g_new0(struct GroupObjectsChange
, 1);
961 change
->change
.apply
= (UndoApplyFunc
) group_objects_apply
;
962 change
->change
.revert
= (UndoRevertFunc
) group_objects_revert
;
963 change
->change
.free
= (UndoFreeFunc
) group_objects_free
;
965 change
->layer
= dia
->data
->active_layer
;
966 change
->group
= group
;
967 change
->obj_list
= obj_list
;
968 change
->orig_list
= orig_list
;
971 DEBUG_PRINTF(("UNDO: Push new group objects at %d\n", depth(dia
->undo
)));
972 undo_push_change(dia
->undo
, (Change
*) change
);
973 return (Change
*)change
;
976 /******** Ungroup object list: */
978 struct UngroupObjectsChange
{
982 DiaObject
*group
; /* owning reference if applied */
983 GList
*obj_list
; /* This list is owned by the ungroup. */
989 ungroup_objects_apply(struct UngroupObjectsChange
*change
, Diagram
*dia
)
991 DEBUG_PRINTF(("ungroup_objects_apply()\n"));
995 diagram_unselect_object(dia
, change
->group
);
996 object_add_updates(change
->group
, dia
);
997 layer_replace_object_with_list(change
->layer
, change
->group
,
998 g_list_copy(change
->obj_list
));
999 object_add_updates_list(change
->obj_list
, dia
);
1001 properties_hide_if_shown(dia
, change
->group
);
1003 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
1004 diagram_tree_remove_object(diagram_tree(), change
->group
);
1008 ungroup_objects_revert(struct UngroupObjectsChange
*change
, Diagram
*dia
)
1012 DEBUG_PRINTF(("ungroup_objects_revert()\n"));
1013 change
->applied
= 0;
1016 diagram_unselect_objects(dia
, change
->obj_list
);
1017 layer_remove_objects(change
->layer
, change
->obj_list
);
1018 layer_add_object_at(change
->layer
, change
->group
, change
->group_index
);
1019 object_add_updates(change
->group
, dia
);
1021 list
= change
->obj_list
;
1022 while (list
!= NULL
) {
1023 DiaObject
*obj
= (DiaObject
*)list
->data
;
1025 /* Have to hide any open properties dialog
1026 if it contains some object in cut_list */
1027 properties_hide_if_shown(dia
, obj
);
1029 list
= g_list_next(list
);
1032 diagram_tree_add_object(diagram_tree(), dia
, change
->group
);
1033 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
1037 ungroup_objects_free(struct UngroupObjectsChange
*change
)
1039 DEBUG_PRINTF(("ungroup_objects_free()\n"));
1040 if (change
->applied
) {
1041 group_destroy_shallow(change
->group
);
1042 change
->group
= NULL
;
1043 change
->obj_list
= NULL
;
1048 undo_ungroup_objects(Diagram
*dia
, GList
*obj_list
, DiaObject
*group
,
1051 struct UngroupObjectsChange
*change
;
1053 change
= g_new0(struct UngroupObjectsChange
, 1);
1055 change
->change
.apply
= (UndoApplyFunc
) ungroup_objects_apply
;
1056 change
->change
.revert
= (UndoRevertFunc
) ungroup_objects_revert
;
1057 change
->change
.free
= (UndoFreeFunc
) ungroup_objects_free
;
1059 change
->layer
= dia
->data
->active_layer
;
1060 change
->group
= group
;
1061 change
->obj_list
= obj_list
;
1062 change
->group_index
= group_index
;
1063 change
->applied
= 1;
1065 DEBUG_PRINTF(("UNDO: Push new ungroup objects at %d\n", depth(dia
->undo
)));
1066 undo_push_change(dia
->undo
, (Change
*) change
);
1067 return (Change
*)change
;
1070 /******* PARENTING */
1072 struct ParentChange
{
1074 DiaObject
*parentobj
, *childobj
;
1078 /** Performs the actual parenting of a child to a parent.
1079 * Since no display changes arise from this, we need call no update. */
1081 parent_object(Diagram
*dia
, DiaObject
*parent
, DiaObject
*child
)
1083 child
->parent
= parent
;
1084 parent
->children
= g_list_prepend(parent
->children
, child
);
1087 /** Performs the actual removal of a child from a parent.
1088 * Since no display changes arise from this, we need call no update. */
1090 unparent_object(Diagram
*dia
, DiaObject
*parent
, DiaObject
*child
)
1092 child
->parent
= NULL
;
1093 parent
->children
= g_list_remove(parent
->children
, child
);
1096 /** Applies the given ParentChange */
1098 parent_change_apply(Change
*change
, Diagram
*dia
)
1100 struct ParentChange
*parentchange
= (struct ParentChange
*)change
;
1101 if (parentchange
->parent
) {
1102 parent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1104 unparent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1108 /** Reverts the given ParentChange */
1110 parent_change_revert(Change
*change
, Diagram
*dia
)
1112 struct ParentChange
*parentchange
= (struct ParentChange
*)change
;
1113 if (!parentchange
->parent
) {
1114 parent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1116 unparent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1120 /** Frees items in the change -- none really */
1122 parent_change_free(Change
*change
)
1126 /** Create a new Change object for parenting/unparenting.
1127 * `parent' is TRUE if applying this change makes childobj a
1128 * child of parentobj.
1131 undo_parenting(Diagram
*dia
, DiaObject
* parentobj
, DiaObject
* childobj
,
1134 struct ParentChange
*parentchange
= g_new0(struct ParentChange
, 1);
1135 Change
*change
= (Change
*)parentchange
;
1136 change
->apply
= parent_change_apply
;
1137 change
->revert
= parent_change_revert
;
1138 change
->free
= parent_change_free
;
1140 parentchange
->parentobj
= parentobj
;
1141 parentchange
->childobj
= childobj
;
1142 parentchange
->parent
= parent
;
1144 DEBUG_PRINTF(("UNDO: Push new obj_change at %d\n", depth(dia
->undo
)));
1145 undo_push_change(dia
->undo
, change
);