This is Controller.m in view mode; [Download] [Up]
/* * This sourcecode is part of FileSpy, a logfile observing utility. * Copyright (C) 1996 Felix Rauch * * This program 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. * * Notice that this program may not be possessed, used, copied, * distributed or modified by people having to do with nuclear * weapons. See the file CONDITIONS for details. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * To contact the original author, try: * e-mail: Felix.Rauch@nice.ch * Traditional mail: Felix Rauch * Sempacherstrasse 33 * 8032 Zurich * Switzerland */ #import "Controller.h" #define SHORTESTTIME 1 /* minimal time between two tests on a file */ #define LONGESTTIME 60 /* maximal time - " - */ #define WIN_DELTA_X 25.0 /* coord-difference of new windows */ #define WIN_DELTA_Y 25.0 /* remember: Y comes down! */ #define WIN_START_X 100.0 #define WIN_START_Y 500.0 #define WIN_MAX_X 500.0 #define WIN_MAX_Y 100.0 #define MAXFILELEN MAXNAMLEN #ifdef DEBUG #define DEFOWNER "FileSpyDebug" #else #define DEFOWNER "FileSpy" #endif int wildmat(char *text, char *p); // still uses wildmat, should use GNU-regexp in the near future @implementation Controller - appWillInit:sender { whileInit = YES; return self; } - appDidInit:sender { NXRect matrixRect, scrollRect; NXSize interCellSpacing = {0.0, 0.0}, cellSize; const char *fileType[] = {NXFilenamePboardType}; winx = WIN_START_X; winy = WIN_START_Y; fileCount = 0; // no files yet secs = 2.0; // this one should probably be in the defaults database // now set some defaults saveFileList = YES; prefPopup = YES; prefBeepOnChange = YES; prefSuperlog = NO; prefUseFilter = NO; prefFileMode = RADIO_ENTIRE; prefColor = NX_COLORBLACK; // defined in <appkit/color.h> prefTimeStamp = NO; // no timestamps is default prefSuperCopyFilename = ONCE; prefSpytype = SPY_CONTENTS; // only spy for contents superPopup = YES; superBeepOnChange = YES; superUseFilter = NO; useFilter = NO; filterMode = FILTER_DONTBEEP; filterIsUpToDate = YES; displayCurWindow = YES; // only used when loading preferences becomeKey = NO; saveState = NO; maxLineState = NO; maxLines = 100; inspectorFrame = (char *)0; myWindowIsVisible = NO; nrOpenWindows = 0; lastSuperlogString = (char *)0; tmpList = [[List allocFromZone:[self zone]] init]; // temporary List used by all objects [SpyTextFieldCell setSharedTmpList:tmpList]; existenceSeen = YES; mySound = nil; // why do I need this??? swapfilename = NULL; swapfilesize = -1; swapfileTooBig = swapfileError = NO; [[NXApp appListener] setServicesDelegate:self]; [self registerServices:self]; if(system("/bin/stty pass8 pass8out nl > /dev/console") == 127) // proposed by mwa printf("filespy: couldn't open shell for 'stty pass8 pass8out nl > /dev/console\n"); [[[myScrollView setHorizScrollerRequired: NO] // setup mainwindow setVertScrollerRequired: YES] setBorderType: NX_BEZEL]; [myScrollView getFrame:&scrollRect]; [ScrollView getContentSize:&(matrixRect.size) forFrameSize:&(scrollRect.size) horizScroller: NO vertScroller: YES borderType:NX_BEZEL]; myMatrix = [[MyMatrix alloc] initFrame: &matrixRect mode: NX_LISTMODE cellClass: [SpyTextFieldCell class] numRows: 0 numCols: 1]; [myMatrix setIntercell:&interCellSpacing]; [myMatrix getCellSize:&cellSize]; cellSize.width = NX_WIDTH(&matrixRect); [myMatrix setCellSize:&cellSize]; [myMatrix sizeToCells]; [myMatrix setAutosizeCells:YES]; [myMatrix setAutoscroll:YES]; [myScrollView setDocView:myMatrix]; [[myMatrix superview] setAutoresizeSubviews:YES]; [myMatrix setAutosizing:NX_WIDTHSIZABLE]; [myMatrix setTarget:self]; [myMatrix setAction:@selector(singleClick:)]; [myMatrix setDoubleAction:@selector(doubleClick:)]; [myScrollView setController:self]; [myScrollView registerForDraggedTypes:fileType count:1]; [[[myExistenceScrollView setHorizScrollerRequired: NO] // setup existencelog setVertScrollerRequired: YES] setBorderType: NX_BEZEL]; [myExistenceScrollView getFrame:&scrollRect]; [ScrollView getContentSize:&(matrixRect.size) forFrameSize:&(scrollRect.size) horizScroller: NO vertScroller: YES borderType:NX_BEZEL]; myExistenceMatrix = [[SimpleMatrix alloc] initFrame: &matrixRect mode: NX_TRACKMODE cellClass: [ExistenceTextFieldCell class] numRows: 0 numCols: 1]; [myExistenceMatrix setIntercell:&interCellSpacing]; [myExistenceMatrix getCellSize:&cellSize]; cellSize.width = NX_WIDTH(&matrixRect); [myExistenceMatrix setCellSize:&cellSize]; [myExistenceMatrix sizeToCells]; [myExistenceMatrix setAutosizeCells:YES]; [myExistenceMatrix setAutoscroll:YES]; [myExistenceScrollView setDocView:myExistenceMatrix]; [[myExistenceMatrix superview] setAutoresizeSubviews:YES]; [myExistenceMatrix setAutosizing:NX_WIDTHSIZABLE]; [myExistenceMatrix setTarget:self]; [myExistenceScrollView setController:self]; [myExistenceScrollView registerForDraggedTypes:fileType count:1]; finder = [[Finder alloc] init]; [finder setDelegate:self]; [self setupFilter]; [self setupSuperlog]; [self loadPreferences:self]; if(firstFileStore) { // load files dragged on icon before start unsigned int max = [firstFileStore count], i; newFileOffset = YES; displayCurWindow = NO; for(i = 1; i != max; i++) [self addFileWithName:[firstFileStore elementAt:i]]; [firstFileStore free]; } if(fileCount == 0) { // set the main window correctly [radioMatrix selectCellAt:0:prefFileMode]; [popupSwitch setState:(prefPopup ? 1 : 0)]; [soundButton setState:(prefBeepOnChange ? 1 : 0)]; [filterSwitch setState:(prefUseFilter ? 1 : 0)]; [superlogSwitch setState:(prefSuperlog ? 1 : 0)]; } [self startSpyIfNeeded]; #ifdef DEBUG [myWindow setTitle:"Debug"]; #endif whileInit = NO; return self; } - appWillTerminate:sender { if(saveState) [self savePreferences:self]; [self stopSpy]; return self; } - app:sender powerOffIn:(int)ms andSave:(int)aFlag { return [self appWillTerminate:sender]; } - free // hmm.. I'd say there're some more things to free, aren't there? { [myWindow free]; return [super free]; } - (BOOL)appAcceptsAnotherFile:sender { return YES; } - (int)app:sender openFile:(const char *)filename type:(const char *)aType; { BOOL tmpdcw = displayCurWindow; // tmpDisplayCurWindow displayCurWindow = NO; if(whileInit) { if(!firstFileStore) firstFileStore = [[Storage alloc] initCount:1 elementSize:MAXFILELEN description:"[MAXFILELENc]"]; [firstFileStore addElement:(char *)filename]; } else { newFileOffset = YES; // place window at a new position (its position is not in the defaults database) displayCurWindow = NO; [self addFileWithName:filename]; displayCurWindow = YES; } displayCurWindow = tmpdcw; return YES; } - addFileWithName:(const char *)name { [myTextField setStringValue:name]; [self addFile:self]; return self; } - addFile:sender { const char *str; int rowCount, colCount, button, i = 0; SpyTextFieldCell *newCell; BOOL fileExists = NO; // is the file already in the list? str = [myTextField stringValue]; if(*str == '\000') { [self chooseFile:self]; return self; } [myTextField selectText:self]; [myMatrix getNumRows:&rowCount numCols:&colCount]; while((i < rowCount) && !fileExists) { // only one window per file if(strcmp([[myMatrix cellAt:i :0] stringValue], str) == 0) fileExists = TRUE; else i++; } if(!fileExists) { BOOL newFile = YES; struct stat st; int actRowNr, actColNr, statRet; [myMatrix getRow:&actRowNr andCol:&actColNr ofCell:[myMatrix selectedCell]]; [myMatrix selectCellAt:-1:-1]; [myMatrix addRow]; newCell = [myMatrix cellAt:rowCount :0]; [newCell setTag:rowCount]; [newCell setStringValue: str]; // now set all the default-values [newCell setFileMode:prefFileMode]; [newCell setAutoPopUp:prefPopup]; [newCell setBeepOnChange:prefBeepOnChange]; [newCell setMyDelegate:self]; [newCell setLogToSuperlog:prefSuperlog]; [newCell setUseFilter:prefUseFilter]; [newCell setDontCopy:prefDontCopySuperlog]; [newCell setSuperCopyFilename:prefSuperCopyFilename]; [newCell setColor:prefColor]; [newCell setTimeStamp:prefTimeStamp]; [newCell setMaxLines:(maxLineState ? maxLines : 0)]; [newCell setSpytype:prefSpytype]; [newCell setShowTime:showTime]; if(prefFont) [newCell setSpyFont:prefFont]; if(((statRet = stat(str, &st)) < 0) && !whileInit) { if(errno == ENOENT) { displayCurWindow = NO; button = NXRunAlertPanel("Alert", "File %s doesn't exist.\nAre you sure you want to spy it?", "Ok", "Cancel", NULL, str); if(button != NX_ALERTDEFAULT) { [myMatrix selectCellAt:rowCount :0]; [self deleteFile:self]; newFile = NO; } } else if(errno == EACCES) { displayCurWindow = NO; button = NXRunAlertPanel("Alert", "No permission for file %s.\nAre you sure you want to spy it?", "Ok", "Cancel", NULL, str); if(button != NX_ALERTDEFAULT) { [myMatrix selectCellAt:rowCount :0]; [self deleteFile:self]; newFile = NO; } } } if(newFile) { if(newFileOffset) { winx = winx + WIN_DELTA_X; winy = winy - WIN_DELTA_Y; if((winx > WIN_MAX_X) || (winy < WIN_MAX_Y)) { winx = WIN_START_X; winy = WIN_START_Y; } [newCell moveWindowTo:winx:winy]; } else { [[newCell window] setFrameFromString:frameStr]; } [newCell updateFile]; } [myMatrix sizeToCells]; [myMatrix selectCellAt:(newFile ? rowCount : actRowNr) :0]; [myMatrix scrollCellToVisible:rowCount :0]; fileCount++; [self startSpyIfNeeded]; } else { // file is already beeing spyed, so beep and select it [self nxbeep]; [myMatrix selectCellAt:i :0]; [myMatrix scrollCellToVisible:i :0]; } [self singleClick:self]; return self; } - deleteFile:sender { id selectedCellsList; int i, rowCount, colCount; [myTextField setStringValue:""]; selectedCellsList = [tmpList empty]; [myMatrix getSelectedCells:selectedCellsList]; [myMatrix getNumRows:&rowCount numCols:&colCount]; for(i=0; i<rowCount; i++) { if([selectedCellsList indexOf:[myMatrix cellAt:i :0]] != NX_NOT_IN_LIST) { [[myMatrix cellAt:i :0] delete]; [myMatrix removeRowAt:i-- andFree:YES]; fileCount--; } } [[myMatrix sizeToCells] display]; [myExistenceMatrix sizeToCells]; [myExistenceScrollView display]; if((fileCount == 0) || ([myMatrix selectedCell] == nil)) { [self setInspectorToView:[inspectorNoView contentView]]; } [self stopSpyIfNeeded]; return self; } - chooseFile:sender { id openPanel; const char *const fileType[1] = {NULL}; const char *const *files; char tmpfile[MAXFILENAMELENGHT]; int i = 0; openPanel = [OpenPanel new]; [openPanel setDelegate:self]; [openPanel chooseDirectories:NO]; [openPanel allowMultipleFiles:YES]; if([openPanel runModalForDirectory:[myTextField stringValue] file:NULL types:fileType] == NX_OKTAG) { if((files = [openPanel filenames]) != (const char *const *)0) { while(files[i]) { sprintf(tmpfile, "%s/%s", [openPanel directory], files[i++]); [self addFileWithName:tmpfile]; } } } [self singleClick:self]; return self; } - singleClick:sender { PopUpList *popupList = [[superFilenameButton cell] target], *spytypePopuplist = [[spytypeButton cell] target]; Matrix *popupMatrix = [popupList itemList], *spytypeMatrix = [spytypePopuplist itemList]; id selectedCell = [myMatrix selectedCell]; if(selectedCell != nil) { // this does not work correctly because of a bug in NS! // tempi passati [myTextField setStringValue:[selectedCell stringValue]]; [myTextField selectText:self]; if(inspectorPanel) { // if the inspectorPanel is open, then set all the values [radioMatrix selectCellAt:0 :[selectedCell fileMode]]; [soundButton setState:[selectedCell beepOnChange]]; [popupSwitch setState:[selectedCell autoPopUp]]; [superlogSwitch setState:[selectedCell logToSuperlog]]; [filterSwitch setState:[selectedCell useFilter]]; [dontCopySwitch setState:[selectedCell dontCopy]]; [timeSwitch setState:[selectedCell timeStamp]]; [popupMatrix selectCellWithTag:[selectedCell superCopyFilename]]; [superFilenameButton setTitle: [[popupMatrix findCellWithTag:[selectedCell superCopyFilename]] title]]; [superColorWell setColor:[selectedCell color]]; [fontTextField setFont:[selectedCell spyFont]]; [myFontManager setSelFont:[selectedCell spyFont] isMultiple:NO]; [spytypeMatrix selectCellWithTag:(int)[selectedCell spytype]]; [spytypeButton setTitle: [[spytypeMatrix findCellWithTag:(int)[selectedCell spytype]] title]]; if([[myMatrix getSelectedCells:[tmpList empty]] count] > 1) { // if multiple selection... [inspectorFile setStringValue:"Files: "]; [inspectorName setTextGray:NX_DKGRAY]; } else { [inspectorFile setStringValue:"File: "]; [inspectorName setTextGray:NX_BLACK]; } [inspectorName setStringValue:[selectedCell stringValue]]; [self setInspectorToView:[inspectorNormalView contentView]]; } } else { // if no cell is selected #ifdef DEBUG // puts("selectedCell == nil"); // for testing if the bug still exists // it doesn't... #endif [myTextField setStringValue:""]; [myTextField selectText:self]; [self setInspectorToView:[inspectorNoView contentView]]; } return self; } - doubleClick:sender { [[myMatrix selectedCell] displayWindow]; return self; } - radioClick:sender // if user selects the radio-button for entire file/only new text { List *selectedCellsList = [tmpList empty]; unsigned int i; int mode = [[radioMatrix selectedCell] tag]; [myMatrix getSelectedCells:selectedCellsList]; for(i = 0; i < [selectedCellsList count]; i++) [[selectedCellsList objectAt:i] setFileMode:mode]; return self; } - autoPopUpClick:sender { List *selectedCellsList = [tmpList empty]; unsigned int i; BOOL state = [popupSwitch state]; [myMatrix getSelectedCells:selectedCellsList]; for(i = 0; i < [selectedCellsList count]; i++) [[selectedCellsList objectAt:i] setAutoPopUp:state]; return self; } - beepOnChangeClick:sender { List *selectedCellsList = [tmpList empty]; unsigned int i; BOOL state = [soundButton state]; [myMatrix getSelectedCells:selectedCellsList]; for(i = 0; i < [selectedCellsList count]; i++) [[selectedCellsList objectAt:i] setBeepOnChange:state]; return self; } - superlogClick:sender { List *selectedCellsList = [tmpList empty]; unsigned int i, max; BOOL state = [sender state]; [myMatrix getSelectedCells:selectedCellsList]; max = [selectedCellsList count]; for(i = 0; i < max; i++) [[selectedCellsList objectAt:i] setLogToSuperlog:state]; return self; } - useFilterClick:sender { List *selectedCellsList = [tmpList empty]; unsigned int i, max; BOOL state = [sender state]; [myMatrix getSelectedCells:selectedCellsList]; max = [selectedCellsList count]; for(i = 0; i < max; i++) [[selectedCellsList objectAt:i] setUseFilter:state]; return self; } - copySuperlogClick:sender { List *selectedCellsList = [tmpList empty]; unsigned int i, max; BOOL state = [sender state]; selectedCellsList = [tmpList empty]; [myMatrix getSelectedCells:selectedCellsList]; max = [selectedCellsList count]; for(i = 0; i < max; i++) [[selectedCellsList objectAt:i] setDontCopy:state]; return self; } - filterModeClick:sender { switch([[sender selectedCell] tag]) { case 0: filterMode = FILTER_DONTCOPY; break; case 1: filterMode = FILTER_DONTBEEP; break; #ifdef DEBUG default: printf("filespy: unknown filtermode %d\n", [sender state]); #endif } return self; } // if user changes something in the preferences-window - prefRadioClick:sender { prefFileMode = [[prefRadioMatrix selectedCell] tag]; return self; } - prefSuperlogClick:sender { prefSuperlog = [sender state]; return self; } - prefAutoPopUpClick:sender { prefPopup = [sender state]; return self; } - prefBeepOnChangeClick:sender { prefBeepOnChange = [sender state]; return self; } - prefUseFilterClick:sender { prefUseFilter = [sender state]; return self; } - prefCopySuperlogClick:sender { prefDontCopySuperlog = [sender state]; return self; } - superAutoPopUpClick:sender { superPopup = [sender state]; return self; } - superBeepOnChangeClick:sender { superBeepOnChange = [sender state]; return self; } - superUseFilterClick:sender { superUseFilter = [sender state]; return self; } - superDupLinesClick:sender { BOOL oldState = noDuplicatedLines; noDuplicatedLines = [sender state]; if((noDuplicatedLines == YES) && (oldState == NO)) lastSuperlogString = (char *)malloc(MAXSTRLEN * sizeof(char)); else if((noDuplicatedLines == NO) && (oldState == YES)) free(lastSuperlogString); return self; } - saveFileListClick:sender { saveFileList = [sender state]; return self; } - keyClick:sender { becomeKey = [sender state]; return self; } - stateClick:sender { saveState = [sender state]; return self; } - setShowTimeClick:sender { unsigned int i, max; List *selectedCellsList = [myMatrix cellList]; showTime = [sender state]; max = [selectedCellsList count]; for(i = 0; i < max; i++) [[selectedCellsList objectAt:i] setShowTime:showTime]; if(existencelogWindow) [existencelogWindow display]; return self; } - (BOOL)showTime { return showTime; } - startSpy { if(!running) { alarmTimedEntry = DPSAddTimedEntry(secs, &alarmHandler, self, NX_BASETHRESHOLD); running = YES; } return self; } - startSpyIfNeeded { if(fileCount > 0 || (swapfilename != NULL && swapfilesize >= 0)) [self startSpy]; return self; } - stopSpy { if(running) { DPSRemoveTimedEntry(alarmTimedEntry); NXPing(); running = NO; } return self; } - stopSpyIfNeeded { if(fileCount == 0 && (swapfilename == NULL || swapfilesize < 0)) [self stopSpy]; return self; } - checkFiles // update all the files { unsigned int i, max; int row, col; SpyTextFieldCell *actualCell; BOOL exMatrixUpdate = NO; [tmpList empty]; for(i=0; i<fileCount; i++) { actualCell = [myMatrix cellAt:i :0]; [actualCell updateFile]; if([actualCell changedState]) [actualCell updateText]; if([actualCell askUpdateTime] && showTime) exMatrixUpdate = YES; } max = [tmpList count]; if(max > 0) { if(existenceSeen) { existenceSeen = NO; [myExistenceMatrix clearSelectedCell]; } for(i=0; i<max; i++) { // select all cell that changed existence in existencelog [myExistenceMatrix getRow:&row andCol:&col ofCell:[tmpList objectAt:i]]; [myExistenceMatrix setSelectionFrom:row to:row anchor:row lit:YES]; } [myExistenceMatrix getRow:&row andCol:&col ofCell:[tmpList objectAt:0]]; // get first selected cell [myExistenceMatrix scrollCellToVisible:row :col]; // and scroll it to visible } if((max > 0) || (exMatrixUpdate)) { [existencelogWindow display]; } if((swapfilename != NULL) && (swapfilesize >= 0)) { [self updateSwapfile]; } return self; } - changeUpdatePeriod:sender { int newPeriod = [sender intValue]; if(newPeriod > LONGESTTIME) newPeriod = LONGESTTIME; if(newPeriod < SHORTESTTIME) newPeriod = SHORTESTTIME; [secsTextField setIntValue:newPeriod]; [secsScroller setIntValue:newPeriod]; secs = newPeriod; [self stopSpy]; [self startSpyIfNeeded]; return self; } - showPreferences:sender // shows preferences panel { PopUpList *popupList; Matrix *popupMatrix; if(!preferencesPanel) { if(![NXApp loadNibSection:"Preferences.nib" owner:self withNames:NO fromZone:[self zone]]) { NXLogError("Can't open Preferences.nib!"); } [self setPrefToView:[prefGenView contentView]]; } popupList = [[prefSuperFilenameButton cell] target]; popupMatrix = [popupList itemList]; [secsScroller setDoubleValue:secs]; [secsTextField setDoubleValue:secs]; [prefPopupSwitch setState:prefPopup]; [prefSoundButton setState:prefBeepOnChange]; [prefFilterSwitch setState:prefUseFilter]; [prefSuperlogSwitch setState:prefSuperlog]; [superPopupSwitch setState:superPopup]; [superSoundSwitch setState:superBeepOnChange]; [superFilterSwitch setState:superUseFilter]; [superDupSwitch setState:noDuplicatedLines]; [prefRadioMatrix selectCellAt:0:prefFileMode]; [keySwitch setState:becomeKey]; [stateSwitch setState:saveState]; [fileListButton setState:saveFileList]; [prefDontCopySwitch setState:prefDontCopySuperlog]; [showTimeSwitch setState:showTime]; [prefSuperFilenameButton setTitle: [[popupMatrix findCellWithTag:prefSuperCopyFilename] title]]; [prefColorWell setColor:prefColor]; popupList = [[prefSpytypeButton cell] target]; popupMatrix = [popupList itemList]; [prefSpytypeButton setTitle: [[popupMatrix findCellWithTag:prefSpytype] title]]; [prefFontTextField setFont:prefFont]; [myFontManager setSelFont:prefFont isMultiple:NO]; [prefTimeSwitch setState:prefTimeStamp]; [[maxLinesScroller setIntValue:maxLines] setEnabled:maxLineState]; [[maxLinesTextField setIntValue:maxLines] setEnabled:maxLineState]; [maxLinesMatrix selectCellWithTag:maxLineState]; if(mySound != nil) [soundTextField setStringValue:[mySound name]]; if(swapfilename != NULL) { [prefSwapfileTextField setStringValue:swapfilename]; [prefSwapfileSizeTextField setIntValue:swapfilesize/(1024*1024)]; } else { [prefSwapfileTextField setStringValue:""]; [prefSwapfileSizeTextField setStringValue:""]; } [preferencesPanel makeKeyAndOrderFront:sender]; return self; } - setPref:sender { id newView = nil; int tag = [[sender selectedCell] tag]; switch(tag) { case 0: newView = [prefGenView contentView]; break; case 1: newView = [prefNewView contentView]; break; case 2: newView = [prefSuperView contentView]; break; case 3: newView = [prefSwapfileView contentView]; break; #ifdef DEBUG default: printf("filespy: unknown tag in setPref:sender\n"); // this shouldn't happen break; #endif } [self setPrefToView:newView]; [popButton setTitle:[[sender selectedCell] title]]; return self; } - setPrefToView:theView { NXRect boxRect, viewRect; [multiView getFrame:&boxRect]; [theView getFrame:&viewRect]; [multiView setContentView:theView]; NX_X(&viewRect) = (NX_WIDTH(&boxRect) - NX_WIDTH(&viewRect)) / 2.0; NX_Y(&viewRect) = (NX_HEIGHT(&boxRect) - NX_HEIGHT(&viewRect)) / 2.0; [theView setFrame:&viewRect]; [multiView display]; return self; } - savePreferences:sender // saves preferences to defaults-database { unsigned int i, oldCount = 0; char *str; id cellList, actualCell; NXDefaultsVector vec = { // contains global defaults {"filterMode", ""}, // 0 {"superUseFilter", (superUseFilter ? "YES" : "NO")}, // 1 {"prefUseFilter", (prefUseFilter ? "YES" : "NO")}, // 2 {"secs",""}, // 3 {"prefPopup", (prefPopup ? "YES" : "NO")}, // 4 {"prefBeepOnChange", (prefBeepOnChange ? "YES" : "NO")}, // 5 {"prefSuperlog", (prefSuperlog ? "YES" : "NO")}, // 6 {"superPopup", (superPopup ? "YES" : "NO")}, // 7 {"superBeepOnChange", (superBeepOnChange ? "YES" : "NO")}, // 8 {"prefFileMode", ""}, // 9 {"saveFileList", (saveFileList ? "YES" : "NO")}, // 10 {"fileCount",""}, // 11 {"myWindowFrame", ""}, // 12 {"myWindowVisible", [myWindow isVisible] ? "YES" : "NO"}, // 13 {"superWindowFrame", ""}, // 14 {"superWindowVisible", [superWindow isVisible] ? "YES" : "NO"}, // 15 {"becomeKey", becomeKey ? "YES" : "NO"}, // 16 {"saveState", saveState ? "YES" : "NO"}, // 17 {"prefDontCopySuperlog", prefDontCopySuperlog ? "YES" : "NO"}, // 18 {"prefSuperCopyFilename", ""}, // 19 {"prefColor", ""}, // 20 {"prefTimeStamp", prefTimeStamp ? "YES" : "NO"}, // 21 {"prefFont", ""}, // 22 {"maxLines", ""}, // 23 {"inspectorFrame", ""}, // 24 {"superNoDupLines", noDuplicatedLines ? "YES" : "NO"}, // 25 {"prefSpytype", ""}, // 26 {"exWindowFrame", ""}, // 27 {"exWindowVisible",[existencelogWindow isVisible]? "YES":"NO"}, // 28 {"soundfile", ""}, // 29 {"showTime", "NO"}, // 30 {"swapFileName", ""}, // 31 {"swapFileSize", "-1"}, // 32 {NULL, NULL} // <- enter this number in VECLEN }; #define VECLEN 33 NXDefaultsVector fileVec = { // contains defaults for each file {"", ""}, // 0 {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, // 13 {NULL, NULL}, // <- enter this number in FILEVECLEN! }; #define FILEVECLEN 14 oldCount = atoi(NXGetDefaultValue(DEFOWNER, "fileCount")); // need to remember how many files were in the database // so that I can remove thouse which now longer belong there vec[0].value = (char *)alloca(16); sprintf(vec[0].value, "%d", filterMode); vec[3].value = (char *)alloca(16); sprintf(vec[3].value, "%f", secs); vec[9].value = (char *)alloca(16); sprintf(vec[9].value, "%d", prefFileMode); vec[19].value = (char *)alloca(16); sprintf(vec[19].value, "%d", prefSuperCopyFilename); vec[20].value = (char *)alloca(32); sprintf(vec[20].value, "%f,%f,%f", NXRedComponent(prefColor), NXGreenComponent(prefColor), NXBlueComponent(prefColor)); vec[22].value = (char *)alloca(32); // hope this is enough for a fontname, is there some constant somewhere? sprintf(vec[22].value, "%s %f", [prefFont name], [prefFont pointSize]); vec[23].value = (char *)alloca(16); sprintf(vec[23].value, "%d", maxLineState ? maxLines : -maxLines); vec[26].value = (char *)alloca(16); sprintf(vec[26].value, "%hu", prefSpytype); vec[29].value = (char *)alloca(MAXNAMLEN); sprintf(vec[29].value, [self soundName]); vec[30].value = (char *)alloca(4); sprintf(vec[30].value, showTime ? "YES" : "NO"); if(swapfilename != NULL) { vec[31].value = (char *)alloca(strlen(swapfilename) + 1); strcpy(vec[31].value, swapfilename); vec[32].value = (char *)alloca(sizeof(char)*11); sprintf(vec[32].value, "%ld", swapfilesize); } vec[11].value = (char *)alloca(16); if(saveFileList) sprintf(vec[11].value, "%d", fileCount); else sprintf(vec[11].value, "%d", oldFileCount); vec[12].value = (char *)alloca(NX_MAXFRAMESTRINGLENGTH); [myWindow saveFrameToString:vec[12].value]; vec[14].value = (char *)alloca(NX_MAXFRAMESTRINGLENGTH); [superWindow saveFrameToString:vec[14].value]; vec[24].value = (char *)alloca(NX_MAXFRAMESTRINGLENGTH); if(inspectorPanel) { // remember the inspector panel's position [inspectorPanel saveFrameToString:vec[24].value]; } else if(inspectorFrame != (char *)0) { strcpy(vec[24].value, inspectorFrame); } vec[27].value = (char *)alloca(NX_MAXFRAMESTRINGLENGTH); [existencelogWindow saveFrameToString:vec[27].value]; if(NXWriteDefaults(DEFOWNER, vec) != VECLEN) NXLogError("error while writing to defaults database"); [self saveFilter:self]; if(saveFileList) { // save defaults for each file NXColor col; for(i = 0; i < FILEVECLEN; i++) { fileVec[i].name = (char *)alloca(32); fileVec[i].value = (char *)alloca(NX_MAXFRAMESTRINGLENGTH); } cellList = [myMatrix cellList]; for(i = 0; i < fileCount; i++) { actualCell = [cellList objectAt:i]; sprintf(fileVec[0].name, "fileName%d", i); strcpy(fileVec[0].value, [actualCell stringValue]); sprintf(fileVec[1].name, "fileFrame%d", i); [[actualCell window] saveFrameToString:fileVec[1].value]; sprintf(fileVec[2].name, "fileMode%d", i); sprintf(fileVec[2].value, "%d", [actualCell fileMode]); sprintf(fileVec[3].name, "filePop%d", i); strcpy(fileVec[3].value, [actualCell autoPopUp] ? "YES" : "NO"); sprintf(fileVec[4].name, "fileBeep%d", i); strcpy(fileVec[4].value, [actualCell beepOnChange] ? "YES" : "NO"); sprintf(fileVec[5].name, "fileLog%d", i); strcpy(fileVec[5].value, [actualCell logToSuperlog] ? "YES" : "NO"); sprintf(fileVec[6].name, "fileFilter%d", i); strcpy(fileVec[6].value, [actualCell useFilter] ? "YES" : "NO"); sprintf(fileVec[7].name, "fileVisible%d", i); strcpy(fileVec[7].value, [[actualCell window] isVisible] ? "YES" : "NO"); sprintf(fileVec[8].name, "fileDontCopy%d", i); strcpy(fileVec[8].value, [actualCell dontCopy] ? "YES" : "NO"); sprintf(fileVec[9].name, "fileSuperCopyName%d", i); sprintf(fileVec[9].value, "%d", [actualCell superCopyFilename]); col = [actualCell color]; sprintf(fileVec[10].name, "fileColor%d", i); sprintf(fileVec[10].value, "%f,%f,%f", NXRedComponent(col), NXGreenComponent(col), NXBlueComponent(col)); sprintf(fileVec[11].name, "fileTimeStamp%d", i); sprintf(fileVec[11].value, [actualCell timeStamp] ? "YES" : "NO"); sprintf(fileVec[12].name, "fileFont%d", i); sprintf(fileVec[12].value, "%s %f", [[actualCell spyFont] name], [[actualCell spyFont] pointSize]); sprintf(fileVec[13].name, "fileSpytype%d", i); sprintf(fileVec[13].value, "%hu", [actualCell spytype]); if(NXWriteDefaults(DEFOWNER, fileVec) != FILEVECLEN) NXLogError("error while writing filevector to defaults database"); } if(oldCount > fileCount) { // remove old entries which sould no longer be there str = (char *)alloca(32); for(i = fileCount; i < oldCount; i++) { sprintf(str, "fileName%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileFrame%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileMode%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "filePop%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileBeep%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileLog%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileFilter%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileVisible%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileDontCopy%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileSuperCopyName%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileColor%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileTimeStamp%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileFont%d", i); NXRemoveDefault(DEFOWNER, str); sprintf(str, "fileSpytype%d", i); NXRemoveDefault(DEFOWNER, str); } } } return self; } - saveFilter:sender // save filter-patterns to defaults database { char *tmp = (char *)alloca(16); const char *tmpStr; unsigned int i, maxFilter, oldCount = 0; maxFilter = [filterStore count]; tmpStr = NXGetDefaultValue(DEFOWNER, "filterStoreCount"); if(tmpStr != (const char *)0) oldCount = atoi(tmpStr); sprintf(tmp, "%d", maxFilter); if(!NXWriteDefault(DEFOWNER, "filterStoreCount", tmp)) NXLogError("error while writing filterStoreCount to defaults database"); for(i = 0; i < maxFilter; i++) { // save all filter strings sprintf(tmp, "filterLine%d", i); if(!NXWriteDefault(DEFOWNER, tmp, (char *)[filterStore elementAt:i])) NXLogError("error while writing filterLine to defaults database"); } for(i = maxFilter; i < oldCount; i++) { // remove remaining old entries sprintf(tmp, "filterLine%d", i); NXRemoveDefault(DEFOWNER, tmp); } if([filterWindow isDocEdited]) [filterWindow setDocEdited:NO]; return self; } - loadPreferences:sender // load preferences from defaults database { NXDefaultsVector vec = { // contains global defaults {"filterMode", "1"}, // 0 {"superUseFilter", "NO"}, // 1 {"prefUseFilter", "NO"}, // 2 {"secs", "2.000000"}, // 3 {"prefPopup", "YES"}, // 4 {"prefBeepOnChange", "YES"}, // 5 {"prefSuperlog", "NO"}, // 6 {"superPopup", "YES"}, // 7 {"superBeepOnChange", "YES"}, // 8 {"prefFileMode", "0"}, // 9 {"saveFileList", "YES"}, // 10 {"fileCount", "0"}, // 11 {"myWindowFrame", ""}, // 12 {"myWindowVisible", "YES"}, // 13 {"superWindowFrame", ""}, // 14 {"superWindowVisible", "NO"}, // 15 {"becomeKey", "NO"}, // 16 {"saveState", "NO"}, // 17 {"prefDontCopySuperlog", "YES"}, // 18 {"filterStoreCount", "0"}, // 19 {"prefSuperCopyFilename", "0"}, // 20 {"prefColor", "0,0,0"}, // 21 {"prefTimeStamp", "NO"}, // 22 {"prefFont", "Ohlfs 10.000000"}, // 23 {"maxLines", "-100"}, // 24 {"inspectorFrame", ""}, // 25 {"superNoDupLines", "NO"}, // 26 {"prefSpytype", "1"}, // 27 {"exWindowFrame", ""}, // 28 {"exWindowVisible", "NO"}, // 29 {"soundfile", ""}, // 30 {"showTime", "NO"}, // 31 {"swapFileName", ""}, // 32 {"swapFileSize", "-1"}, // 33 {NULL, NULL} }; NXDefaultsVector fileVec = { // contains defaults for individual files {"", ""}, // 0 {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, // 13 {NULL, NULL}, // <- enter this number in NRFILEVEC }; #define NRFILEVEC 14 unsigned int max, i; BOOL tmpPopup, tmpBeepOnChange, tmpLogToSuperlog, tmpUseFilter; unsigned short int tmpSpytype; int tmpFileMode; float red, green, blue; char str[MAXFILELEN], fontStr[48]; const char *tmpStr; NXRegisterDefaults(DEFOWNER, vec); [self setSound:NXGetDefaultValue(DEFOWNER, "soundfile")]; // set 'beep' filterMode = atoi(NXGetDefaultValue(DEFOWNER, "filterMode")); superUseFilter = (strncmp(NXGetDefaultValue(DEFOWNER, "superUseFilter"), "NO", 2) == 0) ? NO : YES; tmpUseFilter = (strncmp(NXGetDefaultValue(DEFOWNER, "prefUseFilter"), "NO", 2) == 0) ? NO : YES; secs = atof(NXGetDefaultValue(DEFOWNER, "secs")); tmpPopup = (strncmp(NXGetDefaultValue(DEFOWNER, "prefPopup"), "NO", 2) == 0) ? NO : YES; tmpBeepOnChange = (strncmp(NXGetDefaultValue(DEFOWNER, "prefBeepOnChange"), "NO", 2) == 0) ? NO : YES; tmpLogToSuperlog = (strncmp(NXGetDefaultValue(DEFOWNER, "prefSuperlog"), "NO", 2) == 0) ? NO : YES; superPopup = (strncmp(NXGetDefaultValue(DEFOWNER, "superPopup"), "NO", 2) == 0) ? NO : YES; superBeepOnChange = (strncmp(NXGetDefaultValue(DEFOWNER, "superBeepOnChange"), "NO", 2) == 0) ? NO : YES; noDuplicatedLines = (strncmp(NXGetDefaultValue(DEFOWNER, "superNoDupLines"), "NO", 2) == 0) ? NO : YES; if(noDuplicatedLines) lastSuperlogString = (char *)malloc(MAXSTRLEN * sizeof(char)); else lastSuperlogString = (char *)0; tmpFileMode = atoi(NXGetDefaultValue(DEFOWNER, "prefFileMode")); tmpSpytype = (unsigned short int)atoi(NXGetDefaultValue(DEFOWNER, "prefSpytype")); saveFileList = (strncmp(NXGetDefaultValue(DEFOWNER, "saveFileList"), "NO", 2) == 0) ? NO : YES; maxLines = atoi(NXGetDefaultValue(DEFOWNER, "maxLines")); if(maxLines < 0) { maxLineState = NO; maxLines = -maxLines; } else maxLineState = YES; showTime = (strncmp(NXGetDefaultValue(DEFOWNER, "showTime"), "NO", 2) == 0) ? NO : YES; tmpStr = NXGetDefaultValue(DEFOWNER, "swapFileName"); if(tmpStr != NULL && *tmpStr != '\000') { swapfilename = (char *)malloc(strlen(tmpStr)+1); strcpy(swapfilename, tmpStr); swapfilesize = atoi(NXGetDefaultValue(DEFOWNER, "swapFileSize")); } [superWindow setFrameFromString:NXGetDefaultValue(DEFOWNER, "superWindowFrame")]; max = atoi(NXGetDefaultValue(DEFOWNER, "filterStoreCount")); for(i = 0; i < max; i++) { const char *ts; sprintf(str, "filterLine%d", i); ts = NXGetDefaultValue(DEFOWNER, str); if(ts != (const char *)0) [filterStore addElement:(char *)ts]; } filterIsUpToDate = NO; for(i = 0; i < NRFILEVEC; i++) { fileVec[i].name = (char *)alloca(32); fileVec[i].value = (char *)alloca(NX_MAXFRAMESTRINGLENGTH); } max = oldFileCount= atoi(NXGetDefaultValue(DEFOWNER, "fileCount")); displayCurWindow = NO; newFileOffset = NO; for(i = 0; i < max; i++) { sprintf(fileVec[0].name, "fileName%d", i); sprintf(fileVec[1].name, "fileFrame%d", i); sprintf(fileVec[2].name, "fileMode%d", i); sprintf(fileVec[3].name, "filePop%d", i); sprintf(fileVec[4].name, "fileBeep%d", i); sprintf(fileVec[5].name, "fileLog%d", i); sprintf(fileVec[6].name, "fileDontCopy%d", i); sprintf(fileVec[7].name, "fileFilter%d", i); sprintf(fileVec[8].name, "fileVisible%d", i); sprintf(fileVec[9].name, "fileSuperCopyName%d", i); sprintf(fileVec[10].name, "fileColor%d", i); sprintf(fileVec[11].name, "fileTimeStamp%d", i); sprintf(fileVec[12].name, "fileFont%d", i); sprintf(fileVec[13].name, "fileSpytype%d", i); strcpy(fileVec[0].value, "/"); strcpy(fileVec[1].value, ""); strcpy(fileVec[2].value, "0"); strcpy(fileVec[3].value, "YES"); strcpy(fileVec[4].value, "YES"); strcpy(fileVec[5].value, "NO"); strcpy(fileVec[6].value, "YES"); strcpy(fileVec[7].value, "NO"); strcpy(fileVec[8].value, "YES"); strcpy(fileVec[9].value, "0"); strcpy(fileVec[10].value, "0,0,0"); strcpy(fileVec[11].value, "NO"); strcpy(fileVec[12].value, "Ohlfs 10.000000"); strcpy(fileVec[13].value, "1"); NXRegisterDefaults(DEFOWNER, fileVec); [myTextField setStringValue:NXGetDefaultValue(DEFOWNER, fileVec[0].name)]; strcpy(frameStr, NXGetDefaultValue(DEFOWNER, fileVec[1].name)); prefFileMode = atoi(NXGetDefaultValue(DEFOWNER, fileVec[2].name)); prefPopup = (strncmp(NXGetDefaultValue(DEFOWNER, fileVec[3].name), "NO", 2) == 0) ? NO : YES; prefBeepOnChange = (strncmp(NXGetDefaultValue(DEFOWNER, fileVec[4].name), "NO", 2) == 0) ? NO : YES; prefSuperlog = (strncmp(NXGetDefaultValue(DEFOWNER, fileVec[5].name), "NO", 2) == 0) ? NO : YES; prefDontCopySuperlog = (strncmp(NXGetDefaultValue(DEFOWNER, fileVec[6].name), "NO", 2) == 0) ? NO : YES; prefUseFilter = (strncmp(NXGetDefaultValue(DEFOWNER, fileVec[7].name), "NO", 2) == 0) ? NO : YES; prefSuperCopyFilename = atoi(NXGetDefaultValue(DEFOWNER, fileVec[9].name)); strcpy(str, NXGetDefaultValue(DEFOWNER, fileVec[10].name)); sscanf(str, "%f,%f,%f", &red, &green, &blue); prefColor = NXConvertRGBToColor(red, green, blue); prefTimeStamp = (strncmp(NXGetDefaultValue(DEFOWNER, fileVec[11].name), "NO", 2) == 0) ? NO : YES; strcpy(str, NXGetDefaultValue(DEFOWNER, fileVec[12].name)); sscanf(str, "%s %f", fontStr, &red); prefFont = [Font newFont:fontStr size:red]; prefSpytype = atoi(NXGetDefaultValue(DEFOWNER, fileVec[13].name)); [self addFile:self]; if(strncmp(NXGetDefaultValue(DEFOWNER, fileVec[8].name), "YES", 3) == 0) { [[myMatrix selectedCell] displayWindow]; [self addWindow:self]; } } displayCurWindow = YES; newFileOffset = YES; [myWindow setFrameFromString:NXGetDefaultValue(DEFOWNER, "myWindowFrame")]; if(strncmp(NXGetDefaultValue(DEFOWNER, "myWindowVisible"), "YES", 3) == 0) { myWindowIsVisible = YES; [myWindow makeKeyAndOrderFront:self]; } else myWindowIsVisible = NO; [existencelogWindow setFrameFromString:NXGetDefaultValue(DEFOWNER, "exWindowFrame")]; if(strncmp(NXGetDefaultValue(DEFOWNER, "exWindowVisible"), "YES", 3) == 0) { [existencelogWindow makeKeyAndOrderFront:self]; } prefPopup = tmpPopup; prefBeepOnChange = tmpBeepOnChange; prefSuperlog = tmpLogToSuperlog; prefUseFilter = tmpUseFilter; prefFileMode = tmpFileMode; prefDontCopySuperlog = (strncmp(NXGetDefaultValue(DEFOWNER, "prefDontCopySuperlog"), "NO", 2) == 0) ? NO : YES; prefSuperCopyFilename = atoi(NXGetDefaultValue(DEFOWNER, "prefSuperCopyFilename")); strcpy(str, NXGetDefaultValue(DEFOWNER, "prefColor")); sscanf(str, "%f,%f,%f", &red, &green, &blue); prefColor = NXConvertRGBToColor(red, green, blue); prefTimeStamp = (strncmp(NXGetDefaultValue(DEFOWNER, "prefTimeStamp"), "NO", 2) == 0) ? NO : YES; strcpy(str, NXGetDefaultValue(DEFOWNER, "prefFont")); sscanf(str, "%s %f", fontStr, &red); prefFont = [Font newFont:fontStr size:red]; prefSpytype = tmpSpytype; if(strncmp(NXGetDefaultValue(DEFOWNER, "superWindowVisible"), "YES", 3) == 0) [superWindow makeKeyAndOrderFront:self]; becomeKey = strncmp(NXGetDefaultValue(DEFOWNER, "becomeKey"), "NO", 2) == 0 ? NO : YES; saveState = strncmp(NXGetDefaultValue(DEFOWNER, "saveState"), "NO", 2) == 0 ? NO : YES; if(NXGetDefaultValue(DEFOWNER, "inspectorFrame") != (const char *)0) { inspectorFrame = (char *)malloc(NX_MAXFRAMESTRINGLENGTH*sizeof(char)); strcpy(inspectorFrame, NXGetDefaultValue(DEFOWNER, "inspectorFrame")); } [self singleClick:self]; // update the filelist with all buttons return self; } - changeBeepState:sender; { BOOL beepOnChange; unsigned int i, max; List *selectedCellsList = [tmpList empty]; if([sender state] == 0) beepOnChange = NO; else beepOnChange = YES; [myMatrix getSelectedCells:selectedCellsList]; max = [selectedCellsList count]; for(i = 0; i < max; i++) [[selectedCellsList objectAt:i] setBeepOnChange:beepOnChange]; return self; } - showSuperlog:sender { [superWindow orderFront:self]; return self; } - updateSuperlog:sender :(char *)newText :(BOOL)changed :(BOOL)beepThis :(BOOL)popThis { long int tmpPos, superLen; char myText[strlen(newText) + MAXFILELEN], senderName[MAXFILELEN]; if(*newText == '\000') // if there's no new text then forget it return self; if(maxLineState) [self shortSuperText]; if(noDuplicatedLines && (sender != lastSuperlogUser)) { // if user doesn't want the same line from multiple log-files // logged more than once, then don't append the line to superlog unsigned int len, len2, oldLineNumber = 0 , newLineNumber = 0, i ,j, k; NXSelPt start, end; char *oldText, *pos; char **oldLines, **newLines; [superText getSel:&start :&end]; len = end.cp - start.cp; if(len != 0) { oldText = (char *)alloca(sizeof(char) * (len + 1)); [superText getSubstring:oldText start:start.cp length:len]; oldText[len] = '\000'; for(pos = oldText; *pos != '\000'; ) { // remove all \r from oldText if(*pos == '\n') { // count number of lines oldLineNumber++; pos++; } else if(*pos == '\r') // (they are inserted in some logfiles and in some not) strcpy(pos, pos+1); else pos++; } for(pos = newText; *pos != '\000'; ) { // same for newtext if(*pos == '\n') { newLineNumber++; pos++; } else if(*pos == '\r') strcpy(pos, pos+1); else pos++; } // get the starting positions of the lines oldLines = (char **)malloc(oldLineNumber * sizeof(char *)); newLines = (char **)malloc(newLineNumber * sizeof(char *)); oldLineNumber = newLineNumber = 1; oldLines[0] = oldText; newLines[0] = newText; for(pos = oldText; *pos != '\000'; pos++) { if((pos[0] == '\n') && (pos[1] != '\000')) oldLines[oldLineNumber++] = pos+1; } for(pos = newText; *pos != '\000'; pos++) { if((pos[0] == '\n') && (pos[1] != '\000')) newLines[newLineNumber++] = pos+1; } // compare all the new lines with the old ones for(i = 0; i < newLineNumber; i++) { // for each line in the new text for(len = 0; (newLines[i][len] != '\n') && (newLines[i][len] != '\000'); len++) ; for(j = 0; j < oldLineNumber; j++) { for(len2 = 0; (oldLines[j][len2] != '\n') && (oldLines[j][len2] != '\000'); len2++) ; if((len == len2) && (strncmp(newLines[i], oldLines[j], len) == 0)) { // in case of a match, remove the new line for(k = i + 1; k < newLineNumber; k++) strcpy(newLines[k-1], newLines[k]); len = newLines[i+1] - newLines[i]; for(k = i+1; k < newLineNumber; k++) newLines[k] -= len; newLineNumber--; i--; // will be increased in the for loop, so adjust here if(i < newLineNumber) break; } } } if(newLineNumber == 0) // if there are no new lines left, we don't have to add any text return self; } } if(changed || (filterMode == FILTER_DONTBEEP)) { if(changed) { // if something passed the filter if(superBeepOnChange && beepThis) // and we prefer beeps in general and in this very special case [self nxbeep]; // then beep if(superPopup && popThis) { // if we prefer popups uf the superlogwindow and especially in this case... [superWindow orderFrontRegardless]; if(becomeKey) { [NXApp unhide:self]; [superWindow makeKeyWindow]; } } } if(![superWindow isKeyWindow] && ![superWindow isDocEdited]) [superWindow setDocEdited:YES]; myText[0] = '\000'; strcpy(senderName, [sender stringValue]); // sender's filename superLen = [superText textLength]; [superText setAutodisplay:NO]; [superText setSel:superLen :superLen]; switch([sender superCopyFilename]) { case ONCE: if(sender != lastSuperlogUser) { strcpy(myText, senderName); strcat(myText, ":\n"); } else *myText = '\000'; tmpPos = superLen + strlen(myText); strcat(myText, newText); [superText replaceSel :myText]; [[superText setSel :superLen :tmpPos] underline:self]; [superText setSel :superLen :superLen + strlen(myText) + 1]; break; case EACHLINE:{ char tmpText[strlen(newText) + MAXFILELEN], *p, *cp, tmp; tmpPos = superLen; // remember current length of superText to select new text afterwards strcpy(myText, senderName); strcat(myText, ":\t"); // tab better than space (Tremblin), maybe use rulers? cp = newText; while(*cp != '\000') { // start each line with myText strcpy(tmpText, myText); p = cp; while((*p != '\000') && (*p != '\n')) // search end of line/string p++; tmp = *p; *p = '\000'; strcat(tmpText, cp); strcat(tmpText, "\n"); // copy text up to there and append newline if(tmp == '\n') // go to next line if we haven't found end of string yet cp = p + 1; else cp = p; superLen = [superText textLength]; [superText setSel:superLen :superLen]; [superText replaceSel :tmpText]; // append this line to superText } [superText setSel :tmpPos :[superText textLength]]; break;} case NONE: [superText replaceSel :newText]; [superText setSel :superLen :[superText textLength]]; break; #ifdef DEBUG default: // that doesn't happen anyway... printf("unmatched case-value\n"); #endif } [superText setSelColor:[sender color]]; if([sender spyFont]) [superText setSelFont:[sender spyFont]]; if([superText needsDisplay]) [superText display]; [superText setAutodisplay:YES]; [[[superText sizeToFit] scrollSelToVisible] display]; if(!lastSuperlogUser && inspectorPanel && [inspectorPanel isVisible] && [superWindow isKeyWindow] && !myWindowIsVisible) [self setInspectorToView:[inspectorNormalView contentView]]; lastSuperlogUser = sender; } return self; } - setupSuperlog { superFont = [Font newFont:"Ohlfs" size:10 style:0 matrix:NX_FLIPPEDMATRIX]; [Text setDefaultFont:superFont]; superDoc = [Document new:self]; superWindow = [[superDoc scrollView] window]; superScrollView = [superDoc scrollView]; superText = [[superDoc scrollView] docView]; [superWindow setFreeWhenClosed:NO]; [superWindow setTitle:"Multilog"]; [superWindow setDelegate:self]; [superText setMonoFont:NO]; return self; } - setupFilter { filterStore = [[Storage alloc] initCount:0 // contains filter-lines elementSize:128 description:"[128c]"]; return self; } - showFilter:sender { if(!filterWindow) { if(![NXApp loadNibSection:"Filter.nib" owner:self withNames:NO fromZone:[self zone]]) { NXLogError("Can't open Filter.nib!"); return self; } [filterText setDelegate:self]; } [filterModeMatrix selectCellAt:filterMode:0]; if(!filterIsUpToDate) { unsigned int i, max; [filterText setSel:0 :[filterText textLength]]; [filterText replaceSel:""]; max = [filterStore count]; for(i = 0; i < max; i++) { // read lines from filterStore and insert them in the text in the filter-panel char str[128]; int filterTextLen; filterTextLen = [filterText textLength]; [filterText setSel:filterTextLen :filterTextLen]; strcpy(str, (char *)[filterStore elementAt:i]); strcat(str, "\n"); [filterText replaceSel:str]; } filterIsUpToDate = YES; } [filterWindow makeKeyAndOrderFront:self]; return self; } - textDidGetKeys:sender isEmpty:(BOOL)flag { if(sender == filterText) { if(![filterWindow isDocEdited]) [filterWindow setDocEdited:YES]; } return self; } - applyFilter:sender // copy all the filter-lines from the text-object to the filterStore { int max,i, s, l; char str[128]; [filterStore empty]; max = [filterText lineFromPosition:[filterText textLength]]; for(i = 1; i < max; i++) { s = [filterText positionFromLine:i]; l = [filterText positionFromLine:i+1] - s; if(l > 127) { [[[filterText setSel:s :127] scrollSelToVisible] display]; NXRunAlertPanel("Warning", "Filterline to long, string is truncated to 127 characters.", "Ok", NULL, NULL); l = 127; } [filterText getSubstring:str start: s length: l]; str[l-1] = '\000'; // without '\n' please if((str[0] == '|') && (strchr(str+1, '|') == NULL)) { // illegal syntax for file-sensitive filterstrings [[[filterText setSel:s :l] scrollSelToVisible] display]; NXRunAlertPanel("Alert", "Filename for file-sensitive filterstring must be between two '|'.", "Ok", NULL, NULL); } else { [filterStore addElement:str]; } } return self; } - (BOOL)filterString:(char *)str andRemove:(BOOL)rm who:sender // returns YES if something passes the filter { unsigned int i, max; char *from, *to, *ptr, ch; BOOL matched = NO, pass = NO; // pass: TRUE if something passed the filter char *senderName = (char *)[sender stringValue]; from = to = str; max = [filterStore count]; while(*from != '\000') { ptr = from; while((*ptr != '\n') && (*ptr != '\000')) ptr++; ch = *ptr; // in case that this line has no NL at the end *ptr = '\000'; for(i = 0; i < max; i++) { // go through all filter-lines char *filtStr = (char *)[filterStore elementAt:i], *tmpStr = filtStr; if(((filtStr = strchr(filtStr, '|')) != (char *)0) && (filtStr[1] != '|')) { // file-sensitive filterstring *filtStr = '\000'; if(!wildmat(senderName, tmpStr)) { *filtStr = '|'; break; // if we're doing file-sensitive filtering and this is the wrong file, then skip filterline } *filtStr++ = '|'; // restore filterstring and advance to real filterstring (the one after the filename) } else filtStr = tmpStr; if(wildmat(from, filtStr)) { matched = TRUE; break; } } if(!matched && rm) { // if we didn't match anything but are removing matches line, we have to copy the whole line while(*from != '\000') *to++ = *from++; *to++ = ch; from++; while(*from == '\r') from++; } else { from = (char *)(ptr + 1); *ptr = ch; while(*from == '\r') { // remove '\r's from begin of line ptr = from; while(ptr[1] != '\000') { *ptr++ = ptr[1]; } *ptr = ptr[1]; } } if(!matched) pass = YES; } if(rm) *to = '\000'; return pass; } - (int)filterMode { return filterMode; } - (BOOL)superUsesFilter { return superUseFilter; } - (BOOL)becomeKey { return becomeKey; } - unhideApp:sender { [NXApp unhide:self]; return self; } - clearBuffer:sender { id keyWindow = [NXApp keyWindow]; if((keyWindow != nil) && (keyWindow != myWindow) && (keyWindow != superWindow)) { [[keyWindow delegate] clearBuffer:self]; } else if(keyWindow == myWindow) { List *selectedCellsList = [tmpList empty]; unsigned int i; [myMatrix getSelectedCells:selectedCellsList]; for(i = 0; i < [selectedCellsList count]; i++) [[selectedCellsList objectAt:i] clearBuffer:self]; } else if(keyWindow == superWindow) { [superText setSel :0 :[superText textLength]]; [superText replaceSel:""]; [[superText sizeToFit] scrollSelToVisible]; if(lastSuperlogUser && inspectorPanel && [inspectorPanel isVisible] && !myWindowIsVisible && [superWindow isKeyWindow]) { // if there is already something in the superlog AND the inspectorPanel is already loaded AND it is visible // AND the mainwindow is not visible AND the (now empty) superlogwindow is the keywindow // THEN the inspectorpanel doesn't know which file it should inspect... [self setInspectorToView:[inspectorNoView contentView]]; } lastSuperlogUser = nil; } return self; } - windowDidBecomeKey:sender { if(sender == myWindow) { myWindowIsVisible = YES; if([myMatrix selectedCell] != nil) { [self setInspectorToView:[inspectorNormalView contentView]]; [self singleClick:self]; } return self; } else if(sender == superWindow) { if([superWindow isDocEdited]) [superWindow setDocEdited:NO]; if(!myWindowIsVisible && inspectorPanel && [inspectorPanel isVisible]) { if(lastSuperlogUser) { // if the superwindow just became the keywindow and the mainwindow is not visible but the // inspectorpanel is, then set the inspector to the last file that logged something in the superlog [self setInspectorToView:[inspectorNormalView contentView]]; [myMatrix selectCell:lastSuperlogUser]; [self singleClick:self]; } else { // if nothing is in the superlog, then set the inspector to the empty view [self setInspectorToView:[inspectorNoView contentView]]; } } } else if(sender == inspectorPanel) { if(myWindowIsVisible) { if([myMatrix cellCount] > 0) { [myFontManager setSelFont:[[myMatrix selectedCell] spyFont] isMultiple:NO]; [self setInspectorToView:[inspectorNormalView contentView]]; } else { [self setInspectorToView:[inspectorNoView contentView]]; } } else if((nrOpenWindows > 0) || ([superWindow isVisible] && lastSuperlogUser)) { [self setInspectorToView:[inspectorNormalView contentView]]; } else { [self setInspectorToView:[inspectorNoView contentView]]; } } else if(sender == preferencesPanel) { [myFontManager setSelFont:prefFont isMultiple:NO]; } else if(sender == existencelogWindow) { existenceSeen = YES; // existenceWindow has been seen by the user } else if(!myWindowIsVisible && inspectorPanel && [inspectorPanel isVisible] && ([[sender delegate] class] == [SpyTextFieldCell class])) { // if the mainwindow is not visible but the inspectorpanel is and the window which just became the // keywindow is a normal window, then update the inspector the the right file [myMatrix selectCell:[sender delegate]]; [self singleClick:self]; [self setInspectorToView:[inspectorNormalView contentView]]; } return self; } - windowWillClose:sender { Window *keyWindow; if(sender == myWindow) { myWindowIsVisible = NO; keyWindow = [NXApp keyWindow]; if((keyWindow != myWindow) && (keyWindow != nil) && (([[keyWindow delegate] class] == [SpyTextFieldCell class]) || (keyWindow == superWindow))) { [self windowDidBecomeKey:keyWindow]; } else if(nrOpenWindows == 0) { [self setInspectorToView:[inspectorNoView contentView]]; } } else if(sender == existencelogWindow) { existenceSeen = YES; // we assume that the user has noticed eventual changes in the existencelogWindow } else if([[sender delegate] class] == [SpyTextFieldCell class]) { if(nrOpenWindows > 0) { if((--nrOpenWindows == 0) && !myWindowIsVisible && ![superWindow isVisible]) { // if this was tha last open window (except the panels) then clear the inspectorpanel [self setInspectorToView:[inspectorNoView contentView]]; } } } else if((sender == superWindow) && (nrOpenWindows == 0)) { [self setInspectorToView:[inspectorNoView contentView]]; } return self; } - showInspectorPanel:sender { if(!inspectorPanel) { if(![NXApp loadNibSection:"Inspector.nib" owner:self withNames:NO fromZone:[self zone]]) { NXLogError("Can't open Inspector.nib!"); } if(inspectorFrame != (char *)0) { // if we read a window-position for the inspectorpanel from the defaults database, // then set the window accordingly [inspectorPanel setFrameFromString:inspectorFrame]; free(inspectorFrame); } if((myWindowIsVisible && ([myMatrix cellCount] > 0) && ([myMatrix selectedCell] != nil)) || (nrOpenWindows > 0) || ([superWindow isVisible] && lastSuperlogUser)) { [self setInspectorToView:[inspectorNormalView contentView]]; } else { [self setInspectorToView:[inspectorNoView contentView]]; } } [self singleClick:self]; [inspectorPanel makeKeyAndOrderFront:self]; return self; } - setInspectorToView:theView { NXRect boxRect, viewRect; if([inspectorMultiView contentView] != theView) { [inspectorMultiView getFrame:&boxRect]; [theView getFrame:&viewRect]; [inspectorMultiView setContentView:theView]; NX_X(&viewRect) = (NX_WIDTH(&boxRect) - NX_WIDTH(&viewRect)) / 2.0; NX_Y(&viewRect) = (NX_HEIGHT(&boxRect) - NX_HEIGHT(&viewRect)) / 2.0; [theView setFrame:&viewRect]; [inspectorMultiView display]; } return self; } - showFindPanel:sender { [finder showFindPanel:self]; return self; } - findNext:sender { [finder findNext:self]; return self; } - findPrevious:sender { [finder findPrevious:self]; return self; } - enterSelection:sender { [finder enterSelection:self]; return self; } - jumpToSelection:sender { const id mainWindow = [NXApp mainWindow]; if(mainWindow == superWindow) [superText makeSelectionVisible]; else if(mainWindow == filterWindow) [filterText makeSelectionVisible]; else if([[mainWindow delegate] class] == [SpyTextFieldCell class]) [[[mainWindow delegate] text] makeSelectionVisible]; return self; } - findTexts:(BOOL)all { List *textList; const id mainWindow = [NXApp mainWindow]; textList = [[List alloc] init]; if(all) { // return ALL text objects you have unsigned int i; List *cellList; cellList = [myMatrix cellList]; if(mainWindow == superWindow) // if the superlogWindow is main, search there first [textList addObject:superText]; else if(mainWindow == filterWindow) [textList addObject:filterText]; else if(mainWindow == helpWindow) [textList addObject:helpText]; else if((mainWindow != nil) && ([[mainWindow delegate] class] == [SpyTextFieldCell class])) [textList addObject:[[mainWindow delegate] text]]; // then search in the mainWindows text for(i = 0; i < [cellList count]; i++) // add all other texts [textList addObjectIfAbsent:[[cellList objectAt:i] text]]; [textList addObjectIfAbsent:superText]; // if the superWindow is not opened, add it at the end [textList addObjectIfAbsent:filterText]; return textList; } else if(mainWindow == myWindow) { // return only the text objects currently selected in the matrix [myMatrix getSelectedCells:textList]; return textList; } else if(mainWindow == superWindow) { [textList addObject:superText]; return textList; } else if(mainWindow == filterWindow) { [textList addObject:filterText]; return textList; } else if(mainWindow == helpWindow) { [textList addObject:helpText]; return textList; } else if((mainWindow != nil) && ([[mainWindow delegate] class] == [SpyTextFieldCell class])) { [textList addObject:[[mainWindow delegate] text]]; return textList; } else { [textList free]; return nil; } } - superFilenameClick:sender { List *selectedCellsList = [tmpList empty]; unsigned int i, max, state = [[sender selectedCell] tag]; PopUpList *popupList = [[superFilenameButton cell] target]; Matrix *popupMatrix = [popupList itemList]; [myMatrix getSelectedCells:selectedCellsList]; max = [selectedCellsList count]; for(i = 0; i < max; i++) [[selectedCellsList objectAt:i] setSuperCopyFilename:state]; [popupMatrix selectCellWithTag:state]; [superFilenameButton setTitle:[[popupMatrix findCellWithTag:state] title]]; return self; } - prefSuperFilenameClick:sender { PopUpList *popupList = [[prefSuperFilenameButton cell] target]; Matrix *popupMatrix = [popupList itemList]; unsigned int state = [[sender selectedCell] tag]; prefSuperCopyFilename = state; [popupMatrix selectCellWithTag:state]; [prefSuperFilenameButton setTitle:[[popupMatrix findCellWithTag:state] title]]; return self; } - timeClick:sender { List *selectedCellsList; unsigned int i, max; BOOL state = [sender state]; selectedCellsList = [tmpList empty]; [myMatrix getSelectedCells:selectedCellsList]; max = [selectedCellsList count]; for(i = 0; i < max; i++) [[selectedCellsList objectAt:i] setTimeStamp:state]; return self; } - prefTimeClick:sender { prefTimeStamp = [sender state]; return self; } - spytypeClick:sender { unsigned int i, max; int tag = [[sender selectedCell] tag]; [tmpList empty]; [myMatrix getSelectedCells:tmpList]; max = [tmpList count]; for(i = 0; i < max; i++) [[tmpList objectAt:i] setSpytype:(unsigned short int)tag]; [myMatrix display]; return self; } - prefSpytypeClick:sender { prefSpytype = (unsigned short int)[[sender selectedCell] tag]; return self; } - showExistenceLog:sender { return self; } - colorChanged:sender { List *selectedCellsList = [tmpList empty]; unsigned int i, max; NXColor color = [superColorWell color]; [myMatrix getSelectedCells:selectedCellsList]; max = [selectedCellsList count]; for(i = 0; i < max; i++) { [[selectedCellsList objectAt:i] setColor:color]; } [myMatrix display]; return self; } - prefColorChanged:sender { prefColor = [sender color]; return self; } - (NXColor)prefColor { return prefColor; } - changeFont:sender { List *selectedCellsList = [tmpList empty]; unsigned int i, max; id actCell; if([NXApp keyWindow] != preferencesPanel) { [fontTextField setFont:[sender convertFont:[fontTextField font]]]; [myMatrix getSelectedCells:selectedCellsList]; max = [selectedCellsList count]; for(i = 0; i < max; i++) { actCell = [selectedCellsList objectAt:i]; [actCell setSpyFont:[sender convertFont:[actCell spyFont]]]; } } else { [prefFontTextField setFont:[sender convertFont:[prefFontTextField font]]]; prefFont = [prefFontTextField font]; } return self; } - showFontPanel:sender { return [myFontManager orderFrontFontPanel:sender]; } - setMaxLines:sender { int oldMaxLines = maxLines; if((sender == maxLinesScroller) || (sender == maxLinesTextField)) { maxLines = [sender intValue]; if(maxLines < 10) maxLines = 10; if(maxLines > INT_MAX) maxLines = INT_MAX; if(sender == maxLinesScroller) // set the other one to the correct value [maxLinesTextField setIntValue:maxLines]; else [maxLinesScroller setIntValue:maxLines]; } else { // so it must be the matrix of ButtonCells maxLineState = [[sender selectedCell] tag]; [maxLinesScroller setEnabled:maxLineState]; [maxLinesTextField setEnabled:maxLineState]; } if(oldMaxLines != maxLines) { List *selectedCellsList = [tmpList empty]; unsigned int i, max; int state = (maxLineState ? maxLines : 0); [myMatrix getSelectedCells:selectedCellsList]; max = [selectedCellsList count]; for(i = 0; i < max; i++) [(SpyTextFieldCell *)[selectedCellsList objectAt:i] setMaxLines:state]; } return self; } - (int)maxLines; { return maxLines; } - shortSuperText { int textLen = [superText textLength]; int textLines = [superText lineFromPosition:textLen]; #ifdef DEBUG assert(maxLines != 0); #endif if(textLines > maxLines) [[superText setSel:0 :[superText positionFromLine:textLines - maxLines]] replaceSel:""]; return self; } - addWindow:sender; { if(nrOpenWindows++ == 0) { if(!myWindowIsVisible && inspectorPanel && [inspectorPanel isVisible]) { [self setInspectorToView:[inspectorNormalView contentView]]; [myMatrix selectCell:sender]; [self singleClick:self]; } } return self; } - existenceMatrix { return myExistenceMatrix; } - showExistencelogRegardless { [existencelogWindow orderFrontRegardless]; return self; } - window { return [NXApp mainWindow]; } @end void alarmHandler(DPSTimedEntry te, double timeNow, void *data) { [(id)data checkFiles]; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.