diff --git a/Documentation/ChangeLog b/Documentation/ChangeLog index db90190..8832027 100644 --- a/Documentation/ChangeLog +++ b/Documentation/ChangeLog @@ -1,3 +1,9 @@ +2007-09-24 Sergii Stoian + + * English.lproj/FindPanel.gorm: Added Find panel. + * PCMenuController.m: Added Find panel support. + * TextFinder.[hm]: Added implementation of Find panel. + 2007-08-29 Sergii Stoian * Frameworks/PCFileManager.m: diff --git a/English.lproj/FindPanel.gorm/data.classes b/English.lproj/FindPanel.gorm/data.classes new file mode 100644 index 0000000..aabcf9f --- /dev/null +++ b/English.lproj/FindPanel.gorm/data.classes @@ -0,0 +1,34 @@ +{ + "## Comment" = "Do NOT change this file, Gorm maintains it"; + FirstResponder = { + Actions = ( + "findNext:", + "findNextAndOrderFindPanelOut:", + "findPrevious:", + "ignoreCase:", + "replace:", + "replaceAll:", + "replaceAndFind:" + ); + Super = NSObject; + }; + TextFinder = { + Actions = ( + "findNext:", + "findNextAndOrderFindPanelOut:", + "findPrevious:", + "replace:", + "replaceAll:", + "replaceAndFind:" + ); + Outlets = ( + findNextButton, + findTextField, + ignoreCaseButton, + replaceAllScopeMatrix, + replaceTextField, + statusField + ); + Super = NSObject; + }; +} \ No newline at end of file diff --git a/English.lproj/FindPanel.gorm/data.info b/English.lproj/FindPanel.gorm/data.info new file mode 100644 index 0000000..e233f82 Binary files /dev/null and b/English.lproj/FindPanel.gorm/data.info differ diff --git a/English.lproj/FindPanel.gorm/objects.gorm b/English.lproj/FindPanel.gorm/objects.gorm new file mode 100644 index 0000000..c4c7c4c Binary files /dev/null and b/English.lproj/FindPanel.gorm/objects.gorm differ diff --git a/English.lproj/Info.gorm/Info.tiff b/English.lproj/Info.gorm/Info.tiff new file mode 100644 index 0000000..2f3e173 Binary files /dev/null and b/English.lproj/Info.gorm/Info.tiff differ diff --git a/English.lproj/Info.gorm/data.classes b/English.lproj/Info.gorm/data.classes new file mode 100644 index 0000000..168dd6b --- /dev/null +++ b/English.lproj/Info.gorm/data.classes @@ -0,0 +1,3 @@ +{ + "## Comment" = "Do NOT change this file, Gorm maintains it"; +} \ No newline at end of file diff --git a/English.lproj/Info.gorm/data.info b/English.lproj/Info.gorm/data.info new file mode 100644 index 0000000..e233f82 Binary files /dev/null and b/English.lproj/Info.gorm/data.info differ diff --git a/English.lproj/Info.gorm/objects.gorm b/English.lproj/Info.gorm/objects.gorm new file mode 100644 index 0000000..2369733 Binary files /dev/null and b/English.lproj/Info.gorm/objects.gorm differ diff --git a/English.lproj/ProjectCenter.gorm/data.classes b/English.lproj/ProjectCenter.gorm/data.classes index 6e191dc..cf6d48d 100644 --- a/English.lproj/ProjectCenter.gorm/data.classes +++ b/English.lproj/ProjectCenter.gorm/data.classes @@ -1,5 +1,15 @@ { "## Comment" = "Do NOT change this file, Gorm maintains it"; + FirstResponder = { + Actions = ( + "findEnterSelection:", + "findNext:", + "findPrevious:", + "findShowPanel:", + "findJumpToSelection:" + ); + Super = NSObject; + }; PCAppController = { Actions = ( ); @@ -44,7 +54,12 @@ "loadedFilesSortByName:", "loadedFilesNextFile:", "loadedFilesPreviousFile:", - "showLogPanel:" + "showLogPanel:", + "findEnterSelection:", + "findNext:", + "findPrevious:", + "findShowPanel:", + "findJumpToSelection:" ); Outlets = ( ); diff --git a/English.lproj/ProjectCenter.gorm/data.info b/English.lproj/ProjectCenter.gorm/data.info index 152bdec..e233f82 100644 Binary files a/English.lproj/ProjectCenter.gorm/data.info and b/English.lproj/ProjectCenter.gorm/data.info differ diff --git a/English.lproj/ProjectCenter.gorm/objects.gorm b/English.lproj/ProjectCenter.gorm/objects.gorm index bf9959a..d3dcf9c 100644 Binary files a/English.lproj/ProjectCenter.gorm/objects.gorm and b/English.lproj/ProjectCenter.gorm/objects.gorm differ diff --git a/Framework/English.lproj/ProjectWindow.gorm/objects.gorm b/Framework/English.lproj/ProjectWindow.gorm/objects.gorm index 552c41b..3773199 100644 Binary files a/Framework/English.lproj/ProjectWindow.gorm/objects.gorm and b/Framework/English.lproj/ProjectWindow.gorm/objects.gorm differ diff --git a/Framework/PCProjectEditor.m b/Framework/PCProjectEditor.m index 897590a..ccd7e55 100644 --- a/Framework/PCProjectEditor.m +++ b/Framework/PCProjectEditor.m @@ -27,6 +27,7 @@ #import #import #import + #import #import #import @@ -673,7 +674,8 @@ NSString *PCEditorDidResignActiveNotification = - (void)editorDidClose:(NSNotification *)aNotif { - id editor = [aNotif object]; +// id editor = [aNotif object]; + id editor = [aNotif object]; // It is not our editor if ([editor projectEditor] != self) diff --git a/GNUmakefile b/GNUmakefile index f6236c0..12cb934 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -89,7 +89,9 @@ Modules/Parsers/ProjectCenter/ProjectCenter.parser # Localization # ProjectCenter_LOCALIZED_RESOURCE_FILES = \ -ProjectCenter.gorm +ProjectCenter.gorm \ +Info.gorm \ +FindPanel.gorm ProjectCenter_LANGUAGES = \ English @@ -110,6 +112,7 @@ ProjectCenter_OBJC_FILES = \ PCAppController.m \ PCInfoController.m \ PCMenuController.m \ +TextFinder.m \ ProjectCenter_main.m -include GNUmakefile.preamble diff --git a/Images/FileH.tiff b/Images/FileH.tiff index 7987a7d..94106cd 100644 Binary files a/Images/FileH.tiff and b/Images/FileH.tiff differ diff --git a/Modules/Editors/ProjectCenter/PCEditor.h b/Modules/Editors/ProjectCenter/PCEditor.h index d3f8d57..8d82666 100644 --- a/Modules/Editors/ProjectCenter/PCEditor.h +++ b/Modules/Editors/ProjectCenter/PCEditor.h @@ -48,6 +48,7 @@ NSString *_categoryPath; NSWindow *_window; + BOOL _isEdited; BOOL _isWindowed; BOOL _isExternal; @@ -58,8 +59,6 @@ // NSMutableArray *classNames; // NSMutableArray *methodNames; - IBOutlet NSMenu *menu; - NSFont *defaultFont; NSFont *highlightFont; diff --git a/Modules/Editors/ProjectCenter/PCEditor.m b/Modules/Editors/ProjectCenter/PCEditor.m index e2f2081..b61914c 100644 --- a/Modules/Editors/ProjectCenter/PCEditor.m +++ b/Modules/Editors/ProjectCenter/PCEditor.m @@ -31,7 +31,6 @@ #import "PCEditorView.h" //#import "CommandQueryPanel.h" //#import "LineQueryPanel.h" -//#import "TextFinder.h" @implementation PCEditor (UInterface) @@ -218,6 +217,7 @@ [super dealloc]; } +// --- Protocol - (void)setParser:(id)parser { // NSLog(@"RC aParser:%i parser:%i", @@ -345,6 +345,7 @@ return self; } +// --- Protocol End - (void)externalEditorDidClose:(NSNotification *)aNotif { @@ -365,10 +366,10 @@ } // =========================================================================== -// ==== Accessory methods +// ==== CodeEditor protocol // =========================================================================== -//--- CodeEditor protocol +// --- Accessor methods - (id)projectEditor { @@ -508,16 +509,12 @@ return items; } -- (NSMenu *)menu +- (void)show { - return nil; -} - -//--- protocol end - -- (BOOL)isWindowed -{ - return _isWindowed; + if (_isWindowed) + { + [_window makeKeyAndOrderFront:nil]; + } } - (void)setWindowed:(BOOL)yn @@ -541,17 +538,12 @@ _isWindowed = yn; } -- (void)show +- (BOOL)isWindowed { - if (_isWindowed) - { - [_window makeKeyAndOrderFront:nil]; - } + return _isWindowed; } -// =========================================================================== -// ==== Object managment -// =========================================================================== +// --- Object managment - (BOOL)saveFileIfNeeded { diff --git a/Modules/Editors/ProjectCenter/PCEditorView.m b/Modules/Editors/ProjectCenter/PCEditorView.m index f0e9a7e..c03ed86 100644 --- a/Modules/Editors/ProjectCenter/PCEditorView.m +++ b/Modules/Editors/ProjectCenter/PCEditorView.m @@ -276,6 +276,7 @@ static int ComputeIndentingOffset(NSString * string, unsigned int start) - (unichar)firstCharOfNextLineForIndex:(int)index { + return 0; } - (void)performIndentation @@ -284,11 +285,11 @@ static int ComputeIndentingOffset(NSString * string, unsigned int start) int location; int line_start; int offset; - unichar c, fc, plfc, clfc; + unichar c, plfc, clfc; NSRange wsRange; NSMutableString *indentString; int i; - int point; +// int point; location = [self selectedRange].location; @@ -461,7 +462,7 @@ static int ComputeIndentingOffset(NSString * string, unsigned int start) - (void)drawRect:(NSRect)r { - NSEnumerator *e; +// NSEnumerator *e; NSRange drawnRange; drawnRange = [[self layoutManager] diff --git a/PCInfoController.m b/PCInfoController.m index a4dc9cf..5afc358 100644 --- a/PCInfoController.m +++ b/PCInfoController.m @@ -56,7 +56,13 @@ - (void)showInfoWindow:(id)sender { -#if defined(GNUSTEP) + if ([NSBundle loadNibNamed:@"Info" owner:self] == NO) + { +// PCLogError(self, @"error loading Menu NIB file!"); + return; + } + +/*#if defined(GNUSTEP) if (!infoWindow) { infoWindow = [[GSInfoPanel alloc] initWithDictionary:infoDict]; @@ -69,7 +75,7 @@ NSRunAlertPanel(@"Info", @"OPENSTEP has no support for GSInfoPanel", @"OK",nil,nil,nil); -#endif +#endif*/ } @end diff --git a/PCMenuController.m b/PCMenuController.m index fb43762..1b25ffd 100644 --- a/PCMenuController.m +++ b/PCMenuController.m @@ -29,6 +29,8 @@ #include "PCMenuController.h" #include "PCInfoController.h" +#import "TextFinder.h" + @implementation PCMenuController - (id)init @@ -256,24 +258,33 @@ @"OK",nil,nil); } -// Edit. PCProjectEditor have to provide this menu and functionality -/*- (void)findShowPanel:(id)sender +// Edit +- (void)findShowPanel:(id)sender { - [[PCTextFinder sharedFinder] showFindPanel:self]; + [[TextFinder sharedInstance] orderFrontFindPanel:self]; } - (void)findNext:(id)sender { - [[PCTextFinder sharedFinder] findNext:self]; + [[TextFinder sharedInstance] findNext:self]; } - (void)findPrevious:(id)sender { - [[PCTextFinder sharedFinder] findPrevious:self]; -}*/ + [[TextFinder sharedInstance] findPrevious:self]; +} + +- (void)findJumpToSelection:(id)sender +{ + [[TextFinder sharedInstance] jumpToSelection:self]; +} + +- (void)findEnterSelection:(id)sender +{ + [[TextFinder sharedInstance] enterSelection:self]; +} // Tools - - (void)toggleToolbar:(id)sender { [[[projectManager rootActiveProject] projectWindow] toggleToolbar]; diff --git a/TextFinder.h b/TextFinder.h new file mode 100644 index 0000000..0e0ba2d --- /dev/null +++ b/TextFinder.h @@ -0,0 +1,64 @@ +#import + +#define Forward YES +#define Backward NO + +@interface TextFinder : NSObject +{ + NSString *findString; + id findTextField; + id replaceTextField; + id ignoreCaseButton; + id findNextButton; + id replaceAllScopeMatrix; + id statusField; + BOOL findStringChangedSinceLastPasteboardUpdate; + BOOL lastFindWasSuccessful; /* A bit of a kludge */ +} + +/* Common way to get a text finder. One instance of TextFinder per + * app is good enough. */ ++ (id)sharedInstance; + +/* Main method for external users; does a find in the first responder. + * Selects found range or beeps. */ +- (BOOL)find:(BOOL)direction; + +/* Loads UI lazily */ +- (NSPanel *)findPanel; + +/* Gets the first responder and returns it if it's an NSTextView */ +- (NSTextView *)textObjectToSearchIn; + +/* Get/set the current find string. Will update UI if UI is loaded */ +- (NSString *)findString; +- (void)setFindString:(NSString *)string; + +/* Misc internal methods */ +- (void)appDidActivate:(NSNotification *)notification; +- (void)addWillDeactivate:(NSNotification *)notification; +- (void)loadFindStringFromPasteboard; +- (void)loadFindStringToPasteboard; + +/* Methods sent from the find panel UI */ +- (void)findNext:(id)sender; +- (void)findPrevious:(id)sender; +- (void)enterSelection:(id)sender; +- (void)jumpToSelection:(id)sender; +- (void)findNextAndOrderFindPanelOut:(id)sender; +- (void)replace:(id)sender; +- (void)replaceAndFind:(id)sender; +- (void)replaceAll:(id)sender; +- (void)orderFrontFindPanel:(id)sender; + +@end + +@interface NSString (NSStringTextFinding) + + - (NSRange)findString:(NSString *)string + selectedRange:(NSRange)selectedRange + options:(unsigned)mask + wrap:(BOOL)wrapFlag; + + @end + diff --git a/TextFinder.m b/TextFinder.m new file mode 100644 index 0000000..5807ed2 --- /dev/null +++ b/TextFinder.m @@ -0,0 +1,434 @@ +/* + TextFinder.m + Copyright (c) 1995-1996, NeXT Software, Inc. + All rights reserved. + Author: Ali Ozer + + You may freely copy, distribute and reuse the code in this example. + NeXT disclaims any warranty of any kind, expressed or implied, + as to its fitness for any particular use. + + Find and replace functionality with a minimal panel... + + In addition to including this class and FindPanel.nib in your app, you + probably need to hook up the following action methods in your document + object (or whatever object is first responder) to call the appropriate + methods in [TextFinder sharedInstance]: + + orderFrontFindPanel: + findNext: + findPrevious: + enterSelection: (calls setFindString:) + + 2/21/95 aozer Created for Edit II. + 2/24/95 aozer Find pasteboard support + 8/16/95 aozer Replace functionality + 10/4/95 aozer Status field update + 11/12/96 aozer Correctly send shouldChange... to the textview + while doing a replace + + */ + +#import +#import "TextFinder.h" + +@implementation TextFinder + +- (id)init +{ + if (!(self = [super init])) + return nil; + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector (appDidActivate:) + name:NSApplicationDidBecomeActiveNotification + object:[NSApplication sharedApplication]]; + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector (addWillDeactivate:) + name:NSApplicationWillResignActiveNotification + object:[NSApplication sharedApplication]]; + + [self setFindString:@""]; + [self loadFindStringFromPasteboard]; + + return self; +} + +- (void)appDidActivate:(NSNotification *)notification +{ + [self loadFindStringFromPasteboard]; +} + +- (void)addWillDeactivate:(NSNotification *)notification +{ + [self loadFindStringToPasteboard]; +} + +- (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; + } +} + +static id sharedFindObject = nil; + ++ (id)sharedInstance +{ + if (!sharedFindObject) + { + sharedFindObject = [[self alloc] init]; + } + return sharedFindObject; +} + +- (void)awakeFromNib +{ + [ignoreCaseButton setRefusesFirstResponder:YES]; + [findNextButton setRefusesFirstResponder:YES]; + [replaceAllScopeMatrix setRefusesFirstResponder:YES]; + [statusField setRefusesFirstResponder:YES]; +} + +- (void)loadUI +{ + if (!findTextField) + { + if (![NSBundle loadNibNamed:@"FindPanel" owner:self]) + { + NSLog(@"Failed to load FindPanel.gorm"); + NSBeep(); + } + if (self == sharedFindObject) + { + [[findTextField window] setFrameAutosaveName:@"Find"]; + } + } + [findTextField setStringValue:[self findString]]; +} + +- (void)dealloc +{ + if (self != sharedFindObject) + { + [findString release]; + [super dealloc]; + } +} + +- (NSString *)findString +{ + return findString; +} + +- (void)setFindString:(NSString *)string +{ + if ([string isEqualToString:findString]) + { + return; + } + + [findString autorelease]; + findString = [string copy]; + + if (findTextField) + { + [findTextField setStringValue:string]; + [findTextField selectText:nil]; + } + + findStringChangedSinceLastPasteboardUpdate = YES; +} + +- (NSTextView *)textObjectToSearchIn +{ + id obj = [[NSApp mainWindow] firstResponder]; + + return (obj && [obj isKindOfClass:[NSTextView class]]) ? obj : nil; +} + +- (NSPanel *)findPanel +{ + if (!findTextField) + { + [self loadUI]; + } + + return (NSPanel *)[findTextField window]; +} + +/* + The primitive for finding; this ends up setting the status field (and + beeping if necessary)... + */ +- (BOOL)find:(BOOL)direction +{ + NSTextView *text = [self textObjectToSearchIn]; + + lastFindWasSuccessful = NO; + + if (text) + { + NSString *textContents = [text string]; + unsigned int textLength; + + if (textContents && (textLength = [textContents length])) + { + NSRange range; + unsigned int options = 0; + + if (direction == Backward) + options |= NSBackwardsSearch; + if ([ignoreCaseButton state]) + 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; +} + +- (void)orderFrontFindPanel:(id)sender +{ + NSPanel *panel = [self findPanel]; + + [findTextField selectText:nil]; + [panel makeKeyAndOrderFront:nil]; +} + +/**** Action methods for gadgets in the find panel; these should all end up setting or clearing the status field ****/ + +- (void)findNextAndOrderFindPanelOut:(id)sender +{ + [findNextButton performClick:nil]; + + if (lastFindWasSuccessful) + { + [[self findPanel] orderOut: sender]; + } + else + { + [findTextField selectText:nil]; + } +} + +- (void)findNext:(id)sender +{ + if (findTextField) + { + // findTextField should be set + [self setFindString:[findTextField stringValue]]; + } + + [self find:Forward]; +} + +- (void)findPrevious:(id)sender +{ + if (findTextField) + { + // findTextField should be set + [self setFindString:[findTextField stringValue]]; + } + + [self find:Backward]; +} + +- (void)enterSelection:(id)sender +{ + NSTextView *text = [self textObjectToSearchIn]; + NSRange range = [text selectedRange]; + NSString *string = [text string]; + + [self setFindString:[string substringWithRange:range]]; +} + +- (void)jumpToSelection:(id)sender +{ + NSTextView *text = [self textObjectToSearchIn]; + NSRange range = [text selectedRange]; + + [text scrollRangeToVisible:range]; +} + +- (void)replace:(id)sender +{ + NSTextView *text = [self textObjectToSearchIn]; + + if (!text) + { + NSBeep (); + } + else + { + [[text textStorage] + replaceCharactersInRange:[text selectedRange] + withString:[replaceTextField stringValue]]; + [text didChangeText]; + } + + [statusField setStringValue:@""]; +} + +- (void)replaceAndFind:(id)sender +{ + [self replace:sender]; + [self findNext:sender]; +} + +#define ReplaceAllScopeEntireFile 42 +#define ReplaceAllScopeSelection 43 + +- (void)replaceAll:(id)sender +{ + NSTextView *text = [self textObjectToSearchIn]; + + if (!text) + { + NSBeep(); + } + else + { + NSTextStorage *textStorage = [text textStorage]; + NSString *textContents = [text string]; + NSString *replaceString = [replaceTextField stringValue]; + BOOL entireFile = replaceAllScopeMatrix ? ([replaceAllScopeMatrix selectedTag] == ReplaceAllScopeEntireFile) : YES; + NSRange replaceRange = entireFile ? NSMakeRange (0, [textStorage length]) : [text selectedRange]; + unsigned int options = NSBackwardsSearch | ([ignoreCaseButton state] ? NSCaseInsensitiveSearch : 0); + unsigned int replaced = 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; + } + } + + if (replaced > 0) + { /* There was at least one replacement */ + + /* We need this to bracket the beginEditing */ + [textStorage endEditing]; + /* We need one of these to terminate the shouldChange... + * methods we sent */ + [text didChangeText]; + [statusField setStringValue:[NSString stringWithFormat:@"%d replaced", replaced]]; + } + else + { /* No replacements were done... */ + NSBeep(); + [statusField setStringValue:@"Not found"]; + } + } +} + +@end + + +@implementation NSString (NSStringTextFinding) + + - (NSRange)findString:(NSString *)string + selectedRange:(NSRange)selectedRange + options:(unsigned)options + wrap:(BOOL)wrap +{ + BOOL forwards = (options & NSBackwardsSearch) == 0; + unsigned int 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) + { // If not found look at the first part of the string + 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 +