Re: text storage aggregator
Re: text storage aggregator
- Subject: Re: text storage aggregator
- From: Todd Ransom <email@hidden>
- Date: Thu, 23 Feb 2006 20:07:36 -0700
Martin,
Thanks for the reply. I don't think I was clear enough in my original
description of the problem. My text aggregator is not empty and the
text storage primitives are implemented using the contents ivar. I
can assign an array of text storage objects and bring it up just fine
read-only. As I make changes to the component text storage objects
those changes are reflected in the aggregator.
Your suggested design sidesteps the problem I am having because it
never needs to build a display string outside of the text storage
primitives. I may very well end up taking your advice, but I would
like to understand why the two methods in my original email do not
accomplish the same thing. The way I understand it I should be able
to make changes to the display string as long as they are followed by
calls to edited: range: changeInLength:. But I have not been able to
do so successfully.
Todd
On Feb 23, 2006, at 3:54 PM, Martin Wierschin wrote:
Hello Todd,
But when I use the second method I get a crash on the second edit
to one of the component text storage objects.
I suspect this is because your aggregator storage is basically
empty. The first call to edited will always pass a range of (0,0)
which is never unsafe. This issue with your second call is that
your parent class (NSTextStorage) may attempt to access characters/
attributes at the index "contentsLen" (or at least verify that they
can be accessed). If your aggregator subclass has not overridden
the primitive methods (eg: length,
attributesAtIndex:effectiveRange:, etc) the "contentsLen" index
will be out of bounds because your subclass is effectively empty
(eg: you have never inserted text into it, just your "contents" ivar).
In any case, unless you really need to copy all that data back and
forth between your constituent storages (eg: to do some special
transformations), I would suggest a different approach for your
aggregator. Simply override all the text storage primitives to call
through to your constituent storages, (warning: typed in Mail) eg:
- (NSDictionary*) attributesAtIndex:(unsigned)charIdx
effectiveRange:(NSRange*)effRngPtr
{
// ask the proper constituent storage for its attributes
NSTextStorage* subTs;
NSRange subRng = [self _convertGlobalRange:NSMakeRange(charIdx,0)
toSubTextStorage:&subTs];
NSRange subEffRng;
NSDictionary* attrs = [subTs attributesAtIndex:subRng.location
effectiveRange:&subEffRng];
// convert back to global coordinates if they need to know the
effective range
if( NULL != effRngPtr ) {
NSRange effRng = [self _convertSubRange:subEffRng
fromSubTextStorage:subTs];
*effRngPtr = effRng;
}
return attrs;
}
- (void) setAttributes:(NSDictionary*)attrs range:(NSRange)rng
{
unsigned at = rng.location, lim = NSMaxRange(rng);
while( at < lim ) {
NSTextStorage* subTs;
NSRange subRng = [self _convertGlobalRange:NSMakeRange(at, lim -
at) toSubTextStorage:&subTs];
[subTs setAttributes:attrs range:subRng];
at += subRng.length;
}
}
You'll need to define those mapping methods (eg:
_convertGlobalRange) and worry about editing notifications and all
that, but I think this approach will pay for its complexity with a
cleaner and more scalable design. One additional caveat: the -
string and -mutableString methods need to return a custom subclass
that knows how to talk to your aggregator.
Hopefully this gets you started. I think you'll find that the
Cocoa text system is largely a pleasure to work with once you get
your bearings. Cheers,
~Martin
_______________________________________________
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