ReactOS 0.4.15-dev-7887-g64a59a1
undo.c
Go to the documentation of this file.
1/*
2 * RichEdit - functions dealing with editor object
3 *
4 * Copyright 2004 by Krzysztof Foltman
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include "editor.h"
22
24
25static void destroy_undo_item( struct undo_item *undo )
26{
27 switch( undo->type )
28 {
29 case undo_insert_run:
30 heap_free( undo->u.insert_run.str );
31 ME_ReleaseStyle( undo->u.insert_run.style );
32 break;
33 case undo_split_para:
34 ME_DestroyString( undo->u.split_para.eol_str );
35 break;
36 default:
37 break;
38 }
39
40 heap_free( undo );
41}
42
43static void empty_redo_stack(ME_TextEditor *editor)
44{
45 struct undo_item *cursor, *cursor2;
46 LIST_FOR_EACH_ENTRY_SAFE( cursor, cursor2, &editor->redo_stack, struct undo_item, entry )
47 {
48 list_remove( &cursor->entry );
50 }
51}
52
54{
55 struct undo_item *cursor, *cursor2;
56 if (editor->nUndoMode == umIgnore)
57 return;
58
59 TRACE("Emptying undo stack\n");
60
61 editor->nUndoStackSize = 0;
62
63 LIST_FOR_EACH_ENTRY_SAFE( cursor, cursor2, &editor->undo_stack, struct undo_item, entry )
64 {
65 list_remove( &cursor->entry );
67 }
68
69 empty_redo_stack( editor );
70}
71
72static struct undo_item *add_undo( ME_TextEditor *editor, enum undo_type type )
73{
74 struct undo_item *undo, *item;
75 struct list *head;
76
77 if (editor->nUndoMode == umIgnore) return NULL;
78 if (editor->nUndoLimit == 0) return NULL;
79
80 undo = heap_alloc( sizeof(*undo) );
81 if (!undo) return NULL;
82 undo->type = type;
83
84 if (editor->nUndoMode == umAddToUndo || editor->nUndoMode == umAddBackToUndo)
85 {
86
87 head = list_head( &editor->undo_stack );
88 if (head)
89 {
90 item = LIST_ENTRY( head, struct undo_item, entry );
93 }
94
95 if (editor->nUndoMode == umAddToUndo)
96 TRACE("Pushing id=%d to undo stack, deleting redo stack\n", type);
97 else
98 TRACE("Pushing id=%d to undo stack\n", type);
99
100 list_add_head( &editor->undo_stack, &undo->entry );
101
103 editor->nUndoStackSize++;
104
105 if (editor->nUndoStackSize > editor->nUndoLimit)
106 {
107 struct undo_item *cursor2;
108 /* remove oldest undo from stack */
109 LIST_FOR_EACH_ENTRY_SAFE_REV( item, cursor2, &editor->undo_stack, struct undo_item, entry )
110 {
111 BOOL done = (item->type == undo_end_transaction);
112 list_remove( &item->entry );
114 if (done) break;
115 }
116 editor->nUndoStackSize--;
117 }
118
119 /* any new operation (not redo) clears the redo stack */
120 if (editor->nUndoMode == umAddToUndo) empty_redo_stack( editor );
121 }
122 else if (editor->nUndoMode == umAddToRedo)
123 {
124 TRACE("Pushing id=%d to redo stack\n", type);
125 list_add_head( &editor->redo_stack, &undo->entry );
126 }
127
128 return undo;
129}
130
132{
133 struct undo_item *undo = add_undo( editor, undo_insert_run );
134 if (!undo) return FALSE;
135
136 undo->u.insert_run.str = heap_alloc( (len + 1) * sizeof(WCHAR) );
137 if (!undo->u.insert_run.str)
138 {
139 ME_EmptyUndoStack( editor );
140 return FALSE;
141 }
142 memcpy( undo->u.insert_run.str, str, len * sizeof(WCHAR) );
143 undo->u.insert_run.str[len] = 0;
144 undo->u.insert_run.pos = pos;
145 undo->u.insert_run.len = len;
146 undo->u.insert_run.flags = flags;
147 undo->u.insert_run.style = style;
149 return TRUE;
150}
151
153{
154 struct undo_item *undo = add_undo( editor, undo_set_para_fmt );
155 if (!undo) return FALSE;
156
157 undo->u.set_para_fmt.pos = para->nCharOfs;
158 undo->u.set_para_fmt.fmt = para->fmt;
159 undo->u.set_para_fmt.border = para->border;
160
161 return TRUE;
162}
163
165{
166 struct undo_item *undo = add_undo( editor, undo_set_char_fmt );
167 if (!undo) return FALSE;
168
169 undo->u.set_char_fmt.pos = pos;
170 undo->u.set_char_fmt.len = len;
171 undo->u.set_char_fmt.fmt = *fmt;
172
173 return TRUE;
174}
175
177{
178 struct undo_item *undo = add_undo( editor, undo_join_paras );
179 if (!undo) return FALSE;
180
181 undo->u.join_paras.pos = pos;
182 return TRUE;
183}
184
185BOOL add_undo_split_para( ME_TextEditor *editor, const ME_Paragraph *para, ME_String *eol_str, const ME_Cell *cell )
186{
187 struct undo_item *undo = add_undo( editor, undo_split_para );
188 if (!undo) return FALSE;
189
190 undo->u.split_para.pos = para->nCharOfs - eol_str->nLen;
191 undo->u.split_para.eol_str = eol_str;
192 undo->u.split_para.fmt = para->fmt;
193 undo->u.split_para.border = para->border;
194 undo->u.split_para.flags = para->prev_para->member.para.nFlags & ~MEPF_CELL;
195
196 if (cell)
197 {
198 undo->u.split_para.cell_border = cell->border;
199 undo->u.split_para.cell_right_boundary = cell->nRightBoundary;
200 }
201 return TRUE;
202}
203
205{
206 struct undo_item *undo = add_undo( editor, undo_delete_run );
207 if (!undo) return FALSE;
208
209 undo->u.delete_run.pos = pos;
210 undo->u.delete_run.len = len;
211
212 return TRUE;
213}
214
228{
229 struct undo_item *item;
230 struct list *head;
231
232 if (editor->nUndoMode == umIgnore)
233 return;
234
235 assert(editor->nUndoMode == umAddToUndo);
236
237 /* no transactions, no need to commit */
238 head = list_head( &editor->undo_stack );
239 if (!head) return;
240
241 /* no need to commit empty transactions */
242 item = LIST_ENTRY( head, struct undo_item, entry );
243 if (item->type == undo_end_transaction) return;
244
246 {
248 return;
249 }
250
252}
253
266{
267 struct undo_item *item;
268 struct list *head;
269
270 if (editor->nUndoMode == umIgnore)
271 return;
272
273 assert(editor->nUndoMode == umAddToUndo);
274
275 head = list_head( &editor->undo_stack );
276 if (!head) return;
277
278 item = LIST_ENTRY( head, struct undo_item, entry );
280 {
281 list_remove( &item->entry );
282 editor->nUndoStackSize--;
284 }
285}
286
302{
303 struct undo_item *item;
304 struct list *head;
305
306 if (editor->nUndoMode == umIgnore)
307 return;
308
309 assert(editor->nUndoMode == umAddToUndo);
310
311 head = list_head( &editor->undo_stack );
312 if (!head) return;
313
314 /* no need to commit empty transactions */
315 item = LIST_ENTRY( head, struct undo_item, entry );
316 if (item->type == undo_end_transaction ||
318 return;
319
321}
322
323static void ME_PlayUndoItem(ME_TextEditor *editor, struct undo_item *undo)
324{
325
326 if (editor->nUndoMode == umIgnore)
327 return;
328 TRACE("Playing undo/redo item, id=%d\n", undo->type);
329
330 switch(undo->type)
331 {
334 assert(0);
336 {
337 ME_Cursor tmp;
338 ME_DisplayItem *para;
339 ME_CursorFromCharOfs(editor, undo->u.set_para_fmt.pos, &tmp);
340 para = ME_FindItemBack(tmp.pRun, diParagraph);
341 add_undo_set_para_fmt( editor, &para->member.para );
342 para->member.para.fmt = undo->u.set_para_fmt.fmt;
343 para->member.para.border = undo->u.set_para_fmt.border;
344 mark_para_rewrap(editor, para);
345 break;
346 }
348 {
350 ME_CursorFromCharOfs(editor, undo->u.set_char_fmt.pos, &start);
351 end = start;
352 ME_MoveCursorChars(editor, &end, undo->u.set_char_fmt.len, FALSE);
353 ME_SetCharFormat(editor, &start, &end, &undo->u.set_char_fmt.fmt);
354 break;
355 }
356 case undo_insert_run:
357 {
358 ME_Cursor tmp;
359 ME_CursorFromCharOfs(editor, undo->u.insert_run.pos, &tmp);
360 ME_InsertRunAtCursor(editor, &tmp, undo->u.insert_run.style,
361 undo->u.insert_run.str,
362 undo->u.insert_run.len,
363 undo->u.insert_run.flags);
364 break;
365 }
366 case undo_delete_run:
367 {
368 ME_Cursor tmp;
369 ME_CursorFromCharOfs(editor, undo->u.delete_run.pos, &tmp);
370 ME_InternalDeleteText(editor, &tmp, undo->u.delete_run.len, TRUE);
371 break;
372 }
373 case undo_join_paras:
374 {
375 ME_Cursor tmp;
376 ME_CursorFromCharOfs(editor, undo->u.join_paras.pos, &tmp);
377 ME_JoinParagraphs(editor, tmp.pPara, TRUE);
378 break;
379 }
380 case undo_split_para:
381 {
382 ME_Cursor tmp;
383 ME_DisplayItem *this_para, *new_para;
384 BOOL bFixRowStart;
385 int paraFlags = undo->u.split_para.flags & (MEPF_ROWSTART|MEPF_CELL|MEPF_ROWEND);
386 ME_CursorFromCharOfs(editor, undo->u.split_para.pos, &tmp);
387 if (tmp.nOffset)
388 ME_SplitRunSimple(editor, &tmp);
389 this_para = tmp.pPara;
390 bFixRowStart = this_para->member.para.nFlags & MEPF_ROWSTART;
391 if (bFixRowStart)
392 {
393 /* Re-insert the paragraph before the table, making sure the nFlag value
394 * is correct. */
395 this_para->member.para.nFlags &= ~MEPF_ROWSTART;
396 }
397 new_para = ME_SplitParagraph(editor, tmp.pRun, tmp.pRun->member.run.style,
398 undo->u.split_para.eol_str->szData, undo->u.split_para.eol_str->nLen, paraFlags);
399 if (bFixRowStart)
400 new_para->member.para.nFlags |= MEPF_ROWSTART;
401 new_para->member.para.fmt = undo->u.split_para.fmt;
402 new_para->member.para.border = undo->u.split_para.border;
403 if (paraFlags)
404 {
405 ME_DisplayItem *pCell = new_para->member.para.pCell;
406 pCell->member.cell.nRightBoundary = undo->u.split_para.cell_right_boundary;
407 pCell->member.cell.border = undo->u.split_para.cell_border;
408 }
409 break;
410 }
411 }
412}
413
415{
416 ME_UndoMode nMode = editor->nUndoMode;
417 struct list *head;
418 struct undo_item *undo, *cursor2;
419
420 if (editor->nUndoMode == umIgnore) return FALSE;
421 assert(nMode == umAddToUndo || nMode == umIgnore);
422
423 head = list_head( &editor->undo_stack );
424 if (!head) return FALSE;
425
426 /* watch out for uncommitted transactions ! */
427 undo = LIST_ENTRY( head, struct undo_item, entry );
430
431 editor->nUndoMode = umAddToRedo;
432
433 list_remove( &undo->entry );
434 destroy_undo_item( undo );
435
436 LIST_FOR_EACH_ENTRY_SAFE( undo, cursor2, &editor->undo_stack, struct undo_item, entry )
437 {
438 if (undo->type == undo_end_transaction) break;
439 ME_PlayUndoItem( editor, undo );
440 list_remove( &undo->entry );
441 destroy_undo_item( undo );
442 }
443
447 editor->nUndoStackSize--;
448 editor->nUndoMode = nMode;
449 ME_UpdateRepaint(editor, FALSE);
450 return TRUE;
451}
452
454{
455 ME_UndoMode nMode = editor->nUndoMode;
456 struct list *head;
457 struct undo_item *undo, *cursor2;
458
459 assert(nMode == umAddToUndo || nMode == umIgnore);
460
461 if (editor->nUndoMode == umIgnore) return FALSE;
462
463 head = list_head( &editor->redo_stack );
464 if (!head) return FALSE;
465
466 /* watch out for uncommitted transactions ! */
467 undo = LIST_ENTRY( head, struct undo_item, entry );
468 assert( undo->type == undo_end_transaction );
469
470 editor->nUndoMode = umAddBackToUndo;
471 list_remove( &undo->entry );
472 destroy_undo_item( undo );
473
474 LIST_FOR_EACH_ENTRY_SAFE( undo, cursor2, &editor->redo_stack, struct undo_item, entry )
475 {
476 if (undo->type == undo_end_transaction) break;
477 ME_PlayUndoItem( editor, undo );
478 list_remove( &undo->entry );
479 destroy_undo_item( undo );
480 }
484 editor->nUndoMode = nMode;
485 ME_UpdateRepaint(editor, FALSE);
486 return TRUE;
487}
struct outqueuenode * head
Definition: adnsresfilter.c:66
Arabic default style
Definition: afstyles.h:94
static void * heap_alloc(size_t len)
Definition: appwiz.h:66
static BOOL heap_free(void *mem)
Definition: appwiz.h:76
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
static void list_remove(struct list_entry *entry)
Definition: list.h:90
static void list_add_head(struct list_entry *head, struct list_entry *entry)
Definition: list.h:76
Definition: list.h:37
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
int ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *cursor, int nRelOfs, BOOL final_eop)
Definition: caret.c:720
BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start, int nChars, BOOL bForce)
Definition: caret.c:360
#define assert(x)
Definition: debug.h:53
void ME_ReleaseStyle(ME_Style *item) DECLSPEC_HIDDEN
Definition: style.c:462
void ME_MoveCursorFromTableRowStartParagraph(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: table.c:622
void ME_AddRefStyle(ME_Style *item) DECLSPEC_HIDDEN
Definition: style.c:454
ME_DisplayItem * ME_InsertRunAtCursor(ME_TextEditor *editor, ME_Cursor *cursor, ME_Style *style, const WCHAR *str, int len, int flags) DECLSPEC_HIDDEN
Definition: run.c:325
void mark_para_rewrap(ME_TextEditor *editor, ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: para.c:26
void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor) DECLSPEC_HIDDEN
Definition: run.c:171
void ME_CheckTablesForCorruption(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: table.c:192
ME_DisplayItem * ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass) DECLSPEC_HIDDEN
Definition: list.c:111
ME_DisplayItem * ME_SplitRunSimple(ME_TextEditor *editor, ME_Cursor *cursor) DECLSPEC_HIDDEN
Definition: run.c:258
ME_DisplayItem * ME_JoinParagraphs(ME_TextEditor *editor, ME_DisplayItem *tp, BOOL keepFirstParaFormat) DECLSPEC_HIDDEN
Definition: para.c:687
ME_DisplayItem * ME_SplitParagraph(ME_TextEditor *editor, ME_DisplayItem *rp, ME_Style *style, const WCHAR *eol_str, int eol_len, int paraFlags) DECLSPEC_HIDDEN
Definition: para.c:545
void ME_UpdateRepaint(ME_TextEditor *editor, BOOL update_now) DECLSPEC_HIDDEN
Definition: paint.c:116
void ME_DestroyString(ME_String *s) DECLSPEC_HIDDEN
Definition: string.c:96
void ME_SetCharFormat(ME_TextEditor *editor, ME_Cursor *start, ME_Cursor *end, CHARFORMAT2W *pFmt) DECLSPEC_HIDDEN
Definition: run.c:725
#define MEPF_CELL
Definition: editstr.h:143
#define MEPF_ROWSTART
Definition: editstr.h:144
#define MEPF_ROWEND
Definition: editstr.h:145
@ diParagraph
Definition: editstr.h:85
ME_UndoMode
Definition: editstr.h:280
@ umAddBackToUndo
Definition: editstr.h:284
@ umAddToUndo
Definition: editstr.h:281
@ umAddToRedo
Definition: editstr.h:282
@ umIgnore
Definition: editstr.h:283
undo_type
Definition: editstr.h:288
@ undo_split_para
Definition: editstr.h:292
@ undo_join_paras
Definition: editstr.h:291
@ undo_set_char_fmt
Definition: editstr.h:294
@ undo_set_para_fmt
Definition: editstr.h:293
@ undo_end_transaction
Definition: editstr.h:295
@ undo_potential_end_transaction
Definition: editstr.h:296
@ undo_insert_run
Definition: editstr.h:289
@ undo_delete_run
Definition: editstr.h:290
unsigned int BOOL
Definition: ntddk_ex.h:94
GLuint start
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLbitfield flags
Definition: glext.h:7161
GLenum GLsizei len
Definition: glext.h:6722
const char cursor[]
Definition: icontest.c:13
uint32_t entry
Definition: isohybrid.c:63
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static ATOM item
Definition: dde.c:856
const WCHAR * str
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:204
#define LIST_FOR_EACH_ENTRY_SAFE_REV(cursor, cursor2, list, type, field)
Definition: list.h:228
#define TRACE(s)
Definition: solgame.cpp:4
Definition: dsound.c:943
Definition: list.h:15
int nRightBoundary
Definition: editstr.h:224
ME_BorderRect border
Definition: editstr.h:225
ME_DisplayItem * pPara
Definition: editstr.h:275
int nOffset
Definition: editstr.h:277
ME_DisplayItem * pRun
Definition: editstr.h:276
union tagME_DisplayItem::@536 member
ME_Cell cell
Definition: editstr.h:261
ME_Paragraph para
Definition: editstr.h:262
ME_BorderRect border
Definition: editstr.h:208
struct tagME_DisplayItem * prev_para
Definition: editstr.h:217
PARAFORMAT2 fmt
Definition: editstr.h:204
struct tagME_DisplayItem * pCell
Definition: editstr.h:207
ME_Style * style
Definition: editstr.h:160
int nLen
Definition: editstr.h:57
struct list redo_stack
Definition: editstr.h:403
int nUndoStackSize
Definition: editstr.h:404
ME_UndoMode nUndoMode
Definition: editstr.h:406
struct list undo_stack
Definition: editstr.h:402
struct delete_run_item delete_run
Definition: editstr.h:348
struct set_para_fmt_item set_para_fmt
Definition: editstr.h:351
struct split_para_item split_para
Definition: editstr.h:350
struct list entry
Definition: editstr.h:343
struct join_paras_item join_paras
Definition: editstr.h:349
enum undo_type type
Definition: editstr.h:344
union undo_item::@537 u
struct insert_run_item insert_run
Definition: editstr.h:347
struct set_char_fmt_item set_char_fmt
Definition: editstr.h:352
#define LIST_ENTRY(type)
Definition: queue.h:175
static void empty_redo_stack(ME_TextEditor *editor)
Definition: undo.c:43
void ME_ContinueCoalescingTransaction(ME_TextEditor *editor)
Definition: undo.c:265
BOOL add_undo_set_char_fmt(ME_TextEditor *editor, int pos, int len, const CHARFORMAT2W *fmt)
Definition: undo.c:164
BOOL add_undo_insert_run(ME_TextEditor *editor, int pos, const WCHAR *str, int len, int flags, ME_Style *style)
Definition: undo.c:131
void ME_CommitUndo(ME_TextEditor *editor)
Definition: undo.c:227
void ME_CommitCoalescingUndo(ME_TextEditor *editor)
Definition: undo.c:301
BOOL ME_Undo(ME_TextEditor *editor)
Definition: undo.c:414
static void ME_PlayUndoItem(ME_TextEditor *editor, struct undo_item *undo)
Definition: undo.c:323
BOOL add_undo_delete_run(ME_TextEditor *editor, int pos, int len)
Definition: undo.c:204
BOOL ME_Redo(ME_TextEditor *editor)
Definition: undo.c:453
BOOL add_undo_set_para_fmt(ME_TextEditor *editor, const ME_Paragraph *para)
Definition: undo.c:152
static struct undo_item * add_undo(ME_TextEditor *editor, enum undo_type type)
Definition: undo.c:72
BOOL add_undo_split_para(ME_TextEditor *editor, const ME_Paragraph *para, ME_String *eol_str, const ME_Cell *cell)
Definition: undo.c:185
static void destroy_undo_item(struct undo_item *undo)
Definition: undo.c:25
void ME_EmptyUndoStack(ME_TextEditor *editor)
Definition: undo.c:53
BOOL add_undo_join_paras(ME_TextEditor *editor, int pos)
Definition: undo.c:176
__wchar_t WCHAR
Definition: xmlstorage.h:180