apps-projectcenter/PCLib/PCTextFinder.m
Philippe C.D. Robert 005848beb8 Optimised text edition reflection. Embedded editing will need more changes
in that respect, I fear...


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/projectcenter/trunk@12400 72102866-910b-0410-8b05-ffd578937521
2002-02-03 19:31:28 +00:00

590 lines
15 KiB
Objective-C

/*
* PCTextFinder.m created by probert on 2002-02-03 13:22:59 +0000
*
* Project ProjectCenter
*
* Created with ProjectCenter - http://www.gnustep.org
*
* $Id$
*/
/*
* This code is heavily based on Ali Ozers TextFinder. All credits belong
* to Ali!
*
*/
#import "PCTextFinder.h"
#define Forward YES
#define Backward NO
#define ReplaceAllScopeEntireFile 42
#define ReplaceAllScopeSelection 43
@interface NSString (NSStringTextFinding)
- (NSRange)findString:(NSString *)string
selectedRange:(NSRange)selectedRange
options:(unsigned)options
wrap:(BOOL)wrap;
@end
@implementation NSString (NSStringTextFinding)
- (NSRange)findString:(NSString *)string
selectedRange:(NSRange)selectedRange
options:(unsigned)options
wrap:(BOOL)wrap
{
BOOL forwards = (options & NSBackwardsSearch) == 0;
unsigned length = [self length];
NSRange searchRange, range;
if (forwards)
{
searchRange.location = NSMaxRange(selectedRange);
searchRange.length = length - searchRange.location;
range = [self rangeOfString:string options:options range:searchRange];
if ((range.length == 0) && wrap)
{
searchRange.location = 0;
searchRange.length = selectedRange.location;
range=[self rangeOfString:string options:options range:searchRange];
}
}
else
{
searchRange.location = 0;
searchRange.length = selectedRange.location;
range = [self rangeOfString:string options:options range:searchRange];
if ((range.length == 0) && wrap)
{
searchRange.location = NSMaxRange(selectedRange);
searchRange.length = length - searchRange.location;
range=[self rangeOfString:string options:options range:searchRange];
}
}
return range;
}
@end
@interface PCTextFinder (CreateUI)
- (void)_initUI;
@end
@implementation PCTextFinder (CreateUI)
- (void)_initUI
{
int mask = (NSTitledWindowMask | NSClosableWindowMask);
NSRect rect = NSMakeRect( 100, 100, 440, 184 );
NSTextField *textField;
NSBox *box;
NSButtonCell *cell;
NSMatrix *borderMatrix;
panel = [[NSPanel alloc] initWithContentRect:rect
styleMask:mask
backing:NSBackingStoreBuffered
defer:YES];
[panel setTitle: @"Find Panel"];
[panel setReleasedWhenClosed: NO];
// Find textfield
textField = [[NSTextField alloc] initWithFrame:NSMakeRect(16,148,88,21)];
[textField setAlignment: NSRightTextAlignment];
[textField setBordered: NO];
[textField setEditable: NO];
[textField setBezeled: NO];
[textField setDrawsBackground: NO];
[textField setStringValue:@"Find:"];
[[panel contentView] addSubview:textField];
RELEASE(textField);
rect = NSMakeRect(104,148,328 ,21);
findTextField = [[NSTextField alloc] initWithFrame:rect];
[findTextField setAlignment: NSLeftTextAlignment];
[findTextField setBordered: NO];
[findTextField setEditable: YES];
[findTextField setBezeled: YES];
[findTextField setDrawsBackground: YES];
[findTextField setStringValue:@""];
[findTextField setDelegate:self];
[findTextField setTarget:self];
[findTextField setAction:@selector(setHost:)];
[[panel contentView] addSubview:findTextField];
RELEASE(findTextField);
[panel makeFirstResponder:findTextField];
// Replace field
textField = [[NSTextField alloc] initWithFrame:NSMakeRect(16,120,88,21)];
[textField setAlignment: NSRightTextAlignment];
[textField setBordered: NO];
[textField setEditable: NO];
[textField setBezeled: NO];
[textField setDrawsBackground: NO];
[textField setStringValue:@"Replace with:"];
[[panel contentView] addSubview:textField];
RELEASE(textField);
rect = NSMakeRect(104,120,328 ,21);
replaceTextField = [[NSTextField alloc] initWithFrame:rect];
[replaceTextField setAlignment: NSLeftTextAlignment];
[replaceTextField setBordered: NO];
[replaceTextField setEditable: YES];
[replaceTextField setBezeled: YES];
[replaceTextField setDrawsBackground: YES];
[replaceTextField setStringValue:@""];
[replaceTextField setDelegate:self];
[replaceTextField setTarget:self];
[replaceTextField setAction:@selector(setHost:)];
[[panel contentView] addSubview:replaceTextField];
RELEASE(replaceTextField);
[findTextField setNextResponder:replaceTextField];
// Options
rect = NSMakeRect(104,40,144 ,80);
box = [[NSBox alloc] initWithFrame:rect];
[box setTitle:@"Replace All Scope"];
[[panel contentView] addSubview:box];
RELEASE(box);
cell = [[NSButtonCell alloc] init];
[cell setButtonType: NSRadioButton];
[cell setBordered: NO];
[cell setImagePosition: NSImageLeft];
rect = NSMakeRect(16,8,112 ,48);
borderMatrix = [[NSMatrix alloc] initWithFrame: rect
mode: NSRadioModeMatrix
prototype: cell
numberOfRows: 2
numberOfColumns: 1];
[borderMatrix setIntercellSpacing: NSMakeSize (0, 4) ];
[borderMatrix setTarget: self];
[borderMatrix setAutosizesCells: NO];
cell = [borderMatrix cellAtRow: 0 column: 0];
[cell setTitle: @"Entire File"];
[cell setTag:0];
[cell setAction: @selector(setReplaceAllScope:)];
cell = [borderMatrix cellAtRow: 1 column: 0];
[cell setTitle: @"Selection"];
[cell setTag:1];
[cell setAction: @selector(setReplaceAllScope:)];
[borderMatrix sizeToFit];
[box addSubview:borderMatrix];
RELEASE(borderMatrix);
rect = NSMakeRect(252,40,180 ,80);
box = [[NSBox alloc] initWithFrame:rect];
[box setTitle:@"Find Options"];
[[panel contentView] addSubview:box];
RELEASE(box);
cell = [[NSButtonCell alloc] init];
[cell setButtonType: NSSwitchButton];
[cell setBordered: NO];
[cell setImagePosition: NSImageLeft];
rect = NSMakeRect(16,8,140 ,48);
borderMatrix = [[NSMatrix alloc] initWithFrame: rect
mode: NSHighlightModeMatrix
prototype: cell
numberOfRows: 2
numberOfColumns: 1];
[borderMatrix setIntercellSpacing: NSMakeSize (0, 4) ];
[borderMatrix setTarget: self];
[borderMatrix setAutosizesCells: NO];
ignoreCaseButton = [borderMatrix cellAtRow: 0 column: 0];
[ignoreCaseButton setTitle: @"Ignore Case"];
[ignoreCaseButton setState: YES];
[ignoreCaseButton setAction: @selector(setIgnoreCase:)];
regexpButton = [borderMatrix cellAtRow: 1 column: 0];
[regexpButton setTitle: @"Regular Expression"];
[regexpButton setState: NO];
//[regexpButton setAction: @selector(setIsRegExp:)];
[borderMatrix sizeToFit];
[box addSubview:borderMatrix];
RELEASE(borderMatrix);
cell = [[NSButtonCell alloc] init];
[cell setImagePosition: NSNoImage];
rect = NSMakeRect(8,8,412,24);
borderMatrix = [[NSMatrix alloc] initWithFrame: rect
mode: NSHighlightModeMatrix
prototype: cell
numberOfRows: 1
numberOfColumns: 4];
[borderMatrix setIntercellSpacing: NSMakeSize (4, 0) ];
[borderMatrix setTarget: self];
[borderMatrix setAction: @selector(buttonPressed:)];
[borderMatrix setAutosizesCells: NO];
[replaceTextField setNextResponder:borderMatrix];
cell = [borderMatrix cellAtRow:0 column:0];
[cell setTitle: @"Replace All"];
[cell setTag:0];
cell = [borderMatrix cellAtRow:0 column:1];
[cell setTitle: @"Replace"];
[cell setTag:1];
cell = [borderMatrix cellAtRow:0 column:2];
[cell setTitle: @"Previous"];
[cell setTag:2];
cell = [borderMatrix cellAtRow:0 column:3];
[cell setTitle: @"Next"];
[cell setTag:3];
[[panel contentView] addSubview:borderMatrix];
RELEASE(borderMatrix);
rect = NSMakeRect(16,64,80,24);
statusField = [[NSTextField alloc] initWithFrame:rect];
[statusField setAlignment: NSLeftTextAlignment];
[statusField setBordered: NO];
[statusField setEditable: NO];
[statusField setBezeled: NO];
[statusField setDrawsBackground: NO];
[statusField setStringValue:@""];
[statusField setDelegate:self];
[[panel contentView] addSubview:statusField];
RELEASE(statusField);
[panel setDelegate: self];
[panel center];
}
@end
@implementation PCTextFinder
static PCTextFinder *_finder = nil;
+ (PCTextFinder*)sharedFinder
{
if( _finder == nil )
{
_finder = [[PCTextFinder alloc] init];
}
return _finder;
}
- (id)init
{
if((self = [super init]))
{
shouldReplaceAll = YES;
shouldIgnoreCase = YES;
[self setFindString:@""];
[self loadFindStringFromPasteboard];
}
return self;
}
- (void)dealloc
{
if( panel != nil )
{
RELEASE(panel);
}
[super dealloc];
}
- (NSPanel *)findPanel
{
if( panel == nil )
{
[self _initUI];
}
return panel;
}
- (void)showFindPanel:(id)sender
{
if( panel == nil )
{
[self _initUI];
}
[panel orderFront:self];
}
- (void)buttonPressed:(id)sender
{
switch([[sender selectedCell] tag] )
{
case 0:
[self replaceAll:sender];
break;
case 1:
[self replace:sender];
break;
case 2:
[self findPrevious:sender];
break;
case 3:
[self findNext:sender];
break;
}
}
- (void)setReplaceAllScope:(id)sender
{
switch([[sender selectedCell] tag] )
{
case 0:
shouldReplaceAll = YES;
break;
case 1:
shouldReplaceAll = NO;
break;
}
}
- (void)setIgnoreCase:(id)sender
{
if( [ignoreCaseButton state] )
{
shouldIgnoreCase = YES;
}
else
{
shouldIgnoreCase = NO;
}
}
- (BOOL)find:(BOOL)direction
{
NSTextView *text = [self textObjectToSearchIn];
lastFindWasSuccessful = NO;
if (text)
{
NSString *textContents = [text string];
unsigned textLength;
if (textContents && (textLength = [textContents length]))
{
NSRange range;
unsigned options = 0;
if (direction == Backward) options |= NSBackwardsSearch;
if (shouldIgnoreCase) options |= NSCaseInsensitiveSearch;
range = [textContents findString:[self findString]
selectedRange:[text selectedRange]
options:options
wrap:YES];
if (range.length)
{
[text setSelectedRange:range];
[text scrollRangeToVisible:range];
lastFindWasSuccessful = YES;
}
}
}
if (!lastFindWasSuccessful)
{
NSBeep();
[statusField setStringValue:@"Not found"];
}
else
{
[statusField setStringValue:@""];
}
return lastFindWasSuccessful;
}
- (NSTextView *)textObjectToSearchIn
{
id obj = [[NSApp mainWindow] firstResponder];
return (obj && [obj isKindOfClass:[NSTextView class]]) ? obj : nil;
}
- (NSString *)findString
{
return findString;
}
- (void)setFindString:(NSString *)string
{
if ([string isEqualToString:findString]) return;
AUTORELEASE(findString);
findString = [string copyWithZone:[self zone]];
if (findTextField)
{
[findTextField setStringValue:string];
[findTextField selectText:nil];
}
findStringChangedSinceLastPasteboardUpdate = YES;
}
- (void)loadFindStringFromPasteboard
{
NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
if ([[pasteboard types] containsObject:NSStringPboardType])
{
NSString *string = [pasteboard stringForType:NSStringPboardType];
if (string && [string length])
{
[self setFindString:string];
findStringChangedSinceLastPasteboardUpdate = NO;
}
}
}
- (void)loadFindStringToPasteboard
{
NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
if (findStringChangedSinceLastPasteboardUpdate)
{
[pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType]
owner:nil];
[pasteboard setString:[self findString] forType:NSStringPboardType];
findStringChangedSinceLastPasteboardUpdate = NO;
}
}
- (void)findNext:(id)sender
{
if (findTextField)
{
[self setFindString:[findTextField stringValue]];
}
[self find:Forward];
}
- (void)findPrevious:(id)sender
{
if (findTextField)
{
[self setFindString:[findTextField stringValue]];
}
[self find:Backward];
}
- (void)findNextAndOrderFindPanelOut:(id)sender;
{
}
- (void)replace:(id)sender
{
NSTextView *text = [self textObjectToSearchIn];
if (!text)
{
NSBeep();
[statusField setStringValue:@"No text!"];
}
else
{
[[text textStorage] replaceCharactersInRange:[text selectedRange]
withString:[replaceTextField stringValue]];
[text didChangeText];
}
[statusField setStringValue:@""];
}
- (void)replaceAll:(id)sender;
{
NSTextView *text = [self textObjectToSearchIn];
if (!text)
{
NSBeep();
}
else
{
NSTextStorage *textStorage = [text textStorage];
NSString *textContents = [text string];
NSString *replaceString = [replaceTextField stringValue];
unsigned replaced = 0;
NSRange replaceRange = shouldReplaceAll
? NSMakeRange(0, [textStorage length])
: [text selectedRange];
unsigned options = NSBackwardsSearch |
( shouldIgnoreCase ? NSCaseInsensitiveSearch : 0);
if (findTextField) [self setFindString:[findTextField stringValue]];
while (1)
{
NSRange foundRange = [textContents rangeOfString:[self findString]
options:options
range:replaceRange];
if (foundRange.length == 0)
{
break;
}
if ([text shouldChangeTextInRange:foundRange replacementString:replaceString])
{
if (replaced == 0)
{
[textStorage beginEditing];
}
replaced++;
[textStorage replaceCharactersInRange:foundRange
withString:replaceString];
replaceRange.length = foundRange.location - replaceRange.location;
}
}
// There was at least one replacement
if (replaced > 0)
{
[textStorage endEditing];
[text didChangeText];
[statusField setStringValue:[NSString stringWithFormat:@"%d replaced", replaced]];
}
else
{
NSBeep();
[statusField setStringValue:@"Not found"];
}
}
}
@end