This is Script.m in view mode; [Download] [Up]
#import <appkit/appkit.h> #import <objc/List.h> #import <sys/file.h> #import "MoveMatrix.h" #import "StateManager.h" #import "Filter.h" #import "Script.h" #import "FilterInspector.h" #import "ScriptInspector.h" #import "HelpManager.h" #import "support.h" #import "pscode.h" @implementation Script #define SCRIPT_VERSION 1 #define NOTSET strdup("") static id speaker; + initialize { [Script setVersion: SCRIPT_VERSION]; return self; } + alloc { self = [super alloc]; filterList = [[List alloc] init]; scriptName = strdup("Untitled"); resultIconPath = NOTSET; helpText = NOTSET; return self; } - setStateManager: anObject { stateManager = anObject; inspector = [stateManager scriptInspector]; return self; } - createWindow { static NXRect wRect={{160.0,500.0},{211.0,119.0}}; static NXSize intercell = { 0.0, 1.0 }; NXRect wBounds; NXRect optionFrame, textFrame, filterFrame, aFrame; NXSize cellSize; id scrollView, aButtonCell, aTextCell, aFilterCell; window = [[Window alloc] initContent:&wRect style:NX_TITLEDSTYLE backing:NX_BUFFERED buttonMask:NX_ALLBUTTONS defer:NO]; [window setMiniwindowIcon: "script"]; [window setDelegate: self]; [[window contentView] getFrame: &aFrame]; scrollView = [[ScrollView alloc] initFrame: &aFrame]; [scrollView setVertScrollerRequired:YES]; [scrollView setHorizScrollerRequired:YES]; [ScrollView getContentSize: &docFrame.size forFrameSize: &aFrame.size horizScroller:(BOOL) YES vertScroller:(BOOL) YES borderType: NX_NOBORDER]; docFrame.origin.x = docFrame.origin.y = 0.0; optionFrame = docFrame; optionFrame.origin.x += 48.0; optionFrame.size.width -= 96.0; filterFrame = textFrame = optionFrame; docView = [[View alloc] initFrame: &docFrame]; [docView setClipping: NO]; [scrollView setDocView: docView]; [window setContentView: scrollView]; aButtonCell = [[ButtonCell alloc] initTextCell: ""]; [aButtonCell setIcon: "popup"]; [aButtonCell setIconPosition: NX_ICONRIGHT]; [aButtonCell setAltIcon: "popupH"]; [aButtonCell setHighlightsBy: NX_NONE]; [aButtonCell setAlignment: NX_LEFTALIGNED]; [aButtonCell sendActionOn: NX_MOUSEDOWNMASK]; optionFrame.origin.y = 0.0; optionFrame.size.height = 20.0; optionMatrix = [[Matrix alloc] initFrame: &optionFrame mode: NX_TRACKMODE prototype: aButtonCell numRows: 1 numCols: 0]; cellSize.width = 96.0; cellSize.height = 20.0; [optionMatrix setCellSize: &cellSize]; [optionMatrix sizeToCells]; [optionMatrix setIntercell: &intercell]; [docView addSubview: optionMatrix]; aTextCell = [[TextFieldCell alloc] initTextCell: "empty"]; [aTextCell setEditable: YES]; [aTextCell setAlignment: NX_CENTERED]; textFrame.origin.y = 20.0; textFrame.size.height = 32.0; textMatrix = [[Matrix alloc] initFrame: &textFrame mode: NX_TRACKMODE prototype: aTextCell numRows: 1 numCols: 0]; cellSize.height = 32.0; [textMatrix setCellSize: &cellSize]; [textMatrix sizeToCells]; [textMatrix setIntercell: &intercell]; [textMatrix setTarget: self]; [textMatrix setAction: @selector(filterNameChanged)]; [docView addSubview: textMatrix]; aFilterCell = [[ButtonCell alloc] initIconCell: "filterArrow"]; // create prototype [aFilterCell setAltIcon: "filterArrowH"]; [aFilterCell setBordered: NO]; [aFilterCell setType: NX_RADIOBUTTON]; filterFrame.origin.y = 52.0; matrix = [[MoveMatrix alloc] initFrame: &filterFrame mode: NX_RADIOMODE prototype: aFilterCell numRows: 1 numCols: 0]; [matrix setMoveDelegate: self]; // notify me [matrix allowEmptySel: YES]; [matrix setIntercell: &intercell]; [matrix setTarget: self]; [matrix setAction: @selector(buttonPressed)]; cellSize.height = 48.0; [matrix setCellSize: &cellSize]; [matrix sizeToCells]; [docView addSubview: matrix]; [window display]; // register this window to window server (for icon dragging) speaker = [NXApp appSpeaker]; NXConvertWinNumToGlobal([window windowNum], &globalWindowNum); [speaker setSendPort: NXPortFromName(NX_WORKSPACEREQUEST, NULL)]; [speaker registerWindow: globalWindowNum toPort:[[NXApp appListener] listenPort]]; return self; } - addFilters { int i, n; id aFilter; n = [filterList count]; for (i = 0; i < n; ++i) { [matrix addCol]; [textMatrix addCol]; [optionMatrix addCol]; aFilter= [filterList objectAt: i]; [aFilter setStateManager: stateManager]; [aFilter setNameCell: [textMatrix cellAt: 0 : i]]; [aFilter setOptionCell: [optionMatrix cellAt: 0 : i]]; [aFilter update]; } sizeChanged = YES; return self; } - addFilter: newFilter { int index; [matrix addCol]; [textMatrix addCol]; [optionMatrix addCol]; [filterList addObject: newFilter]; index = [filterList count] -1; [[filterList lastObject] setNameCell: [textMatrix cellAt: 0 : index]]; [[filterList lastObject] setOptionCell: [optionMatrix cellAt: 0 : index]]; sizeChanged = YES; return self; } - removeFilter { int col; [filterList removeObject: activeFilter]; activeFilter = nil; col = [matrix selectedCol]; [matrix clearSelectedCell]; [matrix removeColAt: col andFree: YES]; [textMatrix removeColAt: col andFree: YES]; [optionMatrix removeColAt: col andFree: YES]; [[matrix cellList] removeObjectAt: col]; [[textMatrix cellList] removeObjectAt: col]; [[optionMatrix cellList] removeObjectAt: col]; sizeChanged = YES; return self; } - workspaceBitmap:(char *)path { int ok, length; char *tiffData; NXStream *bitmapStream; id aBitmap; [speaker getFileIconFor:path TIFF:&tiffData TIFFLength:&length ok:&ok]; if (!ok) { return nil; } bitmapStream = NXOpenMemory(tiffData, length, NX_READONLY); if (!bitmapStream) { return nil; } aBitmap = [[NXImage alloc] initFromStream: bitmapStream]; NXClose(bitmapStream); return aBitmap; } - drawBitmap: aBitmap side: (int) side { static NXPoint aPoint = {0.0, 52.0}; [docView lockFocus]; if (side == 0) { aPoint.x = 0.0; [aBitmap composite: NX_SOVER toPoint: &aPoint]; } else { aPoint.x = docFrame.size.width - 48.0; [aBitmap composite: NX_SOVER toPoint: &aPoint]; } [docView unlockFocus]; } // Delegate for Window class - windowDidBecomeKey: sender { [stateManager setActiveScript: self]; if ([matrix selectedCol] >= 0) { activeFilter = [filterList objectAt: [matrix selectedCol]]; } else { activeFilter = nil; } [stateManager setActiveFilter: activeFilter]; return self; } - windowWillClose: sender { int response; if ([window isDocEdited]) { response = NXRunAlertPanel("Save", pathname ? "Save changes to %s?" : "Save changes?", "Save", "No", "Cancel", pathname); switch (response) { case NX_ALERTDEFAULT: [stateManager saveScript: self]; break; case NX_ALERTALTERNATE: break; case NX_ALERTOTHER: default: return nil; } } [speaker unregisterWindow: globalWindowNum]; [stateManager removeScript: self]; [stateManager removeFromActivate: self]; return self; } - windowWillMiniaturize: sender toMiniwindow: aWindow { miniwindow = aWindow; NXConvertWinNumToGlobal([miniwindow windowNum], &globalMiniwindowNum); [stateManager miniaturized: self]; miniaturized = YES; [speaker unregisterWindow: globalWindowNum]; [speaker registerWindow: globalMiniwindowNum toPort:[[NXApp appListener] listenPort]]; return self; } - windowDidDeminiaturize: sender { [stateManager deminiaturized: self]; miniaturized = NO; [speaker unregisterWindow: globalMiniwindowNum]; [speaker registerWindow: globalWindowNum toPort:[[NXApp appListener] listenPort]]; return self; } // Delegate for MoveMatrix class - matrixDidExchange: (int) index1 : (int) index2 { id aFilter, list1, list2; char *str1, str2; if (index1 < index2) { aFilter = [filterList removeObjectAt: index1]; [filterList insertObject: aFilter at: index2-1]; aFilter = [filterList removeObjectAt: index2]; [filterList insertObject: aFilter at: index1]; } else { aFilter = [filterList removeObjectAt: index2]; [filterList insertObject: aFilter at: index1-1]; aFilter = [filterList removeObjectAt: index1]; [filterList insertObject: aFilter at: index2]; } [[filterList objectAt: index1] setNameCell: [textMatrix cellAt: 0 : index1]]; [[filterList objectAt: index2] setNameCell: [textMatrix cellAt: 0 : index2]]; [[[filterList objectAt: index1] setOptionCell: [optionMatrix cellAt: 0 : index1]] update]; [[[filterList objectAt: index2] setOptionCell: [optionMatrix cellAt: 0 : index2]] update]; return self; } - (unsigned int) globalWindowNum { return globalWindowNum; } - (unsigned int) globalMiniwindowNum { return globalMiniwindowNum; } - window { return window; } - miniwindow { return miniwindow; } - update { NXRect mRect, tRect, oRect; NXSize sSize; if (sizeChanged) { [matrix sizeToCells]; [textMatrix sizeToCells]; [optionMatrix sizeToCells]; [matrix getFrame: &mRect]; [textMatrix getFrame: &tRect]; [optionMatrix getFrame: &oRect]; docFrame = mRect; docFrame.size.height = mRect.size.height + tRect.size.height + oRect.size.height; docFrame.size.width += 96.0; [docView setFrame: &docFrame]; sizeChanged = NO; if ([stateManager autosize]) { if (docFrame.size.width < 144.0) docFrame.size.width = 144.0; if (docFrame.size.width > 960.0) docFrame.size.width = 960.0; [ScrollView getFrameSize: &sSize forContentSize: &docFrame.size horizScroller: YES vertScroller:YES borderType:NX_NOBORDER]; [window sizeWindow: sSize.width : sSize.height]; } } [window setTitle: scriptName]; [stateManager removeFromActivate: self]; [stateManager addToActivate: self]; [window display]; return self; } - activate: sender // glue for activate menu { [window makeKeyAndOrderFront: self]; return self; } // methods to manipulate filter objects - parameterChanged { if (strcmp(scriptName, [inspector scriptName])) { [stateManager removeFromActivate: self]; scriptName = stringDup(scriptName, [inspector scriptName]); [stateManager addToActivate: self]; } else { scriptName = stringDup(scriptName, [inspector scriptName]); } confirm = [inspector confirm]; errorTerminate = [inspector errorTerminate]; foreground = [inspector foreground]; iconType = [inspector iconType]; resultIconPath = stringDup(resultIconPath, [inspector resultIconPath]); helpText = stringDup(helpText, [inspector helpText]); return self; } - (char *) scriptName {return scriptName;} - (int) confirm {return confirm;} - (int) errorTerminate {return errorTerminate;} - (int) foreground {return foreground;} - (int) iconType {return iconType;} - (char *) resultIconPath{return resultIconPath; } - (char *) helpText {return helpText; } - setPathname: (char *) aString { pathname = stringDup(pathname, aString); return self; } - (char *) pathname { return pathname; } - write: (NXTypedStream *)ts { [super write: ts]; NXWriteTypes(ts, "*iiii**@", &scriptName, &confirm, &errorTerminate, &foreground, &iconType, &resultIconPath, &helpText, &filterList); return self; } - read: (NXTypedStream *)ts { [super read: ts]; if (NXTypedStreamClassVersion(ts, [self name]) != SCRIPT_VERSION) { NXRunAlertPanel(NULL, "Specified file contains contains incompatible data.\n" "You might have specified non-script file.", "OK", NULL, NULL); return nil; } NXReadTypes(ts, "*iiii**@", &scriptName, &confirm, &errorTerminate, &foreground, &iconType, &resultIconPath, &helpText, &filterList); return self; } - buttonPressed { activeFilter = [filterList objectAt: [matrix selectedCol]]; [stateManager setActiveFilter: activeFilter]; } - filterNameChanged { [[filterList objectAt: [textMatrix selectedCol]] nameChanged]; return self; } - (int)iconEntered:(int)windowNum at:(double)x :(double)y iconWindow:(int)iconWindowNum iconX:(double)iconX iconY:(double)iconY iconWidth:(double)iconWidth iconHeight:(double)iconHeight pathList:(char *)pathList { NXSize size = {48.0, 48.0}; NXRect bounds; bounds.origin.x = bounds.origin.y = 0.0; bounds.size = size; bitmap = [[NXImage alloc] initSize: &size]; [bitmap lockFocus]; PSsetgray(NX_LTGRAY); NXRectFill(&bounds); copyIconPicture(iconWindowNum, (float) iconX, (float) iconY, (float) iconWidth, (float) iconHeight); [bitmap unlockFocus]; iconPathList = stringDup(iconPathList, pathList); return 0; } - fromFile: (char *) inFile toFile: (char **) outFile pipeTo: (int *) pipefd waitFor: (int *) waitpid { int infd = 0, outfd = 1, pfd[2], pid; char *infile, *outfile, *commandline; id filter, nextFilter; int invoke(char *, int, char *, int, char *); filter = [filterList objectAt: filterIndex]; if (++filterIndex < [matrix cellCount]) nextFilter = [filterList objectAt: filterIndex]; else nextFilter = nil; if ([filter inputFromStdin]) { if (inFile != NULL) { // namely, previous process wrote output to file; although // this process demands input from stdin infile = inFile; infd = -1; } else { // conventional piped execution (right side) pipe(pfd); *pipefd = pfd[1]; infd = pfd[0]; } } else { if (inFile != NULL) { // conventional file-to-file, sequential execution // no redirection needed } else { // this must not occur. } } commandline = strdup([filter assignVariable: inFile to: [filter command]]); if ([filter outputToStdout]) { if (nextFilter == nil || ! [nextFilter inputFromStdin]) { // needs redirection to temporary file outfile = strdup("/tmp/faXXXXXX"); mktemp(outfile); *outFile = outfile; outfd = -1; } else { // conventional piped execution (left side) [self fromFile: NULL toFile: outFile pipeTo: &outfd waitFor: waitpid]; } } else { *outFile = [filter destination]; if (*outFile[0] == '\0') { // discard result } else { *outFile = strdup([filter assignVariable: inFile to: *outFile]); } } pid = invoke(commandline, infd, infile, outfd, outfile); free(commandline); if (outfd <= 1) { *waitpid = pid; } } - showTargetIcon { NXStream *bitmapStream; char filename[256]; if (iconType) { [self drawBitmap: [self workspaceBitmap: finalOutputFile] side: 1]; } else { filename[0] = '\0'; if (resultIconPath[0] != '/') { strcpy(filename, NXGetDefaultValue(APPNAME, "IconOpenPath")); strcat(filename, "/"); } strcat(filename, resultIconPath); tilde_expand(filename); bitmapStream = NXOpenFile(open(filename, O_RDONLY), NX_READONLY); if (!bitmapStream) { return nil; } [self drawBitmap: [[NXImage alloc] initFromStream: bitmapStream] side: 1]; } } - animate { int i; if (!iconShown && (iconType == 0 && resultIconPath || iconType && finalOutputFile)) { [self showTargetIcon]; iconShown = YES; } for (i = firstFilter; i < lastFilter; ++i) { [[matrix cellAt: 0 : i] setIcon: (flip == 0 ? "filterAnim1" : (flip == 1 ? "filterAnim2" : "filterAnim3"))]; } flip = ++flip % 3; return self; } void DrawIt (DPSTimedEntry te, double timeNow, void *data) { [(id)data animate]; } - (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag { int response; if (processing && foreground) { *flag = NO; return 0; } if (confirm) { response = NXRunAlertPanel("Do it?", "Apply %s to \"%s\" ?", "OK", "Cancel", NULL, scriptName, iconPathList); if (response == NX_ALERTALTERNATE) { *flag = NO; return 0; } } [self drawBitmap: bitmap side: 0]; [window flushWindow]; fromFile = strdup(iconPathList); filterIndex = 0; firstFilter = lastFilter = 0; iconShown = NO; finalOutputFile = NULL; processing = YES; chdir([[filterList objectAt: 0] assignVariable: iconPathList to: "$s"]); [self executeOneStep]; if (foreground) { selectedCol = [matrix selectedCol]; [matrix clearSelectedCell]; timedEntry = DPSAddTimedEntry(0.8, &DrawIt, self, NX_BASETHRESHOLD); } *flag = YES; return 0; } - executeOneStep { char *toFile; int waitpid, i, n; if (filterIndex < [filterList count]) { for (i = firstFilter; i < lastFilter; ++i) { [[matrix cellAt: 0 : i] setIcon: "filterArrow"]; } firstFilter = filterIndex; [self fromFile: fromFile toFile: &toFile pipeTo: NULL waitFor: &waitpid]; lastFilter = filterIndex; if (fromFile) free(fromFile); fromFile = toFile; if (lastFilter == [filterList count]) // goal finalOutputFile = fromFile; [stateManager registerProcess: self id: waitpid]; } else { processing = NO; if (foreground) { n = [matrix cellCount]; for (i = 0; i < n; ++i) { [[matrix cellAt: 0 : i] setIcon: "filterArrow"]; } [matrix selectCellAt: 0 : selectedCol]; [window display]; DPSRemoveTimedEntry(timedEntry); } } return self; } - childTerminated: (int) pid status: (union wait *) status { int response; int proceed = 1; if (WIFSTOPPED(*status)) { response = NXRunAlertPanel(NULL, "Process %d has stopped due to signal #%d. What now?", "Kill", "Continue", NULL, pid, status->w_stopsig); switch (response) { case NX_ALERTDEFAULT: kill(pid, SIGKILL); proceed = 0; /* fallthrough */ case NX_ALERTALTERNATE: kill(pid, SIGCONT); break; default: ; // ignore } } else if (WIFSIGNALED(*status)) { NXRunAlertPanel(NULL, "Process %d was terminated by signal #%d. %s", "OK", NULL, NULL, pid, status->w_termsig, (status->w_coredump) ? "(Core dumped)" : ""); proceed = 0; } else if (WIFEXITED(*status)) { if (errorTerminate && status->w_retcode) proceed = 0; } if (!proceed) filterIndex = 1000; // such that (filterIndex > [filterList count]) holds [self executeOneStep]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.