comparison pidgin/gtksourceundomanager.c @ 22674:27c9c55499f8

Smiley insertions can be undone with this fix. References #5577. But redo doesn't work yet.
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Sun, 20 Apr 2008 15:35:16 +0000
parents 44b4e8bd759b
children 7fc110f70662
comparison
equal deleted inserted replaced
22672:269bba623a62 22674:27c9c55499f8
39 39
40 40
41 typedef struct _GtkSourceUndoAction GtkSourceUndoAction; 41 typedef struct _GtkSourceUndoAction GtkSourceUndoAction;
42 typedef struct _GtkSourceUndoInsertAction GtkSourceUndoInsertAction; 42 typedef struct _GtkSourceUndoInsertAction GtkSourceUndoInsertAction;
43 typedef struct _GtkSourceUndoDeleteAction GtkSourceUndoDeleteAction; 43 typedef struct _GtkSourceUndoDeleteAction GtkSourceUndoDeleteAction;
44 typedef struct _GtkSourceUndoInsertAnchorAction GtkSourceUndoInsertAnchorAction;
44 45
45 typedef enum { 46 typedef enum {
46 GTK_SOURCE_UNDO_ACTION_INSERT, 47 GTK_SOURCE_UNDO_ACTION_INSERT,
47 GTK_SOURCE_UNDO_ACTION_DELETE 48 GTK_SOURCE_UNDO_ACTION_DELETE,
49 GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR,
48 } GtkSourceUndoActionType; 50 } GtkSourceUndoActionType;
49 51
50 /* 52 /*
51 * We use offsets instead of GtkTextIters because the last ones 53 * We use offsets instead of GtkTextIters because the last ones
52 * require to much memory in this context without giving us any advantage. 54 * require to much memory in this context without giving us any advantage.
66 gint end; 68 gint end;
67 gchar *text; 69 gchar *text;
68 gboolean forward; 70 gboolean forward;
69 }; 71 };
70 72
73 struct _GtkSourceUndoInsertAnchorAction
74 {
75 gint pos;
76 GtkTextChildAnchor *anchor;
77 };
78
71 struct _GtkSourceUndoAction 79 struct _GtkSourceUndoAction
72 { 80 {
73 GtkSourceUndoActionType action_type; 81 GtkSourceUndoActionType action_type;
74 82
75 union { 83 union {
76 GtkSourceUndoInsertAction insert; 84 GtkSourceUndoInsertAction insert;
77 GtkSourceUndoDeleteAction delete; 85 GtkSourceUndoDeleteAction delete;
86 GtkSourceUndoInsertAnchorAction insert_anchor;
78 } action; 87 } action;
79 88
80 gint order_in_group; 89 gint order_in_group;
81 90
82 /* It is TRUE whether the action can be merged with the following action. */ 91 /* It is TRUE whether the action can be merged with the following action. */
137 static void gtk_source_undo_manager_insert_text_handler (GtkTextBuffer *buffer, 146 static void gtk_source_undo_manager_insert_text_handler (GtkTextBuffer *buffer,
138 GtkTextIter *pos, 147 GtkTextIter *pos,
139 const gchar *text, 148 const gchar *text,
140 gint length, 149 gint length,
141 GtkSourceUndoManager *um); 150 GtkSourceUndoManager *um);
151 static void gtk_source_undo_manager_insert_anchor_handler (GtkTextBuffer *buffer,
152 GtkTextIter *pos,
153 GtkTextChildAnchor *anchor,
154 GtkSourceUndoManager *um);
142 static void gtk_source_undo_manager_delete_range_handler (GtkTextBuffer *buffer, 155 static void gtk_source_undo_manager_delete_range_handler (GtkTextBuffer *buffer,
143 GtkTextIter *start, 156 GtkTextIter *start,
144 GtkTextIter *end, 157 GtkTextIter *end,
145 GtkSourceUndoManager *um); 158 GtkSourceUndoManager *um);
146 static void gtk_source_undo_manager_begin_user_action_handler (GtkTextBuffer *buffer, 159 static void gtk_source_undo_manager_begin_user_action_handler (GtkTextBuffer *buffer,
273 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document), 286 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
274 G_CALLBACK (gtk_source_undo_manager_insert_text_handler), 287 G_CALLBACK (gtk_source_undo_manager_insert_text_handler),
275 um); 288 um);
276 289
277 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document), 290 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
291 G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler),
292 um);
293
294 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
278 G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler), 295 G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler),
279 um); 296 um);
280 297
281 g_free (um->priv); 298 g_free (um->priv);
282 299
293 g_return_val_if_fail (um->priv != NULL, NULL); 310 g_return_val_if_fail (um->priv != NULL, NULL);
294 um->priv->document = buffer; 311 um->priv->document = buffer;
295 312
296 g_signal_connect (G_OBJECT (buffer), "insert_text", 313 g_signal_connect (G_OBJECT (buffer), "insert_text",
297 G_CALLBACK (gtk_source_undo_manager_insert_text_handler), 314 G_CALLBACK (gtk_source_undo_manager_insert_text_handler),
315 um);
316
317 g_signal_connect (G_OBJECT (buffer), "insert_child_anchor",
318 G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler),
298 um); 319 um);
299 320
300 g_signal_connect (G_OBJECT (buffer), "delete_range", 321 g_signal_connect (G_OBJECT (buffer), "delete_range",
301 G_CALLBACK (gtk_source_undo_manager_delete_range_handler), 322 G_CALLBACK (gtk_source_undo_manager_delete_range_handler),
302 um); 323 um);
398 { 419 {
399 GtkTextIter iter; 420 GtkTextIter iter;
400 421
401 gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos); 422 gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos);
402 gtk_text_buffer_insert (buffer, &iter, text, len); 423 gtk_text_buffer_insert (buffer, &iter, text, len);
424 }
425
426 static void
427 insert_anchor (GtkTextBuffer *buffer, gint pos, GtkTextChildAnchor *anchor)
428 {
429 GtkTextIter iter;
430
431 gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos);
432 gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
403 } 433 }
404 434
405 static void 435 static void
406 delete_text (GtkTextBuffer *buffer, gint start, gint end) 436 delete_text (GtkTextBuffer *buffer, gint start, gint end)
407 { 437 {
495 set_cursor ( 525 set_cursor (
496 um->priv->document, 526 um->priv->document,
497 undo_action->action.insert.pos); 527 undo_action->action.insert.pos);
498 break; 528 break;
499 529
530 case GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR:
531 delete_text (
532 um->priv->document,
533 undo_action->action.insert_anchor.pos,
534 undo_action->action.insert_anchor.pos + 1);
535 undo_action->action.insert_anchor.anchor->segment = NULL; /* XXX: This may be a bug in GTK+ */
536 break;
500 default: 537 default:
501 /* Unknown action type. */ 538 /* Unknown action type. */
502 g_return_if_reached (); 539 g_return_if_reached ();
503 } 540 }
504 541
586 undo_action->action.insert.text, 623 undo_action->action.insert.text,
587 undo_action->action.insert.length); 624 undo_action->action.insert.length);
588 625
589 break; 626 break;
590 627
628 case GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR:
629 set_cursor (
630 um->priv->document,
631 undo_action->action.insert_anchor.pos);
632
633 insert_anchor (
634 um->priv->document,
635 undo_action->action.insert_anchor.pos,
636 undo_action->action.insert_anchor.anchor);
637 break;
638
591 default: 639 default:
592 /* Unknown action type */ 640 /* Unknown action type */
593 ++um->priv->next_redo; 641 ++um->priv->next_redo;
594 g_return_if_reached (); 642 g_return_if_reached ();
595 } 643 }
631 679
632 if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT) 680 if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
633 g_free (action->action.insert.text); 681 g_free (action->action.insert.text);
634 else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE) 682 else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
635 g_free (action->action.delete.text); 683 g_free (action->action.delete.text);
684 else if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR)
685 g_object_unref(action->action.insert_anchor.anchor);
636 else 686 else
637 g_return_if_reached (); 687 g_return_if_reached ();
638 688
639 g_free (action); 689 g_free (action);
640 } 690 }
688 738
689 undo_action.mergeable = FALSE; 739 undo_action.mergeable = FALSE;
690 else 740 else
691 undo_action.mergeable = TRUE; 741 undo_action.mergeable = TRUE;
692 742
743 undo_action.modified = FALSE;
744
745 gtk_source_undo_manager_add_action (um, &undo_action);
746 }
747
748 static void gtk_source_undo_manager_insert_anchor_handler (GtkTextBuffer *buffer,
749 GtkTextIter *pos,
750 GtkTextChildAnchor *anchor,
751 GtkSourceUndoManager *um)
752 {
753 GtkSourceUndoAction undo_action;
754
755 if (um->priv->running_not_undoable_actions > 0)
756 return;
757
758 undo_action.action_type = GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR;
759
760 undo_action.action.insert_anchor.pos = gtk_text_iter_get_offset (pos);
761 undo_action.action.insert_anchor.anchor = g_object_ref (anchor);
762
763 undo_action.mergeable = FALSE;
693 undo_action.modified = FALSE; 764 undo_action.modified = FALSE;
694 765
695 gtk_source_undo_manager_add_action (um, &undo_action); 766 gtk_source_undo_manager_add_action (um, &undo_action);
696 } 767 }
697 768
773 844
774 if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT) 845 if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
775 action->action.insert.text = g_strndup (undo_action->action.insert.text, undo_action->action.insert.length); 846 action->action.insert.text = g_strndup (undo_action->action.insert.text, undo_action->action.insert.length);
776 else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE) 847 else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
777 action->action.delete.text = g_strdup (undo_action->action.delete.text); 848 action->action.delete.text = g_strdup (undo_action->action.delete.text);
849 else if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR)
850 {
851 /* Nothing needs to be done */
852 }
778 else 853 else
779 { 854 {
780 g_free (action); 855 g_free (action);
781 g_return_if_reached (); 856 g_return_if_reached ();
782 } 857 }
996 last_action->action.insert.length += undo_action->action.insert.length; 1071 last_action->action.insert.length += undo_action->action.insert.length;
997 last_action->action.insert.text = str; 1072 last_action->action.insert.text = str;
998 last_action->action.insert.chars += undo_action->action.insert.chars; 1073 last_action->action.insert.chars += undo_action->action.insert.chars;
999 1074
1000 } 1075 }
1076 else if (undo_action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR)
1077 {
1078 /* Nothing needs to be done */
1079 }
1001 else 1080 else
1002 /* Unknown action inside undo merge encountered */ 1081 /* Unknown action inside undo merge encountered */
1003 g_return_val_if_reached (TRUE); 1082 g_return_val_if_reached (TRUE);
1004 1083
1005 return TRUE; 1084 return TRUE;