mirror of
https://github.com/gnustep/apps-projectcenter.git
synced 2025-02-20 18:32:17 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/projectcenter/trunk@19527 72102866-910b-0410-8b05-ffd578937521
398 lines
9.1 KiB
Objective-C
398 lines
9.1 KiB
Objective-C
/*
|
|
GNUstep ProjectCenter - http://www.gnustep.org
|
|
|
|
Copyright (C) 2002-2004 Free Software Foundation
|
|
|
|
Authors: This code is heavily based on Ali Ozers TextFinder.
|
|
All credits belong to Ali!
|
|
|
|
This file is part of GNUstep.
|
|
|
|
This application is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This application 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 General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
|
*/
|
|
|
|
#include "PCTextFinder.h"
|
|
#include "PCDefines.h"
|
|
|
|
#include "PCTextFinder+UInterface.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
|
|
|
|
@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
|