2000-03-16 14:16:46 +00:00
|
|
|
|
/*
|
1996-05-30 20:03:15 +00:00
|
|
|
|
NSText.m
|
|
|
|
|
|
|
|
|
|
The RTFD text class
|
|
|
|
|
|
|
|
|
|
Copyright (C) 1996 Free Software Foundation, Inc.
|
|
|
|
|
|
1999-11-11 17:17:14 +00:00
|
|
|
|
Author: Scott Christley <scottc@net-community.com>
|
1996-05-30 20:03:15 +00:00
|
|
|
|
Date: 1996
|
1998-08-01 15:41:49 +00:00
|
|
|
|
Author: Felipe A. Rodriguez <far@ix.netcom.com>
|
|
|
|
|
Date: July 1998
|
1999-11-11 17:17:14 +00:00
|
|
|
|
Author: Daniel B<EFBFBD>hringer <boehring@biomed.ruhr-uni-bochum.de>
|
1998-08-20 09:56:26 +00:00
|
|
|
|
Date: August 1998
|
2000-03-16 14:16:46 +00:00
|
|
|
|
Author: Fred Kiefer <FredKiefer@gmx.de>
|
|
|
|
|
Date: March 2000
|
|
|
|
|
Reorganised and cleaned up code, added some action methods
|
|
|
|
|
|
1996-05-30 20:03:15 +00:00
|
|
|
|
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.
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
1996-05-30 20:03:15 +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.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
1996-10-18 17:14:13 +00:00
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
|
If not, write to the Free Software Foundation,
|
1999-11-02 07:58:11 +00:00
|
|
|
|
59 Temple Place - Suite 330, Boston, MA 02111 - 1307, USA.
|
1999-06-22 23:37:24 +00:00
|
|
|
|
*/
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
1999-11-11 17:17:14 +00:00
|
|
|
|
// toDo: - caret blinking
|
1998-10-15 12:04:53 +00:00
|
|
|
|
|
1999-11-14 03:23:54 +00:00
|
|
|
|
#include <Foundation/NSNotification.h>
|
1997-08-18 17:10:23 +00:00
|
|
|
|
#include <Foundation/NSString.h>
|
2000-09-18 23:33:30 +00:00
|
|
|
|
#include <Foundation/NSArchiver.h>
|
|
|
|
|
#include <Foundation/NSValue.h>
|
|
|
|
|
#include <Foundation/NSData.h>
|
1998-08-20 09:56:26 +00:00
|
|
|
|
|
1998-09-02 15:05:13 +00:00
|
|
|
|
#include <AppKit/NSFileWrapper.h>
|
|
|
|
|
#include <AppKit/NSControl.h>
|
1997-02-18 00:29:25 +00:00
|
|
|
|
#include <AppKit/NSText.h>
|
|
|
|
|
#include <AppKit/NSApplication.h>
|
|
|
|
|
#include <AppKit/NSWindow.h>
|
2000-03-08 08:43:15 +00:00
|
|
|
|
#include <AppKit/NSFontManager.h>
|
1997-02-18 00:29:25 +00:00
|
|
|
|
#include <AppKit/NSFont.h>
|
|
|
|
|
#include <AppKit/NSColor.h>
|
2000-03-08 08:43:15 +00:00
|
|
|
|
#include <AppKit/NSParagraphStyle.h>
|
1998-08-20 09:56:26 +00:00
|
|
|
|
#include <AppKit/NSPasteboard.h>
|
1998-09-02 15:05:13 +00:00
|
|
|
|
#include <AppKit/NSSpellChecker.h>
|
1999-06-22 23:37:24 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
#include <AppKit/NSDragging.h>
|
2000-03-23 11:32:59 +00:00
|
|
|
|
#include <AppKit/NSTextStorage.h>
|
2000-04-23 22:31:25 +00:00
|
|
|
|
#include <AppKit/NSTextContainer.h>
|
2000-10-12 23:02:25 +00:00
|
|
|
|
#include <AppKit/NSLayoutManager.h>
|
1998-09-02 15:05:13 +00:00
|
|
|
|
|
1998-10-15 12:04:53 +00:00
|
|
|
|
|
2000-11-03 00:22:15 +00:00
|
|
|
|
#define HUGE 1e7
|
1998-10-15 12:04:53 +00:00
|
|
|
|
|
|
|
|
|
|
2000-09-18 23:33:30 +00:00
|
|
|
|
static NSNotificationCenter *nc;
|
1999-06-22 23:37:24 +00:00
|
|
|
|
|
|
|
|
|
|
2000-03-08 08:43:15 +00:00
|
|
|
|
@interface NSText(GNUstepPrivate)
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/*
|
2000-09-18 23:33:30 +00:00
|
|
|
|
* these NSLayoutManager- like methods are here only informally
|
2000-03-16 14:16:46 +00:00
|
|
|
|
*/
|
|
|
|
|
- (unsigned) characterIndexForPoint: (NSPoint)point;
|
|
|
|
|
- (NSRect) rectForCharacterIndex: (unsigned)index;
|
2000-08-07 22:06:04 +00:00
|
|
|
|
- (NSRect) rectForCharacterRange: (NSRange)aRange;
|
2000-09-30 23:11:15 +00:00
|
|
|
|
|
|
|
|
|
- (NSTextContainer*) buildUpTextNetwork: (NSSize)aSize;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* various GNU extensions
|
|
|
|
|
*/
|
2000-05-20 16:55:08 +00:00
|
|
|
|
+ (NSDictionary*) defaultTypingAttributes;
|
|
|
|
|
|
2000-03-08 08:43:15 +00:00
|
|
|
|
//
|
2000-06-26 19:55:01 +00:00
|
|
|
|
// GNU utility methods
|
2000-03-08 08:43:15 +00:00
|
|
|
|
//
|
2000-06-26 19:55:01 +00:00
|
|
|
|
- (void) setAttributes: (NSDictionary*) attributes range: (NSRange) aRange;
|
|
|
|
|
- (void) _illegalMovement: (int) notNumber;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) deleteRange: (NSRange)aRange backspace: (BOOL)flag;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
|
|
|
|
|
- (void) drawInsertionPointAtIndex: (unsigned)index
|
|
|
|
|
color: (NSColor*)color
|
|
|
|
|
turnedOn: (BOOL)flag;
|
|
|
|
|
@end
|
|
|
|
|
|
2000-09-30 23:11:15 +00:00
|
|
|
|
// not the same as NSMakeRange!
|
2000-10-12 23:02:25 +00:00
|
|
|
|
static inline
|
|
|
|
|
NSRange MakeRangeFromAbs (unsigned a1, unsigned a2)
|
1998-08-04 08:33:31 +00:00
|
|
|
|
{
|
2000-09-18 23:33:30 +00:00
|
|
|
|
if (a1 < a2)
|
2000-09-30 23:11:15 +00:00
|
|
|
|
return NSMakeRange(a1, a2 - a1);
|
2000-03-08 08:43:15 +00:00
|
|
|
|
else
|
2000-09-30 23:11:15 +00:00
|
|
|
|
return NSMakeRange(a2, a1 - a2);
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
@implementation NSText
|
2000-03-08 08:43:15 +00:00
|
|
|
|
|
|
|
|
|
//
|
2000-03-16 14:16:46 +00:00
|
|
|
|
// Class methods
|
2000-03-08 08:43:15 +00:00
|
|
|
|
//
|
2000-03-16 14:16:46 +00:00
|
|
|
|
+ (void)initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSText class])
|
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
NSArray *types;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
|
2000-10-12 23:02:25 +00:00
|
|
|
|
// Initial version
|
|
|
|
|
[self setVersion: 1];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-08-26 20:41:52 +00:00
|
|
|
|
nc = [NSNotificationCenter defaultCenter];
|
|
|
|
|
|
2000-05-23 22:58:24 +00:00
|
|
|
|
types = [NSArray arrayWithObjects: NSStringPboardType, NSRTFPboardType, NSRTFDPboardType, nil];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-05-23 22:58:24 +00:00
|
|
|
|
[[NSApplication sharedApplication] registerServicesMenuSendTypes: types
|
|
|
|
|
returnTypes: types];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
2000-03-16 14:16:46 +00:00
|
|
|
|
// Instance methods
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Initialization
|
2000-03-08 08:43:15 +00:00
|
|
|
|
//
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
|
|
|
|
- (id) init
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return [self initWithFrame: NSMakeRect (0, 0, 100, 100)];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (id) initWithFrame: (NSRect)frameRect
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-09-30 23:11:15 +00:00
|
|
|
|
NSTextContainer *aTextContainer = [self buildUpTextNetwork: frameRect.size];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
|
2000-09-30 23:11:15 +00:00
|
|
|
|
return [self initWithFrame: frameRect textContainer: aTextContainer];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void)dealloc
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
RELEASE(_background_color);
|
2000-05-13 14:28:02 +00:00
|
|
|
|
RELEASE(_caret_color);
|
|
|
|
|
RELEASE(_typingAttributes);
|
2000-09-30 23:11:15 +00:00
|
|
|
|
RELEASE(_textStorage);
|
|
|
|
|
RELEASE(_textContainer);
|
2000-05-13 14:28:02 +00:00
|
|
|
|
RELEASE(_layoutManager);
|
2000-03-08 08:43:15 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[super dealloc];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* Getting and Setting Contents
|
|
|
|
|
*/
|
|
|
|
|
- (void) replaceCharactersInRange: (NSRange)aRange
|
|
|
|
|
withRTF: (NSData*)rtfData
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-05-04 22:44:20 +00:00
|
|
|
|
[self replaceRange: aRange
|
|
|
|
|
withAttributedString: AUTORELEASE([[NSAttributedString alloc]
|
|
|
|
|
initWithRTF: rtfData
|
|
|
|
|
documentAttributes: NULL])];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) replaceCharactersInRange: (NSRange)aRange
|
|
|
|
|
withRTFD: (NSData*)rtfdData
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[self replaceRange: aRange
|
|
|
|
|
withAttributedString: AUTORELEASE([[NSAttributedString alloc]
|
|
|
|
|
initWithRTFD: rtfdData
|
|
|
|
|
documentAttributes: NULL])];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) replaceCharactersInRange: (NSRange)aRange
|
|
|
|
|
withString: (NSString*)aString
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
if (aRange.location == NSNotFound)
|
|
|
|
|
return;
|
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
2000-06-26 19:55:01 +00:00
|
|
|
|
replacementString: aString])
|
2000-05-20 16:55:08 +00:00
|
|
|
|
return;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
[_textStorage beginEditing];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[_textStorage replaceCharactersInRange: aRange withString: aString];
|
2000-04-02 05:58:50 +00:00
|
|
|
|
[_textStorage endEditing];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self didChangeText];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setString: (NSString*)aString
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-09-18 23:33:30 +00:00
|
|
|
|
[self replaceCharactersInRange: NSMakeRange(0, [_textStorage length])
|
|
|
|
|
withString: aString];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (NSString*) string
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-09-30 23:11:15 +00:00
|
|
|
|
// FIXME: This should remove all the attachement characters.
|
2000-09-19 22:38:56 +00:00
|
|
|
|
return [_textStorage string];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
// old methods
|
|
|
|
|
- (void) replaceRange: (NSRange)aRange withRTFD: (NSData*)rtfdData
|
|
|
|
|
{
|
|
|
|
|
[self replaceCharactersInRange: aRange withRTFD: rtfdData];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) replaceRange: (NSRange)aRange withRTF: (NSData*)rtfData
|
|
|
|
|
{
|
|
|
|
|
[self replaceCharactersInRange: aRange withRTF: rtfData];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) replaceRange: (NSRange)aRange withString: (NSString*)aString
|
|
|
|
|
{
|
|
|
|
|
[self replaceCharactersInRange: aRange withString: aString];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setText: (NSString*)aString range: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
[self replaceCharactersInRange: aRange withString: aString];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setText: (NSString*)string
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[self setString: string];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (NSString*) text
|
|
|
|
|
{
|
|
|
|
|
return [self string];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
//
|
|
|
|
|
// Graphic attributes
|
|
|
|
|
//
|
|
|
|
|
- (NSColor*) backgroundColor
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return _background_color;
|
|
|
|
|
}
|
2000-03-08 08:43:15 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (BOOL) drawsBackground
|
|
|
|
|
{
|
|
|
|
|
return _tf.draws_background;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setBackgroundColor: (NSColor*)color
|
|
|
|
|
{
|
|
|
|
|
ASSIGN(_background_color, color);
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void)setDrawsBackground: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
_tf.draws_background = flag;
|
|
|
|
|
}
|
2000-03-08 08:43:15 +00:00
|
|
|
|
|
|
|
|
|
//
|
2000-03-16 14:16:46 +00:00
|
|
|
|
// Managing Global Characteristics
|
|
|
|
|
//
|
|
|
|
|
- (BOOL) importsGraphics
|
|
|
|
|
{
|
|
|
|
|
return _tf.imports_graphics;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (BOOL) isEditable
|
|
|
|
|
{
|
|
|
|
|
return _tf.is_editable;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (BOOL) isFieldEditor
|
|
|
|
|
{
|
|
|
|
|
return _tf.is_field_editor;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (BOOL) isRichText
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return _tf.is_rich_text;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (BOOL) isSelectable
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return _tf.is_selectable;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void)setEditable: (BOOL)flag
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
_tf.is_editable = flag;
|
2000-05-04 22:44:20 +00:00
|
|
|
|
// If we are editable then we are selectable
|
2000-03-16 14:16:46 +00:00
|
|
|
|
if (flag)
|
2000-03-19 07:33:26 +00:00
|
|
|
|
{
|
|
|
|
|
_tf.is_selectable = YES;
|
|
|
|
|
// FIXME: We should show the insertion point
|
|
|
|
|
}
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setFieldEditor: (BOOL)flag
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
_tf.is_field_editor = flag;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void)setImportsGraphics: (BOOL)flag
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (flag)
|
|
|
|
|
_tf.is_rich_text = flag;
|
2000-06-26 19:55:01 +00:00
|
|
|
|
// FIXME: When switched off remove attachments
|
2000-03-16 14:16:46 +00:00
|
|
|
|
_tf.imports_graphics = flag;
|
|
|
|
|
}
|
2000-03-08 08:43:15 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setRichText: (BOOL)flag
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
_tf.is_rich_text = flag;
|
|
|
|
|
if (!flag)
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
_tf.imports_graphics = flag;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[self setString: [self string]];
|
1999-11-11 17:17:14 +00:00
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setSelectable: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
_tf.is_selectable = flag;
|
|
|
|
|
// If we are not selectable then we must not be editable
|
|
|
|
|
if (!flag)
|
|
|
|
|
_tf.is_editable = NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Using the font panel
|
|
|
|
|
//
|
|
|
|
|
- (BOOL) usesFontPanel
|
|
|
|
|
{
|
|
|
|
|
return _tf.uses_font_panel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setUsesFontPanel: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
_tf.uses_font_panel = flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Managing the Ruler
|
|
|
|
|
//
|
|
|
|
|
- (BOOL) isRulerVisible
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-05-04 22:44:20 +00:00
|
|
|
|
return _tf.is_ruler_visible;
|
1999-06-22 23:37:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) toggleRuler: (id)sender
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self setRulerVisible: !_tf.is_ruler_visible];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Managing the Selection
|
|
|
|
|
//
|
|
|
|
|
- (NSRange)selectedRange
|
|
|
|
|
{
|
|
|
|
|
return _selected_range;
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
1998-10-15 12:04:53 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setSelectedRange: (NSRange)range
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NSRange oldRange = _selected_range;
|
|
|
|
|
NSRange overlap;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-09-30 23:11:15 +00:00
|
|
|
|
// Nothing to do, if the range is still the same
|
2000-08-07 22:06:04 +00:00
|
|
|
|
if (NSEqualRanges(range, oldRange))
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
//<!> ask delegate for selection validation
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
_selected_range = range;
|
|
|
|
|
[self updateFontPanel];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
#if 0
|
2000-08-26 20:41:52 +00:00
|
|
|
|
[nc postNotificationName: NSTextViewDidChangeSelectionNotification
|
|
|
|
|
object: self
|
|
|
|
|
userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
|
NSStringFromRange (_selected_range),
|
|
|
|
|
NSOldSelectedCharacterRange, nil]];
|
2000-08-07 22:06:04 +00:00
|
|
|
|
#endif
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
|
|
|
|
// display
|
|
|
|
|
if (range.length)
|
|
|
|
|
{
|
|
|
|
|
// <!>disable caret timed entry
|
|
|
|
|
}
|
|
|
|
|
else // no selection
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (_tf.is_rich_text)
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self setTypingAttributes: [_textStorage attributesAtIndex: range.location
|
|
|
|
|
effectiveRange: NULL]];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
// <!>enable caret timed entry
|
|
|
|
|
}
|
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
if (!_window)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Make the selected range visible
|
|
|
|
|
[self scrollRangeToVisible: _selected_range];
|
|
|
|
|
|
|
|
|
|
// Redisplay what has changed
|
|
|
|
|
// This does an unhighlight of the old selected region
|
|
|
|
|
overlap = NSIntersectionRange(oldRange, _selected_range);
|
|
|
|
|
if (overlap.length)
|
|
|
|
|
{
|
|
|
|
|
// Try to optimize for overlapping ranges
|
2000-09-08 00:07:42 +00:00
|
|
|
|
if (range.location != oldRange.location)
|
|
|
|
|
[self setNeedsDisplayInRect:
|
|
|
|
|
[self rectForCharacterRange:
|
|
|
|
|
MakeRangeFromAbs(MIN(range.location,
|
|
|
|
|
oldRange.location),
|
|
|
|
|
MAX(range.location,
|
|
|
|
|
oldRange.location))]];
|
|
|
|
|
if (NSMaxRange(range) != NSMaxRange(oldRange))
|
|
|
|
|
[self setNeedsDisplayInRect:
|
|
|
|
|
[self rectForCharacterRange:
|
|
|
|
|
MakeRangeFromAbs(MIN(NSMaxRange(range),
|
|
|
|
|
NSMaxRange(oldRange)),
|
|
|
|
|
MAX(NSMaxRange(range),
|
|
|
|
|
NSMaxRange (oldRange)))]];
|
2000-08-07 22:06:04 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-08-07 22:06:04 +00:00
|
|
|
|
[self setNeedsDisplayInRect: [self rectForCharacterRange: range]];
|
|
|
|
|
[self setNeedsDisplayInRect: [self rectForCharacterRange: oldRange]];
|
1999-11-11 17:17:14 +00:00
|
|
|
|
}
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
1999-11-11 17:17:14 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* Copy and paste
|
|
|
|
|
*/
|
|
|
|
|
- (void) copy: (id)sender
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
NSMutableArray *types = [NSMutableArray array];
|
1998-09-02 15:05:13 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
if (_tf.imports_graphics)
|
|
|
|
|
[types addObject: NSRTFDPboardType];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (_tf.is_rich_text)
|
2000-05-23 22:58:24 +00:00
|
|
|
|
[types addObject: NSRTFPboardType];
|
1998-09-02 15:05:13 +00:00
|
|
|
|
|
2000-05-23 22:58:24 +00:00
|
|
|
|
[types addObject: NSStringPboardType];
|
|
|
|
|
|
|
|
|
|
[self writeSelectionToPasteboard: [NSPasteboard generalPasteboard]
|
|
|
|
|
types: types];
|
1998-09-02 15:05:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
// Copy the current font to the font pasteboard
|
|
|
|
|
- (void) copyFont: (id)sender
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
[self writeSelectionToPasteboard: [NSPasteboard pasteboardWithName: NSFontPboard]
|
|
|
|
|
type: NSFontPboardType];
|
1998-09-02 15:05:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
// Copy the current ruler settings to the ruler pasteboard
|
|
|
|
|
- (void) copyRuler: (id)sender
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
[self writeSelectionToPasteboard: [NSPasteboard pasteboardWithName: NSRulerPboard]
|
|
|
|
|
type: NSRulerPboardType];
|
1999-02-10 15:09:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) delete: (id)sender
|
1999-08-22 04:04:38 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[self deleteRange: _selected_range backspace: NO];
|
|
|
|
|
}
|
2000-03-08 08:43:15 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) cut: (id)sender
|
|
|
|
|
{
|
|
|
|
|
if (_selected_range.length)
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[self copy: sender];
|
|
|
|
|
[self delete: sender];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
1998-08-20 09:56:26 +00:00
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) paste: (id)sender
|
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
[self readSelectionFromPasteboard: [NSPasteboard generalPasteboard]];
|
1999-08-31 09:19:39 +00:00
|
|
|
|
}
|
1999-02-17 09:13:43 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) pasteFont: (id)sender
|
1999-02-17 09:13:43 +00:00
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
[self readSelectionFromPasteboard:
|
|
|
|
|
[NSPasteboard pasteboardWithName: NSFontPboard]
|
|
|
|
|
type: NSFontPboardType];
|
1998-08-20 09:56:26 +00:00
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) pasteRuler: (id)sender
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
[self readSelectionFromPasteboard:
|
|
|
|
|
[NSPasteboard pasteboardWithName: NSRulerPboard]
|
|
|
|
|
type: NSRulerPboardType];
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) selectAll: (id)sender
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-08-07 22:06:04 +00:00
|
|
|
|
[self setSelectedRange: NSMakeRange(0, [self textLength])];
|
1999-11-11 17:17:14 +00:00
|
|
|
|
}
|
1998-09-02 15:05:13 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/*
|
2000-05-20 16:55:08 +00:00
|
|
|
|
* Managing Font
|
2000-03-16 14:16:46 +00:00
|
|
|
|
*/
|
|
|
|
|
- (NSFont*) font
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if ([_textStorage length])
|
|
|
|
|
{
|
|
|
|
|
NSFont *font = [_textStorage attribute: NSFontAttributeName
|
|
|
|
|
atIndex: 0
|
|
|
|
|
effectiveRange: NULL];
|
|
|
|
|
if (font != nil)
|
|
|
|
|
return font;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [_typingAttributes objectForKey: NSFontAttributeName];
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* This action method changes the font of the selection for a rich text object,
|
|
|
|
|
* or of all text for a plain text object. If the receiver doesn't use the Font
|
|
|
|
|
* Panel, however, this method does nothing.
|
|
|
|
|
*/
|
|
|
|
|
- (void) changeFont: (id)sender
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
NSRange foundRange;
|
|
|
|
|
int maxSelRange;
|
|
|
|
|
NSRange aRange= [self rangeForUserCharacterAttributeChange];
|
|
|
|
|
NSRange searchRange = aRange;
|
2000-06-26 19:55:01 +00:00
|
|
|
|
NSFont *font;
|
2000-05-20 16:55:08 +00:00
|
|
|
|
|
|
|
|
|
if (aRange.location == NSNotFound)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
|
|
|
|
replacementString: nil])
|
|
|
|
|
return;
|
|
|
|
|
[_textStorage beginEditing];
|
|
|
|
|
for (maxSelRange = NSMaxRange(aRange);
|
|
|
|
|
searchRange.location < maxSelRange;
|
|
|
|
|
searchRange = NSMakeRange (NSMaxRange (foundRange),
|
|
|
|
|
maxSelRange - NSMaxRange(foundRange)))
|
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
font = [_textStorage attribute: NSFontAttributeName
|
|
|
|
|
atIndex: searchRange.location
|
|
|
|
|
longestEffectiveRange: &foundRange
|
|
|
|
|
inRange: searchRange];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (font != nil)
|
|
|
|
|
{
|
|
|
|
|
[self setFont: [sender convertFont: font]
|
|
|
|
|
ofRange: foundRange];
|
|
|
|
|
}
|
1999-11-11 17:17:14 +00:00
|
|
|
|
}
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[_textStorage endEditing];
|
|
|
|
|
[self didChangeText];
|
2000-06-26 19:55:01 +00:00
|
|
|
|
// Set typing attributes
|
|
|
|
|
font = [_typingAttributes objectForKey: NSFontAttributeName];
|
|
|
|
|
if (font != nil)
|
|
|
|
|
{
|
|
|
|
|
[_typingAttributes setObject: [sender convertFont: font]
|
|
|
|
|
forKey: NSFontAttributeName];
|
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setFont: (NSFont*)font
|
|
|
|
|
{
|
2000-04-02 05:58:50 +00:00
|
|
|
|
NSRange fullRange = NSMakeRange(0, [_textStorage length]);
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-06-29 14:25:07 +00:00
|
|
|
|
if (font == nil)
|
|
|
|
|
return;
|
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self setFont: font ofRange: fullRange];
|
|
|
|
|
[_typingAttributes setObject: font forKey: NSFontAttributeName];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setFont: (NSFont*)font
|
|
|
|
|
ofRange: (NSRange)aRange
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (font != nil)
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
|
|
|
|
replacementString: nil])
|
|
|
|
|
return;
|
|
|
|
|
[_textStorage beginEditing];
|
|
|
|
|
[_textStorage addAttribute: NSFontAttributeName
|
|
|
|
|
value: font
|
|
|
|
|
range: aRange];
|
|
|
|
|
[_textStorage endEditing];
|
|
|
|
|
[self didChangeText];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
1998-10-15 12:04:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* Managing Alingment
|
|
|
|
|
*/
|
|
|
|
|
- (NSTextAlignment) alignment
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
NSRange aRange = [self rangeForUserParagraphAttributeChange];
|
|
|
|
|
NSParagraphStyle *aStyle;
|
|
|
|
|
|
|
|
|
|
if (aRange.location != NSNotFound)
|
|
|
|
|
{
|
|
|
|
|
aStyle = [_textStorage attribute: NSParagraphStyleAttributeName
|
|
|
|
|
atIndex: aRange.location
|
|
|
|
|
effectiveRange: NULL];
|
|
|
|
|
if (aStyle != nil)
|
|
|
|
|
return [aStyle alignment];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get alignment from typing attributes
|
|
|
|
|
return [[[self typingAttributes]
|
|
|
|
|
objectForKey: NSParagraphStyleAttributeName] alignment];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setAlignment: (NSTextAlignment) mode
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self setAlignment: mode
|
|
|
|
|
range: NSMakeRange(0, [_textStorage length])];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) alignCenter: (id) sender
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self setAlignment: NSCenterTextAlignment
|
|
|
|
|
range: [self rangeForUserParagraphAttributeChange]];
|
1998-10-15 12:04:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) alignLeft: (id) sender
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self setAlignment: NSLeftTextAlignment
|
|
|
|
|
range: [self rangeForUserParagraphAttributeChange]];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) alignRight: (id) sender
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self setAlignment: NSRightTextAlignment
|
|
|
|
|
range: [self rangeForUserParagraphAttributeChange]];
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* Text colour
|
|
|
|
|
*/
|
2000-05-20 16:55:08 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (NSColor*) textColor
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
NSRange aRange = [self rangeForUserCharacterAttributeChange];
|
|
|
|
|
|
|
|
|
|
if (aRange.location != NSNotFound)
|
|
|
|
|
return [_textStorage attribute: NSForegroundColorAttributeName
|
|
|
|
|
atIndex: aRange.location
|
|
|
|
|
effectiveRange: NULL];
|
|
|
|
|
else
|
|
|
|
|
return [_typingAttributes objectForKey: NSForegroundColorAttributeName];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
1998-10-15 12:04:53 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setTextColor: (NSColor*) color
|
|
|
|
|
range: (NSRange) aRange
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (aRange.location == NSNotFound)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
|
|
|
|
replacementString: nil])
|
|
|
|
|
return;
|
|
|
|
|
[_textStorage beginEditing];
|
|
|
|
|
if (color != nil)
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[_textStorage addAttribute: NSForegroundColorAttributeName
|
|
|
|
|
value: color
|
|
|
|
|
range: aRange];
|
|
|
|
|
[_typingAttributes setObject: color forKey: NSForegroundColorAttributeName];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
2000-05-20 16:55:08 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[_textStorage removeAttribute: NSForegroundColorAttributeName
|
|
|
|
|
range: aRange];
|
|
|
|
|
}
|
|
|
|
|
[_textStorage endEditing];
|
|
|
|
|
[self didChangeText];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
1998-09-02 15:05:13 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setColor: (NSColor*) color
|
|
|
|
|
ofRange: (NSRange) aRange
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[self setTextColor: color range: aRange];
|
|
|
|
|
}
|
1999-11-11 17:17:14 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) setTextColor: (NSColor*) color
|
|
|
|
|
{
|
2000-04-02 05:58:50 +00:00
|
|
|
|
NSRange fullRange = NSMakeRange(0, [_textStorage length]);
|
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self setTextColor: color range: fullRange];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Text attributes
|
|
|
|
|
//
|
|
|
|
|
- (void) subscript: (id)sender
|
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
NSNumber *value = [_typingAttributes
|
|
|
|
|
objectForKey: NSSuperscriptAttributeName];
|
|
|
|
|
int sValue;
|
2000-05-20 16:55:08 +00:00
|
|
|
|
NSRange aRange = [self rangeForUserCharacterAttributeChange];
|
2000-04-02 05:58:50 +00:00
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (aRange.location == NSNotFound)
|
|
|
|
|
return;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
|
|
|
|
|
if (aRange.length)
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
|
|
|
|
replacementString: nil])
|
|
|
|
|
return;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
[_textStorage beginEditing];
|
|
|
|
|
[_textStorage subscriptRange: aRange];
|
|
|
|
|
[_textStorage endEditing];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self didChangeText];
|
2000-04-02 05:58:50 +00:00
|
|
|
|
}
|
2000-06-26 19:55:01 +00:00
|
|
|
|
|
|
|
|
|
// Set the typing attributes
|
|
|
|
|
if (value != nil)
|
|
|
|
|
sValue = [value intValue] - 1;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
else
|
2000-06-26 19:55:01 +00:00
|
|
|
|
sValue = -1;
|
|
|
|
|
[_typingAttributes setObject: [NSNumber numberWithInt: sValue]
|
|
|
|
|
forKey: NSSuperscriptAttributeName];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) superscript: (id)sender
|
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
NSNumber *value = [_typingAttributes
|
|
|
|
|
objectForKey: NSSuperscriptAttributeName];
|
|
|
|
|
int sValue;
|
2000-05-20 16:55:08 +00:00
|
|
|
|
NSRange aRange = [self rangeForUserCharacterAttributeChange];
|
2000-04-02 05:58:50 +00:00
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (aRange.location == NSNotFound)
|
|
|
|
|
return;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
|
|
|
|
|
if (aRange.length)
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
|
|
|
|
replacementString: nil])
|
|
|
|
|
return;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
[_textStorage beginEditing];
|
|
|
|
|
[_textStorage superscriptRange: aRange];
|
|
|
|
|
[_textStorage endEditing];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self didChangeText];
|
2000-04-02 05:58:50 +00:00
|
|
|
|
}
|
2000-06-26 19:55:01 +00:00
|
|
|
|
|
|
|
|
|
// Set the typing attributes
|
|
|
|
|
if (value != nil)
|
|
|
|
|
sValue = [value intValue] + 1;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
else
|
2000-06-26 19:55:01 +00:00
|
|
|
|
sValue = 1;
|
|
|
|
|
[_typingAttributes setObject: [NSNumber numberWithInt: sValue]
|
|
|
|
|
forKey: NSSuperscriptAttributeName];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) unscript: (id)sender
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
NSRange aRange = [self rangeForUserCharacterAttributeChange];
|
2000-04-02 05:58:50 +00:00
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (aRange.location == NSNotFound)
|
|
|
|
|
return;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
|
|
|
|
|
if (aRange.length)
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
|
|
|
|
replacementString: nil])
|
|
|
|
|
return;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
[_textStorage beginEditing];
|
|
|
|
|
[_textStorage unscriptRange: aRange];
|
|
|
|
|
[_textStorage endEditing];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self didChangeText];
|
2000-04-02 05:58:50 +00:00
|
|
|
|
}
|
2000-06-26 19:55:01 +00:00
|
|
|
|
|
|
|
|
|
// Set the typing attributes
|
|
|
|
|
[_typingAttributes removeObjectForKey: NSSuperscriptAttributeName];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) underline: (id)sender
|
|
|
|
|
{
|
2000-04-02 05:58:50 +00:00
|
|
|
|
BOOL doUnderline = YES;
|
2000-05-20 16:55:08 +00:00
|
|
|
|
NSRange aRange = [self rangeForUserCharacterAttributeChange];
|
1998-09-02 15:05:13 +00:00
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (aRange.location == NSNotFound)
|
|
|
|
|
return;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
|
|
|
|
|
if ([[_textStorage attribute: NSUnderlineStyleAttributeName
|
|
|
|
|
atIndex: aRange.location
|
|
|
|
|
effectiveRange: NULL] intValue])
|
|
|
|
|
doUnderline = NO;
|
|
|
|
|
|
|
|
|
|
if (aRange.length)
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
|
|
|
|
replacementString: nil])
|
|
|
|
|
return;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
[_textStorage beginEditing];
|
|
|
|
|
[_textStorage addAttribute: NSUnderlineStyleAttributeName
|
|
|
|
|
value: [NSNumber numberWithInt: doUnderline]
|
|
|
|
|
range: aRange];
|
|
|
|
|
[_textStorage endEditing];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self didChangeText];
|
1999-11-11 17:17:14 +00:00
|
|
|
|
}
|
2000-06-26 19:55:01 +00:00
|
|
|
|
|
|
|
|
|
[_typingAttributes
|
2000-04-02 05:58:50 +00:00
|
|
|
|
setObject: [NSNumber numberWithInt: doUnderline]
|
|
|
|
|
forKey: NSUnderlineStyleAttributeName];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
2000-03-08 08:43:15 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
//
|
|
|
|
|
// Reading and Writing RTFD Files
|
|
|
|
|
//
|
|
|
|
|
- (BOOL) readRTFDFromFile: (NSString*)path
|
|
|
|
|
{
|
2000-05-04 22:44:20 +00:00
|
|
|
|
NSAttributedString *peek = [[NSAttributedString alloc]
|
|
|
|
|
initWithPath: path
|
|
|
|
|
documentAttributes: NULL];
|
2000-02-19 00:40:47 +00:00
|
|
|
|
|
2000-05-04 22:44:20 +00:00
|
|
|
|
if (peek != nil)
|
1999-11-11 17:17:14 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
if (!_tf.is_rich_text)
|
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
[self setRichText: YES];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
[self replaceRange: NSMakeRange (0, [self textLength])
|
|
|
|
|
withAttributedString: peek];
|
2000-05-04 22:44:20 +00:00
|
|
|
|
RELEASE(peek);
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2000-02-19 00:40:47 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (BOOL) writeRTFDToFile: (NSString*)path atomically: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
NSFileWrapper *wrapper = [_textStorage RTFDFileWrapperFromRange:
|
|
|
|
|
NSMakeRange(0, [_textStorage length])
|
|
|
|
|
documentAttributes: nil];
|
|
|
|
|
return [wrapper writeToFile: path atomically: flag updateFilenames: YES];
|
|
|
|
|
}
|
2000-02-19 00:40:47 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (NSData*) RTFDFromRange: (NSRange) aRange
|
|
|
|
|
{
|
|
|
|
|
return [_textStorage RTFDFromRange: aRange
|
|
|
|
|
documentAttributes: nil];
|
|
|
|
|
}
|
2000-02-19 00:40:47 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (NSData*) RTFFromRange: (NSRange) aRange
|
|
|
|
|
{
|
2000-05-04 22:44:20 +00:00
|
|
|
|
return [_textStorage RTFFromRange: aRange
|
|
|
|
|
documentAttributes: nil];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
2000-02-19 00:40:47 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
//
|
|
|
|
|
// Sizing the Frame Rectangle
|
|
|
|
|
//
|
|
|
|
|
- (BOOL) isHorizontallyResizable
|
|
|
|
|
{
|
|
|
|
|
return _tf.is_horizontally_resizable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isVerticallyResizable
|
|
|
|
|
{
|
|
|
|
|
return _tf.is_vertically_resizable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSSize) maxSize
|
|
|
|
|
{
|
|
|
|
|
return _maxSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSSize) minSize
|
|
|
|
|
{
|
|
|
|
|
return _minSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setHorizontallyResizable: (BOOL)flag
|
|
|
|
|
{
|
2000-11-06 22:12:29 +00:00
|
|
|
|
// FIXME: All the container resizing is here preliminary until we get
|
|
|
|
|
// clipview resizing working without it
|
|
|
|
|
NSSize containerSize = [_textContainer containerSize];
|
|
|
|
|
|
|
|
|
|
if (flag)
|
|
|
|
|
containerSize.width = HUGE;
|
|
|
|
|
else
|
|
|
|
|
containerSize.width = _frame.size.width - 2.0 * [self textContainerInset].width;
|
|
|
|
|
|
|
|
|
|
[_textContainer setContainerSize: containerSize];
|
2000-11-03 00:22:15 +00:00
|
|
|
|
[_textContainer setWidthTracksTextView: !flag];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
_tf.is_horizontally_resizable = flag;
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-03 00:22:15 +00:00
|
|
|
|
- (void) setVerticallyResizable: (BOOL)flag
|
|
|
|
|
{
|
2000-11-06 22:12:29 +00:00
|
|
|
|
// FIXME: All the container resizing is here preliminary until we get
|
|
|
|
|
// clipview resizing working without it
|
|
|
|
|
NSSize containerSize = [_textContainer containerSize];
|
|
|
|
|
|
|
|
|
|
if (flag)
|
|
|
|
|
containerSize.height = HUGE;
|
|
|
|
|
else
|
|
|
|
|
containerSize.height = _frame.size.height - 2.0 * [self textContainerInset].height;
|
|
|
|
|
|
|
|
|
|
[_textContainer setContainerSize: containerSize];
|
2000-11-03 00:22:15 +00:00
|
|
|
|
[_textContainer setHeightTracksTextView: !flag];
|
|
|
|
|
_tf.is_vertically_resizable = flag;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void)setMaxSize: (NSSize)newMaxSize
|
|
|
|
|
{
|
|
|
|
|
_maxSize = newMaxSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setMinSize: (NSSize)newMinSize
|
|
|
|
|
{
|
|
|
|
|
_minSize = newMinSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) sizeToFit
|
|
|
|
|
{
|
|
|
|
|
// if we are a field editor we don't have to handle the size.
|
|
|
|
|
if ([self isFieldEditor])
|
|
|
|
|
return;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSSize oldSize = _frame.size;
|
|
|
|
|
float newWidth = oldSize.width;
|
|
|
|
|
float newHeight = oldSize.height;
|
2000-09-18 23:33:30 +00:00
|
|
|
|
NSRect textRect = [_layoutManager usedRectForTextContainer: [self textContainer]];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
NSSize newSize;
|
|
|
|
|
|
|
|
|
|
if (_tf.is_horizontally_resizable)
|
|
|
|
|
{
|
|
|
|
|
newWidth = textRect.size.width;
|
|
|
|
|
}
|
2000-08-23 17:33:12 +00:00
|
|
|
|
if (_tf.is_vertically_resizable)
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
|
|
|
|
newHeight = textRect.size.height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newSize = NSMakeSize(MIN(_maxSize.width, MAX(newWidth, _minSize.width)),
|
|
|
|
|
MIN(_maxSize.height, MAX(newHeight, _minSize.height)));
|
|
|
|
|
if (!NSEqualSizes(oldSize, newSize))
|
|
|
|
|
{
|
|
|
|
|
[self setFrameSize: newSize];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Spelling
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
- (void) checkSpelling: (id)sender
|
|
|
|
|
{
|
|
|
|
|
NSRange errorRange
|
|
|
|
|
= [[NSSpellChecker sharedSpellChecker]
|
|
|
|
|
checkSpellingOfString: [self string]
|
|
|
|
|
startingAt: NSMaxRange (_selected_range)];
|
|
|
|
|
|
|
|
|
|
if (errorRange.length)
|
|
|
|
|
[self setSelectedRange: errorRange];
|
|
|
|
|
else
|
|
|
|
|
NSBeep();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) showGuessPanel: (id)sender
|
|
|
|
|
{
|
|
|
|
|
[[[NSSpellChecker sharedSpellChecker] spellingPanel] orderFront: self];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Scrolling
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
- (void) scrollRangeToVisible: (NSRange) aRange
|
|
|
|
|
{
|
2000-06-16 19:03:15 +00:00
|
|
|
|
// Don't try scrolling an ancestor clipview if we are field editor.
|
|
|
|
|
// This makes things so much simpler and stabler for now.
|
|
|
|
|
if (_tf.is_field_editor == NO)
|
|
|
|
|
{
|
2000-08-07 22:06:04 +00:00
|
|
|
|
[self scrollRectToVisible: [self rectForCharacterRange:
|
|
|
|
|
_selected_range]];
|
2000-06-16 19:03:15 +00:00
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-16 19:03:15 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* Managing the Delegate
|
|
|
|
|
*/
|
|
|
|
|
- (id) delegate
|
|
|
|
|
{
|
|
|
|
|
return _delegate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setDelegate: (id) anObject
|
|
|
|
|
{
|
|
|
|
|
if (_delegate)
|
|
|
|
|
[nc removeObserver: _delegate name: nil object: self];
|
|
|
|
|
ASSIGN(_delegate, anObject);
|
|
|
|
|
|
|
|
|
|
#define SET_DELEGATE_NOTIFICATION(notif_name) \
|
|
|
|
|
if ([_delegate respondsToSelector: @selector(text##notif_name:)]) \
|
|
|
|
|
[nc addObserver: _delegate \
|
|
|
|
|
selector: @selector(text##notif_name:) \
|
|
|
|
|
name: NSText##notif_name##Notification \
|
|
|
|
|
object: self]
|
|
|
|
|
|
|
|
|
|
SET_DELEGATE_NOTIFICATION(DidBeginEditing);
|
|
|
|
|
SET_DELEGATE_NOTIFICATION(DidChange);
|
|
|
|
|
SET_DELEGATE_NOTIFICATION(DidEndEditing);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Handling Events
|
|
|
|
|
//
|
|
|
|
|
- (void) mouseDown: (NSEvent*)theEvent
|
|
|
|
|
{
|
|
|
|
|
NSSelectionGranularity granularity = NSSelectByCharacter;
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NSRange chosenRange, proposedRange;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
NSPoint point, startPoint;
|
|
|
|
|
NSEvent *currentEvent;
|
|
|
|
|
unsigned startIndex;
|
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
// If not selectable than don't recognize the mouse down
|
2000-03-16 14:16:46 +00:00
|
|
|
|
if (!_tf.is_selectable)
|
|
|
|
|
return;
|
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
// Only try to make first responder if editable, otherwise the
|
|
|
|
|
// delegate will stop it in becomeFirstResponder.
|
|
|
|
|
if (_tf.is_editable && ![_window makeFirstResponder: self])
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
switch ([theEvent clickCount])
|
|
|
|
|
{
|
|
|
|
|
case 1: granularity = NSSelectByCharacter;
|
|
|
|
|
break;
|
|
|
|
|
case 2: granularity = NSSelectByWord;
|
|
|
|
|
break;
|
|
|
|
|
case 3: granularity = NSSelectByParagraph;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
startPoint = [self convertPoint: [theEvent locationInWindow] fromView: nil];
|
|
|
|
|
startIndex = [self characterIndexForPoint: startPoint];
|
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
proposedRange = NSMakeRange(startIndex, 0);
|
|
|
|
|
chosenRange = [self selectionRangeForProposedRange: proposedRange
|
|
|
|
|
granularity: granularity];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
[self setSelectedRange: chosenRange];
|
|
|
|
|
// Do an imidiate redisplay for visual feedback
|
|
|
|
|
[_window flushWindow];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
|
|
|
|
//<!> make this non - blocking (or make use of timed entries)
|
2000-08-07 22:06:04 +00:00
|
|
|
|
// run modal loop
|
2000-03-16 14:16:46 +00:00
|
|
|
|
for (currentEvent = [_window
|
|
|
|
|
nextEventMatchingMask:
|
|
|
|
|
(NSLeftMouseDraggedMask|NSLeftMouseUpMask)];
|
|
|
|
|
[currentEvent type] != NSLeftMouseUp;
|
|
|
|
|
(currentEvent = [_window
|
|
|
|
|
nextEventMatchingMask:
|
2000-08-07 22:06:04 +00:00
|
|
|
|
(NSLeftMouseDraggedMask|NSLeftMouseUpMask)]))
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
|
|
|
|
BOOL didScroll = [self autoscroll: currentEvent];
|
|
|
|
|
point = [self convertPoint: [currentEvent locationInWindow]
|
|
|
|
|
fromView: nil];
|
|
|
|
|
proposedRange = MakeRangeFromAbs ([self characterIndexForPoint: point],
|
|
|
|
|
startIndex);
|
2000-08-07 22:06:04 +00:00
|
|
|
|
// Add one more character as selected, as zero length is cursor.
|
|
|
|
|
proposedRange.length++;
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
chosenRange = [self selectionRangeForProposedRange: proposedRange
|
|
|
|
|
granularity: granularity];
|
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
[self setSelectedRange: chosenRange];
|
2000-02-19 00:40:47 +00:00
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
if (didScroll)
|
|
|
|
|
[self setNeedsDisplay: YES];
|
|
|
|
|
// Do an imidiate redisplay for visual feedback
|
|
|
|
|
[_window flushWindow];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
1999-11-11 17:17:14 +00:00
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NSDebugLog(@"chosenRange. location = %d, length = %d\n",
|
2000-03-16 14:16:46 +00:00
|
|
|
|
(int)chosenRange.location, (int)chosenRange.length);
|
|
|
|
|
// remember for column stable cursor up/down
|
|
|
|
|
_currentCursor = [self rectForCharacterIndex: chosenRange.location].origin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) keyDown: (NSEvent*)theEvent
|
|
|
|
|
{
|
2000-04-02 05:58:50 +00:00
|
|
|
|
// If not editable, don't recognize the key down
|
2000-03-16 14:16:46 +00:00
|
|
|
|
if (!_tf.is_editable)
|
|
|
|
|
{
|
|
|
|
|
[super keyDown: theEvent];
|
2000-03-19 07:33:26 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) insertNewline: (id) sender
|
|
|
|
|
{
|
|
|
|
|
if (_tf.is_field_editor)
|
|
|
|
|
{
|
|
|
|
|
[self _illegalMovement: NSReturnTextMovement];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-19 07:33:26 +00:00
|
|
|
|
[self insertText: [[self class] newlineString]];
|
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-03-19 07:33:26 +00:00
|
|
|
|
- (void) insertTab: (id) sender
|
|
|
|
|
{
|
|
|
|
|
if (_tf.is_field_editor)
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
2000-03-19 07:33:26 +00:00
|
|
|
|
[self _illegalMovement: NSTabTextMovement];
|
|
|
|
|
return;
|
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-03-19 07:33:26 +00:00
|
|
|
|
[self insertText: @"\t"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) insertBacktab: (id) sender
|
|
|
|
|
{
|
|
|
|
|
if (_tf.is_field_editor)
|
|
|
|
|
{
|
|
|
|
|
[self _illegalMovement: NSBacktabTextMovement];
|
|
|
|
|
return;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-19 07:33:26 +00:00
|
|
|
|
//[self insertText: @"\t"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) deleteForward: (id) sender
|
|
|
|
|
{
|
|
|
|
|
if (_selected_range.location != [self textLength])
|
|
|
|
|
{
|
|
|
|
|
/* Not at the end of text -- delete following character */
|
|
|
|
|
[self deleteRange:
|
|
|
|
|
[self selectionRangeForProposedRange:
|
|
|
|
|
NSMakeRange (_selected_range.location, 1)
|
|
|
|
|
granularity: NSSelectByCharacter]
|
|
|
|
|
backspace: NO];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* end of text: behave the same way as NSBackspaceKey */
|
|
|
|
|
[self deleteBackward: sender];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) deleteBackward: (id) sender
|
|
|
|
|
{
|
|
|
|
|
[self deleteRange: _selected_range backspace: YES];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//<!> choose granularity according to keyboard modifier flags
|
|
|
|
|
- (void) moveUp: (id) sender
|
|
|
|
|
{
|
|
|
|
|
unsigned cursorIndex;
|
|
|
|
|
NSPoint cursorPoint;
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NSRange newRange;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-03-19 07:33:26 +00:00
|
|
|
|
if (_tf.is_field_editor)
|
|
|
|
|
{
|
|
|
|
|
[self _illegalMovement: NSUpTextMovement];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/* Do nothing if we are at beginning of text */
|
|
|
|
|
if (_selected_range.location == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (_selected_range.length)
|
|
|
|
|
{
|
|
|
|
|
_currentCursor = [self rectForCharacterIndex:
|
|
|
|
|
_selected_range.location].origin;
|
|
|
|
|
}
|
|
|
|
|
cursorIndex = _selected_range.location;
|
|
|
|
|
cursorPoint = [self rectForCharacterIndex: cursorIndex].origin;
|
|
|
|
|
cursorIndex = [self characterIndexForPoint:
|
|
|
|
|
NSMakePoint (_currentCursor.x + 0.001,
|
|
|
|
|
MAX (0, cursorPoint.y - 0.001))];
|
2000-08-07 22:06:04 +00:00
|
|
|
|
|
|
|
|
|
newRange.location = cursorIndex;
|
|
|
|
|
newRange.length = 0;
|
|
|
|
|
[self setSelectedRange: newRange];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) moveDown: (id) sender
|
|
|
|
|
{
|
|
|
|
|
unsigned cursorIndex;
|
|
|
|
|
NSRect cursorRect;
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NSRange newRange;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-03-19 07:33:26 +00:00
|
|
|
|
if (_tf.is_field_editor)
|
|
|
|
|
{
|
|
|
|
|
[self _illegalMovement: NSDownTextMovement];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/* Do nothing if we are at end of text */
|
|
|
|
|
if (_selected_range.location == [self textLength])
|
|
|
|
|
return;
|
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
if (_selected_range.length != 0)
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
|
|
|
|
_currentCursor = [self rectForCharacterIndex:
|
|
|
|
|
NSMaxRange (_selected_range)].origin;
|
|
|
|
|
}
|
|
|
|
|
cursorIndex = _selected_range.location;
|
|
|
|
|
cursorRect = [self rectForCharacterIndex: cursorIndex];
|
|
|
|
|
cursorIndex = [self characterIndexForPoint:
|
2000-09-08 00:07:42 +00:00
|
|
|
|
NSMakePoint(_currentCursor.x + 0.001,
|
|
|
|
|
NSMaxY (cursorRect) + 0.001)];
|
2000-08-07 22:06:04 +00:00
|
|
|
|
|
|
|
|
|
newRange.location = cursorIndex;
|
|
|
|
|
newRange.length = 0;
|
|
|
|
|
[self setSelectedRange: newRange];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) moveLeft: (id) sender
|
|
|
|
|
{
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NSRange newSelectedRange;
|
|
|
|
|
|
2000-09-11 21:44:53 +00:00
|
|
|
|
/* Do nothing if we are at beginning of text with no selection */
|
|
|
|
|
if (_selected_range.location == 0 && _selected_range.length == 0)
|
2000-09-18 23:33:30 +00:00
|
|
|
|
{
|
|
|
|
|
if (_tf.is_field_editor)
|
|
|
|
|
{
|
|
|
|
|
[self _illegalMovement: NSLeftTextMovement];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-09-11 21:44:53 +00:00
|
|
|
|
if (_selected_range.location == 0)
|
|
|
|
|
newSelectedRange.location = 0;
|
|
|
|
|
else
|
|
|
|
|
newSelectedRange.location = _selected_range.location - 1;
|
2000-08-07 22:06:04 +00:00
|
|
|
|
newSelectedRange.length = 0;
|
|
|
|
|
|
|
|
|
|
[self setSelectedRange: newSelectedRange];
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
_currentCursor.x = [self rectForCharacterIndex:
|
|
|
|
|
_selected_range.location].origin.x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) moveRight: (id) sender
|
|
|
|
|
{
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NSRange newSelectedRange;
|
|
|
|
|
unsigned int length = [self textLength];
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
/* Do nothing if we are at end of text */
|
2000-08-07 22:06:04 +00:00
|
|
|
|
if (_selected_range.location == length)
|
2000-09-18 23:33:30 +00:00
|
|
|
|
{
|
|
|
|
|
if (_tf.is_field_editor)
|
|
|
|
|
{
|
|
|
|
|
[self _illegalMovement: NSRightTextMovement];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-09-18 23:33:30 +00:00
|
|
|
|
newSelectedRange.location = MIN(NSMaxRange(_selected_range) + 1, length);
|
2000-08-07 22:06:04 +00:00
|
|
|
|
newSelectedRange.length = 0;
|
|
|
|
|
|
|
|
|
|
[self setSelectedRange: newSelectedRange];
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
_currentCursor.x = [self rectForCharacterIndex:
|
|
|
|
|
_selected_range.location].origin.x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) acceptsFirstResponder
|
|
|
|
|
{
|
|
|
|
|
if ([self isSelectable])
|
|
|
|
|
return YES;
|
|
|
|
|
else
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) resignFirstResponder
|
|
|
|
|
{
|
|
|
|
|
if (([self isEditable])
|
|
|
|
|
&& ([_delegate respondsToSelector: @selector(textShouldEndEditing:)])
|
|
|
|
|
&& ([_delegate textShouldEndEditing: self] == NO))
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
|
|
// Add any clean-up stuff here
|
|
|
|
|
|
|
|
|
|
if ([self shouldDrawInsertionPoint])
|
2000-08-07 22:06:04 +00:00
|
|
|
|
{
|
2000-04-23 22:31:25 +00:00
|
|
|
|
[self lockFocus];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[self drawInsertionPointAtIndex: _selected_range.location
|
|
|
|
|
color: nil turnedOn: NO];
|
2000-04-23 22:31:25 +00:00
|
|
|
|
[self unlockFocus];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
//<!> stop timed entry
|
|
|
|
|
}
|
|
|
|
|
|
2000-08-26 20:41:52 +00:00
|
|
|
|
[nc postNotificationName: NSTextDidEndEditingNotification object: self];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) becomeFirstResponder
|
|
|
|
|
{
|
|
|
|
|
if ([self isSelectable] == NO)
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
|
|
if (([_delegate respondsToSelector: @selector(textShouldBeginEditing:)])
|
|
|
|
|
&& ([_delegate textShouldBeginEditing: self] == NO))
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
|
|
// Add any initialization stuff here.
|
|
|
|
|
|
|
|
|
|
//if ([self shouldDrawInsertionPoint])
|
|
|
|
|
// {
|
|
|
|
|
// [self lockFocus];
|
|
|
|
|
// [self drawInsertionPointAtIndex: _selected_range.location
|
2000-05-13 14:28:02 +00:00
|
|
|
|
// color: _caret_color turnedOn: YES];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
// [self unlockFocus];
|
|
|
|
|
// //<!> restart timed entry
|
|
|
|
|
// }
|
2000-08-26 20:41:52 +00:00
|
|
|
|
[nc postNotificationName: NSTextDidBeginEditingNotification object: self];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) drawRect: (NSRect)rect
|
|
|
|
|
{
|
2000-09-18 23:33:30 +00:00
|
|
|
|
NSRange drawnRange = [_layoutManager glyphRangeForBoundingRect: rect
|
|
|
|
|
inTextContainer: [self textContainer]];
|
2000-08-07 22:06:04 +00:00
|
|
|
|
if (_tf.draws_background)
|
|
|
|
|
{
|
2000-09-18 23:33:30 +00:00
|
|
|
|
[_layoutManager drawBackgroundForGlyphRange: drawnRange
|
|
|
|
|
atPoint: [self textContainerOrigin]];
|
2000-08-07 22:06:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-09-18 23:33:30 +00:00
|
|
|
|
[_layoutManager drawGlyphsForGlyphRange: drawnRange
|
|
|
|
|
atPoint: [self textContainerOrigin]];
|
2000-08-07 22:06:04 +00:00
|
|
|
|
|
2000-09-18 23:33:30 +00:00
|
|
|
|
if ([self shouldDrawInsertionPoint] &&
|
|
|
|
|
(NSLocationInRange(_selected_range.location, drawnRange) ||
|
|
|
|
|
_selected_range.location == NSMaxRange(drawnRange)))
|
2000-08-07 22:06:04 +00:00
|
|
|
|
{
|
|
|
|
|
[self drawInsertionPointAtIndex: _selected_range.location
|
|
|
|
|
color: _caret_color
|
|
|
|
|
turnedOn: YES];
|
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// text lays out from top to bottom
|
|
|
|
|
- (BOOL) isFlipped
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isOpaque
|
|
|
|
|
{
|
|
|
|
|
if (_tf.draws_background == NO
|
|
|
|
|
|| _background_color == nil
|
|
|
|
|
|| [_background_color alphaComponent] < 1.0)
|
|
|
|
|
return NO;
|
|
|
|
|
else
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Handle enabling/disabling of services menu items.
|
|
|
|
|
*/
|
|
|
|
|
- (id) validRequestorForSendType: (NSString*) sendType
|
|
|
|
|
returnType: (NSString*) returnType
|
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
if ((!sendType || (_selected_range.length &&
|
|
|
|
|
[sendType isEqual: NSStringPboardType]))
|
|
|
|
|
&& (!returnType || ([self isEditable] &&
|
|
|
|
|
[returnType isEqual: NSStringPboardType])))
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
return self;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
2000-05-23 22:58:24 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return [super validRequestorForSendType: sendType
|
|
|
|
|
returnType: returnType];
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// NSCoding protocol
|
|
|
|
|
//
|
|
|
|
|
- (void)encodeWithCoder: aCoder
|
|
|
|
|
{
|
|
|
|
|
BOOL flag;
|
|
|
|
|
[super encodeWithCoder: aCoder];
|
|
|
|
|
|
|
|
|
|
[aCoder encodeConditionalObject: _delegate];
|
|
|
|
|
[aCoder encodeObject: _textStorage];
|
|
|
|
|
|
2000-05-13 14:28:02 +00:00
|
|
|
|
flag = _tf.is_field_editor;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
flag = _tf.is_editable;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
flag = _tf.is_selectable;
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
flag = _tf.is_rich_text;
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
flag = _tf.imports_graphics;
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
flag = _tf.draws_background;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
flag = _tf.is_horizontally_resizable;
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
flag = _tf.is_vertically_resizable;
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
flag = _tf.uses_font_panel;
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
flag = _tf.uses_ruler;
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
flag = _tf.is_ruler_visible;
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
flag = _tf.smart_insert_delete;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
flag = _tf.allows_undo;
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[aCoder encodeObject: _typingAttributes];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[aCoder encodeObject: _background_color];
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(NSRange) at: &_selected_range];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[aCoder encodeObject: _caret_color];
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(NSSize) at: &_minSize];
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(NSSize) at: &_maxSize];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- initWithCoder: aDecoder
|
|
|
|
|
{
|
|
|
|
|
BOOL flag;
|
|
|
|
|
[super initWithCoder: aDecoder];
|
|
|
|
|
|
|
|
|
|
_delegate = [aDecoder decodeObject];
|
|
|
|
|
_textStorage = [aDecoder decodeObject];
|
|
|
|
|
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
_tf.is_field_editor = flag;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
_tf.is_editable = flag;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
_tf.is_selectable = flag;
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
_tf.is_rich_text = flag;
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
_tf.imports_graphics = flag;
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
_tf.draws_background = flag;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
_tf.is_horizontally_resizable = flag;
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
_tf.is_vertically_resizable = flag;
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
_tf.uses_font_panel = flag;
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
_tf.uses_ruler = flag;
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
_tf.is_ruler_visible = flag;
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
2000-05-13 14:28:02 +00:00
|
|
|
|
_tf.smart_insert_delete = flag;
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &flag];
|
|
|
|
|
_tf.allows_undo = flag;
|
2000-05-13 14:28:02 +00:00
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
_typingAttributes = [aDecoder decodeObject];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
_background_color = [aDecoder decodeObject];
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(NSRange) at: &_selected_range];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
_caret_color = [aDecoder decodeObject];
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(NSSize) at: &_minSize];
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(NSSize) at: &_maxSize];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-09-30 23:11:15 +00:00
|
|
|
|
// build up the layout informations that don't get stored
|
|
|
|
|
{
|
|
|
|
|
NSTextContainer *aTextContainer = [self buildUpTextNetwork: _frame.size];
|
|
|
|
|
[aTextContainer setTextView: (NSTextView*)self];
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// NSChangeSpelling protocol
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
- (void) changeSpelling: (id)sender
|
|
|
|
|
{
|
|
|
|
|
[self insertText: [[(NSControl*)sender selectedCell] stringValue]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// NSIgnoreMisspelledWords protocol
|
|
|
|
|
//
|
|
|
|
|
- (void) ignoreSpelling: (id)sender
|
|
|
|
|
{
|
|
|
|
|
[[NSSpellChecker sharedSpellChecker]
|
|
|
|
|
ignoreWord: [[(NSControl*)sender selectedCell] stringValue]
|
|
|
|
|
inSpellDocumentWithTag: [self spellCheckerDocumentTag]];
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSText(GNUstepExtension)
|
|
|
|
|
|
|
|
|
|
+ (NSString*) newlineString
|
|
|
|
|
{
|
|
|
|
|
return @"\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) replaceRange: (NSRange) aRange
|
|
|
|
|
withAttributedString: (NSAttributedString*) attrString
|
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
if (aRange.location == NSNotFound)
|
|
|
|
|
return;
|
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
|
|
|
|
replacementString: [attrString string]])
|
|
|
|
|
return;
|
2000-06-26 19:55:01 +00:00
|
|
|
|
|
2000-04-02 05:58:50 +00:00
|
|
|
|
[_textStorage beginEditing];
|
2000-05-23 22:58:24 +00:00
|
|
|
|
if (_tf.is_rich_text)
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[_textStorage replaceCharactersInRange: aRange
|
|
|
|
|
withAttributedString: attrString];
|
|
|
|
|
else
|
|
|
|
|
[_textStorage replaceCharactersInRange: aRange
|
|
|
|
|
withString: [attrString string]];
|
2000-04-02 05:58:50 +00:00
|
|
|
|
[_textStorage endEditing];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self didChangeText];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned) textLength
|
|
|
|
|
{
|
|
|
|
|
return [_textStorage length];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) sizeToFit: (id)sender
|
|
|
|
|
{
|
|
|
|
|
[self sizeToFit];
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSText(NSTextView)
|
|
|
|
|
|
2000-09-30 23:11:15 +00:00
|
|
|
|
- (id) initWithFrame: (NSRect)frameRect
|
|
|
|
|
textContainer: (NSTextContainer*)aTextContainer
|
|
|
|
|
{
|
|
|
|
|
[super initWithFrame: frameRect];
|
|
|
|
|
|
|
|
|
|
[self setMinSize: frameRect.size];
|
|
|
|
|
[self setMaxSize: NSMakeSize(HUGE,HUGE)];
|
|
|
|
|
|
|
|
|
|
_tf.is_field_editor = NO;
|
|
|
|
|
_tf.is_editable = YES;
|
|
|
|
|
_tf.is_selectable = YES;
|
|
|
|
|
_tf.is_rich_text = NO;
|
|
|
|
|
_tf.imports_graphics = NO;
|
|
|
|
|
_tf.draws_background = YES;
|
|
|
|
|
_tf.is_horizontally_resizable = NO;
|
2000-10-23 23:25:46 +00:00
|
|
|
|
_tf.is_vertically_resizable = NO;
|
2000-09-30 23:11:15 +00:00
|
|
|
|
_tf.uses_font_panel = YES;
|
|
|
|
|
_tf.uses_ruler = YES;
|
|
|
|
|
_tf.is_ruler_visible = NO;
|
|
|
|
|
ASSIGN(_caret_color, [NSColor blackColor]);
|
|
|
|
|
[self setTypingAttributes: [[self class] defaultTypingAttributes]];
|
|
|
|
|
|
|
|
|
|
[self setBackgroundColor: [NSColor textBackgroundColor]];
|
|
|
|
|
|
|
|
|
|
//[self setSelectedRange: NSMakeRange (0, 0)];
|
|
|
|
|
|
|
|
|
|
[aTextContainer setTextView: (NSTextView*)self];
|
2000-11-03 00:22:15 +00:00
|
|
|
|
[aTextContainer setWidthTracksTextView: YES];
|
|
|
|
|
[aTextContainer setHeightTracksTextView: YES];
|
2000-09-30 23:11:15 +00:00
|
|
|
|
[self sizeToFit];
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This should only be called by [NSTextContainer -setTextView:] */
|
|
|
|
|
- (void) setTextContainer: (NSTextContainer*)aTextContainer
|
|
|
|
|
{
|
|
|
|
|
// FIXME: This builds up circular references between those objects
|
|
|
|
|
ASSIGN(_textContainer, aTextContainer);
|
|
|
|
|
ASSIGN(_layoutManager, [aTextContainer layoutManager]);
|
|
|
|
|
ASSIGN(_textStorage, [_layoutManager textStorage]);
|
|
|
|
|
|
|
|
|
|
// Hack to get the layout change
|
|
|
|
|
[_textContainer setContainerSize: _frame.size];
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-18 23:33:30 +00:00
|
|
|
|
- (NSTextContainer *)textContainer
|
|
|
|
|
{
|
2000-09-30 23:11:15 +00:00
|
|
|
|
return _textContainer;
|
2000-09-18 23:33:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPoint)textContainerOrigin
|
|
|
|
|
{
|
|
|
|
|
return NSZeroPoint;
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-30 23:11:15 +00:00
|
|
|
|
- (NSSize) textContainerInset
|
|
|
|
|
{
|
|
|
|
|
return NSZeroSize;
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
- (void) setRulerVisible: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
NSScrollView *sv = [self enclosingScrollView];
|
|
|
|
|
|
|
|
|
|
_tf.is_ruler_visible = flag;
|
|
|
|
|
if (sv != nil)
|
|
|
|
|
[sv setRulersVisible: _tf.is_ruler_visible];
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (int) spellCheckerDocumentTag
|
|
|
|
|
{
|
|
|
|
|
if (!_spellCheckerDocumentTag)
|
|
|
|
|
_spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag];
|
|
|
|
|
|
|
|
|
|
return _spellCheckerDocumentTag;
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
- (BOOL) shouldChangeTextInRange: (NSRange)affectedCharRange
|
|
|
|
|
replacementString: (NSString*)replacementString
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) didChangeText
|
|
|
|
|
{
|
2000-08-26 20:41:52 +00:00
|
|
|
|
[nc postNotificationName: NSTextDidChangeNotification object: self];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-09-18 23:33:30 +00:00
|
|
|
|
// central text inserting method
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (void) insertText: (NSString*) insertString
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
NSRange insertRange = [self rangeForUserTextChange];
|
|
|
|
|
|
|
|
|
|
if (insertRange.location == NSNotFound)
|
|
|
|
|
return;
|
|
|
|
|
|
2000-05-23 22:58:24 +00:00
|
|
|
|
if (_tf.is_rich_text)
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self replaceRange: insertRange
|
2000-03-16 14:16:46 +00:00
|
|
|
|
withAttributedString: AUTORELEASE([[NSAttributedString alloc]
|
|
|
|
|
initWithString: insertString
|
|
|
|
|
attributes: [self typingAttributes]])];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self replaceCharactersInRange: insertRange
|
2000-03-16 14:16:46 +00:00
|
|
|
|
withString: insertString];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// move cursor <!> [self selectionRangeForProposedRange: ]
|
|
|
|
|
[self setSelectedRange:
|
2000-05-20 16:55:08 +00:00
|
|
|
|
NSMakeRange (insertRange.location + [insertString length], 0)];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
|
|
|
|
// remember x for row - stable cursor movements
|
|
|
|
|
_currentCursor = [self rectForCharacterIndex:
|
|
|
|
|
_selected_range.location].origin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setTypingAttributes: (NSDictionary*) dict
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (dict == nil)
|
|
|
|
|
dict = [[self class] defaultTypingAttributes];
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
if (![dict isKindOfClass: [NSMutableDictionary class]])
|
|
|
|
|
{
|
|
|
|
|
RELEASE(_typingAttributes);
|
|
|
|
|
_typingAttributes = [[NSMutableDictionary alloc] initWithDictionary: dict];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ASSIGN(_typingAttributes, (NSMutableDictionary*)dict);
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
- (NSDictionary*) typingAttributes
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
return [NSDictionary dictionaryWithDictionary: _typingAttributes];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) updateFontPanel
|
|
|
|
|
{
|
|
|
|
|
// update fontPanel only if told so
|
|
|
|
|
if (_tf.uses_font_panel)
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
NSRange longestRange;
|
|
|
|
|
NSFont *currentFont = [_textStorage attribute: NSFontAttributeName
|
|
|
|
|
atIndex: _selected_range.location
|
|
|
|
|
longestEffectiveRange: &longestRange
|
|
|
|
|
inRange: _selected_range];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[[NSFontManager sharedFontManager]
|
|
|
|
|
setSelectedFont: currentFont
|
2000-06-11 00:28:35 +00:00
|
|
|
|
isMultiple: !NSEqualRanges(longestRange, _selected_range)];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) shouldDrawInsertionPoint
|
|
|
|
|
{
|
|
|
|
|
return (_selected_range.length == 0) && [self isEditable];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) drawInsertionPointInRect: (NSRect)rect
|
|
|
|
|
color: (NSColor*)color
|
|
|
|
|
turnedOn: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
if (!_window)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (flag)
|
|
|
|
|
{
|
2000-09-18 23:33:30 +00:00
|
|
|
|
if (color == nil)
|
|
|
|
|
color = _caret_color;
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[color set];
|
|
|
|
|
NSRectFill(rect);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[[self backgroundColor] set];
|
|
|
|
|
NSRectFill(rect);
|
2000-04-23 22:31:25 +00:00
|
|
|
|
// FIXME: We should redisplay the character the cursor was on.
|
|
|
|
|
//[self setNeedsDisplayInRect: rect];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-04-23 22:31:25 +00:00
|
|
|
|
[_window flushWindow];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSRange) selectionRangeForProposedRange: (NSRange)proposedCharRange
|
|
|
|
|
granularity: (NSSelectionGranularity)granularity
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
unsigned index;
|
|
|
|
|
NSRange aRange;
|
2000-08-07 22:06:04 +00:00
|
|
|
|
NSRange newRange;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
NSString *string = [self string];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
unsigned length = [string length];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-06-19 17:13:06 +00:00
|
|
|
|
if (proposedCharRange.location >= length)
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
proposedCharRange.location = length;
|
|
|
|
|
proposedCharRange.length = 0;
|
2000-06-19 17:09:45 +00:00
|
|
|
|
return proposedCharRange;
|
2000-05-20 16:55:08 +00:00
|
|
|
|
}
|
2000-08-07 22:06:04 +00:00
|
|
|
|
|
|
|
|
|
if (NSMaxRange(proposedCharRange) > length)
|
2000-05-20 16:55:08 +00:00
|
|
|
|
{
|
|
|
|
|
proposedCharRange.length = length - proposedCharRange.location;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
if (length == 0)
|
|
|
|
|
{
|
2000-05-20 16:55:08 +00:00
|
|
|
|
return proposedCharRange;
|
2000-08-07 22:06:04 +00:00
|
|
|
|
}
|
2000-05-20 16:55:08 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
switch (granularity)
|
|
|
|
|
{
|
|
|
|
|
case NSSelectByWord:
|
2000-08-07 22:06:04 +00:00
|
|
|
|
/* FIXME: The following code (or the routines it calls) does the
|
|
|
|
|
wrong thing when you double-click on the space between two
|
|
|
|
|
words */
|
|
|
|
|
if ((proposedCharRange.location + 1) < length)
|
|
|
|
|
{
|
|
|
|
|
index = [_textStorage nextWordFromIndex:
|
|
|
|
|
(proposedCharRange.location + 1)
|
|
|
|
|
forward: NO];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Exception: end of text */
|
|
|
|
|
index = [_textStorage nextWordFromIndex: proposedCharRange.location
|
|
|
|
|
forward: NO];
|
|
|
|
|
}
|
2000-05-20 16:55:08 +00:00
|
|
|
|
newRange.location = index;
|
2000-08-07 22:06:04 +00:00
|
|
|
|
index = [_textStorage nextWordFromIndex: NSMaxRange (proposedCharRange)
|
|
|
|
|
forward: YES];
|
|
|
|
|
if (index <= newRange.location)
|
|
|
|
|
{
|
|
|
|
|
newRange.length = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (index == length)
|
|
|
|
|
{
|
|
|
|
|
/* We are at the end of text ! */
|
|
|
|
|
newRange.length = index - newRange.location;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: The following will not work if there is more than a
|
|
|
|
|
single character between the two words ! */
|
|
|
|
|
newRange.length = index - 1 - newRange.location;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-05-20 16:55:08 +00:00
|
|
|
|
return newRange;
|
2000-08-07 22:06:04 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
case NSSelectByParagraph:
|
2000-08-07 22:06:04 +00:00
|
|
|
|
return [string lineRangeForRange: proposedCharRange];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
|
|
|
|
|
case NSSelectByCharacter:
|
|
|
|
|
default:
|
2000-08-07 22:06:04 +00:00
|
|
|
|
if (proposedCharRange.length == 0)
|
|
|
|
|
return proposedCharRange;
|
|
|
|
|
|
|
|
|
|
/* Expand the beginning character */
|
|
|
|
|
index = proposedCharRange.location;
|
|
|
|
|
newRange = [string rangeOfComposedCharacterSequenceAtIndex: index];
|
|
|
|
|
/* If the proposedCharRange is empty we only ajust the beginning */
|
|
|
|
|
if (proposedCharRange.length == 0)
|
|
|
|
|
{
|
|
|
|
|
return newRange;
|
|
|
|
|
}
|
|
|
|
|
/* Expand the finishing character */
|
|
|
|
|
index = NSMaxRange (proposedCharRange) - 1;
|
|
|
|
|
aRange = [string rangeOfComposedCharacterSequenceAtIndex: index];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
newRange.length = NSMaxRange(aRange) - newRange.location;
|
|
|
|
|
return newRange;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
2000-05-20 16:55:08 +00:00
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
- (NSRange) rangeForUserCharacterAttributeChange
|
|
|
|
|
{
|
|
|
|
|
if (!_tf.is_editable || !_tf.uses_font_panel)
|
|
|
|
|
return NSMakeRange(NSNotFound, 0);
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
if (_tf.is_rich_text)
|
|
|
|
|
// This expects the selection to be already corrected to characters
|
|
|
|
|
return _selected_range;
|
|
|
|
|
else
|
|
|
|
|
return NSMakeRange(0, [_textStorage length]);
|
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
- (NSRange) rangeForUserParagraphAttributeChange
|
|
|
|
|
{
|
|
|
|
|
if (!_tf.is_editable || !_tf.uses_ruler)
|
|
|
|
|
return NSMakeRange(NSNotFound, 0);
|
|
|
|
|
|
|
|
|
|
if (_tf.is_rich_text)
|
|
|
|
|
return [self selectionRangeForProposedRange: _selected_range
|
|
|
|
|
granularity: NSSelectByParagraph];
|
|
|
|
|
else
|
|
|
|
|
return NSMakeRange(0, [_textStorage length]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSRange) rangeForUserTextChange
|
|
|
|
|
{
|
|
|
|
|
if (!_tf.is_editable)
|
|
|
|
|
return NSMakeRange(NSNotFound, 0);
|
|
|
|
|
|
|
|
|
|
// This expects the selection to be already corrected to characters
|
|
|
|
|
return _selected_range;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setAlignment: (NSTextAlignment)alignment
|
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
{
|
2000-06-16 17:07:11 +00:00
|
|
|
|
NSParagraphStyle *style;
|
|
|
|
|
NSMutableParagraphStyle *mstyle;
|
2000-05-20 16:55:08 +00:00
|
|
|
|
|
|
|
|
|
if (aRange.location == NSNotFound)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
|
|
|
|
replacementString: nil])
|
|
|
|
|
return;
|
|
|
|
|
[_textStorage beginEditing];
|
|
|
|
|
[_textStorage setAlignment: alignment
|
|
|
|
|
range: aRange];
|
|
|
|
|
[_textStorage endEditing];
|
|
|
|
|
[self didChangeText];
|
|
|
|
|
|
|
|
|
|
// Set the typing attributes
|
2000-06-16 17:07:11 +00:00
|
|
|
|
style = [_typingAttributes objectForKey: NSParagraphStyleAttributeName];
|
|
|
|
|
if (style == nil)
|
|
|
|
|
style = [NSParagraphStyle defaultParagraphStyle];
|
|
|
|
|
|
|
|
|
|
mstyle = [style mutableCopy];
|
|
|
|
|
|
|
|
|
|
[mstyle setAlignment: alignment];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
// FIXME: Should use setTypingAttributes
|
2000-06-16 17:07:11 +00:00
|
|
|
|
[_typingAttributes setObject: mstyle forKey: NSParagraphStyleAttributeName];
|
2000-12-13 23:19:17 +00:00
|
|
|
|
RELEASE (mstyle);
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-05-23 22:58:24 +00:00
|
|
|
|
- (NSString*) preferredPasteboardTypeFromArray: (NSArray*)availableTypes
|
|
|
|
|
restrictedToTypesFromArray: (NSArray*)allowedTypes
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
NSString *type;
|
|
|
|
|
|
|
|
|
|
if (availableTypes == nil)
|
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
|
|
if (allowedTypes == nil)
|
|
|
|
|
return [availableTypes objectAtIndex: 0];
|
|
|
|
|
|
|
|
|
|
enumerator = [allowedTypes objectEnumerator];
|
|
|
|
|
while ((type = [enumerator nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([availableTypes containsObject: type])
|
|
|
|
|
{
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) readSelectionFromPasteboard: (NSPasteboard*)pboard
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
Reads the text view's preferred type of data from the pasteboard specified
|
|
|
|
|
by the pboard parameter. This method
|
|
|
|
|
invokes the preferredPasteboardTypeFromArray: restrictedToTypesFromArray:
|
|
|
|
|
method to determine the text view's
|
|
|
|
|
preferred type of data and then reads the data using the
|
|
|
|
|
readSelectionFromPasteboard: type: method. Returns YES if the
|
|
|
|
|
data was successfully read.
|
|
|
|
|
*/
|
|
|
|
|
NSString *type = [self preferredPasteboardTypeFromArray: [pboard types]
|
|
|
|
|
restrictedToTypesFromArray: [self readablePasteboardTypes]];
|
|
|
|
|
|
|
|
|
|
if (type == nil)
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
|
|
return [self readSelectionFromPasteboard: pboard
|
|
|
|
|
type: type];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) readSelectionFromPasteboard: (NSPasteboard*)pboard
|
|
|
|
|
type: (NSString*)type
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
Reads data of the given type from pboard. The new data is placed at the
|
|
|
|
|
current insertion point, replacing the current selection if one exists.
|
|
|
|
|
Returns YES if the data was successfully read.
|
|
|
|
|
|
|
|
|
|
You should override this method to read pasteboard types other than the
|
|
|
|
|
default types. Use the rangeForUserTextChange method to obtain the range
|
|
|
|
|
of characters (if any) to be replaced by the new data.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ([type isEqualToString: NSStringPboardType])
|
|
|
|
|
{
|
|
|
|
|
[self insertText: [pboard stringForType: NSStringPboardType]];
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
|
|
|
|
if ([self isRichText])
|
2000-05-23 22:58:24 +00:00
|
|
|
|
{
|
|
|
|
|
if ([type isEqualToString: NSRTFPboardType])
|
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
[self replaceCharactersInRange: [self rangeForUserTextChange]
|
|
|
|
|
withRTF: [pboard dataForType: NSRTFPboardType]];
|
2000-05-23 22:58:24 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_tf.imports_graphics)
|
|
|
|
|
{
|
|
|
|
|
if ([type isEqualToString: NSRTFDPboardType])
|
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
[self replaceCharactersInRange: [self rangeForUserTextChange]
|
|
|
|
|
withRTFD: [pboard dataForType: NSRTFDPboardType]];
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
// FIXME: Should also support: NSTIFFPboardType
|
|
|
|
|
if ([type isEqualToString: NSFileContentsPboardType])
|
|
|
|
|
{
|
|
|
|
|
NSTextAttachment *attachment = [[NSTextAttachment alloc]
|
|
|
|
|
initWithFileWrapper:
|
|
|
|
|
[pboard readFileWrapper]];
|
|
|
|
|
|
2000-05-23 22:58:24 +00:00
|
|
|
|
[self replaceRange: [self rangeForUserTextChange]
|
2000-06-26 19:55:01 +00:00
|
|
|
|
withAttributedString:
|
|
|
|
|
[NSAttributedString attributedStringWithAttachment: attachment]];
|
|
|
|
|
RELEASE(attachment);
|
2000-05-23 22:58:24 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// color accepting
|
|
|
|
|
if ([type isEqualToString: NSColorPboardType])
|
|
|
|
|
{
|
|
|
|
|
NSColor *color = [NSColor colorFromPasteboard: pboard];
|
|
|
|
|
NSRange aRange = [self rangeForUserCharacterAttributeChange];
|
|
|
|
|
|
|
|
|
|
if (aRange.location != NSNotFound)
|
|
|
|
|
[self setTextColor: color range: aRange];
|
|
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// font pasting
|
|
|
|
|
if ([type isEqualToString: NSFontPboardType])
|
|
|
|
|
{
|
2000-07-01 12:09:57 +00:00
|
|
|
|
// FIXME - This should use a serializer. To get that working a helper object
|
|
|
|
|
// is needed that implements the NSObjCTypeSerializationCallBack protocol.
|
|
|
|
|
// We should add this later, currently the NSArchiver is used.
|
|
|
|
|
// Thanks to Richard, for pointing this out.
|
|
|
|
|
NSData *data = [pboard dataForType: NSFontPboardType];
|
|
|
|
|
NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
|
2000-05-23 22:58:24 +00:00
|
|
|
|
|
2000-06-26 19:55:01 +00:00
|
|
|
|
if (dict != nil)
|
2000-05-23 22:58:24 +00:00
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
[self setAttributes: dict
|
|
|
|
|
range: [self rangeForUserCharacterAttributeChange]];
|
|
|
|
|
return YES;
|
2000-05-23 22:58:24 +00:00
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ruler pasting
|
|
|
|
|
if ([type isEqualToString: NSRulerPboardType])
|
|
|
|
|
{
|
2000-07-01 12:09:57 +00:00
|
|
|
|
// FIXME: see NSFontPboardType above
|
|
|
|
|
NSData *data = [pboard dataForType: NSRulerPboardType];
|
|
|
|
|
NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
|
2000-05-23 22:58:24 +00:00
|
|
|
|
|
2000-06-26 19:55:01 +00:00
|
|
|
|
if (dict != nil)
|
2000-05-23 22:58:24 +00:00
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
[self setAttributes: dict
|
|
|
|
|
range: [self rangeForUserParagraphAttributeChange]];
|
|
|
|
|
return YES;
|
2000-05-23 22:58:24 +00:00
|
|
|
|
}
|
2000-06-26 19:55:01 +00:00
|
|
|
|
return NO;
|
2000-05-23 22:58:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray*) readablePasteboardTypes
|
|
|
|
|
{
|
|
|
|
|
// get default types, what are they?
|
2000-06-26 19:55:01 +00:00
|
|
|
|
NSMutableArray *ret = [NSMutableArray arrayWithObjects: NSRulerPboardType,
|
|
|
|
|
NSColorPboardType, NSFontPboardType, nil];
|
2000-05-23 22:58:24 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
if (_tf.imports_graphics)
|
2000-05-23 22:58:24 +00:00
|
|
|
|
{
|
|
|
|
|
[ret addObject: NSRTFDPboardType];
|
|
|
|
|
//[ret addObject: NSTIFFPboardType];
|
2000-06-26 22:23:11 +00:00
|
|
|
|
[ret addObject: NSFileContentsPboardType];
|
2000-05-23 22:58:24 +00:00
|
|
|
|
}
|
|
|
|
|
if (_tf.is_rich_text)
|
|
|
|
|
[ret addObject: NSRTFPboardType];
|
|
|
|
|
|
|
|
|
|
[ret addObject: NSStringPboardType];
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-23 22:58:24 +00:00
|
|
|
|
- (NSArray*) writablePasteboardTypes
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
// the selected text can be written to the pasteboard with which types.
|
|
|
|
|
return [self readablePasteboardTypes];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) writeSelectionToPasteboard: (NSPasteboard*)pboard
|
|
|
|
|
type: (NSString*)type
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
Writes the current selection to pboard using the given type. Returns YES
|
|
|
|
|
if the data was successfully written. You can override this method to add
|
|
|
|
|
support for writing new types of data to the pasteboard. You should invoke
|
|
|
|
|
super's implementation of the method to handle any types of data your
|
|
|
|
|
overridden version does not.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
return [self writeSelectionToPasteboard: pboard
|
|
|
|
|
types: [NSArray arrayWithObject: type]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) writeSelectionToPasteboard: (NSPasteboard*)pboard
|
|
|
|
|
types: (NSArray*)types
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* Writes the current selection to pboard under each type in the types
|
|
|
|
|
array. Returns YES if the data for any single type was written
|
|
|
|
|
successfully.
|
|
|
|
|
|
|
|
|
|
You should not need to override this method. You might need to invoke this
|
|
|
|
|
method if you are implementing a new type of pasteboard to handle services
|
|
|
|
|
other than copy/paste or dragging. */
|
|
|
|
|
BOOL ret = NO;
|
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
NSString *type;
|
|
|
|
|
|
|
|
|
|
if (types == nil)
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
|
|
[pboard declareTypes: types owner: self];
|
|
|
|
|
|
|
|
|
|
enumerator = [types objectEnumerator];
|
|
|
|
|
while ((type = [enumerator nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([type isEqualToString: NSStringPboardType])
|
|
|
|
|
{
|
|
|
|
|
ret = ret || [pboard setString: [[self string] substringWithRange: _selected_range]
|
|
|
|
|
forType: NSStringPboardType];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([type isEqualToString: NSRTFPboardType])
|
|
|
|
|
{
|
|
|
|
|
ret = ret || [pboard setData: [self RTFFromRange: _selected_range]
|
|
|
|
|
forType: NSRTFPboardType];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([type isEqualToString: NSRTFDPboardType])
|
|
|
|
|
{
|
|
|
|
|
ret = ret || [pboard setData: [self RTFDFromRange: _selected_range]
|
|
|
|
|
forType: NSRTFDPboardType];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([type isEqualToString: NSColorPboardType])
|
|
|
|
|
{
|
|
|
|
|
NSColor *color = [self textColor];
|
|
|
|
|
|
|
|
|
|
if (color != nil)
|
|
|
|
|
{
|
|
|
|
|
[color writeToPasteboard: pboard];
|
|
|
|
|
ret = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([type isEqualToString: NSFontPboardType])
|
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
NSDictionary *dict = [_textStorage fontAttributesInRange: _selected_range];
|
|
|
|
|
|
|
|
|
|
if (dict != nil)
|
2000-05-23 22:58:24 +00:00
|
|
|
|
{
|
2000-07-01 12:09:57 +00:00
|
|
|
|
// FIXME - This should use a serializer. To get that working a helper object
|
|
|
|
|
// is needed that implements the NSObjCTypeSerializationCallBack protocol.
|
|
|
|
|
// We should add this later, currently the NSArchiver is used.
|
|
|
|
|
// Thanks to Richard, for pointing this out.
|
|
|
|
|
[pboard setData: [NSArchiver archivedDataWithRootObject: dict]
|
|
|
|
|
forType: NSFontPboardType];
|
2000-05-23 22:58:24 +00:00
|
|
|
|
ret = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([type isEqualToString: NSRulerPboardType])
|
|
|
|
|
{
|
2000-06-26 19:55:01 +00:00
|
|
|
|
NSDictionary *dict = [_textStorage rulerAttributesInRange: _selected_range];
|
2000-05-23 22:58:24 +00:00
|
|
|
|
|
2000-06-26 19:55:01 +00:00
|
|
|
|
if (dict != nil)
|
2000-05-23 22:58:24 +00:00
|
|
|
|
{
|
2000-07-01 12:09:57 +00:00
|
|
|
|
//FIXME: see NSFontPboardType above
|
|
|
|
|
[pboard setData: [NSArchiver archivedDataWithRootObject: dict]
|
|
|
|
|
forType: NSRulerPboardType];
|
2000-05-23 22:58:24 +00:00
|
|
|
|
ret = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSText(GNUstepPrivate)
|
|
|
|
|
|
2000-05-20 16:55:08 +00:00
|
|
|
|
+ (NSDictionary*) defaultTypingAttributes
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
|
|
|
|
return [NSDictionary dictionaryWithObjectsAndKeys:
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[NSParagraphStyle defaultParagraphStyle], NSParagraphStyleAttributeName,
|
2000-09-02 17:16:26 +00:00
|
|
|
|
[NSFont userFontOfSize: 0], NSFontAttributeName,
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[NSColor textColor], NSForegroundColorAttributeName,
|
2000-03-16 14:16:46 +00:00
|
|
|
|
nil];
|
|
|
|
|
}
|
2000-03-19 07:33:26 +00:00
|
|
|
|
|
2000-06-26 19:55:01 +00:00
|
|
|
|
- (void) setAttributes: (NSDictionary*) attributes range: (NSRange) aRange
|
|
|
|
|
{
|
|
|
|
|
NSString *type;
|
|
|
|
|
id val;
|
|
|
|
|
NSEnumerator *enumerator = [attributes keyEnumerator];
|
|
|
|
|
|
2000-07-01 12:09:57 +00:00
|
|
|
|
if (aRange.location == NSNotFound)
|
2000-06-26 19:55:01 +00:00
|
|
|
|
return;
|
|
|
|
|
if (![self shouldChangeTextInRange: aRange
|
|
|
|
|
replacementString: nil])
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
[_textStorage beginEditing];
|
|
|
|
|
while ((type = [enumerator nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
val = [attributes objectForKey: type];
|
|
|
|
|
[_textStorage addAttribute: type
|
|
|
|
|
value: val
|
|
|
|
|
range: aRange];
|
|
|
|
|
}
|
|
|
|
|
[_textStorage endEditing];
|
|
|
|
|
[self didChangeText];
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-19 07:33:26 +00:00
|
|
|
|
- (void) _illegalMovement: (int) textMovement
|
|
|
|
|
{
|
|
|
|
|
// This is similar to [self resignFirstResponder],
|
|
|
|
|
// with the difference that in the notification we need
|
|
|
|
|
// to put the NSTextMovement, which resignFirstResponder
|
|
|
|
|
// does not. Also, if we are ending editing, we are going
|
|
|
|
|
// to be removed, so it's useless to update any drawing.
|
|
|
|
|
NSNumber *number;
|
|
|
|
|
NSDictionary *uiDictionary;
|
|
|
|
|
|
|
|
|
|
if (([self isEditable])
|
|
|
|
|
&& ([_delegate respondsToSelector:
|
|
|
|
|
@selector(textShouldEndEditing:)])
|
|
|
|
|
&& ([_delegate textShouldEndEditing: self] == NO))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Add any clean-up stuff here
|
|
|
|
|
|
|
|
|
|
number = [NSNumber numberWithInt: textMovement];
|
|
|
|
|
uiDictionary = [NSDictionary dictionaryWithObject: number
|
|
|
|
|
forKey: @"NSTextMovement"];
|
2000-08-26 20:41:52 +00:00
|
|
|
|
[nc postNotificationName: NSTextDidEndEditingNotification
|
|
|
|
|
object: self userInfo: uiDictionary];
|
2000-03-19 07:33:26 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
// begin: dragging of colors and files---------------
|
|
|
|
|
- (unsigned int) draggingEntered: (id <NSDraggingInfo>)sender
|
|
|
|
|
{
|
|
|
|
|
return NSDragOperationGeneric;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned int) draggingUpdated: (id <NSDraggingInfo>)sender
|
|
|
|
|
{
|
|
|
|
|
return NSDragOperationGeneric;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) draggingExited: (id <NSDraggingInfo>)sender
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) prepareForDragOperation: (id <NSDraggingInfo>)sender
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) performDragOperation: (id <NSDraggingInfo>)sender
|
|
|
|
|
{
|
2000-05-23 22:58:24 +00:00
|
|
|
|
return [self readSelectionFromPasteboard: [sender draggingPasteboard]];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) concludeDragOperation: (id <NSDraggingInfo>)sender
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
// end: drag accepting---------------------------------
|
|
|
|
|
|
|
|
|
|
// central text deletion/backspace method
|
|
|
|
|
// (takes care of optimized redraw/ cursor positioning)
|
|
|
|
|
- (void) deleteRange: (NSRange) aRange
|
|
|
|
|
backspace: (BOOL) flag
|
1996-05-30 20:03:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
NSRange deleteRange;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2000-06-26 19:55:01 +00:00
|
|
|
|
if (aRange.location == NSNotFound)
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
|
2000-06-26 19:55:01 +00:00
|
|
|
|
if (!aRange.length && !(flag && aRange.location))
|
2000-03-16 14:16:46 +00:00
|
|
|
|
return;
|
1998-09-02 15:05:13 +00:00
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
if (aRange.length)
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
deleteRange = aRange;
|
|
|
|
|
}
|
|
|
|
|
else
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
deleteRange = NSMakeRange (MAX (0, aRange.location - 1), 1);
|
2000-03-08 08:43:15 +00:00
|
|
|
|
}
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
2000-06-26 19:55:01 +00:00
|
|
|
|
if (![self shouldChangeTextInRange: deleteRange
|
2000-05-20 16:55:08 +00:00
|
|
|
|
replacementString: @""])
|
|
|
|
|
return;
|
2000-04-02 05:58:50 +00:00
|
|
|
|
[_textStorage beginEditing];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
[_textStorage deleteCharactersInRange: deleteRange];
|
2000-04-02 05:58:50 +00:00
|
|
|
|
[_textStorage endEditing];
|
2000-05-20 16:55:08 +00:00
|
|
|
|
[self didChangeText];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
|
|
|
|
|
// move cursor <!> [self selectionRangeForProposedRange: ]
|
|
|
|
|
[self setSelectedRange: NSMakeRange (deleteRange.location, 0)];
|
|
|
|
|
|
|
|
|
|
// remember x for row - stable cursor movements
|
|
|
|
|
_currentCursor = [self rectForCharacterIndex:
|
|
|
|
|
_selected_range.location].origin;
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-16 14:16:46 +00:00
|
|
|
|
- (unsigned) characterIndexForPoint: (NSPoint) point
|
|
|
|
|
{
|
2000-09-18 23:33:30 +00:00
|
|
|
|
unsigned glyphIndex = [_layoutManager glyphIndexForPoint: point
|
|
|
|
|
inTextContainer: [self textContainer]];
|
|
|
|
|
|
|
|
|
|
return [_layoutManager characterIndexForGlyphAtIndex: glyphIndex];
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSRect) rectForCharacterIndex: (unsigned) index
|
|
|
|
|
{
|
2000-09-18 23:33:30 +00:00
|
|
|
|
NSRange glyphRange = [_layoutManager glyphRangeForCharacterRange: NSMakeRange(index, 1)
|
|
|
|
|
actualCharacterRange: NULL];
|
|
|
|
|
unsigned glyphIndex = glyphRange.location;
|
|
|
|
|
NSRect rect = [_layoutManager lineFragmentRectForGlyphAtIndex: glyphIndex
|
|
|
|
|
effectiveRange: NULL];
|
|
|
|
|
NSPoint loc = [_layoutManager locationForGlyphAtIndex: glyphIndex];
|
|
|
|
|
|
|
|
|
|
rect.origin.x += loc.x;
|
|
|
|
|
rect.size.width -= loc.x;
|
|
|
|
|
|
|
|
|
|
return rect;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-08-07 22:06:04 +00:00
|
|
|
|
- (NSRect) rectForCharacterRange: (NSRange) aRange
|
|
|
|
|
{
|
2000-09-18 23:33:30 +00:00
|
|
|
|
NSRange glyphRange = [_layoutManager glyphRangeForCharacterRange: aRange
|
|
|
|
|
actualCharacterRange: NULL];
|
|
|
|
|
|
|
|
|
|
return [_layoutManager boundingRectForGlyphRange: glyphRange
|
|
|
|
|
inTextContainer: [self textContainer]];
|
2000-08-07 22:06:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-09-30 23:11:15 +00:00
|
|
|
|
- (NSTextContainer*) buildUpTextNetwork: (NSSize)aSize;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
{
|
2000-09-30 23:11:15 +00:00
|
|
|
|
NSTextContainer *aTextContainer = [[NSTextContainer alloc] initWithContainerSize: aSize];
|
2000-10-12 23:02:25 +00:00
|
|
|
|
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
|
2000-09-30 23:11:15 +00:00
|
|
|
|
NSTextStorage *textStorage = [[NSTextStorage alloc] init];
|
|
|
|
|
|
|
|
|
|
[layoutManager addTextContainer: aTextContainer];
|
|
|
|
|
[textStorage addLayoutManager: layoutManager];
|
|
|
|
|
AUTORELEASE(aTextContainer);
|
|
|
|
|
AUTORELEASE(layoutManager);
|
|
|
|
|
AUTORELEASE(textStorage);
|
|
|
|
|
|
|
|
|
|
return aTextContainer;
|
2000-03-16 14:16:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) drawInsertionPointAtIndex: (unsigned) index
|
|
|
|
|
color: (NSColor*) color
|
|
|
|
|
turnedOn: (BOOL) flag
|
2000-03-08 08:43:15 +00:00
|
|
|
|
{
|
2000-03-16 14:16:46 +00:00
|
|
|
|
NSRect drawRect = [self rectForCharacterIndex: index];
|
|
|
|
|
|
|
|
|
|
drawRect.size.width = 1;
|
2000-03-19 07:33:26 +00:00
|
|
|
|
if (drawRect.size.height == 0)
|
|
|
|
|
drawRect.size.height = 12;
|
|
|
|
|
|
2000-03-08 08:43:15 +00:00
|
|
|
|
[self drawInsertionPointInRect: drawRect
|
2000-03-16 14:16:46 +00:00
|
|
|
|
color: color
|
2000-03-08 08:43:15 +00:00
|
|
|
|
turnedOn: flag];
|
1996-05-30 20:03:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|