]>
git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/Document.cxx
c883dd253f9a3bd1a5b65b6d0bd578e78fabefde
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 previous 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');
205 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
)
229 // PLAT_GTK or PLAT_WX
230 // TODO: support DBCS under GTK+ and WX
231 bool Document::IsDBCS(int) {
236 int Document::LenChar(int pos
) {
239 } else if (SC_CP_UTF8
== dbcsCodePage
) {
240 unsigned char ch
= static_cast<unsigned char>(cb
.CharAt(pos
));
244 if (ch
>= (0x80+0x40+0x20))
246 int lengthDoc
= Length();
247 if ((pos
+ len
) > lengthDoc
)
248 return lengthDoc
-pos
;
251 } else if (IsDBCS(pos
)) {
258 // Normalise a position so that it is not halfway through a two byte character.
259 // This can occur in two situations -
260 // When lines are terminated with \r\n pairs which should be treated as one character.
261 // When displaying DBCS text such as Japanese.
262 // If moving, move the position in the indicated direction.
263 int Document::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) {
264 //Platform::DebugPrintf("NoCRLF %d %d\n", pos, moveDir);
265 // If out of range, just return value - should be fixed up after
271 // Position 0 and Length() can not be between any two characters
277 // assert pos > 0 && pos < Length()
278 if (checkLineEnd
&& IsCrLf(pos
- 1)) {
285 // Not between CR and LF
289 if (SC_CP_UTF8
== dbcsCodePage
) {
290 unsigned char ch
= static_cast<unsigned char>(cb
.CharAt(pos
));
291 while ((pos
> 0) && (pos
< Length()) && (ch
>= 0x80) && (ch
< (0x80 + 0x40))) {
292 // ch is a trail byte
297 ch
= static_cast<unsigned char>(cb
.CharAt(pos
));
300 // Anchor DBCS calculations at start of line because start of line can
301 // not be a DBCS trail byte.
303 while (startLine
> 0 && cb
.CharAt(startLine
) != '\r' && cb
.CharAt(startLine
) != '\n')
305 bool atLeadByte
= false;
306 while (startLine
< pos
) {
309 else if (IsDBCSLeadByteEx(dbcsCodePage
, cb
.CharAt(startLine
)))
314 //Platform::DebugPrintf("DBCS %s\n", atlead ? "D" : "-");
318 // Position is between a lead byte and a trail byte
331 void Document::ModifiedAt(int pos
) {
336 // Document only modified by gateways DeleteChars, InsertStyledString, Undo, Redo, and SetStyleAt.
337 // SetStyleAt does not change the persistent state of a document
339 // Unlike Undo, Redo, and InsertStyledString, the pos argument is a cell number not a char number
340 void Document::DeleteChars(int pos
, int len
) {
341 if ((pos
+ len
) > Length())
343 if (cb
.IsReadOnly() && enteredReadOnlyCount
==0) {
344 enteredReadOnlyCount
++;
345 NotifyModifyAttempt();
346 enteredReadOnlyCount
--;
348 if (enteredCount
== 0) {
350 if (!cb
.IsReadOnly()) {
353 SC_MOD_BEFOREDELETE
| SC_PERFORMED_USER
,
356 int prevLinesTotal
= LinesTotal();
357 bool startSavePoint
= cb
.IsSavePoint();
358 const char *text
= cb
.DeleteChars(pos
*2, len
* 2);
359 if (startSavePoint
&& cb
.IsCollectingUndo())
360 NotifySavePoint(!startSavePoint
);
364 SC_MOD_DELETETEXT
| SC_PERFORMED_USER
,
366 LinesTotal() - prevLinesTotal
, text
));
372 void Document::InsertStyledString(int position
, char *s
, int insertLength
) {
373 if (cb
.IsReadOnly() && enteredReadOnlyCount
==0) {
374 enteredReadOnlyCount
++;
375 NotifyModifyAttempt();
376 enteredReadOnlyCount
--;
378 if (enteredCount
== 0) {
380 if (!cb
.IsReadOnly()) {
383 SC_MOD_BEFOREINSERT
| SC_PERFORMED_USER
,
384 position
/ 2, insertLength
/ 2,
386 int prevLinesTotal
= LinesTotal();
387 bool startSavePoint
= cb
.IsSavePoint();
388 const char *text
= cb
.InsertString(position
, s
, insertLength
);
389 if (startSavePoint
&& cb
.IsCollectingUndo())
390 NotifySavePoint(!startSavePoint
);
391 ModifiedAt(position
/ 2);
394 SC_MOD_INSERTTEXT
| SC_PERFORMED_USER
,
395 position
/ 2, insertLength
/ 2,
396 LinesTotal() - prevLinesTotal
, text
));
402 int Document::Undo() {
404 if (enteredCount
== 0) {
406 bool startSavePoint
= cb
.IsSavePoint();
407 int steps
= cb
.StartUndo();
408 //Platform::DebugPrintf("Steps=%d\n", steps);
409 for (int step
=0; step
<steps
; step
++) {
410 int prevLinesTotal
= LinesTotal();
411 const Action
&action
= cb
.GetUndoStep();
412 if (action
.at
== removeAction
) {
413 NotifyModified(DocModification(
414 SC_MOD_BEFOREINSERT
| SC_PERFORMED_UNDO
, action
));
416 NotifyModified(DocModification(
417 SC_MOD_BEFOREDELETE
| SC_PERFORMED_UNDO
, action
));
419 cb
.PerformUndoStep();
420 int cellPosition
= action
.position
/ 2;
421 ModifiedAt(cellPosition
);
422 newPos
= cellPosition
;
424 int modFlags
= SC_PERFORMED_UNDO
;
425 // With undo, an insertion action becomes a deletion notification
426 if (action
.at
== removeAction
) {
427 newPos
+= action
.lenData
;
428 modFlags
|= SC_MOD_INSERTTEXT
;
430 modFlags
|= SC_MOD_DELETETEXT
;
433 modFlags
|= SC_LASTSTEPINUNDOREDO
;
434 NotifyModified(DocModification(modFlags
, cellPosition
, action
.lenData
,
435 LinesTotal() - prevLinesTotal
, action
.data
));
438 bool endSavePoint
= cb
.IsSavePoint();
439 if (startSavePoint
!= endSavePoint
)
440 NotifySavePoint(endSavePoint
);
446 int Document::Redo() {
448 if (enteredCount
== 0) {
450 bool startSavePoint
= cb
.IsSavePoint();
451 int steps
= cb
.StartRedo();
452 for (int step
=0; step
<steps
; step
++) {
453 int prevLinesTotal
= LinesTotal();
454 const Action
&action
= cb
.GetRedoStep();
455 if (action
.at
== insertAction
) {
456 NotifyModified(DocModification(
457 SC_MOD_BEFOREINSERT
| SC_PERFORMED_REDO
, action
));
459 NotifyModified(DocModification(
460 SC_MOD_BEFOREDELETE
| SC_PERFORMED_REDO
, action
));
462 cb
.PerformRedoStep();
463 ModifiedAt(action
.position
/ 2);
464 newPos
= action
.position
/ 2;
466 int modFlags
= SC_PERFORMED_REDO
;
467 if (action
.at
== insertAction
) {
468 newPos
+= action
.lenData
;
469 modFlags
|= SC_MOD_INSERTTEXT
;
471 modFlags
|= SC_MOD_DELETETEXT
;
474 modFlags
|= SC_LASTSTEPINUNDOREDO
;
476 DocModification(modFlags
, action
.position
/ 2, action
.lenData
,
477 LinesTotal() - prevLinesTotal
, action
.data
));
480 bool endSavePoint
= cb
.IsSavePoint();
481 if (startSavePoint
!= endSavePoint
)
482 NotifySavePoint(endSavePoint
);
488 void Document::InsertChar(int pos
, char ch
) {
492 InsertStyledString(pos
*2, chs
, 2);
495 // Insert a null terminated string
496 void Document::InsertString(int position
, const char *s
) {
497 InsertString(position
, s
, strlen(s
));
500 // Insert a string with a length
501 void Document::InsertString(int position
, const char *s
, int insertLength
) {
502 char *sWithStyle
= new char[insertLength
* 2];
504 for (int i
= 0; i
< insertLength
; i
++) {
505 sWithStyle
[i
*2] = s
[i
];
506 sWithStyle
[i
*2 + 1] = 0;
508 InsertStyledString(position
*2, sWithStyle
, insertLength
*2);
513 void Document::ChangeChar(int pos
, char ch
) {
518 void Document::DelChar(int pos
) {
519 DeleteChars(pos
, LenChar(pos
));
522 int Document::DelCharBack(int pos
) {
525 } else if (IsCrLf(pos
- 2)) {
526 DeleteChars(pos
- 2, 2);
528 } else if (SC_CP_UTF8
== dbcsCodePage
) {
529 int startChar
= MovePositionOutsideChar(pos
-1, -1, false);
530 DeleteChars(startChar
, pos
- startChar
);
532 } else if (IsDBCS(pos
- 1)) {
533 DeleteChars(pos
- 2, 2);
536 DeleteChars(pos
- 1, 1);
541 static bool isindentchar(char ch
) {
542 return (ch
== ' ') || (ch
== '\t');
545 static int NextTab(int pos
, int tabSize
) {
546 return ((pos
/ tabSize
) + 1) * tabSize
;
549 static void CreateIndentation(char *linebuf
, int length
, int indent
, int tabSize
, bool insertSpaces
) {
550 length
--; // ensure space for \0
552 while ((indent
>= tabSize
) && (length
> 0)) {
558 while ((indent
> 0) && (length
> 0)) {
566 int Document::GetLineIndentation(int line
) {
568 if ((line
>= 0) && (line
< LinesTotal())) {
569 int lineStart
= LineStart(line
);
570 int length
= Length();
571 for (int i
=lineStart
;i
<length
;i
++) {
572 char ch
= cb
.CharAt(i
);
576 indent
= NextTab(indent
, tabInChars
);
584 void Document::SetLineIndentation(int line
, int indent
) {
585 int indentOfLine
= GetLineIndentation(line
);
588 if (indent
!= indentOfLine
) {
590 CreateIndentation(linebuf
, sizeof(linebuf
), indent
, tabInChars
, !useTabs
);
591 int thisLineStart
= LineStart(line
);
592 int indentPos
= GetLineIndentPosition(line
);
593 DeleteChars(thisLineStart
, indentPos
- thisLineStart
);
594 InsertString(thisLineStart
, linebuf
);
598 int Document::GetLineIndentPosition(int line
) {
601 int pos
= LineStart(line
);
602 int length
= Length();
603 while ((pos
< length
) && isindentchar(cb
.CharAt(pos
))) {
609 int Document::GetColumn(int pos
) {
611 int line
= LineFromPosition(pos
);
612 if ((line
>= 0) && (line
< LinesTotal())) {
613 for (int i
=LineStart(line
);i
<pos
;i
++) {
614 char ch
= cb
.CharAt(i
);
616 column
= NextTab(column
, tabInChars
);
628 void Document::Indent(bool forwards
, int lineBottom
, int lineTop
) {
629 // Dedent - suck white space off the front of the line to dedent by equivalent of a tab
630 for (int line
= lineBottom
; line
>= lineTop
; line
--) {
631 int indentOfLine
= GetLineIndentation(line
);
633 SetLineIndentation(line
, indentOfLine
+ IndentSize());
635 SetLineIndentation(line
, indentOfLine
- IndentSize());
639 void Document::ConvertLineEnds(int eolModeSet
) {
641 for (int pos
= 0; pos
< Length(); pos
++) {
642 if (cb
.CharAt(pos
) == '\r') {
643 if (cb
.CharAt(pos
+1) == '\n') {
644 if (eolModeSet
!= SC_EOL_CRLF
) {
646 if (eolModeSet
== SC_EOL_CR
)
647 InsertString(pos
, "\r", 1);
649 InsertString(pos
, "\n", 1);
654 if (eolModeSet
!= SC_EOL_CR
) {
656 if (eolModeSet
== SC_EOL_CRLF
) {
657 InsertString(pos
, "\r\n", 2);
660 InsertString(pos
, "\n", 1);
664 } else if (cb
.CharAt(pos
) == '\n') {
665 if (eolModeSet
!= SC_EOL_LF
) {
667 if (eolModeSet
== SC_EOL_CRLF
) {
668 InsertString(pos
, "\r\n", 2);
671 InsertString(pos
, "\r", 1);
679 bool Document::IsWordChar(unsigned char ch
) {
680 if ((SC_CP_UTF8
== dbcsCodePage
) && (ch
>0x80))
682 return wordchars
[ch
];
685 int Document::ExtendWordSelect(int pos
, int delta
) {
687 while (pos
> 0 && IsWordChar(cb
.CharAt(pos
- 1)))
690 while (pos
< (Length()) && IsWordChar(cb
.CharAt(pos
)))
696 int Document::NextWordStart(int pos
, int delta
) {
698 while (pos
> 0 && (cb
.CharAt(pos
- 1) == ' ' || cb
.CharAt(pos
- 1) == '\t'))
700 if (isspace(cb
.CharAt(pos
- 1))) { // Back up to previous line
701 while (pos
> 0 && isspace(cb
.CharAt(pos
- 1)))
704 bool startAtWordChar
= IsWordChar(cb
.CharAt(pos
- 1));
705 while (pos
> 0 && !isspace(cb
.CharAt(pos
- 1)) && (startAtWordChar
== IsWordChar(cb
.CharAt(pos
- 1))))
709 bool startAtWordChar
= IsWordChar(cb
.CharAt(pos
));
710 while (pos
< (Length()) && isspace(cb
.CharAt(pos
)))
712 while (pos
< (Length()) && !isspace(cb
.CharAt(pos
)) && (startAtWordChar
== IsWordChar(cb
.CharAt(pos
))))
714 while (pos
< (Length()) && (cb
.CharAt(pos
) == ' ' || cb
.CharAt(pos
) == '\t'))
720 bool Document::IsWordStartAt(int pos
) {
722 return !IsWordChar(CharAt(pos
- 1));
727 bool Document::IsWordEndAt(int pos
) {
728 if (pos
< Length() - 1) {
729 return !IsWordChar(CharAt(pos
));
734 bool Document::IsWordAt(int start
, int end
) {
735 return IsWordStartAt(start
) && IsWordEndAt(end
);
738 // Find text in document, supporting both forward and backward
739 // searches (just pass minPos > maxPos to do a backward search)
740 // Has not been tested with backwards DBCS searches yet.
741 long Document::FindText(int minPos
, int maxPos
, const char *s
,
742 bool caseSensitive
, bool word
, bool wordStart
) {
743 bool forward
= minPos
<= maxPos
;
744 int increment
= forward
? 1 : -1;
746 // Range endpoints should not be inside DBCS characters, but just in case, move them.
747 int startPos
= MovePositionOutsideChar(minPos
, increment
, false);
748 int endPos
= MovePositionOutsideChar(maxPos
, increment
, false);
750 // Compute actual search ranges needed
751 int lengthFind
= strlen(s
);
752 int endSearch
= endPos
;
753 if (startPos
<= endPos
) {
754 endSearch
= endPos
- lengthFind
+ 1;
756 //Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind);
757 char firstChar
= s
[0];
759 firstChar
= static_cast<char>(toupper(firstChar
));
761 while (forward
? (pos
< endSearch
) : (pos
>= endSearch
)) {
762 char ch
= CharAt(pos
);
764 if (ch
== firstChar
) {
766 for (int posMatch
= 1; posMatch
< lengthFind
&& found
; posMatch
++) {
767 ch
= CharAt(pos
+ posMatch
);
768 if (ch
!= s
[posMatch
])
772 if ((!word
&& !wordStart
) ||
773 word
&& IsWordAt(pos
, pos
+ lengthFind
) ||
774 wordStart
&& IsWordStartAt(pos
))
779 if (toupper(ch
) == firstChar
) {
781 for (int posMatch
= 1; posMatch
< lengthFind
&& found
; posMatch
++) {
782 ch
= CharAt(pos
+ posMatch
);
783 if (toupper(ch
) != toupper(s
[posMatch
]))
787 if (!(word
&& wordStart
) ||
788 word
&& IsWordAt(pos
, pos
+ lengthFind
) ||
789 wordStart
&& IsWordStartAt(pos
))
796 // Ensure trying to match from start of character
797 pos
= MovePositionOutsideChar(pos
, increment
, false);
800 //Platform::DebugPrintf("Not found\n");
804 int Document::LinesTotal() {
808 void Document::ChangeCase(Range r
, bool makeUpperCase
) {
809 for (int pos
=r
.start
; pos
<r
.end
; pos
++) {
810 char ch
= CharAt(pos
);
811 if (dbcsCodePage
&& IsDBCS(pos
)) {
816 ChangeChar(pos
, static_cast<char>(toupper(ch
)));
820 ChangeChar(pos
, static_cast<char>(tolower(ch
)));
827 void Document::SetWordChars(unsigned char *chars
) {
829 for (ch
= 0; ch
< 256; ch
++) {
830 wordchars
[ch
] = false;
834 wordchars
[*chars
] = true;
838 for (ch
= 0; ch
< 256; ch
++) {
839 wordchars
[ch
] = isalnum(ch
) || ch
== '_';
844 void Document::SetStylingBits(int bits
) {
847 for (int bit
=0; bit
<stylingBits
; bit
++) {
848 stylingBitsMask
<<= 1;
849 stylingBitsMask
|= 1;
853 void Document::StartStyling(int position
, char mask
) {
854 stylingPos
= position
;
858 void Document::SetStyleFor(int length
, char style
) {
859 if (enteredCount
== 0) {
861 int prevEndStyled
= endStyled
;
862 if (cb
.SetStyleFor(stylingPos
, length
, style
, stylingMask
)) {
863 DocModification
mh(SC_MOD_CHANGESTYLE
| SC_PERFORMED_USER
,
864 prevEndStyled
, length
);
867 stylingPos
+= length
;
868 endStyled
= stylingPos
;
873 void Document::SetStyles(int length
, char *styles
) {
874 if (enteredCount
== 0) {
876 int prevEndStyled
= endStyled
;
877 bool didChange
= false;
878 for (int iPos
= 0; iPos
< length
; iPos
++, stylingPos
++) {
879 if (cb
.SetStyleAt(stylingPos
, styles
[iPos
], stylingMask
)) {
883 endStyled
= stylingPos
;
885 DocModification
mh(SC_MOD_CHANGESTYLE
| SC_PERFORMED_USER
,
886 prevEndStyled
, endStyled
- prevEndStyled
);
893 bool Document::EnsureStyledTo(int pos
) {
894 // Ask the watchers to style, and stop as soon as one responds.
895 for (int i
= 0; pos
> GetEndStyled() && i
< lenWatchers
; i
++)
896 watchers
[i
].watcher
->NotifyStyleNeeded(this, watchers
[i
].userData
, pos
);
897 return pos
<= GetEndStyled();
900 bool Document::AddWatcher(DocWatcher
*watcher
, void *userData
) {
901 for (int i
= 0; i
< lenWatchers
; i
++) {
902 if ((watchers
[i
].watcher
== watcher
) &&
903 (watchers
[i
].userData
== userData
))
906 WatcherWithUserData
*pwNew
= new WatcherWithUserData
[lenWatchers
+ 1];
909 for (int j
= 0; j
< lenWatchers
; j
++)
910 pwNew
[j
] = watchers
[j
];
911 pwNew
[lenWatchers
].watcher
= watcher
;
912 pwNew
[lenWatchers
].userData
= userData
;
919 bool Document::RemoveWatcher(DocWatcher
*watcher
, void *userData
) {
920 for (int i
= 0; i
< lenWatchers
; i
++) {
921 if ((watchers
[i
].watcher
== watcher
) &&
922 (watchers
[i
].userData
== userData
)) {
923 if (lenWatchers
== 1) {
928 WatcherWithUserData
*pwNew
= new WatcherWithUserData
[lenWatchers
];
931 for (int j
= 0; j
< lenWatchers
- 1; j
++) {
932 pwNew
[j
] = (j
< i
) ? watchers
[j
] : watchers
[j
+ 1];
944 void Document::NotifyModifyAttempt() {
945 for (int i
= 0; i
< lenWatchers
; i
++) {
946 watchers
[i
].watcher
->NotifyModifyAttempt(this, watchers
[i
].userData
);
950 void Document::NotifySavePoint(bool atSavePoint
) {
951 for (int i
= 0; i
< lenWatchers
; i
++) {
952 watchers
[i
].watcher
->NotifySavePoint(this, watchers
[i
].userData
, atSavePoint
);
956 void Document::NotifyModified(DocModification mh
) {
957 for (int i
= 0; i
< lenWatchers
; i
++) {
958 watchers
[i
].watcher
->NotifyModified(this, mh
, watchers
[i
].userData
);