pidgin/gtksourceundomanager.c

changeset 26378
e85d894af8a5
parent 25888
d0fdd378a635
child 30623
d0368101bd0d
equal deleted inserted replaced
26377:9124a345ed3a 26378:e85d894af8a5
2 /* 2 /*
3 * gtksourceundomanager.c 3 * gtksourceundomanager.c
4 * This file is part of GtkSourceView 4 * This file is part of GtkSourceView
5 * 5 *
6 * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence 6 * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
7 * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi 7 * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
8 * Copyright (C) 2002-2005 Paolo Maggi 8 * Copyright (C) 2002-2005 Paolo Maggi
9 * 9 *
10 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by 11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or 12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. 13 * (at your option) any later version.
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details. 18 * GNU General Public License for more details.
19 * 19 *
20 * You should have received a copy of the GNU General Public License 20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software 21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02111-1301, USA. 23 * Boston, MA 02111-1301, USA.
24 */ 24 */
25 25
26 #ifdef HAVE_CONFIG_H 26 #ifdef HAVE_CONFIG_H
27 #include <config.h> 27 #include <config.h>
47 GTK_SOURCE_UNDO_ACTION_INSERT, 47 GTK_SOURCE_UNDO_ACTION_INSERT,
48 GTK_SOURCE_UNDO_ACTION_DELETE, 48 GTK_SOURCE_UNDO_ACTION_DELETE,
49 GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR, 49 GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR,
50 } GtkSourceUndoActionType; 50 } GtkSourceUndoActionType;
51 51
52 /* 52 /*
53 * We use offsets instead of GtkTextIters because the last ones 53 * We use offsets instead of GtkTextIters because the last ones
54 * 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.
55 */ 55 */
56 56
57 struct _GtkSourceUndoInsertAction 57 struct _GtkSourceUndoInsertAction
58 { 58 {
59 gint pos; 59 gint pos;
60 gchar *text; 60 gchar *text;
61 gint length; 61 gint length;
62 gint chars; 62 gint chars;
63 }; 63 };
64 64
77 }; 77 };
78 78
79 struct _GtkSourceUndoAction 79 struct _GtkSourceUndoAction
80 { 80 {
81 GtkSourceUndoActionType action_type; 81 GtkSourceUndoActionType action_type;
82 82
83 union { 83 union {
84 GtkSourceUndoInsertAction insert; 84 GtkSourceUndoInsertAction insert;
85 GtkSourceUndoDeleteAction delete; 85 GtkSourceUndoDeleteAction delete;
86 GtkSourceUndoInsertAnchorAction insert_anchor; 86 GtkSourceUndoInsertAnchorAction insert_anchor;
87 } action; 87 } action;
90 90
91 /* 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. */
92 guint mergeable : 1; 92 guint mergeable : 1;
93 93
94 /* It is TRUE whether the action is marked as "modified". 94 /* It is TRUE whether the action is marked as "modified".
95 * An action is marked as "modified" if it changed the 95 * An action is marked as "modified" if it changed the
96 * state of the buffer from "not modified" to "modified". Only the first 96 * state of the buffer from "not modified" to "modified". Only the first
97 * action of a group can be marked as modified. 97 * action of a group can be marked as modified.
98 * There can be a single action marked as "modified" in the actions list. 98 * There can be a single action marked as "modified" in the actions list.
99 */ 99 */
100 guint modified : 1; 100 guint modified : 1;
104 #define INVALID ((void *) "IA") 104 #define INVALID ((void *) "IA")
105 105
106 struct _GtkSourceUndoManagerPrivate 106 struct _GtkSourceUndoManagerPrivate
107 { 107 {
108 GtkTextBuffer *document; 108 GtkTextBuffer *document;
109 109
110 GList* actions; 110 GList* actions;
111 gint next_redo; 111 gint next_redo;
112 112
113 gint actions_in_current_group; 113 gint actions_in_current_group;
114 114
115 gint running_not_undoable_actions; 115 gint running_not_undoable_actions;
116 116
117 gint num_of_groups; 117 gint num_of_groups;
118 118
119 gint max_undo_levels; 119 gint max_undo_levels;
120 120
121 guint can_undo : 1; 121 guint can_undo : 1;
122 guint can_redo : 1; 122 guint can_redo : 1;
123 123
124 /* It is TRUE whether, while undoing an action of the current group (with order_in_group > 1), 124 /* It is TRUE whether, while undoing an action of the current group (with order_in_group > 1),
125 * the state of the buffer changed from "not modified" to "modified". 125 * the state of the buffer changed from "not modified" to "modified".
126 */ 126 */
127 guint modified_undoing_group : 1; 127 guint modified_undoing_group : 1;
128 128
129 /* Pointer to the action (in the action list) marked as "modified". 129 /* Pointer to the action (in the action list) marked as "modified".
130 * It is NULL when no action is marked as "modified". 130 * It is NULL when no action is marked as "modified".
131 * It is INVALID when the action marked as "modified" has been removed 131 * It is INVALID when the action marked as "modified" has been removed
132 * from the action list (freeing the list or resizing it) */ 132 * from the action list (freeing the list or resizing it) */
133 GtkSourceUndoAction *modified_action; 133 GtkSourceUndoAction *modified_action;
134 }; 134 };
135 135
136 enum { 136 enum {
141 141
142 static void gtk_source_undo_manager_class_init (GtkSourceUndoManagerClass *klass); 142 static void gtk_source_undo_manager_class_init (GtkSourceUndoManagerClass *klass);
143 static void gtk_source_undo_manager_init (GtkSourceUndoManager *um); 143 static void gtk_source_undo_manager_init (GtkSourceUndoManager *um);
144 static void gtk_source_undo_manager_finalize (GObject *object); 144 static void gtk_source_undo_manager_finalize (GObject *object);
145 145
146 static void gtk_source_undo_manager_insert_text_handler (GtkTextBuffer *buffer, 146 static void gtk_source_undo_manager_insert_text_handler (GtkTextBuffer *buffer,
147 GtkTextIter *pos, 147 GtkTextIter *pos,
148 const gchar *text, 148 const gchar *text,
149 gint length, 149 gint length,
150 GtkSourceUndoManager *um); 150 GtkSourceUndoManager *um);
151 static void gtk_source_undo_manager_insert_anchor_handler (GtkTextBuffer *buffer, 151 static void gtk_source_undo_manager_insert_anchor_handler (GtkTextBuffer *buffer,
152 GtkTextIter *pos, 152 GtkTextIter *pos,
153 GtkTextChildAnchor *anchor, 153 GtkTextChildAnchor *anchor,
154 GtkSourceUndoManager *um); 154 GtkSourceUndoManager *um);
155 static void gtk_source_undo_manager_delete_range_handler (GtkTextBuffer *buffer, 155 static void gtk_source_undo_manager_delete_range_handler (GtkTextBuffer *buffer,
156 GtkTextIter *start, 156 GtkTextIter *start,
157 GtkTextIter *end, 157 GtkTextIter *end,
158 GtkSourceUndoManager *um); 158 GtkSourceUndoManager *um);
159 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,
160 GtkSourceUndoManager *um); 160 GtkSourceUndoManager *um);
161 static void gtk_source_undo_manager_modified_changed_handler (GtkTextBuffer *buffer, 161 static void gtk_source_undo_manager_modified_changed_handler (GtkTextBuffer *buffer,
162 GtkSourceUndoManager *um); 162 GtkSourceUndoManager *um);
163 163
164 static void gtk_source_undo_manager_free_action_list (GtkSourceUndoManager *um); 164 static void gtk_source_undo_manager_free_action_list (GtkSourceUndoManager *um);
165 165
166 static void gtk_source_undo_manager_add_action (GtkSourceUndoManager *um, 166 static void gtk_source_undo_manager_add_action (GtkSourceUndoManager *um,
167 const GtkSourceUndoAction *undo_action); 167 const GtkSourceUndoAction *undo_action);
168 static void gtk_source_undo_manager_free_first_n_actions (GtkSourceUndoManager *um, 168 static void gtk_source_undo_manager_free_first_n_actions (GtkSourceUndoManager *um,
169 gint n); 169 gint n);
170 static void gtk_source_undo_manager_check_list_size (GtkSourceUndoManager *um); 170 static void gtk_source_undo_manager_check_list_size (GtkSourceUndoManager *um);
171 171
172 static gboolean gtk_source_undo_manager_merge_action (GtkSourceUndoManager *um, 172 static gboolean gtk_source_undo_manager_merge_action (GtkSourceUndoManager *um,
173 const GtkSourceUndoAction *undo_action); 173 const GtkSourceUndoAction *undo_action);
174 174
175 static GObjectClass *parent_class = NULL; 175 static GObjectClass *parent_class = NULL;
176 static guint undo_manager_signals [LAST_SIGNAL] = { 0 }; 176 static guint undo_manager_signals [LAST_SIGNAL] = { 0 };
177 177
214 214
215 object_class->finalize = gtk_source_undo_manager_finalize; 215 object_class->finalize = gtk_source_undo_manager_finalize;
216 216
217 klass->can_undo = NULL; 217 klass->can_undo = NULL;
218 klass->can_redo = NULL; 218 klass->can_redo = NULL;
219 219
220 undo_manager_signals[CAN_UNDO] = 220 undo_manager_signals[CAN_UNDO] =
221 g_signal_new ("can_undo", 221 g_signal_new ("can_undo",
222 G_OBJECT_CLASS_TYPE (object_class), 222 G_OBJECT_CLASS_TYPE (object_class),
223 G_SIGNAL_RUN_LAST, 223 G_SIGNAL_RUN_LAST,
224 G_STRUCT_OFFSET (GtkSourceUndoManagerClass, can_undo), 224 G_STRUCT_OFFSET (GtkSourceUndoManagerClass, can_undo),
267 { 267 {
268 GtkSourceUndoManager *um; 268 GtkSourceUndoManager *um;
269 269
270 g_return_if_fail (object != NULL); 270 g_return_if_fail (object != NULL);
271 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (object)); 271 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (object));
272 272
273 um = GTK_SOURCE_UNDO_MANAGER (object); 273 um = GTK_SOURCE_UNDO_MANAGER (object);
274 274
275 g_return_if_fail (um->priv != NULL); 275 g_return_if_fail (um->priv != NULL);
276 276
277 if (um->priv->actions != NULL) 277 if (um->priv->actions != NULL)
278 { 278 {
279 gtk_source_undo_manager_free_action_list (um); 279 gtk_source_undo_manager_free_action_list (um);
280 } 280 }
281 281
282 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document), 282 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
283 G_CALLBACK (gtk_source_undo_manager_delete_range_handler), 283 G_CALLBACK (gtk_source_undo_manager_delete_range_handler),
284 um); 284 um);
285 285
286 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document), 286 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
287 G_CALLBACK (gtk_source_undo_manager_insert_text_handler), 287 G_CALLBACK (gtk_source_undo_manager_insert_text_handler),
288 um); 288 um);
289 289
290 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), 291 G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler),
292 um); 292 um);
293 293
294 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document), 294 g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
295 G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler), 295 G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler),
296 um); 296 um);
297 297
298 g_free (um->priv); 298 g_free (um->priv);
299 299
300 G_OBJECT_CLASS (parent_class)->finalize (object); 300 G_OBJECT_CLASS (parent_class)->finalize (object);
309 309
310 g_return_val_if_fail (um->priv != NULL, NULL); 310 g_return_val_if_fail (um->priv != NULL, NULL);
311 um->priv->document = buffer; 311 um->priv->document = buffer;
312 312
313 g_signal_connect (G_OBJECT (buffer), "insert_text", 313 g_signal_connect (G_OBJECT (buffer), "insert_text",
314 G_CALLBACK (gtk_source_undo_manager_insert_text_handler), 314 G_CALLBACK (gtk_source_undo_manager_insert_text_handler),
315 um); 315 um);
316 316
317 g_signal_connect (G_OBJECT (buffer), "insert_child_anchor", 317 g_signal_connect (G_OBJECT (buffer), "insert_child_anchor",
318 G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler), 318 G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler),
319 um); 319 um);
320 320
321 g_signal_connect (G_OBJECT (buffer), "delete_range", 321 g_signal_connect (G_OBJECT (buffer), "delete_range",
322 G_CALLBACK (gtk_source_undo_manager_delete_range_handler), 322 G_CALLBACK (gtk_source_undo_manager_delete_range_handler),
323 um); 323 um);
324 324
325 g_signal_connect (G_OBJECT (buffer), "begin_user_action", 325 g_signal_connect (G_OBJECT (buffer), "begin_user_action",
326 G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler), 326 G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler),
327 um); 327 um);
328 328
329 g_signal_connect (G_OBJECT (buffer), "modified_changed", 329 g_signal_connect (G_OBJECT (buffer), "modified_changed",
330 G_CALLBACK (gtk_source_undo_manager_modified_changed_handler), 330 G_CALLBACK (gtk_source_undo_manager_modified_changed_handler),
331 um); 331 um);
332 return um; 332 return um;
333 } 333 }
334 334
335 void 335 void
336 gtk_source_undo_manager_begin_not_undoable_action (GtkSourceUndoManager *um) 336 gtk_source_undo_manager_begin_not_undoable_action (GtkSourceUndoManager *um)
337 { 337 {
338 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um)); 338 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
339 g_return_if_fail (um->priv != NULL); 339 g_return_if_fail (um->priv != NULL);
340 340
341 ++um->priv->running_not_undoable_actions; 341 ++um->priv->running_not_undoable_actions;
342 } 342 }
343 343
344 static void 344 static void
345 gtk_source_undo_manager_end_not_undoable_action_internal (GtkSourceUndoManager *um) 345 gtk_source_undo_manager_end_not_undoable_action_internal (GtkSourceUndoManager *um)
346 { 346 {
347 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um)); 347 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
348 g_return_if_fail (um->priv != NULL); 348 g_return_if_fail (um->priv != NULL);
349 349
350 g_return_if_fail (um->priv->running_not_undoable_actions > 0); 350 g_return_if_fail (um->priv->running_not_undoable_actions > 0);
351 351
352 --um->priv->running_not_undoable_actions; 352 --um->priv->running_not_undoable_actions;
353 } 353 }
354 354
355 void 355 void
356 gtk_source_undo_manager_end_not_undoable_action (GtkSourceUndoManager *um) 356 gtk_source_undo_manager_end_not_undoable_action (GtkSourceUndoManager *um)
357 { 357 {
358 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um)); 358 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
359 g_return_if_fail (um->priv != NULL); 359 g_return_if_fail (um->priv != NULL);
360 360
361 gtk_source_undo_manager_end_not_undoable_action_internal (um); 361 gtk_source_undo_manager_end_not_undoable_action_internal (um);
362 362
363 if (um->priv->running_not_undoable_actions == 0) 363 if (um->priv->running_not_undoable_actions == 0)
364 { 364 {
365 gtk_source_undo_manager_free_action_list (um); 365 gtk_source_undo_manager_free_action_list (um);
366 366
367 um->priv->next_redo = -1; 367 um->priv->next_redo = -1;
368 368
369 if (um->priv->can_undo) 369 if (um->priv->can_undo)
370 { 370 {
371 um->priv->can_undo = FALSE; 371 um->priv->can_undo = FALSE;
372 g_signal_emit (G_OBJECT (um), 372 g_signal_emit (G_OBJECT (um),
373 undo_manager_signals [CAN_UNDO], 373 undo_manager_signals [CAN_UNDO],
374 0, 374 0,
375 FALSE); 375 FALSE);
376 } 376 }
377 377
378 if (um->priv->can_redo) 378 if (um->priv->can_redo)
379 { 379 {
380 um->priv->can_redo = FALSE; 380 um->priv->can_redo = FALSE;
381 g_signal_emit (G_OBJECT (um), 381 g_signal_emit (G_OBJECT (um),
382 undo_manager_signals [CAN_REDO], 382 undo_manager_signals [CAN_REDO],
383 0, 383 0,
384 FALSE); 384 FALSE);
385 } 385 }
386 } 386 }
387 } 387 }
388 388
393 g_return_val_if_fail (um->priv != NULL, FALSE); 393 g_return_val_if_fail (um->priv != NULL, FALSE);
394 394
395 return um->priv->can_undo; 395 return um->priv->can_undo;
396 } 396 }
397 397
398 gboolean 398 gboolean
399 gtk_source_undo_manager_can_redo (const GtkSourceUndoManager *um) 399 gtk_source_undo_manager_can_redo (const GtkSourceUndoManager *um)
400 { 400 {
401 g_return_val_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um), FALSE); 401 g_return_val_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um), FALSE);
402 g_return_val_if_fail (um->priv != NULL, FALSE); 402 g_return_val_if_fail (um->priv != NULL, FALSE);
403 403
406 406
407 static void 407 static void
408 set_cursor (GtkTextBuffer *buffer, gint cursor) 408 set_cursor (GtkTextBuffer *buffer, gint cursor)
409 { 409 {
410 GtkTextIter iter; 410 GtkTextIter iter;
411 411
412 /* Place the cursor at the requested position */ 412 /* Place the cursor at the requested position */
413 gtk_text_buffer_get_iter_at_offset (buffer, &iter, cursor); 413 gtk_text_buffer_get_iter_at_offset (buffer, &iter, cursor);
414 gtk_text_buffer_place_cursor (buffer, &iter); 414 gtk_text_buffer_place_cursor (buffer, &iter);
415 } 415 }
416 416
417 static void 417 static void
418 insert_text (GtkTextBuffer *buffer, gint pos, const gchar *text, gint len) 418 insert_text (GtkTextBuffer *buffer, gint pos, const gchar *text, gint len)
419 { 419 {
420 GtkTextIter iter; 420 GtkTextIter iter;
421 421
422 gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos); 422 gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos);
423 gtk_text_buffer_insert (buffer, &iter, text, len); 423 gtk_text_buffer_insert (buffer, &iter, text, len);
424 } 424 }
425 425
426 static void 426 static void
427 insert_anchor (GtkTextBuffer *buffer, gint pos, GtkTextChildAnchor *anchor) 427 insert_anchor (GtkTextBuffer *buffer, gint pos, GtkTextChildAnchor *anchor)
428 { 428 {
429 GtkTextIter iter; 429 GtkTextIter iter;
430 430
431 gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos); 431 gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos);
432 gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor); 432 gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
433 } 433 }
434 434
435 static void 435 static void
436 delete_text (GtkTextBuffer *buffer, gint start, gint end) 436 delete_text (GtkTextBuffer *buffer, gint start, gint end)
437 { 437 {
438 GtkTextIter start_iter; 438 GtkTextIter start_iter;
439 GtkTextIter end_iter; 439 GtkTextIter end_iter;
440 440
462 gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end); 462 gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
463 463
464 return gtk_text_buffer_get_slice (buffer, &start_iter, &end_iter, TRUE); 464 return gtk_text_buffer_get_slice (buffer, &start_iter, &end_iter, TRUE);
465 } 465 }
466 466
467 void 467 void
468 gtk_source_undo_manager_undo (GtkSourceUndoManager *um) 468 gtk_source_undo_manager_undo (GtkSourceUndoManager *um)
469 { 469 {
470 GtkSourceUndoAction *undo_action; 470 GtkSourceUndoAction *undo_action;
471 gboolean modified = FALSE; 471 gboolean modified = FALSE;
472 472
473 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um)); 473 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
474 g_return_if_fail (um->priv != NULL); 474 g_return_if_fail (um->priv != NULL);
475 g_return_if_fail (um->priv->can_undo); 475 g_return_if_fail (um->priv->can_undo);
476 476
477 um->priv->modified_undoing_group = FALSE; 477 um->priv->modified_undoing_group = FALSE;
478 478
479 gtk_source_undo_manager_begin_not_undoable_action (um); 479 gtk_source_undo_manager_begin_not_undoable_action (um);
480 480
481 do 481 do
482 { 482 {
483 undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo + 1); 483 undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo + 1);
484 g_return_if_fail (undo_action != NULL); 484 g_return_if_fail (undo_action != NULL);
485 485
486 /* undo_action->modified can be TRUE only if undo_action->order_in_group <= 1 */ 486 /* undo_action->modified can be TRUE only if undo_action->order_in_group <= 1 */
487 g_return_if_fail ((undo_action->order_in_group <= 1) || 487 g_return_if_fail ((undo_action->order_in_group <= 1) ||
488 ((undo_action->order_in_group > 1) && !undo_action->modified)); 488 ((undo_action->order_in_group > 1) && !undo_action->modified));
489 489
490 if (undo_action->order_in_group <= 1) 490 if (undo_action->order_in_group <= 1)
491 { 491 {
492 /* Set modified to TRUE only if the buffer did not change its state from 492 /* Set modified to TRUE only if the buffer did not change its state from
493 * "not modified" to "modified" undoing an action (with order_in_group > 1) 493 * "not modified" to "modified" undoing an action (with order_in_group > 1)
494 * in current group. */ 494 * in current group. */
495 modified = (undo_action->modified && !um->priv->modified_undoing_group); 495 modified = (undo_action->modified && !um->priv->modified_undoing_group);
496 } 496 }
497 497
498 switch (undo_action->action_type) 498 switch (undo_action->action_type)
499 { 499 {
500 case GTK_SOURCE_UNDO_ACTION_DELETE: 500 case GTK_SOURCE_UNDO_ACTION_DELETE:
501 insert_text ( 501 insert_text (
502 um->priv->document, 502 um->priv->document,
503 undo_action->action.delete.start, 503 undo_action->action.delete.start,
504 undo_action->action.delete.text, 504 undo_action->action.delete.text,
505 strlen (undo_action->action.delete.text)); 505 strlen (undo_action->action.delete.text));
506 506
507 if (undo_action->action.delete.forward) 507 if (undo_action->action.delete.forward)
508 set_cursor ( 508 set_cursor (
509 um->priv->document, 509 um->priv->document,
510 undo_action->action.delete.start); 510 undo_action->action.delete.start);
511 else 511 else
512 set_cursor ( 512 set_cursor (
513 um->priv->document, 513 um->priv->document,
514 undo_action->action.delete.end); 514 undo_action->action.delete.end);
515 515
516 break; 516 break;
517 517
518 case GTK_SOURCE_UNDO_ACTION_INSERT: 518 case GTK_SOURCE_UNDO_ACTION_INSERT:
519 delete_text ( 519 delete_text (
520 um->priv->document, 520 um->priv->document,
521 undo_action->action.insert.pos, 521 undo_action->action.insert.pos,
522 undo_action->action.insert.pos + 522 undo_action->action.insert.pos +
523 undo_action->action.insert.chars); 523 undo_action->action.insert.chars);
524 524
525 set_cursor ( 525 set_cursor (
526 um->priv->document, 526 um->priv->document,
527 undo_action->action.insert.pos); 527 undo_action->action.insert.pos);
528 break; 528 break;
529 529
530 case GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR: 530 case GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR:
531 delete_text ( 531 delete_text (
549 gtk_text_buffer_set_modified (um->priv->document, FALSE); 549 gtk_text_buffer_set_modified (um->priv->document, FALSE);
550 ++um->priv->next_redo; 550 ++um->priv->next_redo;
551 } 551 }
552 552
553 gtk_source_undo_manager_end_not_undoable_action_internal (um); 553 gtk_source_undo_manager_end_not_undoable_action_internal (um);
554 554
555 um->priv->modified_undoing_group = FALSE; 555 um->priv->modified_undoing_group = FALSE;
556 556
557 if (!um->priv->can_redo) 557 if (!um->priv->can_redo)
558 { 558 {
559 um->priv->can_redo = TRUE; 559 um->priv->can_redo = TRUE;
560 g_signal_emit (G_OBJECT (um), 560 g_signal_emit (G_OBJECT (um),
561 undo_manager_signals [CAN_REDO], 561 undo_manager_signals [CAN_REDO],
562 0, 562 0,
563 TRUE); 563 TRUE);
564 } 564 }
565 565
566 if (um->priv->next_redo >= (gint)(g_list_length (um->priv->actions) - 1)) 566 if (um->priv->next_redo >= (gint)(g_list_length (um->priv->actions) - 1))
567 { 567 {
568 um->priv->can_undo = FALSE; 568 um->priv->can_undo = FALSE;
569 g_signal_emit (G_OBJECT (um), 569 g_signal_emit (G_OBJECT (um),
570 undo_manager_signals [CAN_UNDO], 570 undo_manager_signals [CAN_UNDO],
571 0, 571 0,
572 FALSE); 572 FALSE);
573 } 573 }
574 } 574 }
575 575
576 void 576 void
577 gtk_source_undo_manager_redo (GtkSourceUndoManager *um) 577 gtk_source_undo_manager_redo (GtkSourceUndoManager *um)
578 { 578 {
579 GtkSourceUndoAction *undo_action; 579 GtkSourceUndoAction *undo_action;
580 gboolean modified = FALSE; 580 gboolean modified = FALSE;
581 581
582 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um)); 582 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
583 g_return_if_fail (um->priv != NULL); 583 g_return_if_fail (um->priv != NULL);
584 g_return_if_fail (um->priv->can_redo); 584 g_return_if_fail (um->priv->can_redo);
585 585
586 undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo); 586 undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo);
587 g_return_if_fail (undo_action != NULL); 587 g_return_if_fail (undo_action != NULL);
588 588
589 gtk_source_undo_manager_begin_not_undoable_action (um); 589 gtk_source_undo_manager_begin_not_undoable_action (um);
590 590
595 g_return_if_fail (undo_action->order_in_group <= 1); 595 g_return_if_fail (undo_action->order_in_group <= 1);
596 modified = TRUE; 596 modified = TRUE;
597 } 597 }
598 598
599 --um->priv->next_redo; 599 --um->priv->next_redo;
600 600
601 switch (undo_action->action_type) 601 switch (undo_action->action_type)
602 { 602 {
603 case GTK_SOURCE_UNDO_ACTION_DELETE: 603 case GTK_SOURCE_UNDO_ACTION_DELETE:
604 delete_text ( 604 delete_text (
605 um->priv->document, 605 um->priv->document,
606 undo_action->action.delete.start, 606 undo_action->action.delete.start,
607 undo_action->action.delete.end); 607 undo_action->action.delete.end);
608 608
609 set_cursor ( 609 set_cursor (
610 um->priv->document, 610 um->priv->document,
611 undo_action->action.delete.start); 611 undo_action->action.delete.start);
612 612
613 break; 613 break;
614 614
615 case GTK_SOURCE_UNDO_ACTION_INSERT: 615 case GTK_SOURCE_UNDO_ACTION_INSERT:
616 set_cursor ( 616 set_cursor (
617 um->priv->document, 617 um->priv->document,
618 undo_action->action.insert.pos); 618 undo_action->action.insert.pos);
619 619
620 insert_text ( 620 insert_text (
621 um->priv->document, 621 um->priv->document,
622 undo_action->action.insert.pos, 622 undo_action->action.insert.pos,
623 undo_action->action.insert.text, 623 undo_action->action.insert.text,
624 undo_action->action.insert.length); 624 undo_action->action.insert.length);
625 625
626 break; 626 break;
627 627
644 644
645 if (um->priv->next_redo < 0) 645 if (um->priv->next_redo < 0)
646 undo_action = NULL; 646 undo_action = NULL;
647 else 647 else
648 undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo); 648 undo_action = g_list_nth_data (um->priv->actions, um->priv->next_redo);
649 649
650 } while ((undo_action != NULL) && (undo_action->order_in_group > 1)); 650 } while ((undo_action != NULL) && (undo_action->order_in_group > 1));
651 651
652 if (modified) 652 if (modified)
653 { 653 {
654 ++um->priv->next_redo; 654 ++um->priv->next_redo;
687 g_return_if_reached (); 687 g_return_if_reached ();
688 688
689 g_free (action); 689 g_free (action);
690 } 690 }
691 691
692 static void 692 static void
693 gtk_source_undo_manager_free_action_list (GtkSourceUndoManager *um) 693 gtk_source_undo_manager_free_action_list (GtkSourceUndoManager *um)
694 { 694 {
695 GList *l; 695 GList *l;
696 696
697 l = um->priv->actions; 697 l = um->priv->actions;
710 710
711 l = g_list_next (l); 711 l = g_list_next (l);
712 } 712 }
713 713
714 g_list_free (um->priv->actions); 714 g_list_free (um->priv->actions);
715 um->priv->actions = NULL; 715 um->priv->actions = NULL;
716 } 716 }
717 717
718 static void 718 static void
719 gtk_source_undo_manager_insert_text_handler (GtkTextBuffer *buffer, 719 gtk_source_undo_manager_insert_text_handler (GtkTextBuffer *buffer,
720 GtkTextIter *pos, 720 GtkTextIter *pos,
721 const gchar *text, 721 const gchar *text,
722 gint length, 722 gint length,
723 GtkSourceUndoManager *um) 723 GtkSourceUndoManager *um)
724 { 724 {
725 GtkSourceUndoAction undo_action; 725 GtkSourceUndoAction undo_action;
726 726
727 if (um->priv->running_not_undoable_actions > 0) 727 if (um->priv->running_not_undoable_actions > 0)
728 return; 728 return;
729 729
730 undo_action.action_type = GTK_SOURCE_UNDO_ACTION_INSERT; 730 undo_action.action_type = GTK_SOURCE_UNDO_ACTION_INSERT;
731 731
764 undo_action.modified = FALSE; 764 undo_action.modified = FALSE;
765 765
766 gtk_source_undo_manager_add_action (um, &undo_action); 766 gtk_source_undo_manager_add_action (um, &undo_action);
767 } 767 }
768 768
769 static void 769 static void
770 gtk_source_undo_manager_delete_range_handler (GtkTextBuffer *buffer, 770 gtk_source_undo_manager_delete_range_handler (GtkTextBuffer *buffer,
771 GtkTextIter *start, 771 GtkTextIter *start,
772 GtkTextIter *end, 772 GtkTextIter *end,
773 GtkSourceUndoManager *um) 773 GtkSourceUndoManager *um)
774 { 774 {
775 GtkSourceUndoAction undo_action; 775 GtkSourceUndoAction undo_action;
776 GtkTextIter insert_iter; 776 GtkTextIter insert_iter;
777 777
778 if (um->priv->running_not_undoable_actions > 0) 778 if (um->priv->running_not_undoable_actions > 0)
779 return; 779 return;
780 780
781 undo_action.action_type = GTK_SOURCE_UNDO_ACTION_DELETE; 781 undo_action.action_type = GTK_SOURCE_UNDO_ACTION_DELETE;
782 782
803 undo_action.mergeable = FALSE; 803 undo_action.mergeable = FALSE;
804 else 804 else
805 undo_action.mergeable = TRUE; 805 undo_action.mergeable = TRUE;
806 806
807 undo_action.modified = FALSE; 807 undo_action.modified = FALSE;
808 808
809 gtk_source_undo_manager_add_action (um, &undo_action); 809 gtk_source_undo_manager_add_action (um, &undo_action);
810 810
811 g_free (undo_action.action.delete.text); 811 g_free (undo_action.action.delete.text);
812 812
813 } 813 }
814 814
815 static void 815 static void
816 gtk_source_undo_manager_begin_user_action_handler (GtkTextBuffer *buffer, GtkSourceUndoManager *um) 816 gtk_source_undo_manager_begin_user_action_handler (GtkTextBuffer *buffer, GtkSourceUndoManager *um)
817 { 817 {
818 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um)); 818 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
819 g_return_if_fail (um->priv != NULL); 819 g_return_if_fail (um->priv != NULL);
820 820
823 823
824 um->priv->actions_in_current_group = 0; 824 um->priv->actions_in_current_group = 0;
825 } 825 }
826 826
827 static void 827 static void
828 gtk_source_undo_manager_add_action (GtkSourceUndoManager *um, 828 gtk_source_undo_manager_add_action (GtkSourceUndoManager *um,
829 const GtkSourceUndoAction *undo_action) 829 const GtkSourceUndoAction *undo_action)
830 { 830 {
831 GtkSourceUndoAction* action; 831 GtkSourceUndoAction* action;
832 832
833 if (um->priv->next_redo >= 0) 833 if (um->priv->next_redo >= 0)
834 { 834 {
835 gtk_source_undo_manager_free_first_n_actions (um, um->priv->next_redo + 1); 835 gtk_source_undo_manager_free_first_n_actions (um, um->priv->next_redo + 1);
836 } 836 }
837 837
843 *action = *undo_action; 843 *action = *undo_action;
844 844
845 if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT) 845 if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
846 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);
847 else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE) 847 else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
848 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) 849 else if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR)
850 { 850 {
851 /* Nothing needs to be done */ 851 /* Nothing needs to be done */
852 } 852 }
853 else 853 else
854 { 854 {
855 g_free (action); 855 g_free (action);
856 g_return_if_reached (); 856 g_return_if_reached ();
857 } 857 }
858 858
859 ++um->priv->actions_in_current_group; 859 ++um->priv->actions_in_current_group;
860 action->order_in_group = um->priv->actions_in_current_group; 860 action->order_in_group = um->priv->actions_in_current_group;
861 861
862 if (action->order_in_group == 1) 862 if (action->order_in_group == 1)
863 ++um->priv->num_of_groups; 863 ++um->priv->num_of_groups;
864 864
865 um->priv->actions = g_list_prepend (um->priv->actions, action); 865 um->priv->actions = g_list_prepend (um->priv->actions, action);
866 } 866 }
867 867
868 gtk_source_undo_manager_check_list_size (um); 868 gtk_source_undo_manager_check_list_size (um);
869 869
870 if (!um->priv->can_undo) 870 if (!um->priv->can_undo)
871 { 871 {
872 um->priv->can_undo = TRUE; 872 um->priv->can_undo = TRUE;
878 um->priv->can_redo = FALSE; 878 um->priv->can_redo = FALSE;
879 g_signal_emit (G_OBJECT (um), undo_manager_signals [CAN_REDO], 0, FALSE); 879 g_signal_emit (G_OBJECT (um), undo_manager_signals [CAN_REDO], 0, FALSE);
880 } 880 }
881 } 881 }
882 882
883 static void 883 static void
884 gtk_source_undo_manager_free_first_n_actions (GtkSourceUndoManager *um, 884 gtk_source_undo_manager_free_first_n_actions (GtkSourceUndoManager *um,
885 gint n) 885 gint n)
886 { 886 {
887 gint i; 887 gint i;
888 888
889 if (um->priv->actions == NULL) 889 if (um->priv->actions == NULL)
902 gtk_source_undo_action_free (action); 902 gtk_source_undo_action_free (action);
903 903
904 um->priv->actions = g_list_delete_link (um->priv->actions, 904 um->priv->actions = g_list_delete_link (um->priv->actions,
905 um->priv->actions); 905 um->priv->actions);
906 906
907 if (um->priv->actions == NULL) 907 if (um->priv->actions == NULL)
908 return; 908 return;
909 } 909 }
910 } 910 }
911 911
912 static void 912 static void
913 gtk_source_undo_manager_check_list_size (GtkSourceUndoManager *um) 913 gtk_source_undo_manager_check_list_size (GtkSourceUndoManager *um)
914 { 914 {
915 gint undo_levels; 915 gint undo_levels;
916 916
917 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um)); 917 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
918 g_return_if_fail (um->priv != NULL); 918 g_return_if_fail (um->priv != NULL);
919 919
920 undo_levels = gtk_source_undo_manager_get_max_undo_levels (um); 920 undo_levels = gtk_source_undo_manager_get_max_undo_levels (um);
921 921
922 if (undo_levels < 1) 922 if (undo_levels < 1)
923 return; 923 return;
924 924
925 if (um->priv->num_of_groups > undo_levels) 925 if (um->priv->num_of_groups > undo_levels)
926 { 926 {
927 GtkSourceUndoAction *undo_action; 927 GtkSourceUndoAction *undo_action;
928 GList *last; 928 GList *last;
929 929
930 last = g_list_last (um->priv->actions); 930 last = g_list_last (um->priv->actions);
931 undo_action = (GtkSourceUndoAction*) last->data; 931 undo_action = (GtkSourceUndoAction*) last->data;
932 932
933 do 933 do
934 { 934 {
935 GList *tmp; 935 GList *tmp;
936 936
937 if (undo_action->order_in_group == 1) 937 if (undo_action->order_in_group == 1)
938 --um->priv->num_of_groups; 938 --um->priv->num_of_groups;
939 939
940 if (undo_action->modified) 940 if (undo_action->modified)
941 um->priv->modified_action = INVALID; 941 um->priv->modified_action = INVALID;
943 gtk_source_undo_action_free (undo_action); 943 gtk_source_undo_action_free (undo_action);
944 944
945 tmp = g_list_previous (last); 945 tmp = g_list_previous (last);
946 um->priv->actions = g_list_delete_link (um->priv->actions, last); 946 um->priv->actions = g_list_delete_link (um->priv->actions, last);
947 last = tmp; 947 last = tmp;
948 g_return_if_fail (last != NULL); 948 g_return_if_fail (last != NULL);
949 949
950 undo_action = (GtkSourceUndoAction*) last->data; 950 undo_action = (GtkSourceUndoAction*) last->data;
951 951
952 } while ((undo_action->order_in_group > 1) || 952 } while ((undo_action->order_in_group > 1) ||
953 (um->priv->num_of_groups > undo_levels)); 953 (um->priv->num_of_groups > undo_levels));
954 } 954 }
955 } 955 }
956 956
957 /** 957 /**
958 * gtk_source_undo_manager_merge_action: 958 * gtk_source_undo_manager_merge_action:
959 * @um: a #GtkSourceUndoManager. 959 * @um: a #GtkSourceUndoManager.
960 * @undo_action: a #GtkSourceUndoAction. 960 * @undo_action: a #GtkSourceUndoAction.
961 * 961 *
962 * This function tries to merge the undo action at the top of 962 * This function tries to merge the undo action at the top of
963 * the stack with a new undo action. So when we undo for example 963 * the stack with a new undo action. So when we undo for example
964 * typing, we can undo the whole word and not each letter by itself. 964 * typing, we can undo the whole word and not each letter by itself.
965 * 965 *
966 * Return Value: %TRUE is merge was sucessful, %FALSE otherwise.² 966 * Return Value: %TRUE is merge was successful, %FALSE otherwise.²
967 **/ 967 **/
968 static gboolean 968 static gboolean
969 gtk_source_undo_manager_merge_action (GtkSourceUndoManager *um, 969 gtk_source_undo_manager_merge_action (GtkSourceUndoManager *um,
970 const GtkSourceUndoAction *undo_action) 970 const GtkSourceUndoAction *undo_action)
971 { 971 {
972 GtkSourceUndoAction *last_action; 972 GtkSourceUndoAction *last_action;
973 973
974 g_return_val_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um), FALSE); 974 g_return_val_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um), FALSE);
975 g_return_val_if_fail (um->priv != NULL, FALSE); 975 g_return_val_if_fail (um->priv != NULL, FALSE);
976 976
977 if (um->priv->actions == NULL) 977 if (um->priv->actions == NULL)
978 return FALSE; 978 return FALSE;
988 last_action->mergeable = FALSE; 988 last_action->mergeable = FALSE;
989 return FALSE; 989 return FALSE;
990 } 990 }
991 991
992 if (undo_action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE) 992 if (undo_action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
993 { 993 {
994 if ((last_action->action.delete.forward != undo_action->action.delete.forward) || 994 if ((last_action->action.delete.forward != undo_action->action.delete.forward) ||
995 ((last_action->action.delete.start != undo_action->action.delete.start) && 995 ((last_action->action.delete.start != undo_action->action.delete.start) &&
996 (last_action->action.delete.start != undo_action->action.delete.end))) 996 (last_action->action.delete.start != undo_action->action.delete.end)))
997 { 997 {
998 last_action->mergeable = FALSE; 998 last_action->mergeable = FALSE;
999 return FALSE; 999 return FALSE;
1000 } 1000 }
1001 1001
1002 if (last_action->action.delete.start == undo_action->action.delete.start) 1002 if (last_action->action.delete.start == undo_action->action.delete.start)
1003 { 1003 {
1004 gchar *str; 1004 gchar *str;
1005 1005
1006 #define L (last_action->action.delete.end - last_action->action.delete.start - 1) 1006 #define L (last_action->action.delete.end - last_action->action.delete.start - 1)
1007 #define g_utf8_get_char_at(p,i) g_utf8_get_char(g_utf8_offset_to_pointer((p),(i))) 1007 #define g_utf8_get_char_at(p,i) g_utf8_get_char(g_utf8_offset_to_pointer((p),(i)))
1008 1008
1009 /* Deleted with the delete key */ 1009 /* Deleted with the delete key */
1010 if ((g_utf8_get_char (undo_action->action.delete.text) != ' ') && 1010 if ((g_utf8_get_char (undo_action->action.delete.text) != ' ') &&
1011 (g_utf8_get_char (undo_action->action.delete.text) != '\t') && 1011 (g_utf8_get_char (undo_action->action.delete.text) != '\t') &&
1012 ((g_utf8_get_char_at (last_action->action.delete.text, L) == ' ') || 1012 ((g_utf8_get_char_at (last_action->action.delete.text, L) == ' ') ||
1013 (g_utf8_get_char_at (last_action->action.delete.text, L) == '\t'))) 1013 (g_utf8_get_char_at (last_action->action.delete.text, L) == '\t')))
1014 { 1014 {
1015 last_action->mergeable = FALSE; 1015 last_action->mergeable = FALSE;
1016 return FALSE; 1016 return FALSE;
1017 } 1017 }
1018 1018
1019 str = g_strdup_printf ("%s%s", last_action->action.delete.text, 1019 str = g_strdup_printf ("%s%s", last_action->action.delete.text,
1020 undo_action->action.delete.text); 1020 undo_action->action.delete.text);
1021 1021
1022 g_free (last_action->action.delete.text); 1022 g_free (last_action->action.delete.text);
1023 last_action->action.delete.end += (undo_action->action.delete.end - 1023 last_action->action.delete.end += (undo_action->action.delete.end -
1024 undo_action->action.delete.start); 1024 undo_action->action.delete.start);
1025 last_action->action.delete.text = str; 1025 last_action->action.delete.text = str;
1026 } 1026 }
1027 else 1027 else
1028 { 1028 {
1029 gchar *str; 1029 gchar *str;
1030 1030
1031 /* Deleted with the backspace key */ 1031 /* Deleted with the backspace key */
1032 if ((g_utf8_get_char (undo_action->action.delete.text) != ' ') && 1032 if ((g_utf8_get_char (undo_action->action.delete.text) != ' ') &&
1033 (g_utf8_get_char (undo_action->action.delete.text) != '\t') && 1033 (g_utf8_get_char (undo_action->action.delete.text) != '\t') &&
1034 ((g_utf8_get_char (last_action->action.delete.text) == ' ') || 1034 ((g_utf8_get_char (last_action->action.delete.text) == ' ') ||
1035 (g_utf8_get_char (last_action->action.delete.text) == '\t'))) 1035 (g_utf8_get_char (last_action->action.delete.text) == '\t')))
1036 { 1036 {
1037 last_action->mergeable = FALSE; 1037 last_action->mergeable = FALSE;
1038 return FALSE; 1038 return FALSE;
1039 } 1039 }
1040 1040
1041 str = g_strdup_printf ("%s%s", undo_action->action.delete.text, 1041 str = g_strdup_printf ("%s%s", undo_action->action.delete.text,
1042 last_action->action.delete.text); 1042 last_action->action.delete.text);
1043 1043
1044 g_free (last_action->action.delete.text); 1044 g_free (last_action->action.delete.text);
1045 last_action->action.delete.start = undo_action->action.delete.start; 1045 last_action->action.delete.start = undo_action->action.delete.start;
1046 last_action->action.delete.text = str; 1046 last_action->action.delete.text = str;
1047 } 1047 }
1048 } 1048 }
1049 else if (undo_action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT) 1049 else if (undo_action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
1050 { 1050 {
1051 gchar* str; 1051 gchar* str;
1052 1052
1053 #define I (last_action->action.insert.chars - 1) 1053 #define I (last_action->action.insert.chars - 1)
1054 1054
1055 if ((undo_action->action.insert.pos != 1055 if ((undo_action->action.insert.pos !=
1056 (last_action->action.insert.pos + last_action->action.insert.chars)) || 1056 (last_action->action.insert.pos + last_action->action.insert.chars)) ||
1057 ((g_utf8_get_char (undo_action->action.insert.text) != ' ') && 1057 ((g_utf8_get_char (undo_action->action.insert.text) != ' ') &&
1058 (g_utf8_get_char (undo_action->action.insert.text) != '\t') && 1058 (g_utf8_get_char (undo_action->action.insert.text) != '\t') &&
1059 ((g_utf8_get_char_at (last_action->action.insert.text, I) == ' ') || 1059 ((g_utf8_get_char_at (last_action->action.insert.text, I) == ' ') ||
1060 (g_utf8_get_char_at (last_action->action.insert.text, I) == '\t'))) 1060 (g_utf8_get_char_at (last_action->action.insert.text, I) == '\t')))
1062 { 1062 {
1063 last_action->mergeable = FALSE; 1063 last_action->mergeable = FALSE;
1064 return FALSE; 1064 return FALSE;
1065 } 1065 }
1066 1066
1067 str = g_strdup_printf ("%s%s", last_action->action.insert.text, 1067 str = g_strdup_printf ("%s%s", last_action->action.insert.text,
1068 undo_action->action.insert.text); 1068 undo_action->action.insert.text);
1069 1069
1070 g_free (last_action->action.insert.text); 1070 g_free (last_action->action.insert.text);
1071 last_action->action.insert.length += undo_action->action.insert.length; 1071 last_action->action.insert.length += undo_action->action.insert.length;
1072 last_action->action.insert.text = str; 1072 last_action->action.insert.text = str;
1073 last_action->action.insert.chars += undo_action->action.insert.chars; 1073 last_action->action.insert.chars += undo_action->action.insert.chars;
1074 1074
1078 /* Nothing needs to be done */ 1078 /* Nothing needs to be done */
1079 } 1079 }
1080 else 1080 else
1081 /* Unknown action inside undo merge encountered */ 1081 /* Unknown action inside undo merge encountered */
1082 g_return_val_if_reached (TRUE); 1082 g_return_val_if_reached (TRUE);
1083 1083
1084 return TRUE; 1084 return TRUE;
1085 } 1085 }
1086 1086
1087 gint 1087 gint
1088 gtk_source_undo_manager_get_max_undo_levels (GtkSourceUndoManager *um) 1088 gtk_source_undo_manager_get_max_undo_levels (GtkSourceUndoManager *um)
1096 void 1096 void
1097 gtk_source_undo_manager_set_max_undo_levels (GtkSourceUndoManager *um, 1097 gtk_source_undo_manager_set_max_undo_levels (GtkSourceUndoManager *um,
1098 gint max_undo_levels) 1098 gint max_undo_levels)
1099 { 1099 {
1100 gint old_levels; 1100 gint old_levels;
1101 1101
1102 g_return_if_fail (um != NULL); 1102 g_return_if_fail (um != NULL);
1103 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um)); 1103 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
1104 1104
1105 old_levels = um->priv->max_undo_levels; 1105 old_levels = um->priv->max_undo_levels;
1106 um->priv->max_undo_levels = max_undo_levels; 1106 um->priv->max_undo_levels = max_undo_levels;
1107 1107
1108 if (max_undo_levels < 1) 1108 if (max_undo_levels < 1)
1109 return; 1109 return;
1110 1110
1111 if (old_levels > max_undo_levels) 1111 if (old_levels > max_undo_levels)
1112 { 1112 {
1113 /* strip redo actions first */ 1113 /* strip redo actions first */
1114 while (um->priv->next_redo >= 0 && (um->priv->num_of_groups > max_undo_levels)) 1114 while (um->priv->next_redo >= 0 && (um->priv->num_of_groups > max_undo_levels))
1115 { 1115 {
1116 gtk_source_undo_manager_free_first_n_actions (um, 1); 1116 gtk_source_undo_manager_free_first_n_actions (um, 1);
1117 um->priv->next_redo--; 1117 um->priv->next_redo--;
1118 } 1118 }
1119 1119
1120 /* now remove undo actions if necessary */ 1120 /* now remove undo actions if necessary */
1121 gtk_source_undo_manager_check_list_size (um); 1121 gtk_source_undo_manager_check_list_size (um);
1122 1122
1123 /* emit "can_undo" and/or "can_redo" if appropiate */ 1123 /* emit "can_undo" and/or "can_redo" if appropiate */
1124 if (um->priv->next_redo < 0 && um->priv->can_redo) 1124 if (um->priv->next_redo < 0 && um->priv->can_redo)
1140 gtk_source_undo_manager_modified_changed_handler (GtkTextBuffer *buffer, 1140 gtk_source_undo_manager_modified_changed_handler (GtkTextBuffer *buffer,
1141 GtkSourceUndoManager *um) 1141 GtkSourceUndoManager *um)
1142 { 1142 {
1143 GtkSourceUndoAction *action; 1143 GtkSourceUndoAction *action;
1144 GList *list; 1144 GList *list;
1145 1145
1146 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um)); 1146 g_return_if_fail (GTK_SOURCE_IS_UNDO_MANAGER (um));
1147 g_return_if_fail (um->priv != NULL); 1147 g_return_if_fail (um->priv != NULL);
1148 1148
1149 if (um->priv->actions == NULL) 1149 if (um->priv->actions == NULL)
1150 return; 1150 return;
1155 action = (GtkSourceUndoAction*) list->data; 1155 action = (GtkSourceUndoAction*) list->data;
1156 else 1156 else
1157 action = NULL; 1157 action = NULL;
1158 1158
1159 if (gtk_text_buffer_get_modified (buffer) == FALSE) 1159 if (gtk_text_buffer_get_modified (buffer) == FALSE)
1160 { 1160 {
1161 if (action != NULL) 1161 if (action != NULL)
1162 action->mergeable = FALSE; 1162 action->mergeable = FALSE;
1163 1163
1164 if (um->priv->modified_action != NULL) 1164 if (um->priv->modified_action != NULL)
1165 { 1165 {
1176 { 1176 {
1177 g_return_if_fail (um->priv->running_not_undoable_actions > 0); 1177 g_return_if_fail (um->priv->running_not_undoable_actions > 0);
1178 1178
1179 return; 1179 return;
1180 } 1180 }
1181 1181
1182 /* gtk_text_buffer_get_modified (buffer) == TRUE */ 1182 /* gtk_text_buffer_get_modified (buffer) == TRUE */
1183 1183
1184 g_return_if_fail (um->priv->modified_action == NULL); 1184 g_return_if_fail (um->priv->modified_action == NULL);
1185 1185
1186 if (action->order_in_group > 1) 1186 if (action->order_in_group > 1)

mercurial