2005-02-22 11:22:44 +00:00
|
|
|
|
/**
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSAttributedString.m
|
|
|
|
|
|
|
|
|
|
Implementation of string class with attributes
|
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
Copyright (C) 1997,1999 Free Software Foundation, Inc.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
Written by: ANOQ of the sun <anoq@vip.cybercity.dk>
|
1997-11-21 18:19:29 +00:00
|
|
|
|
Date: November 1997
|
1999-04-09 17:07:21 +00:00
|
|
|
|
Rewrite by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
|
Date: April 1999
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
This file is part of GNUstep-base
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
1997-09-01 21:59:51 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
|
|
If you are interested in a warranty or support for this source code,
|
|
|
|
|
contact Scott Christley <scottc@net-community.com> for more information.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
1997-09-01 21:59:51 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
2006-06-04 06:42:10 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
|
Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
|
|
<title>NSAttributedString class reference</title>
|
|
|
|
|
$Date$ $Revision$
|
1997-09-01 21:59:51 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
/* Warning - [-initWithString:attributes:] is the designated initialiser,
|
|
|
|
|
* but it doesn't provide any way to perform the function of the
|
|
|
|
|
* [-initWithAttributedString:] initialiser.
|
2000-03-09 19:06:49 +00:00
|
|
|
|
* In order to work round this, the string argument of the
|
1999-04-09 17:07:21 +00:00
|
|
|
|
* designated initialiser has been overloaded such that it
|
|
|
|
|
* is expected to accept an NSAttributedString here instead of
|
|
|
|
|
* a string. If you create an NSAttributedString subclass, you
|
|
|
|
|
* must make sure that your implementation of the initialiser
|
|
|
|
|
* copes with either an NSString or an NSAttributedString.
|
|
|
|
|
* If it receives an NSAttributedString, it should ignore the
|
|
|
|
|
* attributes argument and use the values from the string.
|
|
|
|
|
*/
|
|
|
|
|
|
2000-03-24 05:40:19 +00:00
|
|
|
|
#include "config.h"
|
2010-02-10 17:15:09 +00:00
|
|
|
|
#import "GNUstepBase/preface.h"
|
|
|
|
|
#import "GNUstepBase/Unicode.h"
|
1997-11-21 18:19:29 +00:00
|
|
|
|
|
2010-02-10 17:15:09 +00:00
|
|
|
|
#import "Foundation/NSAttributedString.h"
|
|
|
|
|
#import "Foundation/NSException.h"
|
|
|
|
|
#import "Foundation/NSAutoreleasePool.h"
|
|
|
|
|
#import "Foundation/NSPortCoder.h"
|
|
|
|
|
#import "Foundation/NSRange.h"
|
|
|
|
|
#import "GNUstepBase/NSObject+GNUstepBase.h"
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-09 08:40:09 +00:00
|
|
|
|
@class GSAttributedString;
|
2005-07-08 11:48:37 +00:00
|
|
|
|
@interface GSAttributedString : NSObject // Help the compiler
|
|
|
|
|
@end
|
2001-01-09 08:40:09 +00:00
|
|
|
|
@class GSMutableAttributedString;
|
2005-07-08 11:48:37 +00:00
|
|
|
|
@interface GSMutableAttributedString : NSObject // Help the compiler
|
|
|
|
|
@end
|
2001-01-09 09:17:31 +00:00
|
|
|
|
@class GSMutableDictionary;
|
2005-07-08 11:48:37 +00:00
|
|
|
|
@interface GSMutableDictionary : NSObject // Help the compiler
|
|
|
|
|
@end
|
2000-04-25 15:42:57 +00:00
|
|
|
|
static Class dictionaryClass = 0;
|
2000-10-30 18:00:27 +00:00
|
|
|
|
|
|
|
|
|
static SEL eqSel;
|
|
|
|
|
static SEL setSel;
|
|
|
|
|
static SEL getSel;
|
|
|
|
|
static SEL allocDictSel;
|
|
|
|
|
static SEL initDictSel;
|
|
|
|
|
static SEL addDictSel;
|
|
|
|
|
static SEL setDictSel;
|
|
|
|
|
static SEL relDictSel;
|
|
|
|
|
static SEL remDictSel;
|
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
static IMP allocDictImp;
|
|
|
|
|
static IMP initDictImp;
|
|
|
|
|
static IMP addDictImp;
|
|
|
|
|
static IMP setDictImp;
|
|
|
|
|
static IMP relDictImp;
|
|
|
|
|
static IMP remDictImp;
|
1999-04-09 17:07:21 +00:00
|
|
|
|
|
|
|
|
|
@interface GSMutableAttributedStringTracker : NSMutableString
|
|
|
|
|
{
|
|
|
|
|
NSMutableAttributedString *_owner;
|
|
|
|
|
}
|
|
|
|
|
+ (NSMutableString*) stringWithOwner: (NSMutableAttributedString*)as;
|
|
|
|
|
@end
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* A string in which name-value pairs represented by an [NSDictionary] may
|
|
|
|
|
* be associated to ranges of characters. Used for text rendering by the
|
|
|
|
|
* GUI/AppKit framework, in which fonts, sizes, etc. are stored under standard
|
|
|
|
|
* attributes in the dictionaries.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*
|
2004-06-22 22:40:40 +00:00
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@implementation NSAttributedString
|
|
|
|
|
|
2001-01-09 08:40:09 +00:00
|
|
|
|
static Class NSAttributedStringClass;
|
|
|
|
|
static Class GSAttributedStringClass;
|
|
|
|
|
static Class NSMutableAttributedStringClass;
|
|
|
|
|
static Class GSMutableAttributedStringClass;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSAttributedString class])
|
1999-04-09 17:07:21 +00:00
|
|
|
|
{
|
2001-01-09 08:40:09 +00:00
|
|
|
|
NSAttributedStringClass = self;
|
|
|
|
|
GSAttributedStringClass = [GSAttributedString class];
|
|
|
|
|
NSMutableAttributedStringClass
|
1999-07-14 20:16:49 +00:00
|
|
|
|
= [NSMutableAttributedString class];
|
2001-01-09 08:40:09 +00:00
|
|
|
|
GSMutableAttributedStringClass
|
|
|
|
|
= [GSMutableAttributedString class];
|
2001-01-09 09:17:31 +00:00
|
|
|
|
dictionaryClass = [GSMutableDictionary class];
|
2000-10-30 18:00:27 +00:00
|
|
|
|
|
|
|
|
|
eqSel = @selector(isEqual:);
|
|
|
|
|
setSel = @selector(setAttributes:range:);
|
|
|
|
|
getSel = @selector(attributesAtIndex:effectiveRange:);
|
|
|
|
|
allocDictSel = @selector(allocWithZone:);
|
|
|
|
|
initDictSel = @selector(initWithDictionary:);
|
|
|
|
|
addDictSel = @selector(addEntriesFromDictionary:);
|
|
|
|
|
setDictSel = @selector(setObject:forKey:);
|
|
|
|
|
relDictSel = @selector(release);
|
|
|
|
|
remDictSel = @selector(removeObjectForKey:);
|
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
allocDictImp = [dictionaryClass methodForSelector: allocDictSel];
|
|
|
|
|
initDictImp = [dictionaryClass instanceMethodForSelector: initDictSel];
|
|
|
|
|
addDictImp = [dictionaryClass instanceMethodForSelector: addDictSel];
|
|
|
|
|
setDictImp = [dictionaryClass instanceMethodForSelector: setDictSel];
|
|
|
|
|
remDictImp = [dictionaryClass instanceMethodForSelector: remDictSel];
|
|
|
|
|
relDictImp = [dictionaryClass instanceMethodForSelector: relDictSel];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2001-01-09 08:40:09 +00:00
|
|
|
|
if (self == NSAttributedStringClass)
|
|
|
|
|
return NSAllocateObject(GSAttributedStringClass, 0, z);
|
1999-07-14 15:57:55 +00:00
|
|
|
|
else
|
|
|
|
|
return NSAllocateObject(self, 0, z);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-16 12:35:42 +00:00
|
|
|
|
- (Class) classForCoder
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2001-01-09 08:40:09 +00:00
|
|
|
|
return NSAttributedStringClass;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-16 12:35:42 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2009-08-11 17:01:50 +00:00
|
|
|
|
if ([aCoder allowsKeyedCoding])
|
|
|
|
|
{
|
|
|
|
|
[aCoder encodeObject: [self string] forKey: @"NSString"];
|
|
|
|
|
if ([self length] > 0)
|
|
|
|
|
{
|
2010-02-08 17:52:36 +00:00
|
|
|
|
NSDictionary *attrs;
|
|
|
|
|
|
|
|
|
|
attrs = [self attributesAtIndex: 0 effectiveRange: NULL];
|
2000-10-16 12:35:42 +00:00
|
|
|
|
|
2009-08-11 17:01:50 +00:00
|
|
|
|
[aCoder encodeObject: attrs forKey: @"NSAttributes"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2000-10-16 12:35:42 +00:00
|
|
|
|
{
|
2009-08-11 17:01:50 +00:00
|
|
|
|
NSRange r = NSMakeRange(0, 0);
|
|
|
|
|
unsigned index = NSMaxRange(r);
|
|
|
|
|
unsigned length = [self length];
|
|
|
|
|
NSString *string = [self string];
|
|
|
|
|
NSDictionary *attrs;
|
|
|
|
|
|
|
|
|
|
[aCoder encodeObject: string];
|
|
|
|
|
while (index < length)
|
|
|
|
|
{
|
|
|
|
|
attrs = [self attributesAtIndex: index effectiveRange: &r];
|
|
|
|
|
index = NSMaxRange(r);
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(unsigned) at: &index];
|
|
|
|
|
[aCoder encodeObject: attrs];
|
|
|
|
|
}
|
2000-10-16 12:35:42 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-16 12:35:42 +00:00
|
|
|
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
1997-09-12 17:54:10 +00:00
|
|
|
|
{
|
2004-10-09 15:40:23 +00:00
|
|
|
|
if ([aDecoder allowsKeyedCoding])
|
2000-10-16 12:35:42 +00:00
|
|
|
|
{
|
2004-10-09 15:40:23 +00:00
|
|
|
|
NSString *string = [aDecoder decodeObjectForKey: @"NSString"];
|
|
|
|
|
NSDictionary *attributes = [aDecoder decodeObjectForKey: @"NSAttributes"];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-10-09 15:40:23 +00:00
|
|
|
|
self = [self initWithString: string attributes: attributes];
|
2000-10-16 12:35:42 +00:00
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
else
|
2000-10-16 12:35:42 +00:00
|
|
|
|
{
|
2004-10-09 15:40:23 +00:00
|
|
|
|
NSString *string = [aDecoder decodeObject];
|
|
|
|
|
unsigned length = [string length];
|
|
|
|
|
|
|
|
|
|
if (length == 0)
|
|
|
|
|
{
|
|
|
|
|
self = [self initWithString: string attributes: nil];
|
2000-10-16 12:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2004-10-09 15:40:23 +00:00
|
|
|
|
{
|
2009-08-11 17:01:50 +00:00
|
|
|
|
unsigned index;
|
2004-10-09 15:40:23 +00:00
|
|
|
|
NSDictionary *attrs;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(unsigned) at: &index];
|
2004-10-09 15:40:23 +00:00
|
|
|
|
attrs = [aDecoder decodeObject];
|
|
|
|
|
if (index == length)
|
2000-10-16 12:35:42 +00:00
|
|
|
|
{
|
2004-10-09 15:40:23 +00:00
|
|
|
|
self = [self initWithString: string attributes: attrs];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSRange r = NSMakeRange(0, index);
|
|
|
|
|
unsigned last = index;
|
|
|
|
|
NSMutableAttributedString *m;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-10-09 15:40:23 +00:00
|
|
|
|
m = [NSMutableAttributedString alloc];
|
|
|
|
|
m = [m initWithString: string attributes: nil];
|
2000-10-16 12:35:42 +00:00
|
|
|
|
[m setAttributes: attrs range: r];
|
2004-10-09 15:40:23 +00:00
|
|
|
|
while (index < length)
|
|
|
|
|
{
|
2009-02-23 20:42:32 +00:00
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(unsigned)
|
2004-10-09 15:40:23 +00:00
|
|
|
|
at: &index];
|
|
|
|
|
attrs = [aDecoder decodeObject];
|
|
|
|
|
r = NSMakeRange(last, index - last);
|
|
|
|
|
[m setAttributes: attrs range: r];
|
|
|
|
|
last = index;
|
|
|
|
|
}
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
self = [m copy];
|
|
|
|
|
RELEASE(m);
|
2000-10-16 12:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-10-09 15:40:23 +00:00
|
|
|
|
|
2000-10-16 12:35:42 +00:00
|
|
|
|
return self;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
}
|
1998-12-18 17:05:44 +00:00
|
|
|
|
|
|
|
|
|
- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder
|
1997-09-12 17:54:10 +00:00
|
|
|
|
{
|
1998-12-18 17:05:44 +00:00
|
|
|
|
if ([aCoder isByref] == NO)
|
1997-09-12 17:54:10 +00:00
|
|
|
|
return self;
|
1998-12-18 17:05:44 +00:00
|
|
|
|
return [super replacementObjectForPortCoder: aCoder];
|
1997-09-12 17:54:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
//NSCopying protocol
|
1999-04-09 17:07:21 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-03-08 08:38:42 +00:00
|
|
|
|
if ([self isKindOfClass: [NSMutableAttributedString class]]
|
|
|
|
|
|| NSShouldRetainWithZone(self, zone) == NO)
|
2001-01-09 08:40:09 +00:00
|
|
|
|
return [[GSAttributedStringClass allocWithZone: zone]
|
2000-03-08 08:38:42 +00:00
|
|
|
|
initWithAttributedString: self];
|
1998-07-29 14:04:17 +00:00
|
|
|
|
else
|
1999-04-21 20:16:25 +00:00
|
|
|
|
return RETAIN(self);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//NSMutableCopying protocol
|
1999-04-09 17:07:21 +00:00
|
|
|
|
- (id) mutableCopyWithZone: (NSZone*)zone
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2001-01-09 08:40:09 +00:00
|
|
|
|
return [[GSMutableAttributedStringClass allocWithZone: zone]
|
2000-03-08 08:38:42 +00:00
|
|
|
|
initWithAttributedString: self];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Creating an NSAttributedString
|
1999-04-09 17:07:21 +00:00
|
|
|
|
- (id) init
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
return [self initWithString: nil attributes: nil];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialize to aString with no attributes.
|
|
|
|
|
*/
|
1999-04-09 17:07:21 +00:00
|
|
|
|
- (id) initWithString: (NSString*)aString
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
return [self initWithString: aString attributes: nil];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialize to copy of attributedString.
|
|
|
|
|
*/
|
1999-04-09 17:07:21 +00:00
|
|
|
|
- (id) initWithAttributedString: (NSAttributedString*)attributedString
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
return [self initWithString: (NSString*)attributedString attributes: nil];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialize to aString with given attributes applying over full range of
|
|
|
|
|
* string.
|
|
|
|
|
*/
|
1999-04-09 17:07:21 +00:00
|
|
|
|
- (id) initWithString: (NSString*)aString attributes: (NSDictionary*)attributes
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
//This is the designated initializer
|
1999-04-09 17:07:21 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];/* Primitive method! */
|
|
|
|
|
return nil;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
- (NSString*) description
|
|
|
|
|
{
|
|
|
|
|
NSRange r = NSMakeRange(0, 0);
|
|
|
|
|
unsigned index = NSMaxRange(r);
|
|
|
|
|
unsigned length = [self length];
|
|
|
|
|
NSString *string = [self string];
|
|
|
|
|
NSDictionary *attrs;
|
|
|
|
|
NSMutableString *desc;
|
|
|
|
|
|
2000-09-10 05:34:31 +00:00
|
|
|
|
desc = [[NSMutableString alloc] init];
|
2000-09-09 04:56:50 +00:00
|
|
|
|
while (index < length &&
|
2000-03-17 13:13:08 +00:00
|
|
|
|
(attrs = [self attributesAtIndex: index effectiveRange: &r]) != nil)
|
|
|
|
|
{
|
|
|
|
|
index = NSMaxRange(r);
|
2000-10-24 11:58:25 +00:00
|
|
|
|
[desc appendFormat: @"%@%@", [string substringWithRange: r], attrs];
|
2000-03-17 13:13:08 +00:00
|
|
|
|
}
|
|
|
|
|
return desc;
|
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
//Retrieving character information
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return length of the underlying string.
|
|
|
|
|
*/
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) length
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
return [[self string] length];
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return the underlying string, stripped of attributes.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (NSString*) string
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];/* Primitive method! */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Retrieving attribute information
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns attributes and values at index, and, if effectiveRange
|
|
|
|
|
* is non-nil, this gets filled with a range over which these attributes
|
|
|
|
|
* and values still hold. This may not be the maximum range, depending
|
|
|
|
|
* on the implementation.
|
|
|
|
|
*/
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSDictionary*) attributesAtIndex: (NSUInteger)index
|
1999-04-09 17:07:21 +00:00
|
|
|
|
effectiveRange: (NSRange*)aRange
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];/* Primitive method! */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns attributes and values at index, and, if longestEffectiveRange
|
|
|
|
|
* is non-nil, this gets filled with the range over which the attribute-value
|
|
|
|
|
* set is the same as at index, clipped to rangeLimit.
|
|
|
|
|
*/
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSDictionary*) attributesAtIndex: (NSUInteger)index
|
1999-04-09 17:07:21 +00:00
|
|
|
|
longestEffectiveRange: (NSRange*)aRange
|
|
|
|
|
inRange: (NSRange)rangeLimit
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
NSDictionary *attrDictionary, *tmpDictionary;
|
|
|
|
|
NSRange tmpRange;
|
2000-04-25 15:42:57 +00:00
|
|
|
|
IMP getImp;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
if (rangeLimit.location < 0 || NSMaxRange(rangeLimit) > [self length])
|
|
|
|
|
{
|
2000-03-09 19:06:49 +00:00
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
|
format: @"RangeError in method -attributesAtIndex:longestEffectiveRange:inRange: in class NSAttributedString"];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
2000-04-25 15:42:57 +00:00
|
|
|
|
getImp = [self methodForSelector: getSel];
|
|
|
|
|
attrDictionary = (*getImp)(self, getSel, index, aRange);
|
2000-03-09 19:06:49 +00:00
|
|
|
|
if (aRange == 0)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return attrDictionary;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-03-08 08:38:42 +00:00
|
|
|
|
while (aRange->location > rangeLimit.location)
|
|
|
|
|
{
|
|
|
|
|
//Check extend range backwards
|
2000-04-25 15:42:57 +00:00
|
|
|
|
tmpDictionary = (*getImp)(self, getSel, aRange->location-1, &tmpRange);
|
2000-03-08 08:38:42 +00:00
|
|
|
|
if ([tmpDictionary isEqualToDictionary: attrDictionary])
|
2000-03-09 19:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
aRange->length = NSMaxRange(*aRange) - tmpRange.location;
|
|
|
|
|
aRange->location = tmpRange.location;
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
else
|
2000-03-09 19:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
}
|
|
|
|
|
while (NSMaxRange(*aRange) < NSMaxRange(rangeLimit))
|
|
|
|
|
{
|
|
|
|
|
//Check extend range forwards
|
2000-04-25 15:42:57 +00:00
|
|
|
|
tmpDictionary = (*getImp)(self, getSel, NSMaxRange(*aRange), &tmpRange);
|
2000-03-08 08:38:42 +00:00
|
|
|
|
if ([tmpDictionary isEqualToDictionary: attrDictionary])
|
2000-03-09 19:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
aRange->length = NSMaxRange(tmpRange) - aRange->location;
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
else
|
2000-03-09 19:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
*aRange = NSIntersectionRange(*aRange,rangeLimit);//Clip to rangeLimit
|
|
|
|
|
return attrDictionary;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns value for given attribute at index, and, if effectiveRange is
|
|
|
|
|
* non-nil, this gets filled with a range over which this value holds. This
|
|
|
|
|
* may not be the maximum range, depending on the implementation.
|
|
|
|
|
*/
|
1999-04-09 17:07:21 +00:00
|
|
|
|
- (id) attribute: (NSString*)attributeName
|
2009-02-23 20:42:32 +00:00
|
|
|
|
atIndex: (NSUInteger)index
|
1999-04-09 17:07:21 +00:00
|
|
|
|
effectiveRange: (NSRange*)aRange
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
NSDictionary *tmpDictionary;
|
|
|
|
|
id attrValue;
|
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
tmpDictionary = [self attributesAtIndex: index effectiveRange: aRange];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2000-03-09 19:06:49 +00:00
|
|
|
|
if (attributeName == nil)
|
2000-03-08 08:38:42 +00:00
|
|
|
|
{
|
2000-03-09 19:06:49 +00:00
|
|
|
|
if (aRange != 0)
|
|
|
|
|
{
|
|
|
|
|
*aRange = NSMakeRange(0,[self length]);
|
|
|
|
|
/*
|
|
|
|
|
* If attributeName is nil, then the attribute will not exist in the
|
|
|
|
|
* entire text - therefore aRange of the entire text must be correct
|
|
|
|
|
*/
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
attrValue = [tmpDictionary objectForKey: attributeName];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return attrValue;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns value for given attribute at index, and, if longestEffectiveRange
|
|
|
|
|
* is non-nil, this gets filled with the range over which the attribute
|
|
|
|
|
* applies, clipped to rangeLimit.
|
|
|
|
|
*/
|
2000-03-09 19:06:49 +00:00
|
|
|
|
- (id) attribute: (NSString*)attributeName
|
2009-02-23 20:42:32 +00:00
|
|
|
|
atIndex: (NSUInteger)index
|
2000-03-09 19:06:49 +00:00
|
|
|
|
longestEffectiveRange: (NSRange*)aRange
|
|
|
|
|
inRange: (NSRange)rangeLimit
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-03-09 19:06:49 +00:00
|
|
|
|
NSDictionary *tmpDictionary;
|
|
|
|
|
id attrValue;
|
|
|
|
|
id tmpAttrValue;
|
|
|
|
|
NSRange tmpRange;
|
2000-04-23 05:51:38 +00:00
|
|
|
|
BOOL (*eImp)(id,SEL,id);
|
2000-04-25 15:42:57 +00:00
|
|
|
|
IMP getImp;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
if (rangeLimit.location < 0 || NSMaxRange(rangeLimit) > [self length])
|
2000-03-08 08:38:42 +00:00
|
|
|
|
{
|
2000-03-09 19:06:49 +00:00
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
|
format: @"RangeError in method -attribute:atIndex:longestEffectiveRange:inRange: in class NSAttributedString"];
|
2000-03-08 08:38:42 +00:00
|
|
|
|
}
|
2000-04-25 15:42:57 +00:00
|
|
|
|
|
2000-04-23 05:51:38 +00:00
|
|
|
|
if (attributeName == nil)
|
|
|
|
|
return nil;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-03-09 19:06:49 +00:00
|
|
|
|
attrValue = [self attribute: attributeName
|
|
|
|
|
atIndex: index
|
|
|
|
|
effectiveRange: aRange];
|
2000-04-25 15:42:57 +00:00
|
|
|
|
|
2000-03-09 19:06:49 +00:00
|
|
|
|
if (aRange == 0)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return attrValue;
|
2000-04-23 05:51:38 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If attrValue == nil then eImp will be zero
|
|
|
|
|
*/
|
2000-04-25 15:42:57 +00:00
|
|
|
|
eImp = (BOOL(*)(id,SEL,id))[attrValue methodForSelector: eqSel];
|
|
|
|
|
getImp = [self methodForSelector: getSel];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-03-08 08:38:42 +00:00
|
|
|
|
while (aRange->location > rangeLimit.location)
|
|
|
|
|
{
|
|
|
|
|
//Check extend range backwards
|
2000-04-25 15:42:57 +00:00
|
|
|
|
tmpDictionary = (*getImp)(self, getSel, aRange->location-1, &tmpRange);
|
2000-03-08 08:38:42 +00:00
|
|
|
|
tmpAttrValue = [tmpDictionary objectForKey: attributeName];
|
2000-04-23 05:51:38 +00:00
|
|
|
|
if (tmpAttrValue == attrValue
|
2000-04-25 15:42:57 +00:00
|
|
|
|
|| (eImp != 0 && (*eImp)(attrValue, eqSel, tmpAttrValue)))
|
2000-03-09 19:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
aRange->length = NSMaxRange(*aRange) - tmpRange.location;
|
|
|
|
|
aRange->location = tmpRange.location;
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
else
|
2000-03-09 19:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
}
|
|
|
|
|
while (NSMaxRange(*aRange) < NSMaxRange(rangeLimit))
|
|
|
|
|
{
|
|
|
|
|
//Check extend range forwards
|
2000-04-25 15:42:57 +00:00
|
|
|
|
tmpDictionary = (*getImp)(self, getSel, NSMaxRange(*aRange), &tmpRange);
|
2000-03-08 08:38:42 +00:00
|
|
|
|
tmpAttrValue = [tmpDictionary objectForKey: attributeName];
|
2000-04-23 05:51:38 +00:00
|
|
|
|
if (tmpAttrValue == attrValue
|
2000-04-25 15:42:57 +00:00
|
|
|
|
|| (eImp != 0 && (*eImp)(attrValue, eqSel, tmpAttrValue)))
|
2000-03-09 19:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
aRange->length = NSMaxRange(tmpRange) - aRange->location;
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
else
|
2000-03-09 19:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
*aRange = NSIntersectionRange(*aRange,rangeLimit);//Clip to rangeLimit
|
|
|
|
|
return attrValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Comparing attributed strings
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns whether all characters and attributes are equal between this
|
|
|
|
|
* string and otherString.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (BOOL) isEqualToAttributedString: (NSAttributedString*)otherString
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
NSRange ownEffectiveRange,otherEffectiveRange;
|
|
|
|
|
unsigned int length;
|
|
|
|
|
NSDictionary *ownDictionary,*otherDictionary;
|
|
|
|
|
BOOL result;
|
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
if (!otherString)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return NO;
|
1999-04-09 17:07:21 +00:00
|
|
|
|
if (![[otherString string] isEqual: [self string]])
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return NO;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
length = [otherString length];
|
2010-02-08 17:52:36 +00:00
|
|
|
|
if (length == 0)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return YES;
|
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
ownDictionary = [self attributesAtIndex: 0
|
2000-03-09 19:06:49 +00:00
|
|
|
|
effectiveRange: &ownEffectiveRange];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
otherDictionary = [otherString attributesAtIndex: 0
|
2000-03-09 19:06:49 +00:00
|
|
|
|
effectiveRange: &otherEffectiveRange];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
result = YES;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-03-08 08:38:42 +00:00
|
|
|
|
while (YES)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-03-08 08:38:42 +00:00
|
|
|
|
if (NSIntersectionRange(ownEffectiveRange, otherEffectiveRange).length > 0
|
|
|
|
|
&& ![ownDictionary isEqualToDictionary: otherDictionary])
|
|
|
|
|
{
|
|
|
|
|
result = NO;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (NSMaxRange(ownEffectiveRange) < NSMaxRange(otherEffectiveRange))
|
|
|
|
|
{
|
2000-03-09 19:06:49 +00:00
|
|
|
|
ownDictionary = [self attributesAtIndex: NSMaxRange(ownEffectiveRange)
|
|
|
|
|
effectiveRange: &ownEffectiveRange];
|
2000-03-08 08:38:42 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (NSMaxRange(otherEffectiveRange) >= length)
|
2000-03-09 19:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
break;//End of strings
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
otherDictionary = [otherString
|
|
|
|
|
attributesAtIndex: NSMaxRange(otherEffectiveRange)
|
|
|
|
|
effectiveRange: &otherEffectiveRange];
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
1998-07-29 14:04:17 +00:00
|
|
|
|
- (BOOL) isEqual: (id)anObject
|
|
|
|
|
{
|
|
|
|
|
if (anObject == self)
|
|
|
|
|
return YES;
|
2001-01-09 08:40:09 +00:00
|
|
|
|
if ([anObject isKindOfClass: NSAttributedStringClass])
|
1999-04-09 17:07:21 +00:00
|
|
|
|
return [self isEqualToAttributedString: anObject];
|
1998-07-29 14:04:17 +00:00
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
//Extracting a substring
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns substring with attribute information.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (NSAttributedString*) attributedSubstringFromRange: (NSRange)aRange
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
NSAttributedString *newAttrString;
|
|
|
|
|
NSString *newSubstring;
|
|
|
|
|
NSDictionary *attrs;
|
|
|
|
|
NSRange range;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
unsigned len = [self length];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, len);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-10-24 11:58:25 +00:00
|
|
|
|
newSubstring = [[self string] substringWithRange: aRange];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
attrs = [self attributesAtIndex: aRange.location effectiveRange: &range];
|
|
|
|
|
range = NSIntersectionRange(range, aRange);
|
|
|
|
|
if (NSEqualRanges(range, aRange) == YES)
|
|
|
|
|
{
|
2001-01-09 08:40:09 +00:00
|
|
|
|
newAttrString = [GSAttributedStringClass alloc];
|
2000-04-25 15:42:57 +00:00
|
|
|
|
newAttrString = [newAttrString initWithString: newSubstring
|
|
|
|
|
attributes: attrs];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSMutableAttributedString *m;
|
|
|
|
|
NSRange rangeToSet = range;
|
|
|
|
|
|
2001-01-09 08:40:09 +00:00
|
|
|
|
m = [GSMutableAttributedStringClass alloc];
|
2000-04-25 15:42:57 +00:00
|
|
|
|
m = [m initWithString: newSubstring attributes: nil];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
rangeToSet.location = 0;
|
|
|
|
|
[m setAttributes: attrs range: rangeToSet];
|
|
|
|
|
while (NSMaxRange(range) < NSMaxRange(aRange))
|
|
|
|
|
{
|
|
|
|
|
attrs = [self attributesAtIndex: NSMaxRange(range)
|
|
|
|
|
effectiveRange: &range];
|
|
|
|
|
rangeToSet = NSIntersectionRange(range, aRange);
|
|
|
|
|
rangeToSet.location -= aRange.location;
|
|
|
|
|
[m setAttributes: attrs range: rangeToSet];
|
|
|
|
|
}
|
|
|
|
|
newAttrString = [m copy];
|
1999-04-21 20:16:25 +00:00
|
|
|
|
RELEASE(m);
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-09-28 19:35:09 +00:00
|
|
|
|
IF_NO_GC(AUTORELEASE(newAttrString));
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return newAttrString;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end //NSAttributedString
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Mutable version of [NSAttributedString].
|
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@implementation NSMutableAttributedString
|
|
|
|
|
|
2000-10-16 12:35:42 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2001-01-09 08:40:09 +00:00
|
|
|
|
if (self == NSMutableAttributedStringClass)
|
|
|
|
|
return NSAllocateObject(GSMutableAttributedStringClass, 0, z);
|
1999-07-14 20:16:49 +00:00
|
|
|
|
else
|
|
|
|
|
return NSAllocateObject(self, 0, z);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-16 12:35:42 +00:00
|
|
|
|
- (Class) classForCoder
|
|
|
|
|
{
|
2001-01-09 08:40:09 +00:00
|
|
|
|
return NSMutableAttributedStringClass;
|
2000-10-16 12:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
|
|
|
|
{
|
2009-08-11 17:01:50 +00:00
|
|
|
|
if ([aDecoder allowsKeyedCoding])
|
2000-10-16 12:35:42 +00:00
|
|
|
|
{
|
2009-08-11 17:01:50 +00:00
|
|
|
|
NSString *string = [aDecoder decodeObjectForKey: @"NSString"];
|
|
|
|
|
NSDictionary *attributes = [aDecoder decodeObjectForKey: @"NSAttributes"];
|
|
|
|
|
|
|
|
|
|
self = [self initWithString: string attributes: attributes];
|
2000-10-16 12:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-08-11 17:01:50 +00:00
|
|
|
|
NSString *string = [aDecoder decodeObject];
|
|
|
|
|
unsigned length = [string length];
|
2000-10-16 12:35:42 +00:00
|
|
|
|
|
2009-08-11 17:01:50 +00:00
|
|
|
|
if (length == 0)
|
2000-10-16 12:35:42 +00:00
|
|
|
|
{
|
2009-08-11 17:01:50 +00:00
|
|
|
|
self = [self initWithString: string attributes: nil];
|
2000-10-16 12:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-08-11 17:01:50 +00:00
|
|
|
|
unsigned index;
|
|
|
|
|
NSDictionary *attrs;
|
2000-10-16 12:35:42 +00:00
|
|
|
|
|
2009-08-11 17:01:50 +00:00
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(unsigned) at: &index];
|
|
|
|
|
attrs = [aDecoder decodeObject];
|
|
|
|
|
if (index == length)
|
2000-10-16 12:35:42 +00:00
|
|
|
|
{
|
2009-08-11 17:01:50 +00:00
|
|
|
|
self = [self initWithString: string attributes: attrs];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSRange r = NSMakeRange(0, index);
|
|
|
|
|
unsigned last = index;
|
|
|
|
|
|
|
|
|
|
self = [self initWithString: string attributes: nil];
|
2000-10-16 12:35:42 +00:00
|
|
|
|
[self setAttributes: attrs range: r];
|
2009-08-11 17:01:50 +00:00
|
|
|
|
while (index < length)
|
|
|
|
|
{
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(unsigned)
|
|
|
|
|
at: &index];
|
|
|
|
|
attrs = [aDecoder decodeObject];
|
|
|
|
|
r = NSMakeRange(last, index - last);
|
|
|
|
|
[self setAttributes: attrs range: r];
|
|
|
|
|
last = index;
|
|
|
|
|
}
|
2000-10-16 12:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-08-11 17:01:50 +00:00
|
|
|
|
|
2000-10-16 12:35:42 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
//Retrieving character information
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns mutable version of the underlying string.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (NSMutableString*) mutableString
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
return [GSMutableAttributedStringTracker stringWithOwner: self];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Changing characters
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Removes characters and attributes applying to them.
|
|
|
|
|
*/
|
1999-04-09 17:07:21 +00:00
|
|
|
|
- (void) deleteCharactersInRange: (NSRange)aRange
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
[self replaceCharactersInRange: aRange withString: nil];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Changing attributes
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets attributes to apply over range, replacing any previous attributes.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (void) setAttributes: (NSDictionary*)attributes range: (NSRange)aRange
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];// Primitive method!
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Adds attribute applying to given range.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (void) addAttribute: (NSString*)name value: (id)value range: (NSRange)aRange
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-03-08 08:38:42 +00:00
|
|
|
|
NSRange effectiveRange;
|
|
|
|
|
NSDictionary *attrDict;
|
|
|
|
|
NSMutableDictionary *newDict;
|
|
|
|
|
unsigned int tmpLength;
|
2000-04-25 15:42:57 +00:00
|
|
|
|
IMP getImp;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
tmpLength = [self length];
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, tmpLength);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
getImp = [self methodForSelector: getSel];
|
|
|
|
|
attrDict = (*getImp)(self, getSel, aRange.location, &effectiveRange);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
if (effectiveRange.location < NSMaxRange(aRange))
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-04-25 15:42:57 +00:00
|
|
|
|
IMP setImp;
|
|
|
|
|
|
|
|
|
|
setImp = [self methodForSelector: setSel];
|
|
|
|
|
|
2000-10-23 23:17:40 +00:00
|
|
|
|
[self beginEditing];
|
2000-04-25 15:42:57 +00:00
|
|
|
|
while (effectiveRange.location < NSMaxRange(aRange))
|
2000-03-08 08:38:42 +00:00
|
|
|
|
{
|
2000-04-25 15:42:57 +00:00
|
|
|
|
effectiveRange = NSIntersectionRange(aRange, effectiveRange);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
newDict = (*allocDictImp)(dictionaryClass, allocDictSel,
|
|
|
|
|
NSDefaultMallocZone());
|
|
|
|
|
newDict = (*initDictImp)(newDict, initDictSel, attrDict);
|
|
|
|
|
(*setDictImp)(newDict, setDictSel, value, name);
|
|
|
|
|
(*setImp)(self, setSel, newDict, effectiveRange);
|
|
|
|
|
IF_NO_GC((*relDictImp)(newDict, relDictSel));
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
if (NSMaxRange(effectiveRange) >= NSMaxRange(aRange))
|
|
|
|
|
{
|
|
|
|
|
effectiveRange.location = NSMaxRange(aRange);// stop the loop...
|
|
|
|
|
}
|
|
|
|
|
else if (NSMaxRange(effectiveRange) < tmpLength)
|
|
|
|
|
{
|
|
|
|
|
attrDict = (*getImp)(self, getSel, NSMaxRange(effectiveRange),
|
|
|
|
|
&effectiveRange);
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
}
|
2000-10-23 23:17:40 +00:00
|
|
|
|
[self endEditing];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Add attributes to apply over given range.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (void) addAttributes: (NSDictionary*)attributes range: (NSRange)aRange
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-03-08 08:38:42 +00:00
|
|
|
|
NSRange effectiveRange;
|
|
|
|
|
NSDictionary *attrDict;
|
|
|
|
|
NSMutableDictionary *newDict;
|
|
|
|
|
unsigned int tmpLength;
|
2000-04-25 15:42:57 +00:00
|
|
|
|
IMP getImp;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1999-04-09 17:07:21 +00:00
|
|
|
|
if (!attributes)
|
2000-03-08 08:38:42 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"attributes is nil in method -addAttributes:range: "
|
|
|
|
|
@"in class NSMutableAtrributedString"];
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
tmpLength = [self length];
|
2001-07-12 06:05:11 +00:00
|
|
|
|
if (NSMaxRange(aRange) > tmpLength)
|
2000-03-08 08:38:42 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
|
format: @"RangeError in method -addAttribute:value:range: "
|
|
|
|
|
@"in class NSMutableAttributedString"];
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
getImp = [self methodForSelector: getSel];
|
|
|
|
|
attrDict = (*getImp)(self, getSel, aRange.location, &effectiveRange);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
if (effectiveRange.location < NSMaxRange(aRange))
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-04-25 15:42:57 +00:00
|
|
|
|
IMP setImp;
|
|
|
|
|
|
|
|
|
|
setImp = [self methodForSelector: setSel];
|
|
|
|
|
|
2000-10-23 23:17:40 +00:00
|
|
|
|
[self beginEditing];
|
2000-04-25 15:42:57 +00:00
|
|
|
|
while (effectiveRange.location < NSMaxRange(aRange))
|
2000-03-08 08:38:42 +00:00
|
|
|
|
{
|
2000-04-25 15:42:57 +00:00
|
|
|
|
effectiveRange = NSIntersectionRange(aRange,effectiveRange);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
newDict = (*allocDictImp)(dictionaryClass, allocDictSel,
|
|
|
|
|
NSDefaultMallocZone());
|
|
|
|
|
newDict = (*initDictImp)(newDict, initDictSel, attrDict);
|
|
|
|
|
(*addDictImp)(newDict, addDictSel, attributes);
|
|
|
|
|
(*setImp)(self, setSel, newDict, effectiveRange);
|
|
|
|
|
IF_NO_GC((*relDictImp)(newDict, relDictSel));
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
if (NSMaxRange(effectiveRange) >= NSMaxRange(aRange))
|
|
|
|
|
{
|
|
|
|
|
effectiveRange.location = NSMaxRange(aRange);// stop the loop...
|
|
|
|
|
}
|
|
|
|
|
else if (NSMaxRange(effectiveRange) < tmpLength)
|
|
|
|
|
{
|
|
|
|
|
attrDict = (*getImp)(self, getSel, NSMaxRange(effectiveRange),
|
|
|
|
|
&effectiveRange);
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
}
|
2000-10-23 23:17:40 +00:00
|
|
|
|
[self endEditing];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Removes given attribute from aRange.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (void) removeAttribute: (NSString*)name range: (NSRange)aRange
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-03-08 08:38:42 +00:00
|
|
|
|
NSRange effectiveRange;
|
|
|
|
|
NSDictionary *attrDict;
|
|
|
|
|
NSMutableDictionary *newDict;
|
|
|
|
|
unsigned int tmpLength;
|
2000-04-25 15:42:57 +00:00
|
|
|
|
IMP getImp;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
tmpLength = [self length];
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, tmpLength);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
getImp = [self methodForSelector: getSel];
|
|
|
|
|
attrDict = (*getImp)(self, getSel, aRange.location, &effectiveRange);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
if (effectiveRange.location < NSMaxRange(aRange))
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-04-25 15:42:57 +00:00
|
|
|
|
IMP setImp;
|
|
|
|
|
|
|
|
|
|
setImp = [self methodForSelector: setSel];
|
|
|
|
|
|
2000-10-23 23:17:40 +00:00
|
|
|
|
[self beginEditing];
|
2000-04-25 15:42:57 +00:00
|
|
|
|
while (effectiveRange.location < NSMaxRange(aRange))
|
2000-03-08 08:38:42 +00:00
|
|
|
|
{
|
2000-04-25 15:42:57 +00:00
|
|
|
|
effectiveRange = NSIntersectionRange(aRange,effectiveRange);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
newDict = (*allocDictImp)(dictionaryClass, allocDictSel,
|
|
|
|
|
NSDefaultMallocZone());
|
|
|
|
|
newDict = (*initDictImp)(newDict, initDictSel, attrDict);
|
|
|
|
|
(*remDictImp)(newDict, remDictSel, name);
|
|
|
|
|
(*setImp)(self, setSel, newDict, effectiveRange);
|
|
|
|
|
IF_NO_GC((*relDictImp)(newDict, relDictSel));
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
if (NSMaxRange(effectiveRange) >= NSMaxRange(aRange))
|
|
|
|
|
{
|
|
|
|
|
effectiveRange.location = NSMaxRange(aRange);// stop the loop...
|
|
|
|
|
}
|
|
|
|
|
else if (NSMaxRange(effectiveRange) < tmpLength)
|
|
|
|
|
{
|
|
|
|
|
attrDict = (*getImp)(self, getSel, NSMaxRange(effectiveRange),
|
|
|
|
|
&effectiveRange);
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
}
|
2000-10-23 23:17:40 +00:00
|
|
|
|
[self endEditing];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Changing characters and attributes
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Appends attributed string to end of this one, preserving attributes.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (void) appendAttributedString: (NSAttributedString*)attributedString
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
[self replaceCharactersInRange: NSMakeRange([self length],0)
|
2000-03-08 08:38:42 +00:00
|
|
|
|
withAttributedString: attributedString];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Inserts attributed string within this one, preserving attributes.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (void) insertAttributedString: (NSAttributedString*)attributedString
|
2009-02-23 20:42:32 +00:00
|
|
|
|
atIndex: (NSUInteger)index
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
[self replaceCharactersInRange: NSMakeRange(index,0)
|
2000-03-08 08:38:42 +00:00
|
|
|
|
withAttributedString: attributedString];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Replaces substring and attributes.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (void) replaceCharactersInRange: (NSRange)aRange
|
|
|
|
|
withAttributedString: (NSAttributedString*)attributedString
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-03-08 08:38:42 +00:00
|
|
|
|
NSDictionary *attrDict;
|
|
|
|
|
NSString *tmpStr;
|
2000-04-25 15:42:57 +00:00
|
|
|
|
unsigned max;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-04-25 15:42:57 +00:00
|
|
|
|
if (attributedString == nil)
|
|
|
|
|
{
|
|
|
|
|
[self replaceCharactersInRange: aRange withString: nil];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-23 23:17:40 +00:00
|
|
|
|
[self beginEditing];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
tmpStr = [attributedString string];
|
2000-03-08 08:38:42 +00:00
|
|
|
|
[self replaceCharactersInRange: aRange withString: tmpStr];
|
2000-04-25 15:42:57 +00:00
|
|
|
|
max = [tmpStr length];
|
|
|
|
|
|
|
|
|
|
if (max > 0)
|
2000-03-08 08:38:42 +00:00
|
|
|
|
{
|
2000-04-25 15:42:57 +00:00
|
|
|
|
unsigned loc = 0;
|
|
|
|
|
NSRange effectiveRange = NSMakeRange(0, loc);
|
|
|
|
|
NSRange clipRange = NSMakeRange(0, max);
|
|
|
|
|
IMP getImp;
|
|
|
|
|
IMP setImp;
|
|
|
|
|
|
|
|
|
|
getImp = [attributedString methodForSelector: getSel];
|
|
|
|
|
setImp = [self methodForSelector: setSel];
|
|
|
|
|
while (loc < max)
|
|
|
|
|
{
|
|
|
|
|
NSRange ownRange;
|
|
|
|
|
|
|
|
|
|
attrDict = (*getImp)(attributedString, getSel, loc, &effectiveRange);
|
|
|
|
|
ownRange = NSIntersectionRange(clipRange, effectiveRange);
|
|
|
|
|
ownRange.location += aRange.location;
|
|
|
|
|
(*setImp)(self, setSel, attrDict, ownRange);
|
|
|
|
|
loc = NSMaxRange(effectiveRange);
|
|
|
|
|
}
|
2000-03-08 08:38:42 +00:00
|
|
|
|
}
|
2000-10-23 23:17:40 +00:00
|
|
|
|
[self endEditing];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-11-28 15:41:35 +00:00
|
|
|
|
/** <override-subclass />
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* Replaces substring; replacement is granted attributes equal to those of
|
|
|
|
|
* the first character of the portion replaced.
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (void) replaceCharactersInRange: (NSRange)aRange
|
|
|
|
|
withString: (NSString*)aString
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];// Primitive method!
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Replaces entire contents (so this object can be reused).
|
|
|
|
|
*/
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (void) setAttributedString: (NSAttributedString*)attributedString
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
[self replaceCharactersInRange: NSMakeRange(0,[self length])
|
2000-03-08 08:38:42 +00:00
|
|
|
|
withAttributedString: attributedString];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-11-28 15:41:35 +00:00
|
|
|
|
/** <override-dummy />
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* Call before executing a collection of changes, for optimization.
|
|
|
|
|
*/
|
1999-04-09 17:07:21 +00:00
|
|
|
|
- (void) beginEditing
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-28 15:41:35 +00:00
|
|
|
|
/** <override-dummy />
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* Call after executing a collection of changes, for optimization.
|
|
|
|
|
*/
|
1999-04-09 17:07:21 +00:00
|
|
|
|
- (void) endEditing
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end //NSMutableAttributedString
|
1999-04-09 17:07:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The GSMutableAttributedStringTracker class is a concrete subclass of
|
|
|
|
|
* NSMutableString which keeps it's owner informed of any changes made
|
|
|
|
|
* to it.
|
|
|
|
|
*/
|
|
|
|
|
@implementation GSMutableAttributedStringTracker
|
|
|
|
|
|
|
|
|
|
+ (NSMutableString*) stringWithOwner: (NSMutableAttributedString*)as
|
|
|
|
|
{
|
|
|
|
|
GSMutableAttributedStringTracker *str;
|
|
|
|
|
NSZone *z = NSDefaultMallocZone();
|
|
|
|
|
|
|
|
|
|
str = (GSMutableAttributedStringTracker*) NSAllocateObject(self, 0, z);
|
|
|
|
|
|
|
|
|
|
str->_owner = RETAIN(as);
|
1999-04-21 20:16:25 +00:00
|
|
|
|
return AUTORELEASE(str);
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
RELEASE(_owner);
|
2009-10-10 08:16:17 +00:00
|
|
|
|
[super dealloc];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) length
|
1999-04-09 17:07:21 +00:00
|
|
|
|
{
|
|
|
|
|
return [[_owner string] length];
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (unichar) characterAtIndex: (NSUInteger)index
|
1999-04-09 17:07:21 +00:00
|
|
|
|
{
|
|
|
|
|
return [[_owner string] characterAtIndex: index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)getCharacters: (unichar*)buffer
|
|
|
|
|
{
|
2003-08-20 12:13:34 +00:00
|
|
|
|
[[_owner string] getCharacters: buffer];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)getCharacters: (unichar*)buffer range: (NSRange)aRange
|
|
|
|
|
{
|
2003-08-20 12:13:34 +00:00
|
|
|
|
[[_owner string] getCharacters: buffer range: aRange];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-08 08:38:42 +00:00
|
|
|
|
- (const char*) cString
|
1999-04-09 17:07:21 +00:00
|
|
|
|
{
|
|
|
|
|
return [[_owner string] cString];
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) cStringLength
|
1999-04-09 17:07:21 +00:00
|
|
|
|
{
|
|
|
|
|
return [[_owner string] cStringLength];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSStringEncoding) fastestEncoding
|
|
|
|
|
{
|
|
|
|
|
return [[_owner string] fastestEncoding];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSStringEncoding) smallestEncoding
|
|
|
|
|
{
|
|
|
|
|
return [[_owner string] smallestEncoding];
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSInteger) _baseLength
|
1999-04-09 17:07:21 +00:00
|
|
|
|
{
|
|
|
|
|
return [[_owner string] _baseLength];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
}
|
1999-04-09 17:07:21 +00:00
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
|
|
|
{
|
2003-08-20 12:13:34 +00:00
|
|
|
|
[[_owner string] encodeWithCoder: aCoder];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (Class) classForCoder
|
|
|
|
|
{
|
|
|
|
|
return [[_owner string] classForCoder];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) replaceCharactersInRange: (NSRange)aRange
|
|
|
|
|
withString: (NSString*)aString
|
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
[_owner replaceCharactersInRange: aRange withString: aString];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|