From c325a04f647295baa8d6dff28419121ace59894a Mon Sep 17 00:00:00 2001 From: "Philippe C.D. Robert" Date: Sun, 3 Feb 2002 16:30:35 +0000 Subject: [PATCH] Added a text finder to ProjectCenter (based on Ali Ozer's code). git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/projectcenter/trunk@12397 72102866-910b-0410-8b05-ffd578937521 --- PCLib/GNUmakefile | 6 +- PCLib/PCEditor.m | 22 +- PCLib/PCTextFinder.h | 61 ++++ PCLib/PCTextFinder.m | 587 +++++++++++++++++++++++++++++++++++++ PCLib/ProjectCenter.h | 1 + PCLib/ProjectCenter.pcproj | 6 +- 6 files changed, 673 insertions(+), 10 deletions(-) create mode 100644 PCLib/PCTextFinder.h create mode 100644 PCLib/PCTextFinder.m diff --git a/PCLib/GNUmakefile b/PCLib/GNUmakefile index aececeb..55f54e8 100644 --- a/PCLib/GNUmakefile +++ b/PCLib/GNUmakefile @@ -63,7 +63,8 @@ Server.h \ PCSplitView.h \ PCEditor.h \ PCEditorController.h \ -PCDefines.h +PCDefines.h \ +PCTextFinder.h # @@ -83,7 +84,8 @@ PCProjectManager.m \ PCServer.m \ PCSplitView.m \ PCEditor.m \ -PCEditorController.m +PCEditorController.m \ +PCTextFinder.m # diff --git a/PCLib/PCEditor.m b/PCLib/PCEditor.m index de7c484..225bc9f 100644 --- a/PCLib/PCEditor.m +++ b/PCLib/PCEditor.m @@ -40,7 +40,19 @@ NSString *PCEditorDidResignKeyNotification=@"PCEditorDidResignKeyNotification"; [window setReleasedWhenClosed:NO]; [window setMinSize:NSMakeSize(512,320)]; - view = [[PCEditorView alloc] initWithFrame:NSMakeRect(0,0,498,306)]; + rect = [[window contentView] frame]; + rect.origin.x = -1; + rect.origin.y = -1; + rect.size.width += 2; + + scrollView = [[NSScrollView alloc] initWithFrame:rect]; + + rect.origin.x = 0; + rect.origin.y = 0; + rect.size.height -= 24; + rect.size.width -= 4; + + view = [[PCEditorView alloc] initWithFrame:rect]; [view setEditor:self]; [view setMinSize: NSMakeSize (0, 0)]; @@ -52,14 +64,13 @@ NSString *PCEditorDidResignKeyNotification=@"PCEditorDidResignKeyNotification"; [view setHorizontallyResizable:NO]; [view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; [view setBackgroundColor:[NSColor whiteColor]]; - [[view textContainer] setContainerSize: - NSMakeSize ([view frame].size.width,1e7)]; [[view textContainer] setWidthTracksTextView:YES]; - scrollView = [[NSScrollView alloc] initWithFrame:NSMakeRect (-1,-1,514,322)]; [scrollView setDocumentView:view]; + RELEASE(view); - [[view textContainer] setContainerSize:NSMakeSize([scrollView contentSize].width,1e7)]; + rect.size = NSMakeSize([scrollView contentSize].width,1e7); + [[view textContainer] setContainerSize:rect.size]; [scrollView setHasHorizontalScroller: YES]; [scrollView setHasVerticalScroller: YES]; @@ -98,7 +109,6 @@ NSString *PCEditorDidResignKeyNotification=@"PCEditorDidResignKeyNotification"; - (void)dealloc { RELEASE(window); - RELEASE(view); RELEASE(path); [super dealloc]; diff --git a/PCLib/PCTextFinder.h b/PCLib/PCTextFinder.h new file mode 100644 index 0000000..3582c8e --- /dev/null +++ b/PCLib/PCTextFinder.h @@ -0,0 +1,61 @@ +/* + * PCTextFinder.h created by probert on 2002-02-03 13:23:01 +0000 + * + * Project ProjectCenter + * + * Created with ProjectCenter - http://www.gnustep.org + * + * $Id$ + */ + +#ifndef _PCTEXTFINDER_H_ +#define _PCTEXTFINDER_H_ + +#import + +@interface PCTextFinder : NSObject +{ + NSPanel *panel; + NSString *findString; + id findTextField; + id replaceTextField; + id statusField; + id ignoreCaseButton; + id regexpButton; + + BOOL findStringChangedSinceLastPasteboardUpdate; + BOOL lastFindWasSuccessful; + BOOL shouldReplaceAll; + BOOL shouldIgnoreCase; +} + ++ (PCTextFinder*)sharedFinder; + +- (id)init; +- (void)dealloc; + +- (NSPanel *)findPanel; + +- (void)showFindPanel:(id)sender; +- (void)buttonPressed:(id)sender; +- (void)setReplaceAllScope:(id)sender; +- (void)setIgnoreCase:(id)sender; + +- (BOOL)find:(BOOL)direction; +- (NSTextView *)textObjectToSearchIn; +- (NSString *)findString; +- (void)setFindString:(NSString *)string; + +- (void)loadFindStringFromPasteboard; +- (void)loadFindStringToPasteboard; + +- (void)findNext:(id)sender; +- (void)findPrevious:(id)sender; +- (void)findNextAndOrderFindPanelOut:(id)sender; +- (void)replace:(id)sender; +- (void)replaceAll:(id)sender; + +@end + +#endif // _PCTEXTFINDER_H_ + diff --git a/PCLib/PCTextFinder.m b/PCLib/PCTextFinder.m new file mode 100644 index 0000000..1c1aaeb --- /dev/null +++ b/PCLib/PCTextFinder.m @@ -0,0 +1,587 @@ +/* + * 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); + + // 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]; + + 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 makeKeyAndOrderFront: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 diff --git a/PCLib/ProjectCenter.h b/PCLib/ProjectCenter.h index f6b6190..0047a37 100644 --- a/PCLib/ProjectCenter.h +++ b/PCLib/ProjectCenter.h @@ -47,6 +47,7 @@ #import #import #import +#import #endif diff --git a/PCLib/ProjectCenter.pcproj b/PCLib/ProjectCenter.pcproj index 498f3ce..763e70c 100644 --- a/PCLib/ProjectCenter.pcproj +++ b/PCLib/ProjectCenter.pcproj @@ -14,7 +14,8 @@ PCServer.m, PCSplitView.m, PCEditor.m, - PCEditorController.m + PCEditorController.m, + PCTextFinder.m ); COMPILEROPTIONS = ""; CREATION_DATE = ""; @@ -45,7 +46,8 @@ PCSplitView.h, PCEditor.h, PCEditorController.h, - PCDefines.h + PCDefines.h, + PCTextFinder.h ); INSTALLDIR = "$(GNUSTEP_SYSTEM_ROOT)"; LANGUAGE = English;