ftp.nice.ch/pub/next/connectivity/news/Alexandra-0.9.s.tar.gz#/alex/NiceStuff.subproj/UrlGraphicCell.m

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.