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.