~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/riched20/undo.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  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 
 23 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
 24 
 25 void ME_EmptyUndoStack(ME_TextEditor *editor)
 26 {
 27   ME_DisplayItem *p, *pNext;
 28   
 29   if (editor->nUndoMode == umIgnore)
 30     return;
 31   
 32   TRACE("Emptying undo stack\n");
 33 
 34   p = editor->pUndoStack;
 35   editor->pUndoStack = editor->pUndoStackBottom = NULL;
 36   editor->nUndoStackSize = 0;
 37   while(p) {
 38     pNext = p->next;
 39     ME_DestroyDisplayItem(p);    
 40     p = pNext;
 41   } 
 42   p = editor->pRedoStack;
 43   editor->pRedoStack = NULL;
 44   while(p) {
 45     pNext = p->next;
 46     ME_DestroyDisplayItem(p);    
 47     p = pNext;
 48   } 
 49 }
 50 
 51 ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, const ME_DisplayItem *pdi) {
 52   if (editor->nUndoMode == umIgnore)
 53     return NULL;
 54   else if (editor->nUndoLimit == 0)
 55     return NULL;
 56   else
 57   {
 58     ME_DisplayItem *pItem = (ME_DisplayItem *)ALLOC_OBJ(ME_UndoItem);
 59     ((ME_UndoItem *)pItem)->nCR = ((ME_UndoItem *)pItem)->nLF = -1;
 60     switch(type)
 61     {
 62     case diUndoPotentialEndTransaction:
 63         /* only should be added for manually typed chars, not undos or redos */
 64         assert(editor->nUndoMode == umAddToUndo);
 65         /* intentional fall-through to next case */
 66     case diUndoEndTransaction:
 67       break;
 68     case diUndoSetParagraphFormat:
 69       assert(pdi);
 70       pItem->member.para = pdi->member.para;
 71       pItem->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
 72       *pItem->member.para.pFmt = *pdi->member.para.pFmt;
 73       break;
 74     case diUndoInsertRun:
 75       assert(pdi);
 76       pItem->member.run = pdi->member.run;
 77       pItem->member.run.strText = ME_StrDup(pItem->member.run.strText);
 78       ME_AddRefStyle(pItem->member.run.style);
 79       if (pdi->member.run.ole_obj)
 80       {
 81         pItem->member.run.ole_obj = ALLOC_OBJ(*pItem->member.run.ole_obj);
 82         ME_CopyReObject(pItem->member.run.ole_obj, pdi->member.run.ole_obj);
 83       }
 84       else pItem->member.run.ole_obj = NULL;
 85       break;
 86     case diUndoSetCharFormat:
 87       break;
 88     case diUndoDeleteRun:
 89     case diUndoJoinParagraphs:
 90       break;
 91     case diUndoSplitParagraph:
 92       pItem->member.para.pFmt = ALLOC_OBJ(PARAFORMAT2);
 93       pItem->member.para.pFmt->cbSize = sizeof(PARAFORMAT2);
 94       pItem->member.para.pFmt->dwMask = 0;
 95  
 96       break;
 97     default:
 98       assert(0 == "AddUndoItem, unsupported item type");
 99       return NULL;
100     }
101     pItem->type = type;
102     pItem->prev = NULL;
103     if (editor->nUndoMode == umAddToUndo || editor->nUndoMode == umAddBackToUndo)
104     {
105       if (editor->pUndoStack
106           && editor->pUndoStack->type == diUndoPotentialEndTransaction)
107       {
108           editor->pUndoStack->type = diUndoEndTransaction;
109       }
110       if (editor->nUndoMode == umAddToUndo)
111         TRACE("Pushing id=%s to undo stack, deleting redo stack\n", ME_GetDITypeName(type));
112       else
113         TRACE("Pushing id=%s to undo stack\n", ME_GetDITypeName(type));
114 
115       pItem->next = editor->pUndoStack;
116       if (type == diUndoEndTransaction || type == diUndoPotentialEndTransaction)
117         editor->nUndoStackSize++;
118       if (editor->pUndoStack)
119         editor->pUndoStack->prev = pItem;
120       else
121         editor->pUndoStackBottom = pItem;
122       editor->pUndoStack = pItem;
123       
124       if (editor->nUndoStackSize > editor->nUndoLimit)
125       { /* remove oldest undo from stack */
126         ME_DisplayItem *p = editor->pUndoStackBottom;
127         while (p->type !=diUndoEndTransaction)
128           p = p->prev; /*find new stack bottom */
129         editor->pUndoStackBottom = p->prev;
130           editor->pUndoStackBottom->next = NULL;
131         do
132         {
133           ME_DisplayItem *pp = p->next;
134           ME_DestroyDisplayItem(p);
135           p = pp;
136         } while (p);
137         editor->nUndoStackSize--;
138       }
139       /* any new operation (not redo) clears the redo stack */
140       if (editor->nUndoMode == umAddToUndo) {
141         ME_DisplayItem *p = editor->pRedoStack;
142         while(p)
143         {
144           ME_DisplayItem *pp = p->next;
145           ME_DestroyDisplayItem(p);
146           p = pp;
147         }
148         editor->pRedoStack = NULL;
149       }
150     }
151     else if (editor->nUndoMode == umAddToRedo)
152     {
153       TRACE("Pushing id=%s to redo stack\n", ME_GetDITypeName(type));
154       pItem->next = editor->pRedoStack;
155       if (editor->pRedoStack)
156         editor->pRedoStack->prev = pItem;
157       editor->pRedoStack = pItem;
158     }
159     else
160       assert(0);
161     return (ME_UndoItem *)pItem;
162   }
163 }
164 
165 /**
166  * Commits preceding changes into a transaction that can be undone together.
167  *
168  * This should be called after all the changes occur associated with an event
169  * so that the group of changes can be undone atomically as a transaction.
170  *
171  * This will have no effect the undo mode is set to ignore changes, or if no
172  * changes preceded calling this function before the last time it was called.
173  *
174  * This can also be used to conclude a coalescing transaction (used for grouping
175  * typed characters).
176  */
177 void ME_CommitUndo(ME_TextEditor *editor) {
178   if (editor->nUndoMode == umIgnore)
179     return;
180   
181   assert(editor->nUndoMode == umAddToUndo);
182   
183   /* no transactions, no need to commit */
184   if (!editor->pUndoStack)
185     return;
186 
187   /* no need to commit empty transactions */
188   if (editor->pUndoStack->type == diUndoEndTransaction)
189     return;
190     
191   if (editor->pUndoStack->type == diUndoPotentialEndTransaction)
192   {
193       /* Previous transaction was as a result of characters typed,
194        * so the end of this transaction is confirmed. */
195       editor->pUndoStack->type = diUndoEndTransaction;
196       return;
197   }
198 
199   ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
200   ME_SendSelChange(editor);
201 }
202 
203 /**
204  * Groups supsequent changes with previous ones for an undo if coalescing.
205  *
206  * Has no effect if the previous changes were followed by a ME_CommitUndo. This
207  * function will only have an affect if the previous changes were followed by
208  * a call to ME_CommitCoalescingUndo, which allows the transaction to be
209  * continued.
210  *
211  * This allows multiple consecutively typed characters to be grouped together
212  * to be undone by a single undo operation.
213  */
214 void ME_ContinueCoalescingTransaction(ME_TextEditor *editor)
215 {
216   ME_DisplayItem* p;
217 
218   if (editor->nUndoMode == umIgnore)
219     return;
220 
221   assert(editor->nUndoMode == umAddToUndo);
222 
223   p = editor->pUndoStack;
224 
225   if (p && p->type == diUndoPotentialEndTransaction) {
226     assert(p->next); /* EndTransactions shouldn't be at bottom of undo stack */
227     editor->pUndoStack = p->next;
228     editor->pUndoStack->prev = NULL;
229     editor->nUndoStackSize--;
230     ME_DestroyDisplayItem(p);
231   }
232 }
233 
234 /**
235  * Commits preceding changes into a undo transaction that can be expanded.
236  *
237  * This function allows the transaction to be reopened with
238  * ME_ContinueCoalescingTransaction in order to continue the transaction.  If an
239  * undo item is added to the undo stack as a result of a change without the
240  * transaction being reopened, then the transaction will be ended, and the
241  * changes will become a part of the next transaction.
242  *
243  * This is used to allow typed characters to be grouped together since each
244  * typed character results in a single event, and each event adding undo items
245  * must be committed.  Using this function as opposed to ME_CommitUndo allows
246  * multiple events to be grouped, and undone together.
247  */
248 void ME_CommitCoalescingUndo(ME_TextEditor *editor)
249 {
250   if (editor->nUndoMode == umIgnore)
251     return;
252 
253   assert(editor->nUndoMode == umAddToUndo);
254 
255   /* no transactions, no need to commit */
256   if (!editor->pUndoStack)
257     return;
258 
259   /* no need to commit empty transactions */
260   if (editor->pUndoStack->type == diUndoEndTransaction)
261     return;
262   if (editor->pUndoStack->type == diUndoPotentialEndTransaction)
263     return;
264 
265   ME_AddUndoItem(editor, diUndoPotentialEndTransaction, NULL);
266   ME_SendSelChange(editor);
267 }
268 
269 static void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
270 {
271   ME_UndoItem *pUItem = (ME_UndoItem *)pItem;
272 
273   if (editor->nUndoMode == umIgnore)
274     return;
275   TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));
276 
277   switch(pItem->type)
278   {
279   case diUndoPotentialEndTransaction:
280   case diUndoEndTransaction:
281     assert(0);
282   case diUndoSetParagraphFormat:
283   {
284     ME_Cursor tmp;
285     ME_CursorFromCharOfs(editor, pItem->member.para.nCharOfs, &tmp);
286     ME_SetParaFormat(editor, ME_FindItemBack(tmp.pRun, diParagraph), pItem->member.para.pFmt);
287     break;
288   }
289   case diUndoSetCharFormat:
290   {
291     ME_SetCharFormat(editor, pUItem->nStart, pUItem->nLen, &pItem->member.ustyle->fmt);
292     break;
293   }
294   case diUndoInsertRun:
295   {
296     ME_InsertRun(editor, pItem->member.run.nCharOfs, pItem);
297     break;
298   }
299   case diUndoDeleteRun:
300   {
301     ME_InternalDeleteText(editor, pUItem->nStart, pUItem->nLen);
302     break;
303   }
304   case diUndoJoinParagraphs:
305   {
306     ME_Cursor tmp;
307     ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
308     /* the only thing that's needed is paragraph offset, so no need to split runs */
309     ME_JoinParagraphs(editor, ME_GetParagraph(tmp.pRun));
310     break;
311   }
312   case diUndoSplitParagraph:
313   {
314     ME_Cursor tmp;
315     ME_DisplayItem *new_para;
316     ME_CursorFromCharOfs(editor, pUItem->nStart, &tmp);
317     if (tmp.nOffset)
318       tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
319     assert(pUItem->nCR >= 0);
320     assert(pUItem->nLF >= 0);
321     new_para = ME_SplitParagraph(editor, tmp.pRun, tmp.pRun->member.run.style,
322       pUItem->nCR, pUItem->nLF);
323     assert(pItem->member.para.pFmt->cbSize == sizeof(PARAFORMAT2));
324     *new_para->member.para.pFmt = *pItem->member.para.pFmt;
325     break;
326   }
327   default:
328     assert(0 == "PlayUndoItem, unexpected type");
329   }
330 }
331 
332 BOOL ME_Undo(ME_TextEditor *editor) {
333   ME_DisplayItem *p;
334   ME_UndoMode nMode = editor->nUndoMode;
335   
336   if (editor->nUndoMode == umIgnore)
337     return FALSE;
338   assert(nMode == umAddToUndo || nMode == umIgnore);
339   
340   /* no undo items ? */
341   if (!editor->pUndoStack)
342     return FALSE;
343     
344   /* watch out for uncommitted transactions ! */
345   assert(editor->pUndoStack->type == diUndoEndTransaction
346         || editor->pUndoStack->type == diUndoPotentialEndTransaction);
347   
348   editor->nUndoMode = umAddToRedo;
349   p = editor->pUndoStack->next;
350   ME_DestroyDisplayItem(editor->pUndoStack);
351   editor->pUndoStack = p;
352   do {
353     p->prev = NULL;
354     ME_PlayUndoItem(editor, p);
355     editor->pUndoStack = p->next;
356     ME_DestroyDisplayItem(p);
357     p = editor->pUndoStack;
358   } while(p && p->type != diUndoEndTransaction);
359   if (p)
360     p->prev = NULL;
361   ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
362   editor->nUndoStackSize--;
363   editor->nUndoMode = nMode;
364   ME_UpdateRepaint(editor);
365   return TRUE;
366 }
367 
368 BOOL ME_Redo(ME_TextEditor *editor) {
369   ME_DisplayItem *p;
370   ME_UndoMode nMode = editor->nUndoMode;
371   
372   assert(nMode == umAddToUndo || nMode == umIgnore);
373   
374   if (editor->nUndoMode == umIgnore)
375     return FALSE;
376   /* no redo items ? */
377   if (!editor->pRedoStack)
378     return FALSE;
379     
380   /* watch out for uncommitted transactions ! */
381   assert(editor->pRedoStack->type == diUndoEndTransaction);
382   
383   editor->nUndoMode = umAddBackToUndo;
384   p = editor->pRedoStack->next;
385   ME_DestroyDisplayItem(editor->pRedoStack);
386   editor->pRedoStack = p;
387   do {
388     p->prev = NULL;
389     ME_PlayUndoItem(editor, p);
390     editor->pRedoStack = p->next;
391     ME_DestroyDisplayItem(p);
392     p = editor->pRedoStack;
393   } while(p && p->type != diUndoEndTransaction);
394   if (p)
395     p->prev = NULL;
396   ME_AddUndoItem(editor, diUndoEndTransaction, NULL);
397   editor->nUndoMode = nMode;
398   ME_UpdateRepaint(editor);
399   return TRUE;
400 }
401 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.