Re: Advice on restricting/monitoring character input in NSTextView
Re: Advice on restricting/monitoring character input in NSTextView
- Subject: Re: Advice on restricting/monitoring character input in NSTextView
- From: Keith Blount <email@hidden>
- Date: Tue, 7 Feb 2006 13:58:09 -0800 (PST)
Hmm, the more I think about, the more I think you're
right - a subclass might be the best way after all. I
have subclassed NSTextView quite extensively for my
own app, and I do in fact modify text as it is pasted
in by overriding the pasteboard methods. What you will
need to do is override
-readSelectionFromPasteboard:type: and handle all the
types your app reads yourself. Read them from the
pasteboard, modify the strings, then insert the
modified text into the text view's text storage
yourself. Once you've modified the (attributed)
string, make sure you insert it along these lines:
if ([self shouldChangeTextInRange:[self
rangeForUserTextChange]
replacementString:[modifiedAttributedStr string]])
{
[[self textStorage] replaceCharactersInRange:[self
rangeForUserTextChange]
withAttributedString:modifiedAttributedString];
[self didChangeText];
return YES;
}
else
return NO;
This will ensure that undo still works as usual and
your user can undo/redo the paste - all your changes
will be transparent (sorry if this is obvious
already).
(Be aware that overriding the pasteboard methods can
result in slightly different behaviour than the
default when pasting into tables and lists, because of
some private stuff that NSTextView does - search the
forums for a recent post by myself on this, in which
Douglas Davidson, one of the Apple text gurus,
explained the reasons why.)
All the stuff discussed about restricting user input
through typing would still apply, only instead of
using the delegate method, you would override the text
view's -shouldChangeTextInRanges:replacementStrings:
method directly (making sure you return super's method
if you allow the change).
That way you should be able to handle both user input
and pasting. The only tricky part left will be parsing
through your string and modifying it within the
pasteboard method, but like I say, using
-rangeOfString:... should do for that, so it shouldn't
be too hard.
Hope that helps.
Cheers,
Keith
P.S. If you are implementing smart quotes, let me know
- I modified Andrew Stone's code and put it in my
subclass, and made some improvements to it. I'd be
more than happy to share that code with you to save
you time.
--- Scott Lehman <email@hidden> wrote:
> It was the need to process strings longer than one
> character from the pasteboard that led me to look
> beyond the delegate methods - I want to modify
> rather
> than disallow input. I've been trying what you
> outlined below (I am doing rich text), but am
> failing
> to get it to play nicely with undo. I can get the
> appearance of proper functionality by querying the
> state of the undo manager, but still raise out of
> bounds exceptions.
>
> It looks like modifying the string that late in the
> game poses issues when dealing with undo since the
> original string is already registered. I bet it's
> still possible, but at this point, I'm thinking
> there
> has to be a better solution.
>
> I want undo, so is there an easy way to modify text
> input before the actions that are registered with
> the
> undo manager?
>
> That makes me think an NSTextView subclass might be
> best, but I haven't pieced together precisely how
> the
> input flows thru it yet, or if there are new issues
> when subclassing it.
>
> Thanks,
>
> Scott
>
> PS - Thanks for the tip on the Smart Quotes article.
>
> That is something I will deal with, and
> indidentally,
> his method for inserting processed strings goes
> direct
> to the text storage, bypassing undo .
>
> --- Keith Blount <email@hidden> wrote:
>
> > You shouldn't need to subclass for this - you were
> > on
> > the right track in the first place.
> >
> > The delegate method
> >
>
-textView:shouldChangeTextInRanges:replacementStrings:
> > (or you can use the singular version for pre-Tiger
> > or
> > text views that don't allow multiple selection)
> will
> > get called before undo gets set up. So if you
> > restrict
> > input there, all that will happen is that whenever
> > the
> > user tries to type something restricted, you have
> > this
> > method return NO and nothing will happen when the
> > user
> > types (or you can provide an NSBeep() or a message
> > or
> > whatever you want within that method.
> >
> > This method will also get called whenever you try
> to
> > paste anything into your text view. This is
> probably
> > the sort of thing you want (note that I haven't
> > tested
> > this code so there may be errors in it - it was
> just
> > a
> > quick effort and can definitely be improved):
> >
> > -- code snipped for message size --
> >
> > That should deal with preventing the user from
> > typing
> > consecutive spaces or tabs. Dealing with a paste
> of
> > multiple characters is more difficult. In that
> case,
> > you will need to parse through the string being
> > pasted, looking for restricted characters.
> > NSString's
> > -rangeOfString:options:range: would probably be
> best
> > for this, although you could also look at
> NSScanner.
> > The trouble is, what to do if there is a
> restricted
> > character? You could return NO and disallow the
> > paste
> > entirely, which would be by far the simplest
> > solution.
> > Otherwise, things get tricky. If your text view is
> > plain text only, it's not too difficult. You would
> > just modify the new string and place it in the
> text
> > view yourself, still returning NO to the method.
> > (This
> > is because, unfortunately, the above method allows
> > you
> > to stop the new string getting entered, but it
> > doesn't
> > allow you to modify the actual string unless you
> > insert it yourself.) Google for Andrew Stone's
> > tutorial on smart quotes for handling this
> manually.
> > If you have a rich text view, it's more tricky. In
> > that case, you would probably want to save the
> range
> > of text that has been changed in the above method
> > (NSMakeRange(affectedRange.location, [newString
> > length]) ), and then examine and change that range
> > in
> > -textDidChange:, once the text has been inserted
> > into
> > the text view. The user might be able to undo back
> > to
> > a state you don't want in that case, though.
> >
> > Hope that helps,
> > Keith
> >
> > --- ORIGINAL MESSAGE ---
> >
> > From: Scott Lehman
> > Subject: Re: Advice on restricting/monitoring
> > character input in
> > NSTextView
> > To: Keith Wilson
> > Cc: email@hidden
> > Message-ID:
> >
>
<email@hidden>
> > Content-Type: text/plain; charset=iso-8859-1
> >
> > Well I have to confess that I'm not sure what to
> do
> > with that. I thought the docs state that the
> field
> > editor is for controls, which made sense to me -
> > having an NSTextView instance as a field editor
> for
> > an
> > NSTextView seems redundant and unecessary. Or is
> > it?
> >
> > I realize now that while the NSTextStorage
> delegate
> > may provide a nice hook, it poses problems for
> undo.
> >
> > If I filter out a key stroke, it should be before
> > the
> > action is registered for undo.
> >
> > So now I'm thinking subclassing NSTextView might
> be
> > the way to go. Is it as simple as:
> >
> > -Override insertText: to include
> > filtering/processing
> > (this covers both key press and pastes, correct?)
> > -Either call [super insertText:aString] with any
> > input
> > I want, or return immediately if I want to ignore
> it
> >
> > ?
> >
> > Thanks,
> >
> > Scott
>
>
>
> __________________________________________________
> Do You Yahoo!?
> Tired of spam? Yahoo! Mail has the best spam
> protection around
> http://mail.yahoo.com
>
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden