home *** CD-ROM | disk | FTP | other *** search
-
- static char RCSId[]="$Id: PlotView.m,v 1.1.1.1 1993/03/18 03:34:58 davis Exp $";
-
-
- #import <appkit/Application.h>
- #import <appkit/ClipView.h>
- #import <appkit/Font.h>
- #import <appkit/FontManager.h>
- #import <appkit/Matrix.h>
- #import <appkit/MenuCell.h>
- #import <appkit/NXImage.h>
- #import <appkit/Pasteboard.h>
- #import <appkit/SavePanel.h>
- #import <appkit/Text.h>
-
- #import <defaults/defaults.h> /* NXGetTempFilename() */
-
- #import <dpsclient/psops.h>
- #import <libc.h> /* unlink(), MAXPATHLEN */
-
- #import "GnuplotPlot.h"
- #import "PlotView.h"
-
-
-
- /* Does the list of NXAtoms "types" include the NXAtom "type"? */
- static BOOL includesType(NXAtom *types, NXAtom type)
- {
- while (types && *types) {
- if (type == *types) return YES;
- types++;
- }
- return NO;
- }
-
-
- @implementation PlotView
-
-
- - initFrame:(const NXRect *)frameRect;
- {
- const char *validSendTypes[2];
-
- [super initFrame:frameRect];
- [self setClipping: NO]; /* Because we're in a ClipView already */
- [self drawInSuperview]; /* Use our ClipView's coordinate system */
-
- fullPath = NULL;
- epsStream = NULL;
- image = nil;
- tempFileNeedsUpdate = YES;
-
- /* Setup services */
- validSendTypes[0] = NXPostScriptPboardType;
- validSendTypes[1] = NXTIFFPboardType;
- validSendTypes[2] = NULL;
- [NXApp registerServicesMenuSendTypes: validSendTypes andReturnTypes: NULL];
-
- return self;
- }
-
-
- - (BOOL) acceptsFirstResponder
- {
- return YES; /* So the font can be changed with fontpanel */
- }
-
-
- - (BOOL)acceptsFirstMouse
- {
- return YES; /* So we can drag the EPS out as a file */
- }
-
-
-
- - changeFont:sender
- {
- id newfont;
- id doc;
-
- newfont = [sender convertFont: [(doc = [window delegate]) currentFont]];
- [doc setCurrentFont:newfont];
-
- return self;
- }
-
-
- - copyFont:sender
- {
- /*
- * This method is invoked when a user presses the "Copy Font"
- * menu button. We're supposed to put the current font on the
- * font pasteboard, and the easiest way to do that is to take
- * advantage of the Text class's ability to do that. Every step
- * here is necessary: we create a Text object, set it to RTF
- * (non-monofont), make a selection (even though there is no text
- * to select, there must be a selection), set the font to the
- * doc's current font, tell the text object to copy the font to
- * the font pasteboard, and then free the text object.
- */
- [[[[[[[Text allocFromZone: [self zone]] init]
- setMonoFont: NO]
- setSel: 0:1]
- setFont: [[window delegate] currentFont]]
- copyFont: sender]
- free];
-
- return self;
- }
-
-
- - pasteFont:sender
- {
- Text *text = [[Text allocFromZone: [self zone]] init];
-
- /*
- * We must specify that the text is not monofont (i.e. is RTF)
- * and there must be a selection in order to paste. There
- * doesn't need to be any text.
- */
- [[text setMonoFont:NO] setSel:0 :1];
-
- if ([text pasteFont:sender]) /* Returns nil if there's trouble */
- [[window delegate] setCurrentFont:[text font]];
-
- [text free];
- return self;
- }
-
-
-
- - validRequestorForSendType:(NXAtom)sendType andReturnType:(NXAtom)returnType
- /*
- * Services menu support.
- * We are a valid requestor if the send type is EPS and there is no
- * return data from the request.
- */
- {
- if (image &&
- ((sendType == NXPostScriptPboardType) ||
- (sendType == NXTIFFPboardType)) &&
- (!returnType || !*returnType))
-
- return self;
-
- return [superview validRequestorForSendType:sendType
- andReturnType:returnType];
- }
-
-
-
- - (BOOL) writeSelectionToPasteboard:pboard types:(NXAtom *)types
- /*
- * Services menu support.
- * Here we are asked by the Services menu mechanism to supply
- * the image data (which we said we were a valid requestor for
- * in the above method).
- */
- {
- while (types && *types) {
- if ((*types == NXPostScriptPboardType) || (*types == NXTIFFPboardType))
- break;
- types++;
- }
-
- if (types && *types && [self copyToPasteboard:pboard types:types]) {
- return YES;
- } else {
- return NO;
- }
- }
-
-
- - (BOOL)validateCommand:menuCell
- {
- SEL action = [menuCell action];
-
- if (action == @selector(copy:))
- return image? YES :NO;
- else if (action == @selector(copyFont:)) {
- [[FontManager new] setEnabled:image? YES : NO];
- return image? YES :NO;
- } else if (action == @selector(pasteFont:))
- return image? YES :NO;
- else if (action == @selector(saveAsEPS:))
- return epsStream? YES :NO;
-
- return YES;
- }
-
-
-
- - copy:sender
- {
- return [self copyToPasteboard:
- [Pasteboard newName:(const char *)NXSelectionPboard]];
- }
-
-
-
- - copyToPasteboard:pboard
- {
- return [self copyToPasteboard:pboard types:NULL];
- }
-
-
-
-
- - copyToPasteboard:pboard types:(NXAtom *)typesList
- {
- char *data;
- NXStream *stream;
- const char *types[1];
- int length, maxlen;
-
- if (image) {
- if (!typesList || includesType(typesList, NXPostScriptPboardType)) {
- types[0] = NXPostScriptPboardType;
- stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
- [self copyPSToStream:stream];
- NXGetMemoryBuffer(stream, &data, &length, &maxlen);
- [pboard declareTypes:types num:1 owner:[self class]];
- [pboard writeType:NXPostScriptPboardType data:data length:length];
- NXCloseMemory(stream, NX_FREEBUFFER);
-
- return self;
-
- } else if (typesList && includesType(typesList, NXTIFFPboardType)) {
- types[0] = NXTIFFPboardType;
- stream = NXOpenMemory(NULL, 0, NX_READWRITE);
- [self copyTIFFToStream:stream];
- NXGetMemoryBuffer(stream, &data, &length, &maxlen);
- [pboard declareTypes:types num:1 owner:[self class]];
- [pboard writeType:NXTIFFPboardType data:data length:length];
- NXCloseMemory(stream, NX_FREEBUFFER);
-
- return self;
-
- }
- }
-
- return nil;
- }
-
-
- - copyPSToStream:(NXStream *)stream
- {
- char *streambuf;
- int len, maxlen;
-
- if (image) {
-
- NXGetMemoryBuffer(epsStream, &streambuf, &len, &maxlen);
- NXPrintf (stream, "%s", streambuf);
-
- return self;
-
- }
-
- return nil;
- }
-
-
-
- - copyTIFFToStream:(NXStream *)stream
- {
- if (image) {
- [image writeTIFF:stream];
- return self;
- }
-
- return nil;
- }
-
-
-
- - saveAsEPS:sender
- {
- id savePanel;
-
- savePanel = [SavePanel new];
- [savePanel setRequiredFileType:"eps"];
- [savePanel runModal];
- [self saveEPSToFile:[savePanel filename]];
-
- return self;
- }
-
-
-
- - (const char *) writeEPSToTempFile
- {
- const char *realName;
- char *cur;
- int pos;
-
- /*
- * If epsStream has been written to a temp file before, and the
- * epsStream hasn't changed since then, we don't need to write
- * the temp file again. This checks to see if the stream has
- * changed. It also should (but doesn't) check to see if the
- * temp file still exists and is accessable (readable).
- */
- if (!tempFileNeedsUpdate)
- return fullPath;
- else if (!epsStream) {
- [self unlinkFile];
- return NULL;
- }
-
- [self unlinkFile]; /* Get rid of previous temp file, if any */
- fullPath = (char *) NXZoneMalloc ([self zone], MAXPATHLEN * sizeof (char));
- *fullPath = '\0';
-
- /*
- * We need to come up with a unique name for the temp file, which
- * will reside in /tmp. We use the name of the plot and change
- * it with NXGetTempFilename.
- */
- realName = [[window delegate] name];
- if (cur = rindex(realName, '/')) { /* The plot has been titled */
-
- if (++cur)
- sprintf (fullPath, "/tmp/%s", cur);
- else
- return NULL; /* ...ERROR: path ends in slash */
-
- } else /* The plot is untitled */
-
- sprintf (fullPath, "/tmp/%s", realName);
-
-
- pos = strlen (fullPath);
-
- if (cur = rindex (fullPath, '.')) { /* The name has an extension */
- pos -= strlen (cur); /* Replace it with .eps */
- strcpy (cur, "xxxxxx.eps");
- } else /* The name has no extension */
- strcat (fullPath, "xxxxxx.eps");
-
-
- NXGetTempFilename(fullPath, pos); /* Make sure filename is unique */
- [self saveEPSToFile:fullPath]; /* Save the stream to the file */
-
- tempFileNeedsUpdate = NO;
- return fullPath;
- }
-
-
- - saveEPSToFile:(const char *)filename
- {
- /*
- * Saves the epsStream to a file as Encapsulated PostScript.
- * Assumes filename is a validly formed, unique pathname. (It
- * will overwrite the file if filename is not unique.)
- */
-
- NXStream *newStream;
- char *buf;
- int bufsize, bufmax;
-
- // See Status.m for description of problem with NXSaveToFile().
- // NXSaveToFile (epsStream, filename);
-
- newStream = NXOpenMemory (NULL, 0, NX_WRITEONLY);
- NXGetMemoryBuffer (epsStream, &buf, &bufsize, &bufmax);
- NXPrintf (newStream, "%s", buf);
- NXFlush (newStream);
- NXSaveToFile (newStream, filename);
- NXCloseMemory (newStream, NX_FREEBUFFER);
-
- return self;
- }
-
-
-
- - unlinkFile
- {
- if (fullPath) {
- if (*fullPath)
- unlink (fullPath);
- NXZoneFree ([self zone], fullPath);
- fullPath = NULL;
- }
-
- return self;
- }
-
-
-
- - mouseDown:(NXEvent *)theEvent
- {
- NXRect fileRect = {{theEvent->location.x - 24.0,
- theEvent->location.y - 24.0}, {48.0, 48.0}};
-
- if ([self writeEPSToTempFile]) {
- [[[window contentView] superview] convertRect:&fileRect toView:self];
-
- [self dragFile:fullPath
- fromRect:&fileRect
- slideBack:YES
- event:theEvent];
-
- return self;
- } else
- return nil;
- }
-
-
-
- /*
- * Redisplays the contents of the view by compositing the image onto
- * the view.
- */
- - drawSelf:(NXRect *)r :(int) count
- {
- PSsetgray(NX_WHITE); /* For color machines, we must clear */
- NXRectFill(&(r[0])); /* the window to white. */
-
- if (image)
- [image composite:NX_SOVER fromRect:&(r[0]) toPoint:&(r[0].origin)];
-
- return self;
- }
-
-
- - newStream:(NXStream *) aStream
- {
- NXSize imageSize;
-
- if (image)
- [image free];
-
- if (aStream) {
-
- NXSeek(aStream, 0, NX_FROMSTART);
- image = [[[[NXImage allocFromZone: [self zone]]
- initFromStream: aStream]
- setScalable: YES]
- setDataRetained: YES];
-
- [image getSize:&imageSize];
- imageOrigWidth = imageSize.width;
- imageOrigHeight = imageSize.height;
-
- NX_WIDTH(&bounds) = NX_WIDTH(&frame) = imageSize.width;
- NX_HEIGHT(&bounds) = NX_HEIGHT(&frame) = imageSize.height;
- epsStream = aStream;
-
- } else {
- NX_WIDTH(&bounds) = NX_HEIGHT(&bounds) = NX_WIDTH(&frame) =
- NX_HEIGHT(&frame) = 0;
- imageOrigWidth = imageOrigHeight = 0;
- image = nil;
- epsStream = NULL;
- }
-
- tempFileNeedsUpdate = YES;
-
- return self;
- }
-
-
-
-
-
- /*
- * This method, in addition to freeing the image, unlinks the
- * temporary EPS file if it exists.
- */
- - free
- {
- [self unlinkFile];
-
- if (image)
- [image free];
-
- return [super free];
- }
-
-
- /*
- * This method takes only one scale factor because we never want the
- * view to have different proportions than the image. Scale factor
- * of zero means size to window (so that the entire plot is visible
- * in the window).
- */
- - (float)scale:(float)scaleFactor
- {
- float factor;
- NXSize imageSize;
- NXRect ourRect;
-
- if (image) {
-
- if (scaleFactor) {
-
- factor = scaleFactor;
-
- } else {
-
- [superview getDocVisibleRect: &ourRect];
- factor = ourRect.size.width / imageOrigWidth;
- if ((imageOrigHeight * factor) > ourRect.size.height)
- factor = ourRect.size.height / imageOrigHeight;
-
- }
-
- imageSize.width = imageOrigWidth * factor;
- imageSize.height = imageOrigHeight * factor;
- [image setSize:&imageSize];
-
- /* Show the newly sized image. */
-
- NX_WIDTH(&bounds) = NX_WIDTH(&frame) = imageSize.width;
- NX_HEIGHT(&bounds) = NX_HEIGHT(&frame) = imageSize.height;
- [superview descendantFrameChanged:self];
-
- [self display];
- return factor;
-
- } else
- return 0.0;
- }
-
-
- // Shuts up the compiler about unused RCSId
- - (const char *) rcsid
- {
- return RCSId;
- }
-
-
- @end
-