This is UrlGraphicCell.m in view mode; [Download] [Up]
/** ** Based on a class with the same name from Lennart Lovstand's Urlifier **/ #import <stdio.h> #import <appkit/appkit.h> #import <misckit/MiscAppDefaults.h> #import "graphicCellProtocol.h" // Stolen from the appkit source #import "UrlGraphicCell.h" /* Hack attack, see comment below next to writeRichText:forView: on * why we register ourselves with a null directive name. [no we don't! erik] */ #define DEFAULT_URL_SERVICE "OmniWeb/Open URL" #define URL_SERVICE_DEFAULT "URLService" @implementation UrlGraphicCell static NXImage *urlImage = nil; static char *theUrlService = NULL; + initialize { NXBundle *bundle; char path[MAXPATHLEN]; const char *string; bundle = [NXBundle bundleForClass: [self class]]; if ([bundle getPath: path forResource: "URL" ofType: "tiff"]) { urlImage = [[NXImage alloc] initFromFile: path]; } else { fprintf(stderr, "# Can't find URL image %s\n", path); } string = [NXApp defaultValue:URL_SERVICE_DEFAULT]; if (string == NULL) string = DEFAULT_URL_SERVICE; theUrlService = NXCopyStringBuffer(string); fprintf(stderr, "URLGraphicCell initialised with service '%s'.\n", theUrlService); return self; } - initWithUrl: (const char *) url { if ([super init] == nil) return nil; [self setUrl: url]; return self; } - free { [self setUrl: NULL]; if (myTempFile) { unlink(myTempFile); free(myTempFile); } return [super free]; } - (void) setUrl: (const char *) url { if (myUrl) free(myUrl); myUrl = url ? NXCopyStringBuffer(url) : NULL; } - (const char *) url { return myUrl; } - (BOOL) trackMouse:(NXEvent *) theEvent inRect:(const NXRect *) cellFrame ofView:controlView { NXPoint nullPoint = {0, 0}; NXEvent eventBuf, *ev; #ifdef XXX if (theEvent->flags & NX_SHIFTMASK) return [self shiftTrackMouse:theEvent inRect:cellFrame ofView:controlView]; #endif XXX if (theEvent->data.mouse.click == 1) { ev = [NXApp peekNextEvent:NX_MOUSEDOWNMASK|NX_MOUSEUPMASK into:&eventBuf waitFor:0.3 threshold:NX_MODALRESPTHRESHOLD]; if (!ev || ev->type == NX_MOUSEDRAGGED) { Pasteboard *pboard = [Pasteboard newName:NXDragPboard]; NXPoint point = theEvent->location; NXSize size; [pboard declareTypes: &NXAsciiPboardType num: 1 owner: nil]; [pboard writeType: NXAsciiPboardType data: myUrl length: strlen(myUrl)]; [urlImage getSize: &size]; point.x -= size.width / 2; point.y -= size.height / 2; [controlView convertPoint: &point fromView:nil]; [controlView dragImage: urlImage at: &point offset: &nullPoint event: theEvent pasteboard: pboard source: controlView slideBack:YES]; return YES; } } else if (theEvent->data.mouse.click == 2) { #ifdef XXX char tmpFile[MAXPATHLEN]; FILE *stream; strcpy(tmpFile, "/tmp/url-XXXXXX"); mktemp(tmpFile); strcat(tmpFile, ".html"); stream = fopen(tmpFile, "w"); if (stream == NULL) { perror(tmpFile); return YES; } fprintf(stream, "<URL=%s>\n", myUrl); fclose(stream); myTempFile = NXCopyStringBuffer(tmpFile); [[[NXApp class] workspace] openFile: tmpFile fromImage: urlImage at:&theEvent->location inView:controlView]; return YES; #else static Pasteboard *pboard = nil; /* Cache and reuse the pasteboard */ if (pboard == nil) pboard = [Pasteboard newUnique]; [pboard declareTypes: &NXAsciiPboardType num: 1 owner: nil]; [pboard writeType: NXAsciiPboardType data: myUrl length: strlen(myUrl)]; NXPerformService(theUrlService, pboard); /* [pboard freeGlobally]; */ #endif XXX } return NO; } - drawSelf:(const NXRect *) cellFrame inView:controlView { NXPoint point = cellFrame->origin; point.y += cellFrame->size.height; [urlImage composite:NX_SOVER toPoint:&point]; return self; } - highlight:(const NXRect *) cellFrame inView:controlView lit:(BOOL) flag { return self; } - calcCellSize:(NXSize *) theSize { [urlImage getSize:theSize]; return self; } /* These are no-ops since we don't really have any intention of * reproducing ourselves through RTF. (See the comment next to * the URLIFIER_DIRECTIVE above for more info.) */ /* This is really a bit of a hack, but it does the trick. * What we're trying to accomplish here is some way to avoid being * copied & pasted since (1) if you paste a graphic cell in an app that * doesn't support it, you get that special attachment char (\254) * inserted instead, and (2) even if you forward a rich text message * within Mail.app, we *still* don't want to be there in the Compose * window since the Urlifier icon will be automatically created by * the recipient anyway (presuming that s/he is using NeXT Mail.app * and has the Urlifier bundle). Given that, we play a few tricks. * First, we register ourselves with an empty directive that we'll * never be found under when read back. Second, we go and undo part * of what the Text object already has written out -- namely, back * to the beginning of the previous RTF block. Third, we write out * a dummy \*-prefixed RTF directive that will cause the block which * it is in to be ignored when read back. Fourth, we follow this with * a left brace to make sure that the RTF blocks add up. In short, * we change what would have been this: * * {<whatever>{\<mydirective><nnn> <mydata>}<\254>} * * to this: * * {<whatever>\*\UrlifierDummyCell {<nnn>}<\254>} * * (The <nnn> number is the run position written out by Text.) * The result: Everything from \* to the right brace following * the special attachment char will be ignored, just like we want it. * * (Puh!) */ - writeRichText:(NXStream *) stream forView:view { char *buf; int len, maxlen; /* Oh-oh, this better be a memory buffer! */ NXGetMemoryBuffer(stream, &buf, &len, &maxlen); while (--len > 0 && buf[len] != '{'); NXSeek(stream, len, NX_FROMSTART); NXPrintf(stream, "\\*\\UrlifierDummyCell {"); return nil; } /* Read URL from the RTF-Stream generated by the ArticleViewControl */ - readRichText:(NXStream *) stream forView:(id <NXGraphicCellProtocol>)view { char urlbuffer[2048]; // I know, buffer overrun and friends... NXScanf(stream, "%[^}]", urlbuffer); [self setUrl:urlbuffer]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.