mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-22 17:52:42 +00:00
Initial implementation of NSTextStorage class.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@3885 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
5b33ba9b01
commit
e73a078b30
2 changed files with 285 additions and 39 deletions
|
@ -5,23 +5,28 @@
|
|||
implements change management (beginEditing/endEditing), verification of
|
||||
attributes, delegate handling, and layout management notification. The one
|
||||
aspect it does not implement is the actual attributed string storage ---
|
||||
this is left up to the subclassers, which need to override the two
|
||||
NSMutableAttributedString primitives:
|
||||
this is left up to the subclassers, which need to override the four
|
||||
NSAttributedString and NSMutableAttributedString primitives:
|
||||
|
||||
- (void)replaceCharactersInRange:(NSRange)range
|
||||
withString:(NSString *)str;
|
||||
- (void)setAttributes:(NSDictionary *)attrs
|
||||
range:(NSRange)range;
|
||||
- (NSString*) string;
|
||||
- (NSDictionary*) attributesAtIndex: (unsigned)index
|
||||
effectiveRange: (NSRange*)aRange;
|
||||
|
||||
- (void) replaceCharactersInRange: (NSRange)range
|
||||
withString: (NSString *)str;
|
||||
- (void) setAttributes: (NSDictionary *)attrs
|
||||
range: (NSRange)range;
|
||||
|
||||
These primitives should perform the change then call
|
||||
edited:range:changeInLength: to get everything else to happen.
|
||||
|
||||
Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
Copyright (C) 1996,1999 Free Software Foundation, Inc.
|
||||
|
||||
Author: Daniel Bðhringer <boehring@biomed.ruhr-uni-bochum.de>
|
||||
Date: August 1998
|
||||
Source by Daniel Bðhringer integrated into GNUstep gui
|
||||
by Felipe A. Rodriguez <far@ix.netcom.com>
|
||||
Update: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
|
@ -45,43 +50,69 @@
|
|||
|
||||
@class NSLayoutManager;
|
||||
|
||||
/* These values are or'ed together in notifications to indicate what got changed.
|
||||
*/
|
||||
/*
|
||||
* These values are or'ed together in notifications to indicate
|
||||
* what got changed.
|
||||
*/
|
||||
enum
|
||||
{ NSTextStorageEditedAttributes = 1,
|
||||
NSTextStorageEditedCharacters = 2
|
||||
{
|
||||
NSTextStorageEditedAttributes = 1,
|
||||
NSTextStorageEditedCharacters = 2
|
||||
};
|
||||
|
||||
@interface NSTextStorage : NSMutableAttributedString {
|
||||
NSRange editedRange;
|
||||
int editedDelta;
|
||||
NSMutableArray *layoutManagers;
|
||||
id delegate;
|
||||
@interface NSTextStorage : NSMutableAttributedString
|
||||
{
|
||||
NSRange editedRange;
|
||||
int editedDelta;
|
||||
NSMutableArray *layoutManagers;
|
||||
id delegate;
|
||||
unsigned editedMask;
|
||||
unsigned editCount;
|
||||
}
|
||||
|
||||
// These methods manage the list of layout managers.
|
||||
- (void)addLayoutManager:(NSLayoutManager *)obj; /* Retains & calls setTextStorage: on the item */
|
||||
- (void)removeLayoutManager:(NSLayoutManager *)obj;
|
||||
- (NSArray *)layoutManagers;
|
||||
/*
|
||||
* Managing NSLayoutManagers
|
||||
*/
|
||||
- (void) addLayoutManager: (NSLayoutManager*)obj;
|
||||
- (void) removeLayoutManager: (NSLayoutManager*)obj;
|
||||
- (NSArray*) layoutManagers;
|
||||
|
||||
/* If there are no outstanding beginEditing calls, this method calls processEditing to cause post-editing stuff to happen. This method has to be called by the primitives after changes are made. The range argument to edited:... is the range in the original string (before the edit).
|
||||
*/
|
||||
- (void)edited:(unsigned)editedMask range:(NSRange)range changeInLength:(int)delta;
|
||||
/*
|
||||
* If there are no outstanding beginEditing calls, this method calls
|
||||
* processEditing to cause post-editing stuff to happen. This method
|
||||
* has to be called by the primitives after changes are made.
|
||||
* The range argument to edited:... is the range in the original string
|
||||
* (before the edit).
|
||||
*/
|
||||
- (void) edited: (unsigned)mask range: (NSRange)old changeInLength: (int)delta;
|
||||
|
||||
/* This is called from edited:range:changeInLength: or endEditing. This method sends out NSTextStorageWillProcessEditing, then fixes the attributes, then sends out NSTextStorageDidProcessEditing, and finally notifies the layout managers of change with the textStorage:edited:range:changeInLength:invalidatedRange: method.
|
||||
*/
|
||||
- (void)processEditing;
|
||||
/*
|
||||
* This is called from edited:range:changeInLength: or endEditing.
|
||||
* This method sends out NSTextStorageWillProcessEditing, then fixes
|
||||
* the attributes, then sends out NSTextStorageDidProcessEditing,
|
||||
* and finally notifies the layout managers of change with the
|
||||
* textStorage:edited:range:changeInLength:invalidatedRange: method.
|
||||
*/
|
||||
- (void) processEditing;
|
||||
|
||||
/* These methods return information about the editing status. Especially useful when there are outstanding beginEditing calls or during processEditing... editedRange.location will be NSNotFound if nothing has been edited.
|
||||
*/
|
||||
- (unsigned)editedMask;
|
||||
- (NSRange)editedRange;
|
||||
- (int)changeInLength;
|
||||
- (void) beginEditing;
|
||||
- (void) endEditing;
|
||||
|
||||
/* Set/get the delegate
|
||||
*/
|
||||
- (void)setDelegate:(id)delegate;
|
||||
- (id)delegate;
|
||||
/*
|
||||
* These methods return information about the editing status.
|
||||
* Especially useful when there are outstanding beginEditing calls or
|
||||
* during processEditing... editedRange.location will be NSNotFound if
|
||||
* nothing has been edited.
|
||||
*/
|
||||
- (unsigned) editedMask;
|
||||
- (NSRange) editedRange;
|
||||
- (int) changeInLength;
|
||||
|
||||
/*
|
||||
* Set/get the delegate
|
||||
*/
|
||||
- (void) setDelegate: (id)delegate;
|
||||
- (id) delegate;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -90,10 +121,14 @@ enum
|
|||
|
||||
@interface NSObject (NSTextStorageDelegate)
|
||||
|
||||
/* These methods are sent during processEditing:. The receiver can use the callback methods editedMask, editedRange, and changeInLength to see what has changed. Although these methods can change the contents of the text storage, it's best if only the delegate did this.
|
||||
*/
|
||||
- (void)textStorageWillProcessEditing:(NSNotification *)notification; /* Delegate can change the characters or attributes */
|
||||
- (void)textStorageDidProcessEditing:(NSNotification *)notification; /* Delegate can change the attributes */
|
||||
/*
|
||||
* These methods are sent during processEditing:. The receiver can use
|
||||
* the callback methods editedMask, editedRange, and changeInLength to
|
||||
* see what has changed. Although these methods can change the contents
|
||||
* of the text storage, it's best if only the delegate did this.
|
||||
*/
|
||||
- (void) textStorageWillProcessEditing: (NSNotification*)notification;
|
||||
- (void) textStorageDidProcessEditing: (NSNotification*)notification;
|
||||
|
||||
@end
|
||||
|
||||
|
|
211
Source/NSTextStorage.m
Normal file
211
Source/NSTextStorage.m
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
NSTextStorage.m
|
||||
|
||||
Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
|
||||
Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
Date: 1999
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <AppKit/NSTextStorage.h>
|
||||
|
||||
@implementation NSTextStorage
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[layoutManagers release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
self = [super init];
|
||||
layoutManagers = [[NSMutableArray alloc] initWithCapacity: 2];
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* Managing NSLayoutManagers
|
||||
*/
|
||||
- (void) addLayoutManager: (NSLayoutManager*)obj
|
||||
{
|
||||
if ([layoutManagers indexOfObjectIdenticalTo: obj] == NSNotFound)
|
||||
[layoutManagers addObject: obj];
|
||||
}
|
||||
|
||||
- (void) removeLayoutManager: (NSLayoutManager*)obj
|
||||
{
|
||||
[layoutManagers removeObjectIdenticalTo: obj];
|
||||
}
|
||||
|
||||
- (NSArray*) layoutManagers
|
||||
{
|
||||
return layoutManagers;
|
||||
}
|
||||
|
||||
- (void) beginEditing
|
||||
{
|
||||
editCount++;
|
||||
}
|
||||
|
||||
- (void) endEditing
|
||||
{
|
||||
if (editCount == 0)
|
||||
[NSException raise: NSGenericException
|
||||
format: @"endEditing without corresponding beginEditing"];
|
||||
if (--editCount == 0)
|
||||
{
|
||||
[self processEditing];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are no outstanding beginEditing calls, this method calls
|
||||
* processEditing to cause post-editing stuff to happen. This method
|
||||
* has to be called by the primitives after changes are made.
|
||||
* The range argument to edited:... is the range in the original string
|
||||
* (before the edit).
|
||||
*/
|
||||
- (void) edited: (unsigned)mask range: (NSRange)old changeInLength: (int)delta
|
||||
{
|
||||
/*
|
||||
* Add in any new flags for this edit.
|
||||
*/
|
||||
editedMask |= mask;
|
||||
|
||||
/*
|
||||
* Extend edited range to encompass the latest edit.
|
||||
*/
|
||||
if (editedRange.length == 0)
|
||||
{
|
||||
editedRange = old; // First edit.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (editedRange.location > old.location)
|
||||
editedRange.location = old.location;
|
||||
if (NSMaxRange(editedRange) < NSMaxRange(old))
|
||||
editedRange.length = NSMaxRange(old) - editedRange.location;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the number of characters has been increased or decreased -
|
||||
* adjust the delta accordingly.
|
||||
*/
|
||||
if ((mask & NSTextStorageEditedCharacters) && delta)
|
||||
{
|
||||
if (delta < 0)
|
||||
{
|
||||
NSAssert(old.length > -delta, NSInvalidArgumentException);
|
||||
}
|
||||
editedDelta += delta;
|
||||
}
|
||||
|
||||
if (editCount == 0)
|
||||
[self processEditing];
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called from edited:range:changeInLength: or endEditing.
|
||||
* This method sends out NSTextStorageWillProcessEditing, then fixes
|
||||
* the attributes, then sends out NSTextStorageDidProcessEditing,
|
||||
* and finally notifies the layout managers of change with the
|
||||
* textStorage:edited:range:changeInLength:invalidatedRange: method.
|
||||
*/
|
||||
- (void) processEditing
|
||||
{
|
||||
NSRange r;
|
||||
|
||||
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
|
||||
|
||||
[nc postNotificationName: NSTextStorageWillProcessEditingNotification
|
||||
object: self];
|
||||
|
||||
r = editedRange;
|
||||
r.length += editedDelta;
|
||||
[self fixAttributesInRange: r];
|
||||
|
||||
[nc postNotificationName: NSTextStorageDidProcessEditingNotification
|
||||
object: self];
|
||||
editedRange = NSMakeRange(0, 0);
|
||||
editedDelta = 0;
|
||||
editedMask = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* These methods return information about the editing status.
|
||||
* Especially useful when there are outstanding beginEditing calls or
|
||||
* during processEditing... editedRange.location will be NSNotFound if
|
||||
* nothing has been edited.
|
||||
*/
|
||||
- (unsigned) editedMask
|
||||
{
|
||||
return editedMask;
|
||||
}
|
||||
|
||||
- (NSRange) editedRange
|
||||
{
|
||||
return editedRange;
|
||||
}
|
||||
|
||||
- (int) changeInLength
|
||||
{
|
||||
return editedDelta;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set/get the delegate
|
||||
*/
|
||||
- (void) setDelegate: (id)anObject
|
||||
{
|
||||
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
|
||||
|
||||
if (delegate)
|
||||
[nc removeObserver: delegate name: nil object: self];
|
||||
delegate = anObject;
|
||||
|
||||
#define SET_DELEGATE_NOTIFICATION(notif_name) \
|
||||
if ([delegate respondsToSelector: @selector(textStorage##notif_name:)]) \
|
||||
[nc addObserver: delegate \
|
||||
selector: @selector(textStorage##notif_name:) \
|
||||
name: NSTextStorage##notif_name##Notification object: self]
|
||||
|
||||
SET_DELEGATE_NOTIFICATION(DidProcessEditing);
|
||||
SET_DELEGATE_NOTIFICATION(WillProcessEditing);
|
||||
}
|
||||
|
||||
- (id) delegate
|
||||
{
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/*
|
||||
* Notifications
|
||||
*/
|
||||
|
||||
NSString *NSTextStorageWillProcessEditingNotification =
|
||||
@"NSTextStorageWillProcessEditingNotification";
|
||||
NSString *NSTextStorageDidProcessEditingNotification =
|
||||
@"NSTextStorageDidProcessEditingNotification";
|
||||
|
Loading…
Reference in a new issue