home *** CD-ROM | disk | FTP | other *** search
- /*
- * FindObject.m
- *
- * Purpose:
- * This object controls the searching for strings in a matrix or in a text object.
- *
- * 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.
- *
- * Written by: Mary McNabb
- * Created: Apr 91
- *
- */
- #import "FindObject.h"
-
- #import <libc.h>
- #import <strings.h>
- #import <appkit/publicWraps.h>
- #import <streams/streams.h>
- #import <appkit/Form.h>
- #import <appkit/Button.h>
- #import <appkit/Matrix.h>
- #import <appkit/Text.h>
- #import <appkit/Window.h>
- #import <appkit/Application.h>
-
- #import "cUtils.h"
-
- @implementation FindObject
-
- /* initialize FindObject */
- - init
- {
- [super init];
- [NXApp loadNibSection:"FindPanel.nib" owner:self];
- return self;
- }
-
- /*
- * This method sets the local variable searchMe.
- * searchMe must be either a text object or a
- * matrix of text fields.
- */
- - setSearchMe:object
- {
- searchMe = object;
- return self;
- }
-
- /*
- * Order the findPanel front and select the search string.
- */
- - findPanel:sender
- {
- [findPanel makeKeyAndOrderFront:NULL];
- [findForm selectTextAt:0];
- return self;
- }
-
- /*
- * This method is called when the user types carriage
- * return in the textfield in the find panel.
- */
- - findNextReturn:sender
- {
- [findNextButton performClick:NULL];
- [findPanel orderOut:NULL];
- return self;
- }
-
- /*
- * This method is called when the user pushes the next
- * button on the find panel. It decides if the searchMe
- * is of type matrix or text and calls subsequent methods
- * accordingly.
- */
- - findNext:sender
- {
- const char *findStr = [findForm stringValueAt:0];
- if (!strlen(findStr) || !searchMe) {
- NXBeep();
- return self;
- }
- ignoreCase = [ignoreCaseButton state];
-
- if ([searchMe isKindOf:[Matrix class]]) {
- [self findInMatrix:FORWARD :findStr];
- } else {
- [self findInText:FORWARD];
- }
- return self;
- }
-
- /*
- * This method is called when the user pushes the previous
- * button on the find panel. It decides if the searchMe is of type
- * matrix or text and calls subsequent methods accordingly.
- */
- - findPrevious:sender
- {
- const char *findStr = [findForm stringValueAt:0];
-
- if (!strlen(findStr) || !searchMe) {
- NXBeep();
- return self;
- }
- if ([searchMe isKindOf:[Matrix class]]) {
- [self findInMatrix:BACKWARD :findStr];
- } else {
- [self findInText:BACKWARD];
- }
- return self;
- }
-
- /*
- * Searches through a text object (also wraps around if necessary).
- */
- - findInText:(int)direction
- {
- char *text, *textStart, *match;
- NXSelPt start, end;
- int count, newStart;
- NXStream *stream;
-
- text = (char *)[findForm stringValueAt:0];
-
- [searchMe getSel:&start :&end];
- if (start.cp == end.cp) start.cp = end.cp = 0;
-
- /* We need to set up a stream for the search */
- stream = [searchMe stream];
- if (!stream) {
- NXBeep();
- return self;
- }
-
- /* find out how long the text is, and position ourselves either from the beginning or from
- * the selection position */
- NXSeek(stream, 0, NX_FROMEND);
- count = NXTell(stream);
- NXSeek(stream, 0, NX_FROMSTART);
- textStart = (char *)malloc(count + 1);
- NXRead(stream, textStart, count);
- *(textStart + count) = '\0';
-
- if (direction == FORWARD)
- match = textInString(text, textStart + end.cp, ignoreCase);
- else
- match = textInStringReverse(text, textStart + start.cp + strlen(text) - 1,
- textStart, ignoreCase);
-
- /* wraparound if necessary */
- if (!match) {
- if (direction == FORWARD)
- match = textInString(text, textStart, ignoreCase);
- else
- match = textInStringReverse(text, textStart + strlen(textStart), textStart, ignoreCase);
- }
-
- /* did we find anything? */
- newStart = match - textStart;
- free(textStart);
- if (!match || (newStart == start.cp && (end.cp - start.cp) == strlen(text))) {
- NXBeep();
- return self;
- }
-
- [[searchMe setSel:newStart :newStart + strlen(text)]
- scrollSelToVisible];
-
- return self;
- }
-
- - (BOOL)searchMatrixStrings:(int)start:(int)stop:(int)dir:(const char *)findStr
- {
- int i;
-
- for (i = start; dir == FORWARD? i <= stop: i >= stop; i += dir)
- {
- id myCell = [searchMe cellAt:i :0];
- char *myContents = (char *) [myCell stringValue];
- if (textInString((char *)findStr, myContents, ignoreCase))
- { /* then we've got a match */
- [searchMe selectCellAt: i :0];
- return YES;
- }
- }
- return NO;
- }
-
- - findInMatrix:(int) direction :(const char*) findStr
- {
- int stop, temp, start;
- if (direction == FORWARD) {
- [searchMe getNumRows:&stop numCols:&temp];
- stop--;
- start = [searchMe selectedRow] + 1;
- } else {
- stop = 0;
- start = [searchMe selectedRow] - 1;
- }
- if (![self searchMatrixStrings:start :stop :direction :findStr])
- { /* implements wrap-around search */
- if (direction == FORWARD) {
- start = 0;
- stop = [searchMe selectedRow];
- } else {
- [searchMe getNumRows:&start numCols:&temp];
- start -= 1;
- stop = [searchMe selectedRow] + 1;
- }
- if (![self searchMatrixStrings:start :stop :direction :findStr])
- {
- NXBeep();
- return self;
- }
- }
- return self;
- }
-
- @end
-