~ubuntu-branches/ubuntu/quantal/mysql-workbench/quantal

« back to all changes in this revision

Viewing changes to ext/scintilla/src/CellBuffer.cxx

  • Committer: Package Import Robot
  • Author(s): Dmitry Smirnov
  • Date: 2012-03-01 21:57:30 UTC
  • Revision ID: package-import@ubuntu.com-20120301215730-o7y8av8y38n162ro
Tags: upstream-5.2.38+dfsg
ImportĀ upstreamĀ versionĀ 5.2.38+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Scintilla source code edit control
 
2
/** @file CellBuffer.cxx
 
3
 ** Manages a buffer of cells.
 
4
 **/
 
5
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
 
6
// The License.txt file describes the conditions under which this software may be distributed.
 
7
 
 
8
#include <stdio.h>
 
9
#include <string.h>
 
10
#include <stdlib.h>
 
11
#include <stdarg.h>
 
12
 
 
13
#include "Platform.h"
 
14
 
 
15
#include "Scintilla.h"
 
16
#include "SplitVector.h"
 
17
#include "Partitioning.h"
 
18
#include "CellBuffer.h"
 
19
 
 
20
#ifdef SCI_NAMESPACE
 
21
using namespace Scintilla;
 
22
#endif
 
23
 
 
24
LineVector::LineVector() : starts(256), perLine(0) {
 
25
        Init();
 
26
}
 
27
 
 
28
LineVector::~LineVector() {
 
29
        starts.DeleteAll();
 
30
}
 
31
 
 
32
void LineVector::Init() {
 
33
        starts.DeleteAll();
 
34
        if (perLine) {
 
35
                perLine->Init();
 
36
        }
 
37
}
 
38
 
 
39
void LineVector::SetPerLine(PerLine *pl) {
 
40
        perLine = pl;
 
41
}
 
42
 
 
43
void LineVector::InsertText(int line, int delta) {
 
44
        starts.InsertText(line, delta);
 
45
}
 
46
 
 
47
void LineVector::InsertLine(int line, int position, bool lineStart) {
 
48
        starts.InsertPartition(line, position);
 
49
        if (perLine) {
 
50
                if ((line > 0) && lineStart)
 
51
                        line--;
 
52
                perLine->InsertLine(line);
 
53
        }
 
54
}
 
55
 
 
56
void LineVector::SetLineStart(int line, int position) {
 
57
        starts.SetPartitionStartPosition(line, position);
 
58
}
 
59
 
 
60
void LineVector::RemoveLine(int line) {
 
61
        starts.RemovePartition(line);
 
62
        if (perLine) {
 
63
                perLine->RemoveLine(line);
 
64
        }
 
65
}
 
66
 
 
67
int LineVector::LineFromPosition(int pos) const {
 
68
        return starts.PartitionFromPosition(pos);
 
69
}
 
70
 
 
71
Action::Action() {
 
72
        at = startAction;
 
73
        position = 0;
 
74
        data = 0;
 
75
        lenData = 0;
 
76
        mayCoalesce = false;
 
77
}
 
78
 
 
79
Action::~Action() {
 
80
        Destroy();
 
81
}
 
82
 
 
83
void Action::Create(actionType at_, int position_, char *data_, int lenData_, bool mayCoalesce_) {
 
84
        delete []data;
 
85
        position = position_;
 
86
        at = at_;
 
87
        data = data_;
 
88
        lenData = lenData_;
 
89
        mayCoalesce = mayCoalesce_;
 
90
}
 
91
 
 
92
void Action::Destroy() {
 
93
        delete []data;
 
94
        data = 0;
 
95
}
 
96
 
 
97
void Action::Grab(Action *source) {
 
98
        delete []data;
 
99
 
 
100
        position = source->position;
 
101
        at = source->at;
 
102
        data = source->data;
 
103
        lenData = source->lenData;
 
104
        mayCoalesce = source->mayCoalesce;
 
105
 
 
106
        // Ownership of source data transferred to this
 
107
        source->position = 0;
 
108
        source->at = startAction;
 
109
        source->data = 0;
 
110
        source->lenData = 0;
 
111
        source->mayCoalesce = true;
 
112
}
 
113
 
 
114
// The undo history stores a sequence of user operations that represent the user's view of the
 
115
// commands executed on the text.
 
116
// Each user operation contains a sequence of text insertion and text deletion actions.
 
117
// All the user operations are stored in a list of individual actions with 'start' actions used
 
118
// as delimiters between user operations.
 
119
// Initially there is one start action in the history.
 
120
// As each action is performed, it is recorded in the history. The action may either become
 
121
// part of the current user operation or may start a new user operation. If it is to be part of the
 
122
// current operation, then it overwrites the current last action. If it is to be part of a new
 
123
// operation, it is appended after the current last action.
 
124
// After writing the new action, a new start action is appended at the end of the history.
 
125
// The decision of whether to start a new user operation is based upon two factors. If a
 
126
// compound operation has been explicitly started by calling BeginUndoAction and no matching
 
127
// EndUndoAction (these calls nest) has been called, then the action is coalesced into the current
 
128
// operation. If there is no outstanding BeginUndoAction call then a new operation is started
 
129
// unless it looks as if the new action is caused by the user typing or deleting a stream of text.
 
130
// Sequences that look like typing or deletion are coalesced into a single user operation.
 
131
 
 
132
UndoHistory::UndoHistory() {
 
133
 
 
134
        lenActions = 100;
 
135
        actions = new Action[lenActions];
 
136
        maxAction = 0;
 
137
        currentAction = 0;
 
138
        undoSequenceDepth = 0;
 
139
        savePoint = 0;
 
140
 
 
141
        actions[currentAction].Create(startAction);
 
142
}
 
143
 
 
144
UndoHistory::~UndoHistory() {
 
145
        delete []actions;
 
146
        actions = 0;
 
147
}
 
148
 
 
149
void UndoHistory::EnsureUndoRoom() {
 
150
        // Have to test that there is room for 2 more actions in the array
 
151
        // as two actions may be created by the calling function
 
152
        if (currentAction >= (lenActions - 2)) {
 
153
                // Run out of undo nodes so extend the array
 
154
                int lenActionsNew = lenActions * 2;
 
155
                Action *actionsNew = new Action[lenActionsNew];
 
156
                for (int act = 0; act <= currentAction; act++)
 
157
                        actionsNew[act].Grab(&actions[act]);
 
158
                delete []actions;
 
159
                lenActions = lenActionsNew;
 
160
                actions = actionsNew;
 
161
        }
 
162
}
 
163
 
 
164
void UndoHistory::AppendAction(actionType at, int position, char *data, int lengthData,
 
165
        bool &startSequence, bool mayCoalesce) {
 
166
        EnsureUndoRoom();
 
167
        //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction);
 
168
        //Platform::DebugPrintf("^ %d action %d %d\n", actions[currentAction - 1].at,
 
169
        //      actions[currentAction - 1].position, actions[currentAction - 1].lenData);
 
170
        if (currentAction < savePoint) {
 
171
                savePoint = -1;
 
172
        }
 
173
        int oldCurrentAction = currentAction;
 
174
        if (currentAction >= 1) {
 
175
                if (0 == undoSequenceDepth) {
 
176
                        // Top level actions may not always be coalesced
 
177
                        int targetAct = -1;
 
178
                        const Action *actPrevious = &(actions[currentAction + targetAct]);
 
179
                        // Container actions may forward the coalesce state of Scintilla Actions.
 
180
                        while ((actPrevious->at == containerAction) && actPrevious->mayCoalesce) {
 
181
                                targetAct--;
 
182
                                actPrevious = &(actions[currentAction + targetAct]);
 
183
                        }
 
184
                        // See if current action can be coalesced into previous action
 
185
                        // Will work if both are inserts or deletes and position is same
 
186
                        if (currentAction == savePoint) {
 
187
                                currentAction++;
 
188
                        } else if (!actions[currentAction].mayCoalesce) {
 
189
                                // Not allowed to coalesce if this set
 
190
                                currentAction++;
 
191
                        } else if (!mayCoalesce || !actPrevious->mayCoalesce) {
 
192
                                currentAction++;
 
193
                        } else if (at == containerAction || actions[currentAction].at == containerAction) {
 
194
                                ;       // A coalescible containerAction
 
195
                        } else if ((at != actPrevious->at) && (actPrevious->at != startAction)) {
 
196
                                currentAction++;
 
197
                        } else if ((at == insertAction) &&
 
198
                                   (position != (actPrevious->position + actPrevious->lenData))) {
 
199
                                // Insertions must be immediately after to coalesce
 
200
                                currentAction++;
 
201
                        } else if (at == removeAction) {
 
202
                                if ((lengthData == 1) || (lengthData == 2)) {
 
203
                                        if ((position + lengthData) == actPrevious->position) {
 
204
                                                ; // Backspace -> OK
 
205
                                        } else if (position == actPrevious->position) {
 
206
                                                ; // Delete -> OK
 
207
                                        } else {
 
208
                                                // Removals must be at same position to coalesce
 
209
                                                currentAction++;
 
210
                                        }
 
211
                                } else {
 
212
                                        // Removals must be of one character to coalesce
 
213
                                        currentAction++;
 
214
                                }
 
215
                        } else {
 
216
                                // Action coalesced.
 
217
                        }
 
218
 
 
219
                } else {
 
220
                        // Actions not at top level are always coalesced unless this is after return to top level
 
221
                        if (!actions[currentAction].mayCoalesce)
 
222
                                currentAction++;
 
223
                }
 
224
        } else {
 
225
                currentAction++;
 
226
        }
 
227
        startSequence = oldCurrentAction != currentAction;
 
228
        actions[currentAction].Create(at, position, data, lengthData, mayCoalesce);
 
229
        currentAction++;
 
230
        actions[currentAction].Create(startAction);
 
231
        maxAction = currentAction;
 
232
}
 
233
 
 
234
void UndoHistory::BeginUndoAction() {
 
235
        EnsureUndoRoom();
 
236
        if (undoSequenceDepth == 0) {
 
237
                if (actions[currentAction].at != startAction) {
 
238
                        currentAction++;
 
239
                        actions[currentAction].Create(startAction);
 
240
                        maxAction = currentAction;
 
241
                }
 
242
                actions[currentAction].mayCoalesce = false;
 
243
        }
 
244
        undoSequenceDepth++;
 
245
}
 
246
 
 
247
void UndoHistory::EndUndoAction() {
 
248
        PLATFORM_ASSERT(undoSequenceDepth > 0);
 
249
        EnsureUndoRoom();
 
250
        undoSequenceDepth--;
 
251
        if (0 == undoSequenceDepth) {
 
252
                if (actions[currentAction].at != startAction) {
 
253
                        currentAction++;
 
254
                        actions[currentAction].Create(startAction);
 
255
                        maxAction = currentAction;
 
256
                }
 
257
                actions[currentAction].mayCoalesce = false;
 
258
        }
 
259
}
 
260
 
 
261
void UndoHistory::DropUndoSequence() {
 
262
        undoSequenceDepth = 0;
 
263
}
 
264
 
 
265
void UndoHistory::DeleteUndoHistory() {
 
266
        for (int i = 1; i < maxAction; i++)
 
267
                actions[i].Destroy();
 
268
        maxAction = 0;
 
269
        currentAction = 0;
 
270
        actions[currentAction].Create(startAction);
 
271
        savePoint = 0;
 
272
}
 
273
 
 
274
void UndoHistory::SetSavePoint() {
 
275
        savePoint = currentAction;
 
276
}
 
277
 
 
278
bool UndoHistory::IsSavePoint() const {
 
279
        return savePoint == currentAction;
 
280
}
 
281
 
 
282
bool UndoHistory::CanUndo() const {
 
283
        return (currentAction > 0) && (maxAction > 0);
 
284
}
 
285
 
 
286
int UndoHistory::StartUndo() {
 
287
        // Drop any trailing startAction
 
288
        if (actions[currentAction].at == startAction && currentAction > 0)
 
289
                currentAction--;
 
290
 
 
291
        // Count the steps in this action
 
292
        int act = currentAction;
 
293
        while (actions[act].at != startAction && act > 0) {
 
294
                act--;
 
295
        }
 
296
        return currentAction - act;
 
297
}
 
298
 
 
299
const Action &UndoHistory::GetUndoStep() const {
 
300
        return actions[currentAction];
 
301
}
 
302
 
 
303
void UndoHistory::CompletedUndoStep() {
 
304
        currentAction--;
 
305
}
 
306
 
 
307
bool UndoHistory::CanRedo() const {
 
308
        return maxAction > currentAction;
 
309
}
 
310
 
 
311
int UndoHistory::StartRedo() {
 
312
        // Drop any leading startAction
 
313
        if (actions[currentAction].at == startAction && currentAction < maxAction)
 
314
                currentAction++;
 
315
 
 
316
        // Count the steps in this action
 
317
        int act = currentAction;
 
318
        while (actions[act].at != startAction && act < maxAction) {
 
319
                act++;
 
320
        }
 
321
        return act - currentAction;
 
322
}
 
323
 
 
324
const Action &UndoHistory::GetRedoStep() const {
 
325
        return actions[currentAction];
 
326
}
 
327
 
 
328
void UndoHistory::CompletedRedoStep() {
 
329
        currentAction++;
 
330
}
 
331
 
 
332
CellBuffer::CellBuffer() {
 
333
        readOnly = false;
 
334
        collectingUndo = true;
 
335
}
 
336
 
 
337
CellBuffer::~CellBuffer() {
 
338
}
 
339
 
 
340
char CellBuffer::CharAt(int position) const {
 
341
        return substance.ValueAt(position);
 
342
}
 
343
 
 
344
void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) const {
 
345
        if (lengthRetrieve < 0)
 
346
                return;
 
347
        if (position < 0)
 
348
                return;
 
349
        if ((position + lengthRetrieve) > substance.Length()) {
 
350
                Platform::DebugPrintf("Bad GetCharRange %d for %d of %d\n", position,
 
351
                                      lengthRetrieve, substance.Length());
 
352
                return;
 
353
        }
 
354
        substance.GetRange(buffer, position, lengthRetrieve);
 
355
}
 
356
 
 
357
char CellBuffer::StyleAt(int position) const {
 
358
        return style.ValueAt(position);
 
359
}
 
360
 
 
361
void CellBuffer::GetStyleRange(unsigned char *buffer, int position, int lengthRetrieve) const {
 
362
        if (lengthRetrieve < 0)
 
363
                return;
 
364
        if (position < 0)
 
365
                return;
 
366
        if ((position + lengthRetrieve) > style.Length()) {
 
367
                Platform::DebugPrintf("Bad GetStyleRange %d for %d of %d\n", position,
 
368
                                      lengthRetrieve, style.Length());
 
369
                return;
 
370
        }
 
371
        style.GetRange(reinterpret_cast<char *>(buffer), position, lengthRetrieve);
 
372
}
 
373
 
 
374
const char *CellBuffer::BufferPointer() {
 
375
        return substance.BufferPointer();
 
376
}
 
377
 
 
378
// The char* returned is to an allocation owned by the undo history
 
379
const char *CellBuffer::InsertString(int position, const char *s, int insertLength, bool &startSequence) {
 
380
        char *data = 0;
 
381
        // InsertString and DeleteChars are the bottleneck though which all changes occur
 
382
        if (!readOnly) {
 
383
                if (collectingUndo) {
 
384
                        // Save into the undo/redo stack, but only the characters - not the formatting
 
385
                        // This takes up about half load time
 
386
                        data = new char[insertLength];
 
387
                        for (int i = 0; i < insertLength; i++) {
 
388
                                data[i] = s[i];
 
389
                        }
 
390
                        uh.AppendAction(insertAction, position, data, insertLength, startSequence);
 
391
                }
 
392
 
 
393
                BasicInsertString(position, s, insertLength);
 
394
        }
 
395
        return data;
 
396
}
 
397
 
 
398
bool CellBuffer::SetStyleAt(int position, char styleValue, char mask) {
 
399
        styleValue &= mask;
 
400
        char curVal = style.ValueAt(position);
 
401
        if ((curVal & mask) != styleValue) {
 
402
                style.SetValueAt(position, static_cast<char>((curVal & ~mask) | styleValue));
 
403
                return true;
 
404
        } else {
 
405
                return false;
 
406
        }
 
407
}
 
408
 
 
409
bool CellBuffer::SetStyleFor(int position, int lengthStyle, char styleValue, char mask) {
 
410
        bool changed = false;
 
411
        PLATFORM_ASSERT(lengthStyle == 0 ||
 
412
                (lengthStyle > 0 && lengthStyle + position <= style.Length()));
 
413
        while (lengthStyle--) {
 
414
                char curVal = style.ValueAt(position);
 
415
                if ((curVal & mask) != styleValue) {
 
416
                        style.SetValueAt(position, static_cast<char>((curVal & ~mask) | styleValue));
 
417
                        changed = true;
 
418
                }
 
419
                position++;
 
420
        }
 
421
        return changed;
 
422
}
 
423
 
 
424
// The char* returned is to an allocation owned by the undo history
 
425
const char *CellBuffer::DeleteChars(int position, int deleteLength, bool &startSequence) {
 
426
        // InsertString and DeleteChars are the bottleneck though which all changes occur
 
427
        PLATFORM_ASSERT(deleteLength > 0);
 
428
        char *data = 0;
 
429
        if (!readOnly) {
 
430
                if (collectingUndo) {
 
431
                        // Save into the undo/redo stack, but only the characters - not the formatting
 
432
                        data = new char[deleteLength];
 
433
                        for (int i = 0; i < deleteLength; i++) {
 
434
                                data[i] = substance.ValueAt(position + i);
 
435
                        }
 
436
                        uh.AppendAction(removeAction, position, data, deleteLength, startSequence);
 
437
                }
 
438
 
 
439
                BasicDeleteChars(position, deleteLength);
 
440
        }
 
441
        return data;
 
442
}
 
443
 
 
444
int CellBuffer::Length() const {
 
445
        return substance.Length();
 
446
}
 
447
 
 
448
void CellBuffer::Allocate(int newSize) {
 
449
        substance.ReAllocate(newSize);
 
450
        style.ReAllocate(newSize);
 
451
}
 
452
 
 
453
void CellBuffer::SetPerLine(PerLine *pl) {
 
454
        lv.SetPerLine(pl);
 
455
}
 
456
 
 
457
int CellBuffer::Lines() const {
 
458
        return lv.Lines();
 
459
}
 
460
 
 
461
int CellBuffer::LineStart(int line) const {
 
462
        if (line < 0)
 
463
                return 0;
 
464
        else if (line >= Lines())
 
465
                return Length();
 
466
        else
 
467
                return lv.LineStart(line);
 
468
}
 
469
 
 
470
bool CellBuffer::IsReadOnly() const {
 
471
        return readOnly;
 
472
}
 
473
 
 
474
void CellBuffer::SetReadOnly(bool set) {
 
475
        readOnly = set;
 
476
}
 
477
 
 
478
void CellBuffer::SetSavePoint() {
 
479
        uh.SetSavePoint();
 
480
}
 
481
 
 
482
bool CellBuffer::IsSavePoint() {
 
483
        return uh.IsSavePoint();
 
484
}
 
485
 
 
486
// Without undo
 
487
 
 
488
void CellBuffer::InsertLine(int line, int position, bool lineStart) {
 
489
        lv.InsertLine(line, position, lineStart);
 
490
}
 
491
 
 
492
void CellBuffer::RemoveLine(int line) {
 
493
        lv.RemoveLine(line);
 
494
}
 
495
 
 
496
void CellBuffer::BasicInsertString(int position, const char *s, int insertLength) {
 
497
        if (insertLength == 0)
 
498
                return;
 
499
        PLATFORM_ASSERT(insertLength > 0);
 
500
 
 
501
        substance.InsertFromArray(position, s, 0, insertLength);
 
502
        style.InsertValue(position, insertLength, 0);
 
503
 
 
504
        int lineInsert = lv.LineFromPosition(position) + 1;
 
505
        bool atLineStart = lv.LineStart(lineInsert-1) == position;
 
506
        // Point all the lines after the insertion point further along in the buffer
 
507
        lv.InsertText(lineInsert-1, insertLength);
 
508
        char chPrev = substance.ValueAt(position - 1);
 
509
        char chAfter = substance.ValueAt(position + insertLength);
 
510
        if (chPrev == '\r' && chAfter == '\n') {
 
511
                // Splitting up a crlf pair at position
 
512
                InsertLine(lineInsert, position, false);
 
513
                lineInsert++;
 
514
        }
 
515
        char ch = ' ';
 
516
        for (int i = 0; i < insertLength; i++) {
 
517
                ch = s[i];
 
518
                if (ch == '\r') {
 
519
                        InsertLine(lineInsert, (position + i) + 1, atLineStart);
 
520
                        lineInsert++;
 
521
                } else if (ch == '\n') {
 
522
                        if (chPrev == '\r') {
 
523
                                // Patch up what was end of line
 
524
                                lv.SetLineStart(lineInsert - 1, (position + i) + 1);
 
525
                        } else {
 
526
                                InsertLine(lineInsert, (position + i) + 1, atLineStart);
 
527
                                lineInsert++;
 
528
                        }
 
529
                }
 
530
                chPrev = ch;
 
531
        }
 
532
        // Joining two lines where last insertion is cr and following substance starts with lf
 
533
        if (chAfter == '\n') {
 
534
                if (ch == '\r') {
 
535
                        // End of line already in buffer so drop the newly created one
 
536
                        RemoveLine(lineInsert - 1);
 
537
                }
 
538
        }
 
539
}
 
540
 
 
541
void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
 
542
        if (deleteLength == 0)
 
543
                return;
 
544
 
 
545
        if ((position == 0) && (deleteLength == substance.Length())) {
 
546
                // If whole buffer is being deleted, faster to reinitialise lines data
 
547
                // than to delete each line.
 
548
                lv.Init();
 
549
        } else {
 
550
                // Have to fix up line positions before doing deletion as looking at text in buffer
 
551
                // to work out which lines have been removed
 
552
 
 
553
                int lineRemove = lv.LineFromPosition(position) + 1;
 
554
                lv.InsertText(lineRemove-1, - (deleteLength));
 
555
                char chPrev = substance.ValueAt(position - 1);
 
556
                char chBefore = chPrev;
 
557
                char chNext = substance.ValueAt(position);
 
558
                bool ignoreNL = false;
 
559
                if (chPrev == '\r' && chNext == '\n') {
 
560
                        // Move back one
 
561
                        lv.SetLineStart(lineRemove, position);
 
562
                        lineRemove++;
 
563
                        ignoreNL = true;        // First \n is not real deletion
 
564
                }
 
565
 
 
566
                char ch = chNext;
 
567
                for (int i = 0; i < deleteLength; i++) {
 
568
                        chNext = substance.ValueAt(position + i + 1);
 
569
                        if (ch == '\r') {
 
570
                                if (chNext != '\n') {
 
571
                                        RemoveLine(lineRemove);
 
572
                                }
 
573
                        } else if (ch == '\n') {
 
574
                                if (ignoreNL) {
 
575
                                        ignoreNL = false;       // Further \n are real deletions
 
576
                                } else {
 
577
                                        RemoveLine(lineRemove);
 
578
                                }
 
579
                        }
 
580
 
 
581
                        ch = chNext;
 
582
                }
 
583
                // May have to fix up end if last deletion causes cr to be next to lf
 
584
                // or removes one of a crlf pair
 
585
                char chAfter = substance.ValueAt(position + deleteLength);
 
586
                if (chBefore == '\r' && chAfter == '\n') {
 
587
                        // Using lineRemove-1 as cr ended line before start of deletion
 
588
                        RemoveLine(lineRemove - 1);
 
589
                        lv.SetLineStart(lineRemove - 1, position + 1);
 
590
                }
 
591
        }
 
592
        substance.DeleteRange(position, deleteLength);
 
593
        style.DeleteRange(position, deleteLength);
 
594
}
 
595
 
 
596
bool CellBuffer::SetUndoCollection(bool collectUndo) {
 
597
        collectingUndo = collectUndo;
 
598
        uh.DropUndoSequence();
 
599
        return collectingUndo;
 
600
}
 
601
 
 
602
bool CellBuffer::IsCollectingUndo() const {
 
603
        return collectingUndo;
 
604
}
 
605
 
 
606
void CellBuffer::BeginUndoAction() {
 
607
        uh.BeginUndoAction();
 
608
}
 
609
 
 
610
void CellBuffer::EndUndoAction() {
 
611
        uh.EndUndoAction();
 
612
}
 
613
 
 
614
void CellBuffer::AddUndoAction(int token, bool mayCoalesce) {
 
615
        bool startSequence;
 
616
        uh.AppendAction(containerAction, token, 0, 0, startSequence, mayCoalesce);
 
617
}
 
618
 
 
619
void CellBuffer::DeleteUndoHistory() {
 
620
        uh.DeleteUndoHistory();
 
621
}
 
622
 
 
623
bool CellBuffer::CanUndo() {
 
624
        return uh.CanUndo();
 
625
}
 
626
 
 
627
int CellBuffer::StartUndo() {
 
628
        return uh.StartUndo();
 
629
}
 
630
 
 
631
const Action &CellBuffer::GetUndoStep() const {
 
632
        return uh.GetUndoStep();
 
633
}
 
634
 
 
635
void CellBuffer::PerformUndoStep() {
 
636
        const Action &actionStep = uh.GetUndoStep();
 
637
        if (actionStep.at == insertAction) {
 
638
                BasicDeleteChars(actionStep.position, actionStep.lenData);
 
639
        } else if (actionStep.at == removeAction) {
 
640
                BasicInsertString(actionStep.position, actionStep.data, actionStep.lenData);
 
641
        }
 
642
        uh.CompletedUndoStep();
 
643
}
 
644
 
 
645
bool CellBuffer::CanRedo() {
 
646
        return uh.CanRedo();
 
647
}
 
648
 
 
649
int CellBuffer::StartRedo() {
 
650
        return uh.StartRedo();
 
651
}
 
652
 
 
653
const Action &CellBuffer::GetRedoStep() const {
 
654
        return uh.GetRedoStep();
 
655
}
 
656
 
 
657
void CellBuffer::PerformRedoStep() {
 
658
        const Action &actionStep = uh.GetRedoStep();
 
659
        if (actionStep.at == insertAction) {
 
660
                BasicInsertString(actionStep.position, actionStep.data, actionStep.lenData);
 
661
        } else if (actionStep.at == removeAction) {
 
662
                BasicDeleteChars(actionStep.position, actionStep.lenData);
 
663
        }
 
664
        uh.CompletedRedoStep();
 
665
}
 
666