svg text alignment
[dia.git] / app / undo.c
blobda8fdd2d95a0acdffc4d9c38b4610a484e3f1791
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.
19 #include <config.h>
21 #include "undo.h"
22 #include "object_ops.h"
23 #include "properties.h"
24 #include "connectionpoint_ops.h"
25 #include "focus.h"
26 #include "group.h"
27 #include "preferences.h"
28 #include "diagram_tree_window.h"
30 #if 0
31 #define DEBUG_PRINTF(args) printf args
32 #else
33 #define DEBUG_PRINTF(args)
34 #endif
36 static void
37 transaction_point_pointer(Change *change, Diagram *dia)
39 /* Empty function used to track transactionpoints. */
42 static int
43 is_transactionpoint(Change *change)
45 return change->apply == transaction_point_pointer;
48 static Change *
49 new_transactionpoint(void)
51 Change *transaction = g_new(Change, 1);
53 if (transaction) {
54 transaction->apply = transaction_point_pointer;
55 transaction->revert = transaction_point_pointer;
56 transaction->free = NULL;
59 return transaction;
62 UndoStack *
63 new_undo_stack(Diagram *dia)
65 UndoStack *stack;
66 Change *transaction;
68 stack = g_new(UndoStack, 1);
69 if (stack!=NULL){
70 stack->dia = dia;
71 transaction = new_transactionpoint();
72 transaction->next = transaction->prev = NULL;
73 stack->last_change = transaction;
74 stack->current_change = transaction;
75 stack->depth = 0;
77 return stack;
80 void
81 undo_destroy(UndoStack *stack)
83 undo_clear(stack);
84 g_free(stack->current_change); /* Free first transaction point. */
85 g_free(stack);
90 static void
91 undo_remove_redo_info(UndoStack *stack)
93 Change *change;
94 Change *next_change;
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;
104 if (change->free)
105 (change->free)(change);
106 g_free(change);
107 change = next_change;
111 static int
112 depth(UndoStack *stack)
114 int i;
115 Change *change;
116 change = stack->current_change;
118 i = 0;
119 while (change->prev != NULL) {
120 change = change->prev;
121 i++;
123 return i;
126 void
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;
135 change->next = NULL;
136 stack->last_change->next = change;
137 stack->last_change = change;
138 stack->current_change = change;
141 static void
142 undo_delete_lowest_transaction(UndoStack *stack)
144 Change *change;
145 Change *next_change;
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.
157 do {
158 if ( (change == NULL) || (change == stack->current_change))
159 break;
161 next_change = change->next;
162 DEBUG_PRINTF(("freeing one change from the bottom.\n"));
163 if (change->free)
164 (change->free)(change);
165 g_free(change);
166 change = next_change;
167 } while (!is_transactionpoint(change));
169 if (is_transactionpoint(change)) {
170 stack->depth--;
171 DEBUG_PRINTF(("Decreasing stack depth to: %d\n", stack->depth));
173 change->prev = NULL;
176 void
177 undo_set_transactionpoint(UndoStack *stack)
179 Change *transaction;
181 if (is_transactionpoint(stack->current_change))
182 return;
184 DEBUG_PRINTF(("UNDO: Push new transactionpoint at %d\n", depth(stack)));
186 transaction = new_transactionpoint();
188 undo_push_change(stack, transaction);
189 stack->depth++;
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);
199 void
200 undo_revert_to_last_tp(UndoStack *stack)
202 Change *change;
203 Change *prev_change;
205 if (stack->current_change->prev == NULL)
206 return; /* Can't revert first transactionpoint */
208 change = stack->current_change;
209 do {
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;
215 stack->depth--;
216 DEBUG_PRINTF(("Decreasing stack depth to: %d\n", stack->depth));
219 void
220 undo_apply_to_next_tp(UndoStack *stack)
222 Change *change;
223 Change *next_change;
225 change = stack->current_change;
227 if (change->next == NULL)
228 return /* Already at top. */;
230 do {
231 next_change = change->next;
232 (change->apply)(change, stack->dia);
233 change = next_change;
234 } while ( (change != NULL) &&
235 (!is_transactionpoint(change)) );
236 if (change == NULL)
237 change = stack->last_change;
238 stack->current_change = change;
239 stack->depth++;
240 DEBUG_PRINTF(("Increasing stack depth to: %d\n", stack->depth));
244 void
245 undo_clear(UndoStack *stack)
247 Change *change;
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;
258 stack->depth = 0;
259 undo_remove_redo_info(stack);
263 /****************************************************************/
264 /****************************************************************/
265 /***************** *********************/
266 /***************** Specific undo functions: *********************/
267 /***************** *********************/
268 /****************************************************************/
269 /****************************************************************/
271 /******** Move object list: */
273 struct MoveObjectsChange {
274 Change change;
276 Point *orig_pos;
277 Point *dest_pos;
278 GList *obj_list;
281 static void
282 move_objects_apply(struct MoveObjectsChange *change, Diagram *dia)
284 GList *list;
285 int i;
286 Object *obj;
288 object_add_updates_list(change->obj_list, dia);
290 list = change->obj_list;
291 i=0;
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;
301 while (list!=NULL) {
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);
312 static void
313 move_objects_revert(struct MoveObjectsChange *change, Diagram *dia)
315 GList *list;
316 int i;
317 Object *obj;
319 object_add_updates_list(change->obj_list, dia);
321 list = change->obj_list;
322 i=0;
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;
332 while (list!=NULL) {
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);
343 static void
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);
351 extern Change *
352 undo_move_objects(Diagram *dia, Point *orig_pos, Point *dest_pos,
353 GList *obj_list)
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 {
375 Change change;
377 Point orig_pos;
378 Point dest_pos;
379 Handle *handle;
380 Object *obj;
383 static void
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,
389 HANDLE_MOVE_USER_FINAL,0);
390 object_add_updates(change->obj, dia);
391 diagram_update_connections_object(dia, change->obj, TRUE);
394 static void
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,
400 HANDLE_MOVE_USER_FINAL,0);
401 object_add_updates(change->obj, dia);
402 diagram_update_connections_object(dia, change->obj, TRUE);
405 static void
406 move_handle_free(struct MoveHandleChange *change)
411 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;
427 change->obj = obj;
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 {
438 Change change;
440 Object *obj;
441 Handle *handle;
442 ConnectionPoint *connectionpoint;
443 Point handle_pos;
446 static void
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);
459 static void
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 ,
466 &change->handle_pos,
467 HANDLE_MOVE_CONNECTED, 0);
469 object_add_updates(change->obj, dia);
472 static void
473 connect_free(struct ConnectChange *change)
477 extern 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;
489 change->obj = obj;
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 {
502 Change change;
504 Object *obj;
505 Handle *handle;
506 ConnectionPoint *connectionpoint;
509 static void
510 unconnect_apply(struct UnconnectChange *change, Diagram *dia)
512 object_unconnect(change->obj, change->handle);
514 object_add_updates(change->obj, dia);
517 static void
518 unconnect_revert(struct UnconnectChange *change, Diagram *dia)
520 object_connect(change->obj, change->handle, change->connectionpoint);
522 object_add_updates(change->obj, dia);
525 static void
526 unconnect_free(struct UnconnectChange *change)
530 extern 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;
541 change->obj = obj;
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 {
554 Change change;
556 Layer *layer;
557 GList *obj_list; /* Owning reference when applied */
558 GList *original_objects;
559 int applied;
562 static void
563 delete_objects_apply(struct DeleteObjectsChange *change, Diagram *dia)
565 GList *list;
567 DEBUG_PRINTF(("delete_objects_apply()\n"));
568 change->applied = 1;
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)) {
583 remove_focus();
586 list = g_list_next(list);
589 diagram_tree_remove_objects(diagram_tree(), change->obj_list);
592 static void
593 delete_objects_revert(struct DeleteObjectsChange *change, Diagram *dia)
595 DEBUG_PRINTF(("delete_objects_revert()\n"));
596 change->applied = 0;
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);
603 static void
604 delete_objects_free(struct DeleteObjectsChange *change)
606 DEBUG_PRINTF(("delete_objects_free()\n"));
607 if (change->applied)
608 destroy_object_list(change->obj_list);
609 else
610 g_list_free(change->obj_list);
611 g_list_free(change->original_objects);
614 Change *
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);
628 change->applied = 0;
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 {
638 Change change;
640 Layer *layer;
641 GList *obj_list; /* Owning reference when not applied */
642 int applied;
645 static void
646 insert_objects_apply(struct InsertObjectsChange *change, Diagram *dia)
648 DEBUG_PRINTF(("insert_objects_apply()\n"));
649 change->applied = 1;
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);
655 static void
656 insert_objects_revert(struct InsertObjectsChange *change, Diagram *dia)
658 GList *list;
660 DEBUG_PRINTF(("insert_objects_revert()\n"));
661 change->applied = 0;
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)) {
676 remove_focus();
679 list = g_list_next(list);
682 diagram_tree_remove_objects(diagram_tree(), change->obj_list);
685 static void
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);
691 else
692 g_list_free(change->obj_list);
695 Change *
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 {
718 Change change;
720 Layer *layer;
721 GList *changed_list; /* Owning reference when applied */
722 GList *original_objects;
723 GList *reordered_objects;
726 static void
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);
735 static void
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);
744 static void
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);
753 Change *
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 {
777 Change change;
779 Object *obj;
780 ObjectChange *obj_change;
784 static void
785 object_change_apply(struct ObjectChangeChange *change,
786 Diagram *dia)
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);
801 static void
802 object_change_revert(struct ObjectChangeChange *change,
803 Diagram *dia)
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);
818 static void
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);
827 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;
839 change->obj = obj;
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 {
850 Change change;
852 Layer *layer;
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 */
856 int applied;
859 static void
860 group_objects_apply(struct GroupObjectsChange *change, Diagram *dia)
862 GList *list;
864 DEBUG_PRINTF(("group_objects_apply()\n"));
866 change->applied = 1;
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)) {
883 remove_focus();
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);
893 static void
894 group_objects_revert(struct GroupObjectsChange *change, Diagram *dia)
896 GList *old_list;
898 DEBUG_PRINTF(("group_objects_revert()\n"));
899 change->applied = 0;
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);
916 static void
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);
928 Change *
929 undo_group_objects(Diagram *dia, GList *obj_list, Object *group,
930 GList *orig_list)
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;
944 change->applied = 1;
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 {
954 Change change;
956 Layer *layer;
957 Object *group; /* owning reference if applied */
958 GList *obj_list; /* This list is owned by the ungroup. */
959 int group_index;
960 int applied;
963 static void
964 ungroup_objects_apply(struct UngroupObjectsChange *change, Diagram *dia)
966 DEBUG_PRINTF(("ungroup_objects_apply()\n"));
968 change->applied = 1;
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);
979 static void
980 ungroup_objects_revert(struct UngroupObjectsChange *change, Diagram *dia)
982 GList *list;
984 DEBUG_PRINTF(("ungroup_objects_revert()\n"));
985 change->applied = 0;
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)) {
1003 remove_focus();
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);
1013 static void
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;
1024 Change *
1025 undo_ungroup_objects(Diagram *dia, GList *obj_list, Object *group,
1026 int group_index)
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;