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
;
75 stack
->last_save
= transaction
;
82 undo_destroy(UndoStack
*stack
)
85 g_free(stack
->current_change
); /* Free first transaction point. */
92 undo_remove_redo_info(UndoStack
*stack
)
97 DEBUG_PRINTF(("UNDO: Removing redo info\n"));
99 change
= stack
->current_change
->next
;
100 stack
->current_change
->next
= NULL
;
101 stack
->last_change
= stack
->current_change
;
103 while (change
!= NULL
) {
104 next_change
= change
->next
;
106 (change
->free
)(change
);
108 change
= next_change
;
113 depth(UndoStack
*stack
)
117 change
= stack
->current_change
;
120 while (change
->prev
!= NULL
) {
121 change
= change
->prev
;
128 undo_push_change(UndoStack
*stack
, Change
*change
)
130 if (stack
->current_change
!= stack
->last_change
)
131 undo_remove_redo_info(stack
);
133 DEBUG_PRINTF(("UNDO: Push new change at %d\n", depth(stack
)));
135 change
->prev
= stack
->last_change
;
137 stack
->last_change
->next
= change
;
138 stack
->last_change
= change
;
139 stack
->current_change
= change
;
143 undo_delete_lowest_transaction(UndoStack
*stack
)
148 /* Find the lowest change: */
149 change
= stack
->current_change
;
150 while (change
->prev
!= NULL
) {
151 change
= change
->prev
;
154 /* Remove changes from the bottom until (and including)
155 * the first transactionpoint.
156 * Stop if we reach current_change or NULL.
159 if ( (change
== NULL
) || (change
== stack
->current_change
))
162 next_change
= change
->next
;
163 DEBUG_PRINTF(("freeing one change from the bottom.\n"));
165 (change
->free
)(change
);
167 change
= next_change
;
168 } while (!is_transactionpoint(change
));
170 if (is_transactionpoint(change
)) {
172 DEBUG_PRINTF(("Decreasing stack depth to: %d\n", stack
->depth
));
178 undo_set_transactionpoint(UndoStack
*stack
)
182 if (is_transactionpoint(stack
->current_change
))
185 DEBUG_PRINTF(("UNDO: Push new transactionpoint at %d\n", depth(stack
)));
187 transaction
= new_transactionpoint();
189 undo_push_change(stack
, transaction
);
191 DEBUG_PRINTF(("Increasing stack depth to: %d\n", stack
->depth
));
193 if (prefs
.undo_depth
> 0) {
194 while (stack
->depth
> prefs
.undo_depth
){
195 undo_delete_lowest_transaction(stack
);
201 undo_revert_to_last_tp(UndoStack
*stack
)
206 if (stack
->current_change
->prev
== NULL
)
207 return; /* Can't revert first transactionpoint */
209 change
= stack
->current_change
;
211 prev_change
= change
->prev
;
212 (change
->revert
)(change
, stack
->dia
);
213 change
= prev_change
;
214 } while (!is_transactionpoint(change
));
215 stack
->current_change
= change
;
217 DEBUG_PRINTF(("Decreasing stack depth to: %d\n", stack
->depth
));
221 undo_apply_to_next_tp(UndoStack
*stack
)
226 change
= stack
->current_change
;
228 if (change
->next
== NULL
)
229 return /* Already at top. */;
232 next_change
= change
->next
;
233 (change
->apply
)(change
, stack
->dia
);
234 change
= next_change
;
235 } while ( (change
!= NULL
) &&
236 (!is_transactionpoint(change
)) );
238 change
= stack
->last_change
;
239 stack
->current_change
= change
;
241 DEBUG_PRINTF(("Increasing stack depth to: %d\n", stack
->depth
));
246 undo_clear(UndoStack
*stack
)
250 DEBUG_PRINTF(("undo_clear()\n"));
252 change
= stack
->current_change
;
254 while (change
->prev
!= NULL
) {
255 change
= change
->prev
;
258 stack
->current_change
= change
;
260 undo_remove_redo_info(stack
);
263 /** Marks the undo stack at the time of a save.
266 undo_mark_save(UndoStack
*stack
)
268 stack
->last_save
= stack
->current_change
;
271 /** Returns true if the diagram is undo-wise in the same state as at
272 * last save, i.e. the current change is the same as it was at last save.
275 undo_is_saved(UndoStack
*stack
)
277 return stack
->last_save
== stack
->current_change
;
282 /****************************************************************/
283 /****************************************************************/
284 /***************** *********************/
285 /***************** Specific undo functions: *********************/
286 /***************** *********************/
287 /****************************************************************/
288 /****************************************************************/
290 /******** Move object list: */
292 struct MoveObjectsChange
{
301 move_objects_apply(struct MoveObjectsChange
*change
, Diagram
*dia
)
307 object_add_updates_list(change
->obj_list
, dia
);
309 list
= change
->obj_list
;
311 while (list
!= NULL
) {
312 obj
= (Object
*) list
->data
;
314 obj
->ops
->move(obj
, &change
->dest_pos
[i
]);
316 list
= g_list_next(list
); i
++;
319 list
= change
->obj_list
;
321 obj
= (Object
*) list
->data
;
323 diagram_update_connections_object(dia
, obj
, TRUE
);
325 list
= g_list_next(list
);
328 object_add_updates_list(change
->obj_list
, dia
);
332 move_objects_revert(struct MoveObjectsChange
*change
, Diagram
*dia
)
338 object_add_updates_list(change
->obj_list
, dia
);
340 list
= change
->obj_list
;
342 while (list
!= NULL
) {
343 obj
= (Object
*) list
->data
;
345 obj
->ops
->move(obj
, &change
->orig_pos
[i
]);
347 list
= g_list_next(list
); i
++;
350 list
= change
->obj_list
;
352 obj
= (Object
*) list
->data
;
354 diagram_update_connections_object(dia
, obj
, TRUE
);
356 list
= g_list_next(list
);
359 object_add_updates_list(change
->obj_list
, dia
);
363 move_objects_free(struct MoveObjectsChange
*change
)
365 g_free(change
->orig_pos
);
366 g_free(change
->dest_pos
);
367 g_list_free(change
->obj_list
);
371 undo_move_objects(Diagram
*dia
, Point
*orig_pos
, Point
*dest_pos
,
374 struct MoveObjectsChange
*change
;
376 change
= g_new(struct MoveObjectsChange
, 1);
378 change
->change
.apply
= (UndoApplyFunc
) move_objects_apply
;
379 change
->change
.revert
= (UndoRevertFunc
) move_objects_revert
;
380 change
->change
.free
= (UndoFreeFunc
) move_objects_free
;
382 change
->orig_pos
= orig_pos
;
383 change
->dest_pos
= dest_pos
;
384 change
->obj_list
= obj_list
;
386 DEBUG_PRINTF(("UNDO: Push new move objects at %d\n", depth(dia
->undo
)));
387 undo_push_change(dia
->undo
, (Change
*) change
);
388 return (Change
*)change
;
391 /********** Move handle: */
393 struct MoveHandleChange
{
403 move_handle_apply(struct MoveHandleChange
*change
, Diagram
*dia
)
405 object_add_updates(change
->obj
, dia
);
406 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
407 &change
->dest_pos
, NULL
,
408 HANDLE_MOVE_USER_FINAL
, 0);
409 object_add_updates(change
->obj
, dia
);
410 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
414 move_handle_revert(struct MoveHandleChange
*change
, Diagram
*dia
)
416 object_add_updates(change
->obj
, dia
);
417 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
418 &change
->orig_pos
, NULL
,
419 HANDLE_MOVE_USER_FINAL
, 0);
420 object_add_updates(change
->obj
, dia
);
421 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
425 move_handle_free(struct MoveHandleChange
*change
)
431 undo_move_handle(Diagram
*dia
,
432 Handle
*handle
, Object
*obj
,
433 Point orig_pos
, Point dest_pos
)
435 struct MoveHandleChange
*change
;
437 change
= g_new(struct MoveHandleChange
, 1);
439 change
->change
.apply
= (UndoApplyFunc
) move_handle_apply
;
440 change
->change
.revert
= (UndoRevertFunc
) move_handle_revert
;
441 change
->change
.free
= (UndoFreeFunc
) move_handle_free
;
443 change
->orig_pos
= orig_pos
;
444 change
->dest_pos
= dest_pos
;
445 change
->handle
= handle
;
448 DEBUG_PRINTF(("UNDO: Push new move handle at %d\n", depth(dia
->undo
)));
450 undo_push_change(dia
->undo
, (Change
*) change
);
451 return (Change
*)change
;
454 /***************** Connect object: */
456 struct ConnectChange
{
461 ConnectionPoint
*connectionpoint
;
466 connect_apply(struct ConnectChange
*change
, Diagram
*dia
)
468 object_connect(change
->obj
, change
->handle
, change
->connectionpoint
);
470 object_add_updates(change
->obj
, dia
);
471 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
472 &change
->connectionpoint
->pos
,
473 change
->connectionpoint
,
474 HANDLE_MOVE_CONNECTED
, 0);
476 object_add_updates(change
->obj
, dia
);
480 connect_revert(struct ConnectChange
*change
, Diagram
*dia
)
482 object_unconnect(change
->obj
, change
->handle
);
484 object_add_updates(change
->obj
, dia
);
485 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
486 &change
->handle_pos
, NULL
,
487 HANDLE_MOVE_CONNECTED
, 0);
489 object_add_updates(change
->obj
, dia
);
493 connect_free(struct ConnectChange
*change
)
498 undo_connect(Diagram
*dia
, Object
*obj
, Handle
*handle
,
499 ConnectionPoint
*connectionpoint
)
501 struct ConnectChange
*change
;
503 change
= g_new(struct ConnectChange
, 1);
505 change
->change
.apply
= (UndoApplyFunc
) connect_apply
;
506 change
->change
.revert
= (UndoRevertFunc
) connect_revert
;
507 change
->change
.free
= (UndoFreeFunc
) connect_free
;
510 change
->handle
= handle
;
511 change
->handle_pos
= handle
->pos
;
512 change
->connectionpoint
= connectionpoint
;
514 DEBUG_PRINTF(("UNDO: Push new connect at %d\n", depth(dia
->undo
)));
515 undo_push_change(dia
->undo
, (Change
*) change
);
516 return (Change
*)change
;
519 /*************** Unconnect object: */
521 struct UnconnectChange
{
526 ConnectionPoint
*connectionpoint
;
530 unconnect_apply(struct UnconnectChange
*change
, Diagram
*dia
)
532 object_unconnect(change
->obj
, change
->handle
);
534 object_add_updates(change
->obj
, dia
);
538 unconnect_revert(struct UnconnectChange
*change
, Diagram
*dia
)
540 object_connect(change
->obj
, change
->handle
, change
->connectionpoint
);
542 object_add_updates(change
->obj
, dia
);
546 unconnect_free(struct UnconnectChange
*change
)
551 undo_unconnect(Diagram
*dia
, Object
*obj
, Handle
*handle
)
553 struct UnconnectChange
*change
;
555 change
= g_new(struct UnconnectChange
, 1);
557 change
->change
.apply
= (UndoApplyFunc
) unconnect_apply
;
558 change
->change
.revert
= (UndoRevertFunc
) unconnect_revert
;
559 change
->change
.free
= (UndoFreeFunc
) unconnect_free
;
562 change
->handle
= handle
;
563 change
->connectionpoint
= handle
->connected_to
;
565 DEBUG_PRINTF(("UNDO: Push new unconnect at %d\n", depth(dia
->undo
)));
566 undo_push_change(dia
->undo
, (Change
*) change
);
567 return (Change
*)change
;
571 /******** Delete object list: */
573 struct DeleteObjectsChange
{
577 GList
*obj_list
; /* Owning reference when applied */
578 GList
*original_objects
;
583 delete_objects_apply(struct DeleteObjectsChange
*change
, Diagram
*dia
)
587 DEBUG_PRINTF(("delete_objects_apply()\n"));
589 diagram_unselect_objects(dia
, change
->obj_list
);
590 layer_remove_objects(change
->layer
, change
->obj_list
);
591 object_add_updates_list(change
->obj_list
, dia
);
593 list
= change
->obj_list
;
594 while (list
!= NULL
) {
595 Object
*obj
= (Object
*)list
->data
;
597 /* Have to hide any open properties dialog
598 if it contains some object in cut_list */
599 properties_hide_if_shown(dia
, obj
);
601 /* Remove focus if active */
602 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
606 if (obj
->parent
) /* Lose references to deleted object */
607 obj
->parent
->children
= g_list_remove(obj
->parent
->children
, obj
);
609 list
= g_list_next(list
);
612 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
616 delete_objects_revert(struct DeleteObjectsChange
*change
, Diagram
*dia
)
619 DEBUG_PRINTF(("delete_objects_revert()\n"));
621 layer_set_object_list(change
->layer
,
622 g_list_copy(change
->original_objects
));
623 object_add_updates_list(change
->obj_list
, dia
);
625 list
= change
->obj_list
;
628 Object
*obj
= (Object
*) list
->data
;
629 if (obj
->parent
) /* Restore child references */
630 obj
->parent
->children
= g_list_append(obj
->parent
->children
, obj
);
632 list
= g_list_next(list
);
635 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
639 delete_objects_free(struct DeleteObjectsChange
*change
)
641 DEBUG_PRINTF(("delete_objects_free()\n"));
643 destroy_object_list(change
->obj_list
);
645 g_list_free(change
->obj_list
);
646 g_list_free(change
->original_objects
);
650 This function deletes specified objects along with any children
652 undo_delete_objects() only deletes the objects that are specified.
655 undo_delete_objects_children(Diagram
*dia
, GList
*obj_list
)
657 return undo_delete_objects(dia
, parent_list_affected(obj_list
));
661 undo_delete_objects(Diagram
*dia
, GList
*obj_list
)
663 struct DeleteObjectsChange
*change
;
665 change
= g_new(struct DeleteObjectsChange
, 1);
667 change
->change
.apply
= (UndoApplyFunc
) delete_objects_apply
;
668 change
->change
.revert
= (UndoRevertFunc
) delete_objects_revert
;
669 change
->change
.free
= (UndoFreeFunc
) delete_objects_free
;
671 change
->layer
= dia
->data
->active_layer
;
672 change
->obj_list
= obj_list
;
673 change
->original_objects
= g_list_copy(dia
->data
->active_layer
->objects
);
676 DEBUG_PRINTF(("UNDO: Push new delete objects at %d\n", depth(dia
->undo
)));
677 undo_push_change(dia
->undo
, (Change
*) change
);
678 return (Change
*)change
;
681 /******** Insert object list: */
683 struct InsertObjectsChange
{
687 GList
*obj_list
; /* Owning reference when not applied */
692 insert_objects_apply(struct InsertObjectsChange
*change
, Diagram
*dia
)
694 DEBUG_PRINTF(("insert_objects_apply()\n"));
696 layer_add_objects(change
->layer
, g_list_copy(change
->obj_list
));
697 object_add_updates_list(change
->obj_list
, dia
);
698 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
702 insert_objects_revert(struct InsertObjectsChange
*change
, Diagram
*dia
)
706 DEBUG_PRINTF(("insert_objects_revert()\n"));
708 diagram_unselect_objects(dia
, change
->obj_list
);
709 layer_remove_objects(change
->layer
, change
->obj_list
);
710 object_add_updates_list(change
->obj_list
, dia
);
712 list
= change
->obj_list
;
713 while (list
!= NULL
) {
714 Object
*obj
= (Object
*)list
->data
;
716 /* Have to hide any open properties dialog
717 if it contains some object in cut_list */
718 properties_hide_if_shown(dia
, obj
);
720 /* Remove focus if active */
721 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
725 list
= g_list_next(list
);
728 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
732 insert_objects_free(struct InsertObjectsChange
*change
)
734 DEBUG_PRINTF(("insert_objects_free()\n"));
735 if (!change
->applied
)
736 destroy_object_list(change
->obj_list
);
738 g_list_free(change
->obj_list
);
742 undo_insert_objects(Diagram
*dia
, GList
*obj_list
, int applied
)
744 struct InsertObjectsChange
*change
;
746 change
= g_new(struct InsertObjectsChange
, 1);
748 change
->change
.apply
= (UndoApplyFunc
) insert_objects_apply
;
749 change
->change
.revert
= (UndoRevertFunc
) insert_objects_revert
;
750 change
->change
.free
= (UndoFreeFunc
) insert_objects_free
;
752 change
->layer
= dia
->data
->active_layer
;
753 change
->obj_list
= obj_list
;
754 change
->applied
= applied
;
756 DEBUG_PRINTF(("UNDO: Push new insert objects at %d\n", depth(dia
->undo
)));
757 undo_push_change(dia
->undo
, (Change
*) change
);
758 return (Change
*)change
;
761 /******** Reorder object list: */
763 struct ReorderObjectsChange
{
767 GList
*changed_list
; /* Owning reference when applied */
768 GList
*original_objects
;
769 GList
*reordered_objects
;
773 reorder_objects_apply(struct ReorderObjectsChange
*change
, Diagram
*dia
)
775 DEBUG_PRINTF(("reorder_objects_apply()\n"));
776 layer_set_object_list(change
->layer
,
777 g_list_copy(change
->reordered_objects
));
778 object_add_updates_list(change
->changed_list
, dia
);
782 reorder_objects_revert(struct ReorderObjectsChange
*change
, Diagram
*dia
)
784 DEBUG_PRINTF(("reorder_objects_revert()\n"));
785 layer_set_object_list(change
->layer
,
786 g_list_copy(change
->original_objects
));
787 object_add_updates_list(change
->changed_list
, dia
);
791 reorder_objects_free(struct ReorderObjectsChange
*change
)
793 DEBUG_PRINTF(("reorder_objects_free()\n"));
794 g_list_free(change
->changed_list
);
795 g_list_free(change
->original_objects
);
796 g_list_free(change
->reordered_objects
);
800 undo_reorder_objects(Diagram
*dia
, GList
*changed_list
, GList
*orig_list
)
802 struct ReorderObjectsChange
*change
;
804 change
= g_new(struct ReorderObjectsChange
, 1);
806 change
->change
.apply
= (UndoApplyFunc
) reorder_objects_apply
;
807 change
->change
.revert
= (UndoRevertFunc
) reorder_objects_revert
;
808 change
->change
.free
= (UndoFreeFunc
) reorder_objects_free
;
810 change
->layer
= dia
->data
->active_layer
;
811 change
->changed_list
= changed_list
;
812 change
->original_objects
= orig_list
;
813 change
->reordered_objects
= g_list_copy(dia
->data
->active_layer
->objects
);
815 DEBUG_PRINTF(("UNDO: Push new reorder objects at %d\n", depth(dia
->undo
)));
816 undo_push_change(dia
->undo
, (Change
*) change
);
817 return (Change
*)change
;
820 /******** ObjectChange: */
822 struct ObjectChangeChange
{
826 ObjectChange
*obj_change
;
831 object_change_apply(struct ObjectChangeChange
*change
,
834 object_add_updates(change
->obj
, dia
);
835 change
->obj_change
->apply(change
->obj_change
, change
->obj
);
836 { /* Make sure object updates its data: */
837 Point p
= change
->obj
->position
;
838 (change
->obj
->ops
->move
)(change
->obj
,&p
);
840 object_add_updates(change
->obj
, dia
);
842 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
844 properties_update_if_shown(dia
, change
->obj
);
848 object_change_revert(struct ObjectChangeChange
*change
,
851 object_add_updates(change
->obj
, dia
);
852 change
->obj_change
->revert(change
->obj_change
, change
->obj
);
853 { /* Make sure object updates its data: */
854 Point p
= change
->obj
->position
;
855 (change
->obj
->ops
->move
)(change
->obj
,&p
);
857 object_add_updates(change
->obj
, dia
);
859 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
861 properties_update_if_shown(dia
, change
->obj
);
865 object_change_free(struct ObjectChangeChange
*change
)
867 DEBUG_PRINTF(("state_change_free()\n"));
868 if (change
->obj_change
->free
)
869 (*change
->obj_change
->free
)(change
->obj_change
);
870 g_free(change
->obj_change
);
874 undo_object_change(Diagram
*dia
, Object
*obj
,
875 ObjectChange
*obj_change
)
877 struct ObjectChangeChange
*change
;
879 change
= g_new(struct ObjectChangeChange
, 1);
881 change
->change
.apply
= (UndoApplyFunc
) object_change_apply
;
882 change
->change
.revert
= (UndoRevertFunc
) object_change_revert
;
883 change
->change
.free
= (UndoFreeFunc
) object_change_free
;
886 change
->obj_change
= obj_change
;
888 DEBUG_PRINTF(("UNDO: Push new obj_change at %d\n", depth(dia
->undo
)));
889 undo_push_change(dia
->undo
, (Change
*) change
);
890 return (Change
*)change
;
893 /******** Group object list: */
895 /** Grouping and ungrouping are two subtly different changes: While
896 * ungrouping preserves the front/back position, grouping cannot do that,
897 * since the act of grouping destroys positions for the members of the
898 * group, and those positions have to be restored in the undo.
901 struct GroupObjectsChange
{
905 Object
*group
; /* owning reference if not applied */
906 GList
*obj_list
; /* The list of objects in this group. Owned by the
908 GList
*orig_list
; /* A copy of the original list of all objects,
909 from before the group was created. Owned by
915 group_objects_apply(struct GroupObjectsChange
*change
, Diagram
*dia
)
919 DEBUG_PRINTF(("group_objects_apply()\n"));
923 diagram_unselect_objects(dia
, change
->obj_list
);
924 layer_remove_objects(change
->layer
, change
->obj_list
);
925 layer_add_object(change
->layer
, change
->group
);
926 object_add_updates(change
->group
, dia
);
928 list
= change
->obj_list
;
929 while (list
!= NULL
) {
930 Object
*obj
= (Object
*)list
->data
;
932 /* Have to hide any open properties dialog
933 if it contains some object in cut_list */
934 properties_hide_if_shown(dia
, obj
);
936 /* Remove focus if active */
937 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
941 object_add_updates(obj
, dia
);
943 list
= g_list_next(list
);
946 diagram_tree_add_object(diagram_tree(), dia
, change
->group
);
947 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
951 group_objects_revert(struct GroupObjectsChange
*change
, Diagram
*dia
)
955 DEBUG_PRINTF(("group_objects_revert()\n"));
958 diagram_unselect_object(dia
, change
->group
);
959 object_add_updates(change
->group
, dia
);
961 layer_set_object_list(change
->layer
, g_list_copy(change
->orig_list
));
963 object_add_updates_list(change
->obj_list
, dia
);
965 properties_hide_if_shown(dia
, change
->group
);
967 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
968 diagram_tree_remove_object(diagram_tree(), change
->group
);
972 group_objects_free(struct GroupObjectsChange
*change
)
974 DEBUG_PRINTF(("group_objects_free()\n"));
975 if (!change
->applied
) {
976 group_destroy_shallow(change
->group
);
977 change
->group
= NULL
;
978 change
->obj_list
= NULL
;
981 g_list_free(change
->orig_list
);
985 undo_group_objects(Diagram
*dia
, GList
*obj_list
, Object
*group
,
988 struct GroupObjectsChange
*change
;
990 change
= g_new(struct GroupObjectsChange
, 1);
992 change
->change
.apply
= (UndoApplyFunc
) group_objects_apply
;
993 change
->change
.revert
= (UndoRevertFunc
) group_objects_revert
;
994 change
->change
.free
= (UndoFreeFunc
) group_objects_free
;
996 change
->layer
= dia
->data
->active_layer
;
997 change
->group
= group
;
998 change
->obj_list
= obj_list
;
999 change
->orig_list
= orig_list
;
1000 change
->applied
= 1;
1002 DEBUG_PRINTF(("UNDO: Push new group objects at %d\n", depth(dia
->undo
)));
1003 undo_push_change(dia
->undo
, (Change
*) change
);
1004 return (Change
*)change
;
1007 /******** Ungroup object list: */
1009 struct UngroupObjectsChange
{
1013 Object
*group
; /* owning reference if applied */
1014 GList
*obj_list
; /* This list is owned by the ungroup. */
1020 ungroup_objects_apply(struct UngroupObjectsChange
*change
, Diagram
*dia
)
1022 DEBUG_PRINTF(("ungroup_objects_apply()\n"));
1024 change
->applied
= 1;
1026 diagram_unselect_object(dia
, change
->group
);
1027 object_add_updates(change
->group
, dia
);
1028 layer_replace_object_with_list(change
->layer
, change
->group
,
1029 g_list_copy(change
->obj_list
));
1030 object_add_updates_list(change
->obj_list
, dia
);
1032 properties_hide_if_shown(dia
, change
->group
);
1034 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
1035 diagram_tree_remove_object(diagram_tree(), change
->group
);
1039 ungroup_objects_revert(struct UngroupObjectsChange
*change
, Diagram
*dia
)
1043 DEBUG_PRINTF(("ungroup_objects_revert()\n"));
1044 change
->applied
= 0;
1047 diagram_unselect_objects(dia
, change
->obj_list
);
1048 layer_remove_objects(change
->layer
, change
->obj_list
);
1049 layer_add_object_at(change
->layer
, change
->group
, change
->group_index
);
1050 object_add_updates(change
->group
, dia
);
1052 list
= change
->obj_list
;
1053 while (list
!= NULL
) {
1054 Object
*obj
= (Object
*)list
->data
;
1056 /* Have to hide any open properties dialog
1057 if it contains some object in cut_list */
1058 properties_hide_if_shown(dia
, obj
);
1060 /* Remove focus if active */
1061 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
1065 object_add_updates(obj
, dia
);
1067 list
= g_list_next(list
);
1070 diagram_tree_add_object(diagram_tree(), dia
, change
->group
);
1071 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
1075 ungroup_objects_free(struct UngroupObjectsChange
*change
)
1077 DEBUG_PRINTF(("ungroup_objects_free()\n"));
1078 if (change
->applied
) {
1079 group_destroy_shallow(change
->group
);
1080 change
->group
= NULL
;
1081 change
->obj_list
= NULL
;
1086 undo_ungroup_objects(Diagram
*dia
, GList
*obj_list
, Object
*group
,
1089 struct UngroupObjectsChange
*change
;
1091 change
= g_new(struct UngroupObjectsChange
, 1);
1093 change
->change
.apply
= (UndoApplyFunc
) ungroup_objects_apply
;
1094 change
->change
.revert
= (UndoRevertFunc
) ungroup_objects_revert
;
1095 change
->change
.free
= (UndoFreeFunc
) ungroup_objects_free
;
1097 change
->layer
= dia
->data
->active_layer
;
1098 change
->group
= group
;
1099 change
->obj_list
= obj_list
;
1100 change
->group_index
= group_index
;
1101 change
->applied
= 1;
1103 DEBUG_PRINTF(("UNDO: Push new ungroup objects at %d\n", depth(dia
->undo
)));
1104 undo_push_change(dia
->undo
, (Change
*) change
);
1105 return (Change
*)change
;
1108 /******* PARENTING */
1110 struct ParentChange
{
1112 Object
*parentobj
, *childobj
;
1116 /** Performs the actual parenting of a child to a parent.
1117 * Since no display changes arise from this, we need call no update. */
1119 parent_object(Diagram
*dia
, Object
*parent
, Object
*child
)
1121 child
->parent
= parent
;
1122 parent
->children
= g_list_prepend(parent
->children
, child
);
1125 /** Performs the actual removal of a child from a parent.
1126 * Since no display changes arise from this, we need call no update. */
1128 unparent_object(Diagram
*dia
, Object
*parent
, Object
*child
)
1130 child
->parent
= NULL
;
1131 parent
->children
= g_list_remove(parent
->children
, child
);
1134 /** Applies the given ParentChange */
1136 parent_change_apply(Change
*change
, Diagram
*dia
)
1138 struct ParentChange
*parentchange
= (struct ParentChange
*)change
;
1139 if (parentchange
->parent
) {
1140 parent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1142 unparent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1146 /** Reverts the given ParentChange */
1148 parent_change_revert(Change
*change
, Diagram
*dia
)
1150 struct ParentChange
*parentchange
= (struct ParentChange
*)change
;
1151 if (!parentchange
->parent
) {
1152 parent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1154 unparent_object(dia
, parentchange
->parentobj
, parentchange
->childobj
);
1158 /** Frees items in the change -- none really */
1160 parent_change_free(Change
*change
)
1164 /** Create a new Change object for parenting/unparenting.
1165 * `parent' is TRUE if applying this change makes childobj a
1166 * child of parentobj.
1169 undo_parenting(Diagram
*dia
, Object
* parentobj
, Object
* childobj
,
1172 struct ParentChange
*parentchange
= g_new0(struct ParentChange
, 1);
1173 Change
*change
= (Change
*)parentchange
;
1174 change
->apply
= parent_change_apply
;
1175 change
->revert
= parent_change_revert
;
1176 change
->free
= parent_change_free
;
1178 parentchange
->parentobj
= parentobj
;
1179 parentchange
->childobj
= childobj
;
1180 parentchange
->parent
= parent
;
1182 DEBUG_PRINTF(("UNDO: Push new obj_change at %d\n", depth(dia
->undo
)));
1183 undo_push_change(dia
->undo
, change
);