]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/Document.cxx
6614a7fc98083f8d7c9155992013da5e96c89568
1 // Scintilla source code edit control
2 // Document.cxx - text document that handles notifications, DBCS, styling, words and end of line
3 // Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
4 // The License.txt file describes the conditions under which this software may be distributed.
13 #include "Scintilla.h"
15 #include "CellBuffer.h"
18 Document::Document() {
23 eolMode
= SC_EOL_CRLF
;
27 stylingBitsMask
= 0x1F;
30 for (int ch
= 0; ch
< 256; ch
++) {
31 wordchars
[ch
] = isalnum(ch
) || ch
== '_';
35 enteredReadOnlyCount
= 0;
43 Document::~Document() {
44 for (int i
= 0; i
< lenWatchers
; i
++) {
45 watchers
[i
].watcher
->NotifyDeleted(this, watchers
[i
].userData
);
52 // Increase reference count and return its previous value.
53 int Document::AddRef() {
57 // Decrease reference count and return its provius value.
58 // Delete the document if reference count reaches zero.
59 int Document::Release() {
60 int curRefCount
= --refCount
;
66 void Document::SetSavePoint() {
68 NotifySavePoint(true);
71 int Document::AddMark(int line
, int markerNum
) {
72 int prev
= cb
.AddMark(line
, markerNum
);
73 DocModification
mh(SC_MOD_CHANGEMARKER
, LineStart(line
), 0, 0, 0);
78 void Document::DeleteMark(int line
, int markerNum
) {
79 cb
.DeleteMark(line
, markerNum
);
80 DocModification
mh(SC_MOD_CHANGEMARKER
, LineStart(line
), 0, 0, 0);
84 void Document::DeleteMarkFromHandle(int markerHandle
) {
85 cb
.DeleteMarkFromHandle(markerHandle
);
86 DocModification
mh(SC_MOD_CHANGEMARKER
, 0, 0, 0, 0);
90 void Document::DeleteAllMarks(int markerNum
) {
91 cb
.DeleteAllMarks(markerNum
);
92 DocModification
mh(SC_MOD_CHANGEMARKER
, 0, 0, 0, 0);
96 int Document::LineStart(int line
) {
97 return cb
.LineStart(line
);
100 int Document::LineEnd(int line
) {
101 if (line
== LinesTotal() - 1) {
102 return LineStart(line
+ 1);
104 int position
= LineStart(line
+ 1) - 1;
105 // When line terminator is CR+LF, may need to go back one more
106 if ((position
> LineStart(line
)) && (cb
.CharAt(position
- 1) == '\r')) {
113 int Document::LineFromPosition(int pos
) {
114 return cb
.LineFromPosition(pos
);
117 int Document::LineEndPosition(int position
) {
118 return LineEnd(LineFromPosition(position
));
121 int Document::VCHomePosition(int position
) {
122 int line
= LineFromPosition(position
);
123 int startPosition
= LineStart(line
);
124 int endLine
= LineStart(line
+ 1) - 1;
125 int startText
= startPosition
;
126 while (startText
< endLine
&& (cb
.CharAt(startText
) == ' ' || cb
.CharAt(startText
) == '\t' ) )
128 if (position
== startText
)
129 return startPosition
;
134 int Document::SetLevel(int line
, int level
) {
135 int prev
= cb
.SetLevel(line
, level
);
137 DocModification
mh(SC_MOD_CHANGEFOLD
, LineStart(line
), 0, 0, 0);
139 mh
.foldLevelNow
= level
;
140 mh
.foldLevelPrev
= prev
;
146 static bool IsSubordinate(int levelStart
, int levelTry
) {
147 if (levelTry
& SC_FOLDLEVELWHITEFLAG
)
150 return (levelStart
& SC_FOLDLEVELNUMBERMASK
) < (levelTry
& SC_FOLDLEVELNUMBERMASK
);
153 int Document::GetLastChild(int lineParent
, int level
) {
155 level
= GetLevel(lineParent
) & SC_FOLDLEVELNUMBERMASK
;
156 int maxLine
= LinesTotal();
157 int lineMaxSubord
= lineParent
;
158 while (lineMaxSubord
< maxLine
-1) {
159 EnsureStyledTo(LineStart(lineMaxSubord
+2));
160 if (!IsSubordinate(level
, GetLevel(lineMaxSubord
+1)))
164 if (lineMaxSubord
> lineParent
) {
165 if (level
> (GetLevel(lineMaxSubord
+1) & SC_FOLDLEVELNUMBERMASK
)) {
166 // Have chewed up some whitespace that belongs to a parent so seek back
167 if ((lineMaxSubord
> lineParent
) && (GetLevel(lineMaxSubord
) & SC_FOLDLEVELWHITEFLAG
)) {
172 return lineMaxSubord
;
175 int Document::GetFoldParent(int line
) {
176 int level
= GetLevel(line
);
177 int lineLook
= line
-1;
178 while ((lineLook
> 0) && (
179 (!(GetLevel(lineLook
) & SC_FOLDLEVELHEADERFLAG
)) ||
180 ((GetLevel(lineLook
) & SC_FOLDLEVELNUMBERMASK
) >= level
))
184 if ((GetLevel(lineLook
) & SC_FOLDLEVELHEADERFLAG
) &&
185 ((GetLevel(lineLook
) & SC_FOLDLEVELNUMBERMASK
) < level
)) {
192 int Document::ClampPositionIntoDocument(int pos
) {
193 return Platform::Clamp(pos
, 0, Length());
196 bool Document::IsCrLf(int pos
) {
199 if (pos
>= (Length() - 1))
201 return (cb
.CharAt(pos
) == '\r') && (cb
.CharAt(pos
+ 1) == '\n');
204 bool Document::IsDBCS(int pos
) {
207 if (SC_CP_UTF8
== dbcsCodePage
) {
208 unsigned char ch
= static_cast<unsigned char>(cb
.CharAt(pos
));
211 // Anchor DBCS calculations at start of line because start of line can
212 // not be a DBCS trail byte.
214 while (startLine
> 0 && cb
.CharAt(startLine
) != '\r' && cb
.CharAt(startLine
) != '\n')
216 while (startLine
<= pos
) {
217 if (IsDBCSLeadByteEx(dbcsCodePage
, cb
.CharAt(startLine
))) {
219 if (startLine
>= pos
)
232 int Document::LenChar(int pos
) {
235 } else if (SC_CP_UTF8
== dbcsCodePage
) {
236 unsigned char ch
= static_cast<unsigned char>(cb
.CharAt(pos
));
240 if (ch
>= (0x80+0x40+0x20))
242 int lengthDoc
= Length();
243 if ((pos
+ len
) > lengthDoc
)
244 return lengthDoc
-pos
;
247 } else if (IsDBCS(pos
)) {
254 // Normalise a position so that it is not halfway through a two byte character.
255 // This can occur in two situations -
256 // When lines are terminated with \r\n pairs which should be treated as one character.
257 // When displaying DBCS text such as Japanese.
258 // If moving, move the position in the indicated direction.
259 int Document::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
260 //Platform::DebugPrintf("NoCRLF %d %d\n", pos, moveDir);
261 // If out of range, just return value - should be fixed up after
267 // Position 0 and Length() can not be between any two characters
273 // assert pos > 0 && pos < Length()
274 if (checkLineEnd
&& IsCrLf(pos
- 1)) {
281 // Not between CR and LF
285 if (SC_CP_UTF8
== dbcsCodePage
) {
286 unsigned char ch
= static_cast<unsigned char>(cb
.CharAt(pos
));
287 while ((pos
> 0) && (pos
< Length()) && (ch
>= 0x80) && (ch
< (0x80 + 0x40))) {
288 // ch is a trail byte
293 ch
= static_cast<unsigned char>(cb
.CharAt(pos
));
296 // Anchor DBCS calculations at start of line because start of line can
297 // not be a DBCS trail byte.
299 while (startLine
> 0 && cb
.CharAt(startLine
) != '\r' && cb
.CharAt(startLine
) != '\n')
301 bool atLeadByte
= false;
302 while (startLine
< pos
) {
305 else if (IsDBCSLeadByteEx(dbcsCodePage
, cb
.CharAt(startLine
)))
310 //Platform::DebugPrintf("DBCS %s\n", atlead ? "D" : "-");
314 // Position is between a lead byte and a trail byte
327 void Document::ModifiedAt(int pos
) {
332 // Document only modified by gateways DeleteChars, InsertStyledString, Undo, Redo, and SetStyleAt.
333 // SetStyleAt does not change the persistent state of a document
335 // Unlike Undo, Redo, and InsertStyledString, the pos argument is a cell number not a char number
336 void Document::DeleteChars(int pos
, int len
) {
337 if (cb
.IsReadOnly() && enteredReadOnlyCount
==0) {
338 enteredReadOnlyCount
++;
339 NotifyModifyAttempt();
340 enteredReadOnlyCount
--;
342 if (enteredCount
== 0) {
344 if (!cb
.IsReadOnly()) {
347 SC_MOD_BEFOREDELETE
| SC_PERFORMED_USER
,
350 int prevLinesTotal
= LinesTotal();
351 bool startSavePoint
= cb
.IsSavePoint();
352 const char *text
= cb
.DeleteChars(pos
*2, len
* 2);
353 if (startSavePoint
&& cb
.IsCollectingUndo())
354 NotifySavePoint(!startSavePoint
);
358 SC_MOD_DELETETEXT
| SC_PERFORMED_USER
,
360 LinesTotal() - prevLinesTotal
, text
));
366 void Document::InsertStyledString(int position
, char *s
, int insertLength
) {
367 if (cb
.IsReadOnly() && enteredReadOnlyCount
==0) {
368 enteredReadOnlyCount
++;
369 NotifyModifyAttempt();
370 enteredReadOnlyCount
--;
372 if (enteredCount
== 0) {
374 if (!cb
.IsReadOnly()) {
377 SC_MOD_BEFOREINSERT
| SC_PERFORMED_USER
,
378 position
/ 2, insertLength
/ 2,
380 int prevLinesTotal
= LinesTotal();
381 bool startSavePoint
= cb
.IsSavePoint();
382 const char *text
= cb
.InsertString(position
, s
, insertLength
);
383 if (startSavePoint
&& cb
.IsCollectingUndo())
384 NotifySavePoint(!startSavePoint
);
385 ModifiedAt(position
/ 2);
388 SC_MOD_INSERTTEXT
| SC_PERFORMED_USER
,
389 position
/ 2, insertLength
/ 2,
390 LinesTotal() - prevLinesTotal
, text
));
396 int Document::Undo() {
398 if (enteredCount
== 0) {
400 bool startSavePoint
= cb
.IsSavePoint();
401 int steps
= cb
.StartUndo();
402 //Platform::DebugPrintf("Steps=%d\n", steps);
403 for (int step
=0; step
<steps
; step
++) {
404 int prevLinesTotal
= LinesTotal();
405 const Action
&action
= cb
.GetUndoStep();
406 if (action
.at
== removeAction
) {
407 NotifyModified(DocModification(
408 SC_MOD_BEFOREINSERT
| SC_PERFORMED_UNDO
, action
));
410 NotifyModified(DocModification(
411 SC_MOD_BEFOREDELETE
| SC_PERFORMED_UNDO
, action
));
413 cb
.PerformUndoStep();
414 int cellPosition
= action
.position
/ 2;
415 ModifiedAt(cellPosition
);
416 newPos
= cellPosition
;
418 int modFlags
= SC_PERFORMED_UNDO
;
419 // With undo, an insertion action becomes a deletion notification
420 if (action
.at
== removeAction
) {
421 newPos
+= action
.lenData
;
422 modFlags
|= SC_MOD_INSERTTEXT
;
424 modFlags
|= SC_MOD_DELETETEXT
;
427 modFlags
|= SC_LASTSTEPINUNDOREDO
;
428 NotifyModified(DocModification(modFlags
, cellPosition
, action
.lenData
,
429 LinesTotal() - prevLinesTotal
, action
.data
));
432 bool endSavePoint
= cb
.IsSavePoint();
433 if (startSavePoint
!= endSavePoint
)
434 NotifySavePoint(endSavePoint
);
440 int Document::Redo() {
442 if (enteredCount
== 0) {
444 bool startSavePoint
= cb
.IsSavePoint();
445 int steps
= cb
.StartRedo();
446 for (int step
=0; step
<steps
; step
++) {
447 int prevLinesTotal
= LinesTotal();
448 const Action
&action
= cb
.GetRedoStep();
449 if (action
.at
== insertAction
) {
450 NotifyModified(DocModification(
451 SC_MOD_BEFOREINSERT
| SC_PERFORMED_REDO
, action
));
453 NotifyModified(DocModification(
454 SC_MOD_BEFOREDELETE
| SC_PERFORMED_REDO
, action
));
456 cb
.PerformRedoStep();
457 ModifiedAt(action
.position
/ 2);
458 newPos
= action
.position
/ 2;
460 int modFlags
= SC_PERFORMED_REDO
;
461 if (action
.at
== insertAction
) {
462 newPos
+= action
.lenData
;
463 modFlags
|= SC_MOD_INSERTTEXT
;
465 modFlags
|= SC_MOD_DELETETEXT
;
468 modFlags
|= SC_LASTSTEPINUNDOREDO
;
470 DocModification(modFlags
, action
.position
/ 2, action
.lenData
,
471 LinesTotal() - prevLinesTotal
, action
.data
));
474 bool endSavePoint
= cb
.IsSavePoint();
475 if (startSavePoint
!= endSavePoint
)
476 NotifySavePoint(endSavePoint
);
482 void Document::InsertChar(int pos
, char ch
) {
486 InsertStyledString(pos
*2, chs
, 2);
489 // Insert a null terminated string
490 void Document::InsertString(int position
, const char *s
) {
491 InsertString(position
, s
, strlen(s
));
494 // Insert a string with a length
495 void Document::InsertString(int position
, const char *s
, int insertLength
) {
496 char *sWithStyle
= new char[insertLength
* 2];
498 for (int i
= 0; i
< insertLength
; i
++) {
499 sWithStyle
[i
*2] = s
[i
];
500 sWithStyle
[i
*2 + 1] = 0;
502 InsertStyledString(position
*2, sWithStyle
, insertLength
*2);
507 void Document::ChangeChar(int pos
, char ch
) {
512 void Document::DelChar(int pos
) {
513 DeleteChars(pos
, LenChar(pos
));
516 int Document::DelCharBack(int pos
) {
519 } else if (IsCrLf(pos
- 2)) {
520 DeleteChars(pos
- 2, 2);
522 } else if (SC_CP_UTF8
== dbcsCodePage
) {
523 int startChar
= MovePositionOutsideChar(pos
-1, -1, false);
524 DeleteChars(startChar
, pos
- startChar
);
526 } else if (IsDBCS(pos
- 1)) {
527 DeleteChars(pos
- 2, 2);
530 DeleteChars(pos
- 1, 1);
535 static bool isindentchar(char ch
) {
536 return (ch
== ' ') || (ch
== '\t');
539 static int NextTab(int pos
, int tabSize
) {
540 return ((pos
/ tabSize
) + 1) * tabSize
;
543 static void CreateIndentation(char *linebuf
, int length
, int indent
, int tabSize
, bool insertSpaces
) {
544 length
--; // ensure space for \0
546 while ((indent
>= tabSize
) && (length
> 0)) {
552 while ((indent
> 0) && (length
> 0)) {
560 int Document::GetLineIndentation(int line
) {
562 if ((line
>= 0) && (line
< LinesTotal())) {
563 int lineStart
= LineStart(line
);
564 int length
= Length();
565 for (int i
=lineStart
;i
<length
;i
++) {
566 char ch
= cb
.CharAt(i
);
570 indent
= NextTab(indent
, tabInChars
);
578 void Document::SetLineIndentation(int line
, int indent
) {
579 int indentOfLine
= GetLineIndentation(line
);
582 if (indent
!= indentOfLine
) {
584 CreateIndentation(linebuf
, sizeof(linebuf
), indent
, tabInChars
, !useTabs
);
585 int thisLineStart
= LineStart(line
);
586 int indentPos
= GetLineIndentPosition(line
);
587 DeleteChars(thisLineStart
, indentPos
- thisLineStart
);
588 InsertString(thisLineStart
, linebuf
);
592 int Document::GetLineIndentPosition(int line
) {
593 int pos
= LineStart(line
);
594 int length
= Length();
595 while ((pos
< length
) && isindentchar(cb
.CharAt(pos
))) {
601 void Document::Indent(bool forwards
, int lineBottom
, int lineTop
) {
602 // Dedent - suck white space off the front of the line to dedent by equivalent of a tab
603 for (int line
= lineBottom
; line
>= lineTop
; line
--) {
604 int indentOfLine
= GetLineIndentation(line
);
606 SetLineIndentation(line
, indentOfLine
+ IndentSize());
608 SetLineIndentation(line
, indentOfLine
- IndentSize());
612 void Document::ConvertLineEnds(int eolModeSet
) {
614 for (int pos
= 0; pos
< Length(); pos
++) {
615 if (cb
.CharAt(pos
) == '\r') {
616 if (cb
.CharAt(pos
+1) == '\n') {
617 if (eolModeSet
!= SC_EOL_CRLF
) {
619 if (eolModeSet
== SC_EOL_CR
)
620 InsertString(pos
, "\r", 1);
622 InsertString(pos
, "\n", 1);
627 if (eolModeSet
!= SC_EOL_CR
) {
629 if (eolModeSet
== SC_EOL_CRLF
) {
630 InsertString(pos
, "\r\n", 2);
633 InsertString(pos
, "\n", 1);
637 } else if (cb
.CharAt(pos
) == '\n') {
638 if (eolModeSet
!= SC_EOL_LF
) {
640 if (eolModeSet
== SC_EOL_CRLF
) {
641 InsertString(pos
, "\r\n", 2);
644 InsertString(pos
, "\r", 1);
652 bool Document::IsWordChar(unsigned char ch
) {
653 if ((SC_CP_UTF8
== dbcsCodePage
) && (ch
>0x80))
655 return wordchars
[ch
];
658 int Document::ExtendWordSelect(int pos
, int delta
) {
660 while (pos
> 0 && IsWordChar(cb
.CharAt(pos
- 1)))
663 while (pos
< (Length()) && IsWordChar(cb
.CharAt(pos
)))
669 int Document::NextWordStart(int pos
, int delta
) {
671 while (pos
> 0 && (cb
.CharAt(pos
- 1) == ' ' || cb
.CharAt(pos
- 1) == '\t'))
673 if (isspace(cb
.CharAt(pos
- 1))) { // Back up to previous line
674 while (pos
> 0 && isspace(cb
.CharAt(pos
- 1)))
677 bool startAtWordChar
= IsWordChar(cb
.CharAt(pos
- 1));
678 while (pos
> 0 && !isspace(cb
.CharAt(pos
- 1)) && (startAtWordChar
== IsWordChar(cb
.CharAt(pos
- 1))))
682 bool startAtWordChar
= IsWordChar(cb
.CharAt(pos
));
683 while (pos
< (Length()) && isspace(cb
.CharAt(pos
)))
685 while (pos
< (Length()) && !isspace(cb
.CharAt(pos
)) && (startAtWordChar
== IsWordChar(cb
.CharAt(pos
))))
687 while (pos
< (Length()) && (cb
.CharAt(pos
) == ' ' || cb
.CharAt(pos
) == '\t'))
693 bool Document::IsWordAt(int start
, int end
) {
694 int lengthDoc
= Length();
696 char ch
= CharAt(start
- 1);
700 if (end
< lengthDoc
- 1) {
701 char ch
= CharAt(end
);
708 // Find text in document, supporting both forward and backward
709 // searches (just pass minPos > maxPos to do a backward search)
710 // Has not been tested with backwards DBCS searches yet.
711 long Document::FindText(int minPos
, int maxPos
, const char *s
, bool caseSensitive
, bool word
) {
712 bool forward
= minPos
<= maxPos
;
713 int increment
= forward
? 1 : -1;
715 // Range endpoints should not be inside DBCS characters, but just in case, move them.
716 int startPos
= MovePositionOutsideChar(minPos
, increment
, false);
717 int endPos
= MovePositionOutsideChar(maxPos
, increment
, false);
719 // Compute actual search ranges needed
720 int lengthFind
= strlen(s
);
721 int endSearch
= endPos
;
722 if (startPos
<= endPos
) {
723 endSearch
= endPos
- lengthFind
+ 1;
725 //Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind);
726 char firstChar
= s
[0];
728 firstChar
= static_cast<char>(toupper(firstChar
));
730 while (forward
? (pos
< endSearch
) : (pos
>= endSearch
)) {
731 char ch
= CharAt(pos
);
733 if (ch
== firstChar
) {
735 for (int posMatch
= 1; posMatch
< lengthFind
&& found
; posMatch
++) {
736 ch
= CharAt(pos
+ posMatch
);
737 if (ch
!= s
[posMatch
])
741 if ((!word
) || IsWordAt(pos
, pos
+ lengthFind
))
746 if (toupper(ch
) == firstChar
) {
748 for (int posMatch
= 1; posMatch
< lengthFind
&& found
; posMatch
++) {
749 ch
= CharAt(pos
+ posMatch
);
750 if (toupper(ch
) != toupper(s
[posMatch
]))
754 if ((!word
) || IsWordAt(pos
, pos
+ lengthFind
))
761 // Ensure trying to match from start of character
762 pos
= MovePositionOutsideChar(pos
, increment
, false);
765 //Platform::DebugPrintf("Not found\n");
769 int Document::LinesTotal() {
773 void Document::ChangeCase(Range r
, bool makeUpperCase
) {
774 for (int pos
=r
.start
; pos
<r
.end
; pos
++) {
775 char ch
= CharAt(pos
);
776 if (dbcsCodePage
&& IsDBCS(pos
)) {
781 ChangeChar(pos
, static_cast<char>(toupper(ch
)));
785 ChangeChar(pos
, static_cast<char>(tolower(ch
)));
792 void Document::SetWordChars(unsigned char *chars
) {
794 for (ch
= 0; ch
< 256; ch
++) {
795 wordchars
[ch
] = false;
799 wordchars
[*chars
] = true;
803 for (ch
= 0; ch
< 256; ch
++) {
804 wordchars
[ch
] = isalnum(ch
) || ch
== '_';
809 void Document::SetStylingBits(int bits
) {
812 for (int bit
=0; bit
<stylingBits
; bit
++) {
813 stylingBitsMask
<<= 1;
814 stylingBitsMask
|= 1;
818 void Document::StartStyling(int position
, char mask
) {
819 stylingPos
= position
;
823 void Document::SetStyleFor(int length
, char style
) {
824 if (enteredCount
== 0) {
826 int prevEndStyled
= endStyled
;
827 if (cb
.SetStyleFor(stylingPos
, length
, style
, stylingMask
)) {
828 DocModification
mh(SC_MOD_CHANGESTYLE
| SC_PERFORMED_USER
,
829 prevEndStyled
, length
);
832 stylingPos
+= length
;
833 endStyled
= stylingPos
;
838 void Document::SetStyles(int length
, char *styles
) {
839 if (enteredCount
== 0) {
841 int prevEndStyled
= endStyled
;
842 bool didChange
= false;
843 for (int iPos
= 0; iPos
< length
; iPos
++, stylingPos
++) {
844 if (cb
.SetStyleAt(stylingPos
, styles
[iPos
], stylingMask
)) {
848 endStyled
= stylingPos
;
850 DocModification
mh(SC_MOD_CHANGESTYLE
| SC_PERFORMED_USER
,
851 prevEndStyled
, endStyled
- prevEndStyled
);
858 bool Document::EnsureStyledTo(int pos
) {
859 // Ask the watchers to style, and stop as soon as one responds.
860 for (int i
= 0; pos
> GetEndStyled() && i
< lenWatchers
; i
++)
861 watchers
[i
].watcher
->NotifyStyleNeeded(this, watchers
[i
].userData
, pos
);
862 return pos
<= GetEndStyled();
865 bool Document::AddWatcher(DocWatcher
*watcher
, void *userData
) {
866 for (int i
= 0; i
< lenWatchers
; i
++) {
867 if ((watchers
[i
].watcher
== watcher
) &&
868 (watchers
[i
].userData
== userData
))
871 WatcherWithUserData
*pwNew
= new WatcherWithUserData
[lenWatchers
+ 1];
874 for (int j
= 0; j
< lenWatchers
; j
++)
875 pwNew
[j
] = watchers
[j
];
876 pwNew
[lenWatchers
].watcher
= watcher
;
877 pwNew
[lenWatchers
].userData
= userData
;
884 bool Document::RemoveWatcher(DocWatcher
*watcher
, void *userData
) {
885 for (int i
= 0; i
< lenWatchers
; i
++) {
886 if ((watchers
[i
].watcher
== watcher
) &&
887 (watchers
[i
].userData
== userData
)) {
888 if (lenWatchers
== 1) {
893 WatcherWithUserData
*pwNew
= new WatcherWithUserData
[lenWatchers
];
896 for (int j
= 0; j
< lenWatchers
- 1; j
++) {
897 pwNew
[j
] = (j
< i
) ? watchers
[j
] : watchers
[j
+ 1];
909 void Document::NotifyModifyAttempt() {
910 for (int i
= 0; i
< lenWatchers
; i
++) {
911 watchers
[i
].watcher
->NotifyModifyAttempt(this, watchers
[i
].userData
);
915 void Document::NotifySavePoint(bool atSavePoint
) {
916 for (int i
= 0; i
< lenWatchers
; i
++) {
917 watchers
[i
].watcher
->NotifySavePoint(this, watchers
[i
].userData
, atSavePoint
);
921 void Document::NotifyModified(DocModification mh
) {
922 for (int i
= 0; i
< lenWatchers
; i
++) {
923 watchers
[i
].watcher
->NotifyModified(this, mh
, watchers
[i
].userData
);