• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: "exponent" action in NSTextView subclass (SOLVED)
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


References: 
 >"exponent" action in NSTextView subclass (From: email@hidden)
 >Re: "exponent" action in NSTextView subclass (From: Martin Wierschin <email@hidden>)
 >Re: "exponent" action in NSTextView subclass (From: email@hidden)
 >Re: "exponent" action in NSTextView subclass (From: Douglas Davidson <email@hidden>)
 >Re: "exponent" action in NSTextView subclass (SOLVED) (From: email@hidden)

  • Prev by Date: Re: call scrollRangeToVisible in multi-threads cause application dead lock
  • Next by Date: Most elegant way to process command-line arguments in Cocoa?
  • Previous by thread: Re: "exponent" action in NSTextView subclass (SOLVED)
  • Next by thread: NSWindowController and nib owner in document-based app
  • Index(es):
    • Date
    • Thread