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
,
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
,
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 HANDLE_MOVE_CONNECTED
, 0);
456 object_add_updates(change
->obj
, dia
);
460 connect_revert(struct ConnectChange
*change
, Diagram
*dia
)
462 object_unconnect(change
->obj
, change
->handle
);
464 object_add_updates(change
->obj
, dia
);
465 change
->obj
->ops
->move_handle(change
->obj
, change
->handle
,
467 HANDLE_MOVE_CONNECTED
, 0);
469 object_add_updates(change
->obj
, dia
);
473 connect_free(struct ConnectChange
*change
)
478 undo_connect(Diagram
*dia
, Object
*obj
, Handle
*handle
,
479 ConnectionPoint
*connectionpoint
)
481 struct ConnectChange
*change
;
483 change
= g_new(struct ConnectChange
, 1);
485 change
->change
.apply
= (UndoApplyFunc
) connect_apply
;
486 change
->change
.revert
= (UndoRevertFunc
) connect_revert
;
487 change
->change
.free
= (UndoFreeFunc
) connect_free
;
490 change
->handle
= handle
;
491 change
->handle_pos
= handle
->pos
;
492 change
->connectionpoint
= connectionpoint
;
494 DEBUG_PRINTF(("UNDO: Push new connect at %d\n", depth(dia
->undo
)));
495 undo_push_change(dia
->undo
, (Change
*) change
);
496 return (Change
*)change
;
499 /*************** Unconnect object: */
501 struct UnconnectChange
{
506 ConnectionPoint
*connectionpoint
;
510 unconnect_apply(struct UnconnectChange
*change
, Diagram
*dia
)
512 object_unconnect(change
->obj
, change
->handle
);
514 object_add_updates(change
->obj
, dia
);
518 unconnect_revert(struct UnconnectChange
*change
, Diagram
*dia
)
520 object_connect(change
->obj
, change
->handle
, change
->connectionpoint
);
522 object_add_updates(change
->obj
, dia
);
526 unconnect_free(struct UnconnectChange
*change
)
531 undo_unconnect(Diagram
*dia
, Object
*obj
, Handle
*handle
)
533 struct UnconnectChange
*change
;
535 change
= g_new(struct UnconnectChange
, 1);
537 change
->change
.apply
= (UndoApplyFunc
) unconnect_apply
;
538 change
->change
.revert
= (UndoRevertFunc
) unconnect_revert
;
539 change
->change
.free
= (UndoFreeFunc
) unconnect_free
;
542 change
->handle
= handle
;
543 change
->connectionpoint
= handle
->connected_to
;
545 DEBUG_PRINTF(("UNDO: Push new unconnect at %d\n", depth(dia
->undo
)));
546 undo_push_change(dia
->undo
, (Change
*) change
);
547 return (Change
*)change
;
551 /******** Delete object list: */
553 struct DeleteObjectsChange
{
557 GList
*obj_list
; /* Owning reference when applied */
558 GList
*original_objects
;
563 delete_objects_apply(struct DeleteObjectsChange
*change
, Diagram
*dia
)
567 DEBUG_PRINTF(("delete_objects_apply()\n"));
569 diagram_unselect_objects(dia
, change
->obj_list
);
570 layer_remove_objects(change
->layer
, change
->obj_list
);
571 object_add_updates_list(change
->obj_list
, dia
);
573 list
= change
->obj_list
;
574 while (list
!= NULL
) {
575 Object
*obj
= (Object
*)list
->data
;
577 /* Have to hide any open properties dialog
578 if it contains some object in cut_list */
579 properties_hide_if_shown(dia
, obj
);
581 /* Remove focus if active */
582 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
586 list
= g_list_next(list
);
589 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
593 delete_objects_revert(struct DeleteObjectsChange
*change
, Diagram
*dia
)
595 DEBUG_PRINTF(("delete_objects_revert()\n"));
597 layer_set_object_list(change
->layer
,
598 g_list_copy(change
->original_objects
));
599 object_add_updates_list(change
->obj_list
, dia
);
600 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
604 delete_objects_free(struct DeleteObjectsChange
*change
)
606 DEBUG_PRINTF(("delete_objects_free()\n"));
608 destroy_object_list(change
->obj_list
);
610 g_list_free(change
->obj_list
);
611 g_list_free(change
->original_objects
);
615 undo_delete_objects(Diagram
*dia
, GList
*obj_list
)
617 struct DeleteObjectsChange
*change
;
619 change
= g_new(struct DeleteObjectsChange
, 1);
621 change
->change
.apply
= (UndoApplyFunc
) delete_objects_apply
;
622 change
->change
.revert
= (UndoRevertFunc
) delete_objects_revert
;
623 change
->change
.free
= (UndoFreeFunc
) delete_objects_free
;
625 change
->layer
= dia
->data
->active_layer
;
626 change
->obj_list
= obj_list
;
627 change
->original_objects
= g_list_copy(dia
->data
->active_layer
->objects
);
630 DEBUG_PRINTF(("UNDO: Push new delete objects at %d\n", depth(dia
->undo
)));
631 undo_push_change(dia
->undo
, (Change
*) change
);
632 return (Change
*)change
;
635 /******** Insert object list: */
637 struct InsertObjectsChange
{
641 GList
*obj_list
; /* Owning reference when not applied */
646 insert_objects_apply(struct InsertObjectsChange
*change
, Diagram
*dia
)
648 DEBUG_PRINTF(("insert_objects_apply()\n"));
650 layer_add_objects(change
->layer
, g_list_copy(change
->obj_list
));
651 object_add_updates_list(change
->obj_list
, dia
);
652 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
656 insert_objects_revert(struct InsertObjectsChange
*change
, Diagram
*dia
)
660 DEBUG_PRINTF(("insert_objects_revert()\n"));
662 diagram_unselect_objects(dia
, change
->obj_list
);
663 layer_remove_objects(change
->layer
, change
->obj_list
);
664 object_add_updates_list(change
->obj_list
, dia
);
666 list
= change
->obj_list
;
667 while (list
!= NULL
) {
668 Object
*obj
= (Object
*)list
->data
;
670 /* Have to hide any open properties dialog
671 if it contains some object in cut_list */
672 properties_hide_if_shown(dia
, obj
);
674 /* Remove focus if active */
675 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
679 list
= g_list_next(list
);
682 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
686 insert_objects_free(struct InsertObjectsChange
*change
)
688 DEBUG_PRINTF(("insert_objects_free()\n"));
689 if (!change
->applied
)
690 destroy_object_list(change
->obj_list
);
692 g_list_free(change
->obj_list
);
696 undo_insert_objects(Diagram
*dia
, GList
*obj_list
, int applied
)
698 struct InsertObjectsChange
*change
;
700 change
= g_new(struct InsertObjectsChange
, 1);
702 change
->change
.apply
= (UndoApplyFunc
) insert_objects_apply
;
703 change
->change
.revert
= (UndoRevertFunc
) insert_objects_revert
;
704 change
->change
.free
= (UndoFreeFunc
) insert_objects_free
;
706 change
->layer
= dia
->data
->active_layer
;
707 change
->obj_list
= obj_list
;
708 change
->applied
= applied
;
710 DEBUG_PRINTF(("UNDO: Push new insert objects at %d\n", depth(dia
->undo
)));
711 undo_push_change(dia
->undo
, (Change
*) change
);
712 return (Change
*)change
;
715 /******** Reorder object list: */
717 struct ReorderObjectsChange
{
721 GList
*changed_list
; /* Owning reference when applied */
722 GList
*original_objects
;
723 GList
*reordered_objects
;
727 reorder_objects_apply(struct ReorderObjectsChange
*change
, Diagram
*dia
)
729 DEBUG_PRINTF(("reorder_objects_apply()\n"));
730 layer_set_object_list(change
->layer
,
731 g_list_copy(change
->reordered_objects
));
732 object_add_updates_list(change
->changed_list
, dia
);
736 reorder_objects_revert(struct ReorderObjectsChange
*change
, Diagram
*dia
)
738 DEBUG_PRINTF(("reorder_objects_revert()\n"));
739 layer_set_object_list(change
->layer
,
740 g_list_copy(change
->original_objects
));
741 object_add_updates_list(change
->changed_list
, dia
);
745 reorder_objects_free(struct ReorderObjectsChange
*change
)
747 DEBUG_PRINTF(("reorder_objects_free()\n"));
748 g_list_free(change
->changed_list
);
749 g_list_free(change
->original_objects
);
750 g_list_free(change
->reordered_objects
);
754 undo_reorder_objects(Diagram
*dia
, GList
*changed_list
, GList
*orig_list
)
756 struct ReorderObjectsChange
*change
;
758 change
= g_new(struct ReorderObjectsChange
, 1);
760 change
->change
.apply
= (UndoApplyFunc
) reorder_objects_apply
;
761 change
->change
.revert
= (UndoRevertFunc
) reorder_objects_revert
;
762 change
->change
.free
= (UndoFreeFunc
) reorder_objects_free
;
764 change
->layer
= dia
->data
->active_layer
;
765 change
->changed_list
= changed_list
;
766 change
->original_objects
= orig_list
;
767 change
->reordered_objects
= g_list_copy(dia
->data
->active_layer
->objects
);
769 DEBUG_PRINTF(("UNDO: Push new reorder objects at %d\n", depth(dia
->undo
)));
770 undo_push_change(dia
->undo
, (Change
*) change
);
771 return (Change
*)change
;
774 /******** ObjectChange: */
776 struct ObjectChangeChange
{
780 ObjectChange
*obj_change
;
785 object_change_apply(struct ObjectChangeChange
*change
,
788 object_add_updates(change
->obj
, dia
);
789 change
->obj_change
->apply(change
->obj_change
, change
->obj
);
790 { /* Make sure object updates its data: */
791 Point p
= change
->obj
->position
;
792 (change
->obj
->ops
->move
)(change
->obj
,&p
);
794 object_add_updates(change
->obj
, dia
);
796 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
798 properties_update_if_shown(dia
, change
->obj
);
802 object_change_revert(struct ObjectChangeChange
*change
,
805 object_add_updates(change
->obj
, dia
);
806 change
->obj_change
->revert(change
->obj_change
, change
->obj
);
807 { /* Make sure object updates its data: */
808 Point p
= change
->obj
->position
;
809 (change
->obj
->ops
->move
)(change
->obj
,&p
);
811 object_add_updates(change
->obj
, dia
);
813 diagram_update_connections_object(dia
, change
->obj
, TRUE
);
815 properties_update_if_shown(dia
, change
->obj
);
819 object_change_free(struct ObjectChangeChange
*change
)
821 DEBUG_PRINTF(("state_change_free()\n"));
822 if (change
->obj_change
->free
)
823 (*change
->obj_change
->free
)(change
->obj_change
);
824 g_free(change
->obj_change
);
828 undo_object_change(Diagram
*dia
, Object
*obj
,
829 ObjectChange
*obj_change
)
831 struct ObjectChangeChange
*change
;
833 change
= g_new(struct ObjectChangeChange
, 1);
835 change
->change
.apply
= (UndoApplyFunc
) object_change_apply
;
836 change
->change
.revert
= (UndoRevertFunc
) object_change_revert
;
837 change
->change
.free
= (UndoFreeFunc
) object_change_free
;
840 change
->obj_change
= obj_change
;
842 DEBUG_PRINTF(("UNDO: Push new obj_change at %d\n", depth(dia
->undo
)));
843 undo_push_change(dia
->undo
, (Change
*) change
);
844 return (Change
*)change
;
847 /******** Group object list: */
849 struct GroupObjectsChange
{
853 Object
*group
; /* owning reference if not applied */
854 GList
*obj_list
; /* This list is owned by the group. */
855 GList
*orig_list
; /* This list (not the object) is owned */
860 group_objects_apply(struct GroupObjectsChange
*change
, Diagram
*dia
)
864 DEBUG_PRINTF(("group_objects_apply()\n"));
868 diagram_unselect_objects(dia
, change
->obj_list
);
869 layer_remove_objects(change
->layer
, change
->obj_list
);
870 layer_add_object(change
->layer
, change
->group
);
871 object_add_updates(change
->group
, dia
);
873 list
= change
->obj_list
;
874 while (list
!= NULL
) {
875 Object
*obj
= (Object
*)list
->data
;
877 /* Have to hide any open properties dialog
878 if it contains some object in cut_list */
879 properties_hide_if_shown(dia
, obj
);
881 /* Remove focus if active */
882 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
886 list
= g_list_next(list
);
889 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
890 diagram_tree_add_object(diagram_tree(), dia
, change
->group
);
894 group_objects_revert(struct GroupObjectsChange
*change
, Diagram
*dia
)
898 DEBUG_PRINTF(("group_objects_revert()\n"));
901 diagram_unselect_object(dia
, change
->group
);
902 object_add_updates(change
->group
, dia
);
904 old_list
= change
->layer
->objects
;
905 change
->layer
->objects
= g_list_copy(change
->orig_list
);
906 g_list_free(old_list
);
908 object_add_updates_list(change
->obj_list
, dia
);
910 properties_hide_if_shown(dia
, change
->group
);
912 diagram_tree_remove_object(diagram_tree(), change
->group
);
913 diagram_tree_add_objects(diagram_tree(), dia
, change
->obj_list
);
917 group_objects_free(struct GroupObjectsChange
*change
)
919 DEBUG_PRINTF(("group_objects_free()\n"));
920 if (!change
->applied
) {
921 group_destroy_shallow(change
->group
);
922 change
->group
= NULL
;
923 change
->obj_list
= NULL
;
925 g_list_free(change
->orig_list
);
929 undo_group_objects(Diagram
*dia
, GList
*obj_list
, Object
*group
,
932 struct GroupObjectsChange
*change
;
934 change
= g_new(struct GroupObjectsChange
, 1);
936 change
->change
.apply
= (UndoApplyFunc
) group_objects_apply
;
937 change
->change
.revert
= (UndoRevertFunc
) group_objects_revert
;
938 change
->change
.free
= (UndoFreeFunc
) group_objects_free
;
940 change
->layer
= dia
->data
->active_layer
;
941 change
->group
= group
;
942 change
->obj_list
= obj_list
;
943 change
->orig_list
= orig_list
;
946 DEBUG_PRINTF(("UNDO: Push new group objects at %d\n", depth(dia
->undo
)));
947 undo_push_change(dia
->undo
, (Change
*) change
);
948 return (Change
*)change
;
951 /******** Ungroup object list: */
953 struct UngroupObjectsChange
{
957 Object
*group
; /* owning reference if applied */
958 GList
*obj_list
; /* This list is owned by the ungroup. */
964 ungroup_objects_apply(struct UngroupObjectsChange
*change
, Diagram
*dia
)
966 DEBUG_PRINTF(("ungroup_objects_apply()\n"));
970 diagram_unselect_object(dia
, change
->group
);
971 object_add_updates(change
->group
, dia
);
972 layer_replace_object_with_list(change
->layer
, change
->group
,
973 g_list_copy(change
->obj_list
));
974 object_add_updates_list(change
->obj_list
, dia
);
976 properties_hide_if_shown(dia
, change
->group
);
980 ungroup_objects_revert(struct UngroupObjectsChange
*change
, Diagram
*dia
)
984 DEBUG_PRINTF(("ungroup_objects_revert()\n"));
988 diagram_unselect_objects(dia
, change
->obj_list
);
989 layer_remove_objects(change
->layer
, change
->obj_list
);
990 layer_add_object_at(change
->layer
, change
->group
, change
->group_index
);
991 object_add_updates(change
->group
, dia
);
993 list
= change
->obj_list
;
994 while (list
!= NULL
) {
995 Object
*obj
= (Object
*)list
->data
;
997 /* Have to hide any open properties dialog
998 if it contains some object in cut_list */
999 properties_hide_if_shown(dia
, obj
);
1001 /* Remove focus if active */
1002 if ((active_focus()!=NULL
) && (active_focus()->obj
== obj
)) {
1006 list
= g_list_next(list
);
1009 diagram_tree_remove_objects(diagram_tree(), change
->obj_list
);
1010 diagram_tree_add_object(diagram_tree(), dia
, change
->group
);
1014 ungroup_objects_free(struct UngroupObjectsChange
*change
)
1016 DEBUG_PRINTF(("ungroup_objects_free()\n"));
1017 if (change
->applied
) {
1018 group_destroy_shallow(change
->group
);
1019 change
->group
= NULL
;
1020 change
->obj_list
= NULL
;
1025 undo_ungroup_objects(Diagram
*dia
, GList
*obj_list
, Object
*group
,
1028 struct UngroupObjectsChange
*change
;
1030 change
= g_new(struct UngroupObjectsChange
, 1);
1032 change
->change
.apply
= (UndoApplyFunc
) ungroup_objects_apply
;
1033 change
->change
.revert
= (UndoRevertFunc
) ungroup_objects_revert
;
1034 change
->change
.free
= (UndoFreeFunc
) ungroup_objects_free
;
1036 change
->layer
= dia
->data
->active_layer
;
1037 change
->group
= group
;
1038 change
->obj_list
= obj_list
;
1039 change
->group_index
= group_index
;
1040 change
->applied
= 1;
1042 DEBUG_PRINTF(("UNDO: Push new ungroup objects at %d\n", depth(dia
->undo
)));
1043 undo_push_change(dia
->undo
, (Change
*) change
);
1044 return (Change
*)change
;