/* Document.m Document class & WindowController : This file is part of Preview Copyright (C) 2003;2004 Fabien VALLON 2003,2004 Alcove ( http://www.alcove.com ) Additional copyrights here Authors : Fabien VALLON Date: 10 Oct 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ // See Doumentation/DEVELOPERS #include "Document.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*********************************************************************/ /**************** NSDocument Private methods *************************/ /*********************************************************************/ #define HEIGHT_HUNDRED_PER_CENT 0 #define FOUR_HUNDRED_PER_CENT 1 #define DOUBLE_SIZE 2 #define FULL_SIZE 3 #define HALF_SIZE 4 #define FIT_WINDOW 5 #define FIT_WIDTH 6 #define ZOOM_IN 0 #define ZOOM_OUT 1 #define SCALEFACTOR 0.1 @interface CheckeredView: NSView @end @implementation CheckeredView - (void)drawRect:(NSRect)rect { NSColor *backColor = [NSColor darkGrayColor]; NSColor *color = [NSColor grayColor]; [backColor set]; NSRectFill(rect); [color set]; int i, j; BOOL drawForeground = NO; for(i = 0; i < rect.size.width; i+=10) { drawForeground = i % 20 == 0; for(j = 0; j < rect.size.height; j+=10) { if(drawForeground) { NSRectFill(NSMakeRect(rect.origin.x+i, rect.origin.y+j, 10, 10)); } drawForeground = !drawForeground; } } } @end @interface Document (Private) -(void) _setScaleFactor: (double) factor; -(double) _scaleFactor; -(void) _updateImage; -(void) _setOriginalSize: (NSSize) originalSize; -(NSSize) _originalSize; -(void) _setCurrentItem:(unsigned) tag; -(unsigned) _currentItem; -(void) _notifyDragScroll: (id)notification; -(void) _setIsAlpha:(BOOL) flag; -(BOOL) _isAlpha; @end @implementation Document (Private) -(void) _updateImage { if ([self _scaleFactor] != 1.0 ) { NSSize imageSize; NSAffineTransform *affineTransform; affineTransform = [NSAffineTransform transform]; [affineTransform scaleBy:[self _scaleFactor]]; imageSize = [imageView frame].size; [imageView setFrameSize:[affineTransform transformSize:imageSize]]; if ( _isAlpha ) { [checkeredView setFrameSize: [affineTransform transformSize:imageSize]]; } [imageView setNeedsDisplay:YES]; } } /* * Set the scale factor (zoom). */ - (void) _setScaleFactor: (double)factor { _scaleFactor = factor; } - (double) _scaleFactor { return _scaleFactor; } -(void) _setOriginalSize: (NSSize) orginalSize { _originalSize = orginalSize; } -(NSSize) _originalSize { return _originalSize; } -(void) _setCurrentItem:(unsigned) tag { if (tag <= FIT_WIDTH) _tag = tag; } -(unsigned) _currentItem { return _tag; } - (void) _notifyDragScroll: (id)notification { NSPoint newOrigin; NSSize scrollAmount; NSSize contentSize; NSRect vRect; scrollAmount = [[[notification userInfo] objectForKey: @"UserInfoKeyScrollAmount"] sizeValue]; vRect = [scrollView documentVisibleRect]; contentSize = [scrollView contentSize]; newOrigin = NSMakePoint(vRect.origin.x + scrollAmount.width, vRect.origin.y + scrollAmount.height); [[scrollView contentView] scrollToPoint: [[scrollView contentView] constrainScrollPoint:newOrigin]]; } -(void) _setIsAlpha:(BOOL) flag { _isAlpha = flag; } -(BOOL) _isAlpha { return _isAlpha; } @end /************************************************************/ /*********** NSDocument subclass methods ********************/ /************************************************************/ @implementation Document /** * NSDocument subclass method * return the nib (Preview) */ - (NSString *) windowNibName { return @"Preview"; } /** * NSDocument subclass method * 1- set the window frame: * window origin is set to (120,100) == (WINDOW_ORIGIN_X,WINDOW_ORIGIN_Y) * the windowSize have a Minsize (set in Preview.gorm) * the window size is not bigger than the NSScreen:visibleFrame (-origin) * * 2- set _image into imageView */ - (void) windowControllerDidLoadNib:(NSWindowController *)windowController { // NSSize windowSize; window = [windowController window]; if ( ( ! window ) || (!_image ) ) return; { BOOL bigger = NO; NSSize imageSize = [_image size]; NSSize contentSize; NSSize screenSize = [[NSScreen mainScreen] frame].size; screenSize.width -= 100 + 64; screenSize.height -= 120; if ( screenSize.width > imageSize.width + [[scrollView verticalScroller] frame].size.width ) contentSize.width = imageSize.width + [[scrollView verticalScroller] frame].size.width; else { contentSize.width = screenSize.width; bigger = YES; } if ( screenSize.height > imageSize.height + [[scrollView horizontalScroller] frame].size.height ) contentSize.height = imageSize.height + [[scrollView horizontalScroller] frame].size.height; else { contentSize.height = screenSize.height; bigger = YES; } if ( [[_image bestRepresentationForDevice:nil] hasAlpha] ) { [self _setIsAlpha: YES]; checkeredView = [[CheckeredView alloc] initWithFrame: NSMakeRect(0,0,imageSize.width,imageSize.height)]; [imageView retain]; [scrollView setDocumentView: checkeredView]; [checkeredView addSubview:imageView ]; } else { [self _setIsAlpha: NO]; } [imageView setFrame:NSMakeRect(0,0,imageSize.width,imageSize.height)]; [imageView setImage:_image]; int test = [imageView addTrackingRect:[imageView bounds] owner:imageView userData:nil assumeInside:YES]; [window setContentSize:contentSize]; [window setFrameOrigin: NSMakePoint(100,120)]; } { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_notifyDragScroll:) name: @"TEST" object: imageView]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_notifyMouseDown:) name: @"MOUSEDOWN" object: nil]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_notifyMouseUp:) name: @"MOUSEUP" object: nil]; } //Registering Objects for Services { [NSApp registerServicesMenuSendTypes:[[NSArray alloc] initWithObjects:NSFilenamesPboardType,nil ] returnTypes:nil]; } } /** * NSDocument subclass method * This will create a new document. * if it the _image is succesfully init it set the size. */ - (BOOL) loadDataRepresentation: (NSData*)data ofType: (NSString*)docType { _image = [[[NSImage alloc] initWithData: data] autorelease]; if (! _image ) return NO; [self _setOriginalSize: [_image size]]; return YES; } /** * NSDocument subclass method */ - (NSData *)dataRepresentationOfType:(NSString *)aType { Class imageRepClass = [NSImageRep imageRepClassForFileType:aType]; if ( ! imageRepClass ) { return nil; } return [_image TIFFRepresentation]; } /** * NSDocument subclass method */ - (NSString *)fileType { return @"tiff"; } - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType { return self; } - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteBoard types:(NSArray *)types { NSArray *pbTypeArray = [[NSArray alloc] initWithObjects:NSStringPboardType,NSFilenamesPboardType,NSTIFFPboardType,nil]; BOOL ok = NO; NSData *tiffRep = [_image TIFFRepresentation]; [pasteBoard declareTypes:pbTypeArray owner:nil]; if ( [types containsObject : NSStringPboardType] ) { if ( [pasteBoard setString: [super fileName] forType: NSStringPboardType] ) ok = YES; } if ( [types containsObject : NSFilenamesPboardType] ) { if ( [pasteBoard setPropertyList: [NSArray arrayWithObject:[super fileName]] forType: NSFilenamesPboardType] ) ok = YES; } if ( [types containsObject : NSTIFFPboardType] ) { if ([pasteBoard setData: tiffRep forType: NSTIFFPboardType] ) ok = YES; } return ok; } /** * * This method copy NSTIFFPboardType, NSFilenamesPboardType or NSStringPboardType * into the general Pasteboard */ - (void) copy: (id) sender { NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; NSData *tiffRep = [_image TIFFRepresentation]; NSArray *pbTypeArray = [[NSArray alloc] initWithObjects:NSStringPboardType,NSFilenamesPboardType,NSTIFFPboardType,nil]; [pasteBoard declareTypes: pbTypeArray owner:self]; if ( ! [pasteBoard setPropertyList: [[NSArray alloc] initWithObjects:[super fileName],nil] forType: NSStringPboardType] ) NSLog(@"Problem : cannot copy NSStringPboardType"); if (! [pasteBoard setPropertyList: [NSArray arrayWithObject:[super fileName]] forType: NSFilenamesPboardType] ) NSLog(@"Problem : cannot copy NSFilenamesPboardType"); if (! [pasteBoard setData: tiffRep forType: NSTIFFPboardType] ) NSLog(@"Problem : cannot copy NSTIFFPboardType"); } /** * Action method * * * */ -(void) resize: (id) sender { unsigned tag; NSSize newSize; //Get Tag (sender comes from popUp or matrix or menu { if ( sender == popUp ) tag = [sender indexOfSelectedItem]; //popUp else if ( sender == matrix ) { tag = [[sender selectedCell] tag]; //matrix } else tag = [sender tag]; //menu } //Deselect matrix cells if popPup is selected { if (tag <= HALF_SIZE) { if ( [matrix selectedCell] ) [matrix deselectAllCells]; [imageView setAutoresizingMask: NSViewNotSizable]; } } switch (tag) { case HEIGHT_HUNDRED_PER_CENT: newSize.width = [self _originalSize].width * 8; newSize.height = [self _originalSize].height * 8; break; case FOUR_HUNDRED_PER_CENT: newSize.width = [self _originalSize].width * 4; newSize.height = [self _originalSize].height * 4; break; case DOUBLE_SIZE: newSize.width = [self _originalSize].width * 2; newSize.height = [self _originalSize].height * 2; break; case FULL_SIZE: newSize.width = [self _originalSize].width ; newSize.height = [self _originalSize].height; break; case HALF_SIZE: newSize.width = [self _originalSize].width / 2; newSize.height = [self _originalSize].height / 2; break; case FIT_WINDOW: newSize.width = [scrollView contentSize].width; newSize.height = [scrollView contentSize].height; [imageView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; if ( [self _isAlpha] ) { NSLog(@"isAlpha"); [checkeredView setAutoresizingMask: (NSViewWidthSizable|NSViewHeightSizable)]; } break; case FIT_WIDTH: newSize.width = [scrollView contentSize].width; newSize.height = [imageView frame].size.height; [imageView setAutoresizingMask: (NSViewWidthSizable)]; if ( [self _isAlpha] ) [checkeredView setAutoresizingMask: NSViewWidthSizable]; break; default: printf("problem resize default \n"); return; } //set autoresizing Mask if ( tag < FIT_WINDOW ) { if ( [self _isAlpha] ) [checkeredView setAutoresizingMask: NSViewNotSizable]; [imageView setAutoresizingMask: NSViewNotSizable]; } //Resize if ( [self _isAlpha] ) { [checkeredView setFrame:NSMakeRect(0,0,newSize.width,newSize.height) ]; } NSLog(@"apres newSize %@",NSStringFromSize(newSize)); [imageView setFrame: NSMakeRect(0,0,newSize.width,newSize.height)]; // why TODO FIXME !!! only need with FIT_WINDOW [imageView setNeedsDisplay:YES]; [checkeredView setNeedsDisplay:YES]; [self _setCurrentItem: tag]; } -(void) zoomImage : (id) sender { unsigned tag; tag = [sender tag]; if ( tag == ZOOM_IN ) { [self _setScaleFactor: (1 + SCALEFACTOR)]; [self _updateImage]; } else if ( tag == ZOOM_OUT ) { [self _setScaleFactor: (1 -SCALEFACTOR)]; [self _updateImage]; } else { NSLog(@"zoomImage tag: %i",tag); } } /** * window delegate method. * The mini icon is generate from _image */ - (void)windowDidMiniaturize:(NSNotification *)aNotification { NSImage *miniImage = _image; [miniImage setSize: NSMakeSize(48,48)]; [window setMiniwindowImage:miniImage]; } /** * window delegate method. * This method is used to refresh the horizontalScroller width */ - (void)windowDidResize:(NSNotification *)aNotification { NSRect scrollerRect = [[scrollView horizontalScroller] frame]; scrollerRect.size.width = [window frame].size.width - 135; [[scrollView horizontalScroller] setFrame:scrollerRect]; } //Validate Menu : - (BOOL) validateMenuItem: (id)menuItem { SEL action = [menuItem action]; if ( sel_eq(action,@selector(resize:)) ) { if ( [menuItem tag] == [self _currentItem] ) return NO; } return YES; } @end