Re: "exponent" action in NSTextView subclass (SOLVED)
Re: "exponent" action in NSTextView subclass (SOLVED)
- Subject: Re: "exponent" action in NSTextView subclass (SOLVED)
- From: Douglas Davidson <email@hidden>
- Date: Wed, 7 Mar 2007 10:24:24 -0800
I don't want to sound harsh--you've made a good start, and this is a
rather involved subject--but there are still a few problems with your
code. I'd like to turn this into a mini-seminar on the subject of
user changes to text, and I'm also going to send this off to the
folks who manage the documentation in hopes that they can find a
place for this somewhere.
There are quite a few things that need to be done to handle a user
change to text in full generality and with everything taken care of.
You need to call a should-change method, and listen to the return
value, before making changes; then you need to call didChangeText
afterwards. You should call beginEditing before actually modifying
the text storage, and endEditing afterwards (unless you're making
only one modification, but that's rare). When you're actually
modifying the text storage, you usually need to iterate through by
effective ranges to deal with the existing attribute values (unless
you're just replacing them without regard to any existing values).
You should deal with multiple selections, which means an array of
ranges. You should get that array of ranges from
rangesForUserCharacterAttributeChange, rather than from
selectedRanges, so as not to change non-editable text views. You
should make the same modification to the typing attributes that you
do to the text attributes. Finally, you should set an appropriate
localized undo action name, so that the undo menu has a useful title.
At the bottom of this mail, I've enclosed an example of what your
exponent action might look like, with all of these things taken care
of. (This code hasn't been compiled and tested, so there may be some
typos, but the gist of it should be correct.)
Now, I realize that all of this is rather difficult--even if you
start with this example, it's hard to understand all of this code.
So, for that reason, we've also provided a simplified mechanism that
will handle most of this for you. All you have to do is provide
callbacks to do the specific change in attributes that you want.
The method to use in this simplified version is called
changeAttributes:, and it takes a "sender" argument. It does all of
the iteration through ranges and so forth, and for each set of
attributes that need changing, the sender will get a
convertAttributes: message, which takes the old attribute dictionary
and returns the new one. So to implement this, you will just need to
set up some state in some object so you will know what change you
want to make, implement a convertAttributes: method on that object,
and call changeAttributes: with that object as the sender. The only
thing this doesn't do for you is to set the undo action name (since
it doesn't know what name to use).
Here's what it might look like, if you have an NSTextView subclass
and use it as the sender:
-(IBAction)exponent:(id)sender {
changeType = exponentChangeType; // I'm assuming that changeType
is a new ivar in your subclass, and exponentChangeType is one of
perhaps many enumerated values, each one describing a different type
of change
[self changeAttributes:self];
[[self undoManager] setActionName:NSLocalizedString(@"Exponent",
@"Undo title for exponent action")];
}
- (NSDictionary *)convertAttributes:(NSDictionary *)oldAttributes {
NSMutableDictionary *newAttributes = [NSMutableDictionary
dictionaryWithDictionary:oldAttributes];
NSFont *font;
float fontSize;
if (changeType == exponentChangeType) {
font = [oldAttributes objectForKey:NSFontAttributeName];
if (!font) font = [NSFont fontWithName:@"Helvetica" size:
12.0]; // this is the default font
fontSize = [font pointSize] / 2.0;
font = [[NSFontManager sharedFontManager] convertFont:font
toSize:fontSize];
[newAttributes setObject:font forKey:NSFontAttributeName];
[newAttributes setObject:[NSNumber numberWithFloat:fontSize
- 2.0] forKey:NSBaselineOffsetAttributeName];
}
return newAttributes;
}
For comparison, here's what it might look like if you implemented it
yourself:
-(IBAction)exponent:(id)sender {
NSRange charRange = [self rangeForUserCharacterAttributeChange],
range, curCharRange;
NSArray *ranges = [self rangesForUserCharacterAttributeChange];
unsigned i, count = [ranges count], curCharIndex;
if (ranges && charRange.location != NSNotFound) {
NSTextStorage *text = [self textStorage];
NSFont *font;
float fontSize;
NSMutableDictionary *typingAttributes;
if (text && charRange.length > 0 && [self
shouldChangeTextInRanges:ranges replacementStrings:nil]) {
[text beginEditing];
for (i = 0; i < count; i++) {
range = [[ranges objectAtIndex:i] rangeValue];
curCharIndex = range.location;
while (NSLocationInRange(curCharIndex, range)) {
font = [text attribute:NSFontAttributeName
atIndex:curCharIndex longestEffectiveRange:&curCharRange inRange:range];
if (!font) font = [NSFont
fontWithName:@"Helvetica" size:12.0];
fontSize = [font pointSize] / 2.0;
font = [[NSFontManager sharedFontManager]
convertFont:font toSize:fontSize];
curCharRange = NSIntersectionRange(curCharRange,
range);
[text addAttribute:NSFontAttributeName
value:font range:curCharRange];
[text addAttribute:NSBaselineOffsetAttributeName
value:[NSNumber numberWithFloat:fontSize - 2.0] range:curCharRange];
curCharIndex = NSMaxRange(curCharRange);
}
}
[text endEditing];
[self didChangeText];
[[self undoManager] setActionName:NSLocalizedString
(@"Exponent", @"Undo title for exponent action")];
}
// Set typing attributes
typingAttributes = [NSMutableDictionary
dictionaryWithDictionary:[self typingAttributes]];
font = [typingAttributes objectForKey:NSFontAttributeName];
if (!font) font = [NSFont fontWithName:@"Helvetica" size:12.0];
fontSize = [font pointSize] / 2.0;
font = [[NSFontManager sharedFontManager] convertFont:font
toSize:fontSize];
[typingAttributes setObject:font forKey:NSFontAttributeName];
[typingAttributes setObject:[NSNumber
numberWithFloat:fontSize - 2.0] forKey:NSBaselineOffsetAttributeName];
[self setTypingAttributes:typingAttributes];
}
}
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden