Re: A Thousand Newbie Questions...
Re: A Thousand Newbie Questions...
- Subject: Re: A Thousand Newbie Questions...
- From: Douglas Davidson <email@hidden>
- Date: Mon, 8 Oct 2001 12:10:30 -0700
On Sunday, October 7, 2001, at 09:56 PM, email@hidden wrote:
Next, I figured I could just subclass NSTextView, and override some
it's methods, creating, in effect an NSCodeView, that could be re-used
by anyone ( god love open-source ). I've created several of those
stupid text editors described in a hundred tutorials, but I'm failing
to see a way to send the NSTextView a formatting command. I looked at
ProjectCenter ( a GNUStep application) source, and they seem to be
doing something really strange with NSScanner and a textView, but this
doesn't seem like it would be the way to go.
Charles Jolley responded with an excellent summary of attributes on text
in Cocoa, so I won't repeat any of that here. That should get you
through taking some text, and some set of rules, and coloring the text
based on those rules. Here I want to discuss a different question:
once you have the text colored and displayed in a text view, if you then
let the user loose to go ahead and edit it, how do you keep the coloring
up to date?
There are a number of different ways you could do this. Probably the
least invasive way of hooking into the text system to do this would be
to act as your NSTextView's delegate. You will then get a message,
- (BOOL)textView:(NSTextView *)textView
shouldChangeTextInRange:(NSRange)affectedCharRange
replacementString:(NSString *)replacementString;
// Delegate only. If characters are changing, replacementString is
what will replace the affectedCharRange. If attributes only are
changing, replacementString will be nil.
whenever the user changes the text, by one means or another. That
should give you enough information to figure out what has changed, and
to redo your coloring, potentially limiting your calculations to the
minimum necessary. Note that you will get this call before the change
actually takes place, and you have the opportunity to veto it by
returning NO if you like. After the change takes place, you will get
- (void)textDidChange:(NSNotification *)notification; /* Any keyDown or
paste which changes the contents causes this */
(defined in the superclass, in NSText.h).
If you are doing with with an NSTextView subclass, on the other hand,
you can override the methods
- (BOOL)shouldChangeTextInRange:(NSRange)affectedCharRange
replacementString:(NSString *)replacementString;
- (void)didChangeText;
to hook in at the same places. Keep in mind that these methods are
called whenever the user does something that causes the text to change;
if some other piece of code programmatically changes the text, they will
not be called.
If you want to find out whenever the text changes, by whatever means,
you could work at a lower level--for example, with NSLayoutManager or
NSTextStorage. NSTextStorage is a mutable attributed string subclass
that has the additional feature of notifying whenever it changes. The
text storage's delegate will get
- (void)textStorageWillProcessEditing:(NSNotification *)notification; /* Delegate
can change the characters or attributes */
- (void)textStorageDidProcessEditing:(NSNotification *)notification; /* Delegate
can change the attributes */
whenever the text storage changes--you can determine what is changing
with editedMask, editedRange, and changeInLength. Others can register
for the NSTextStorageWillProcessEditingNotification or
NSTextStorageDidProcessEditingNotification to do the same thing--see
TextEdit for an example.
A layout manager will get
- (void)textStorage:(NSTextStorage *)str edited:(unsigned)editedMask
range:(NSRange)newCharRange changeInLength:(int)delta
invalidatedRange:(NSRange)invalidatedCharRange;
// Sent from processEditing in NSTextStorage. newCharRange is the
range in the final string which was explicitly edited. invalidatedRange
includes stuff which was changed as a result of attribute fixing.
invalidatedRange is either equal to newCharRange or larger. Layout
managers should not change the contents of the text storage during the
execution of this message.
when its text storage changes. The layout manager should not change the
text storage itself, but it could certainly set temporary attributes on
itself.
Douglas Davidson