1 /* 2 Document.m 3 4 Document class & WindowController : This file is part of Preview 5 6 Copyright (C) 2003;2004 Fabien VALLON 7 2003,2004 Alcove ( http://www.alcove.com ) 8 Additional copyrights here 9 10 Authors : Fabien VALLON <fabien@sonappart.net> 11 Date: 10 Oct 2003 12 13 This program is free software; you can redistribute it and/or 14 modify it under the terms of the GNU General Public License as 15 published by the Free Software Foundation; either version 2 of 16 the License, or (at your option) any later version. 17 18 This program is distributed in the hope that it will be useful, 19 but WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 21 22 See the GNU General Public License for more details. 23 24 You should have received a copy of the GNU General Public 25 License along with this program; if not, write to: 26 27 Free Software Foundation, Inc. 28 59 Temple Place - Suite 330 29 Boston, MA 02111-1307, USA 30*/ 31 32// See Doumentation/DEVELOPERS 33 34#include "Document.h" 35 36#include <Foundation/NSNotification.h> 37 38#include <AppKit/AppKit.h> 39#include <AppKit/NSApplication.h> 40#include <AppKit/NSAffineTransform.h> 41#include <AppKit/NSClipView.h> 42#include <AppKit/NSCursor.h> 43#include <AppKit/NSImage.h> 44#include <AppKit/NSImageView.h> 45#include <AppKit/NSMatrix.h> 46#include <AppKit/NSPasteboard.h> 47#include <AppKit/NSPopUpButton.h> 48#include <AppKit/NSScreen.h> 49#include <AppKit/NSScrollView.h> 50#include <AppKit/NSWindow.h> 51#include <AppKit/NSWindowController.h> 52#include <AppKit/NSScroller.h> 53 54/*********************************************************************/ 55/**************** NSDocument Private methods *************************/ 56/*********************************************************************/ 57 58#define HEIGHT_HUNDRED_PER_CENT 0 59#define FOUR_HUNDRED_PER_CENT 1 60#define DOUBLE_SIZE 2 61#define FULL_SIZE 3 62#define HALF_SIZE 4 63#define FIT_WINDOW 5 64#define FIT_WIDTH 6 65 66#define ZOOM_IN 0 67#define ZOOM_OUT 1 68 69#define SCALEFACTOR 0.1 70 71 72 73@interface CheckeredView: NSView 74@end 75 76 77@implementation CheckeredView 78 79- (void)drawRect:(NSRect)rect 80{ 81 NSColor *backColor = [NSColor darkGrayColor]; 82 NSColor *color = [NSColor grayColor]; 83 84 [backColor set]; 85 NSRectFill(rect); 86 [color set]; 87 int i, j; 88 BOOL drawForeground = NO; 89 for(i = 0; i < rect.size.width; i+=10) 90 { 91 drawForeground = i % 20 == 0; 92 for(j = 0; j < rect.size.height; j+=10) 93 { 94 if(drawForeground) 95 { 96 NSRectFill(NSMakeRect(rect.origin.x+i, rect.origin.y+j, 10, 10)); 97 } 98 drawForeground = !drawForeground; 99 } 100 } 101 102} 103 104@end 105 106 107 108 109@interface Document (Private) 110-(void) _setScaleFactor: (double) factor; 111-(double) _scaleFactor; 112-(void) _updateImage; 113-(void) _setOriginalSize: (NSSize) originalSize; 114-(NSSize) _originalSize; 115-(void) _setCurrentItem:(unsigned) tag; 116-(unsigned) _currentItem; 117-(void) _notifyDragScroll: (id)notification; 118-(void) _setIsAlpha:(BOOL) flag; 119-(BOOL) _isAlpha; 120@end 121 122@implementation Document (Private) 123 124-(void) _updateImage 125{ 126 if ([self _scaleFactor] != 1.0 ) 127 { 128 NSSize imageSize; 129 NSAffineTransform *affineTransform; 130 131 affineTransform = [NSAffineTransform transform]; 132 [affineTransform scaleBy:[self _scaleFactor]]; 133 imageSize = [imageView frame].size; 134 135 [imageView setFrameSize:[affineTransform transformSize:imageSize]]; 136 if ( _isAlpha ) 137 { 138 [checkeredView setFrameSize: 139 [affineTransform transformSize:imageSize]]; 140 } 141 142 [imageView setNeedsDisplay:YES]; 143 144 } 145} 146 147/* 148 * Set the scale factor (zoom). 149 */ 150- (void) _setScaleFactor: (double)factor 151{ 152 _scaleFactor = factor; 153} 154 155- (double) _scaleFactor 156{ 157 return _scaleFactor; 158} 159 160-(void) _setOriginalSize: (NSSize) orginalSize 161{ 162 _originalSize = orginalSize; 163} 164 165-(NSSize) _originalSize 166{ 167 return _originalSize; 168} 169 170-(void) _setCurrentItem:(unsigned) tag 171{ 172 if (tag <= FIT_WIDTH) 173 _tag = tag; 174} 175 176-(unsigned) _currentItem 177{ 178 return _tag; 179} 180 181- (void) _notifyDragScroll: (id)notification 182{ 183 NSPoint newOrigin; 184 NSSize scrollAmount; 185 NSSize contentSize; 186 NSRect vRect; 187 188 scrollAmount = 189 [[[notification userInfo] objectForKey: @"UserInfoKeyScrollAmount"] sizeValue]; 190 191 vRect = [scrollView documentVisibleRect]; 192 contentSize = [scrollView contentSize]; 193 194 newOrigin = NSMakePoint(vRect.origin.x + scrollAmount.width, 195 vRect.origin.y + scrollAmount.height); 196 197 198 [[scrollView contentView] scrollToPoint: 199 [[scrollView contentView] constrainScrollPoint:newOrigin]]; 200} 201 202 203-(void) _setIsAlpha:(BOOL) flag 204{ 205 _isAlpha = flag; 206} 207 208-(BOOL) _isAlpha 209{ 210 return _isAlpha; 211} 212 213 214 215@end 216 217 218/************************************************************/ 219/*********** NSDocument subclass methods ********************/ 220/************************************************************/ 221 222@implementation Document 223 224/** 225 * NSDocument subclass method 226 * return the nib (Preview) 227 */ 228- (NSString *) windowNibName 229{ 230 return @"Preview"; 231} 232 233/** 234 * NSDocument subclass method 235 * 1- set the window frame: 236 * window origin is set to (120,100) == (WINDOW_ORIGIN_X,WINDOW_ORIGIN_Y) 237 * the windowSize have a Minsize (set in Preview.gorm) 238 * the window size is not bigger than the NSScreen:visibleFrame (-origin) 239 * 240 * 2- set _image into imageView 241 */ 242 243- (void) windowControllerDidLoadNib:(NSWindowController *)windowController 244{ 245 // NSSize windowSize; 246 247 window = [windowController window]; 248 249 if ( ( ! window ) || (!_image ) ) 250 return; 251 252 { 253 BOOL bigger = NO; 254 NSSize imageSize = [_image size]; 255 NSSize contentSize; 256 NSSize screenSize = [[NSScreen mainScreen] frame].size; 257 screenSize.width -= 100 + 64; 258 screenSize.height -= 120; 259 260 if ( screenSize.width > imageSize.width + [[scrollView verticalScroller] frame].size.width ) 261 contentSize.width = imageSize.width + [[scrollView verticalScroller] frame].size.width; 262 else 263 { 264 contentSize.width = screenSize.width; 265 bigger = YES; 266 } 267 268 if ( screenSize.height > imageSize.height + [[scrollView horizontalScroller] frame].size.height ) 269 contentSize.height = imageSize.height + [[scrollView horizontalScroller] frame].size.height; 270 else 271 { 272 contentSize.height = screenSize.height; 273 bigger = YES; 274 } 275 276 if ( [[_image bestRepresentationForDevice:nil] hasAlpha] ) 277 { 278 [self _setIsAlpha: YES]; 279 checkeredView = [[CheckeredView alloc] initWithFrame: NSMakeRect(0,0,imageSize.width,imageSize.height)]; 280 [imageView retain]; 281 [scrollView setDocumentView: checkeredView]; 282 [checkeredView addSubview:imageView ]; 283 } 284 else 285 { 286 [self _setIsAlpha: NO]; 287 } 288 289 290 [imageView setFrame:NSMakeRect(0,0,imageSize.width,imageSize.height)]; 291 [imageView setImage:_image]; 292 293 int test = [imageView addTrackingRect:[imageView bounds] 294 owner:imageView 295 userData:nil 296 assumeInside:YES]; 297 298 [window setContentSize:contentSize]; 299 [window setFrameOrigin: NSMakePoint(100,120)]; 300 } 301 302 { 303 [[NSNotificationCenter defaultCenter] addObserver: self 304 selector: @selector(_notifyDragScroll:) 305 name: @"TEST" 306 object: imageView]; 307 308 [[NSNotificationCenter defaultCenter] addObserver: self 309 selector: @selector(_notifyMouseDown:) 310 name: @"MOUSEDOWN" 311 object: nil]; 312 313 [[NSNotificationCenter defaultCenter] addObserver: self 314 selector: @selector(_notifyMouseUp:) 315 name: @"MOUSEUP" 316 object: nil]; 317 318 } 319 320 321 //Registering Objects for Services 322 { 323 [NSApp registerServicesMenuSendTypes:[[NSArray alloc] initWithObjects:NSFilenamesPboardType,nil ] 324 returnTypes:nil]; 325 } 326 327} 328 329 330/** 331 * NSDocument subclass method 332 * This will create a new document. 333 * if it the _image is succesfully init it set the size. 334 */ 335- (BOOL) loadDataRepresentation: (NSData*)data ofType: (NSString*)docType 336{ 337 _image = [[[NSImage alloc] initWithData: data] autorelease]; 338 339 if (! _image ) 340 return NO; 341 342 [self _setOriginalSize: [_image size]]; 343 return YES; 344} 345 346/** 347 * NSDocument subclass method 348 */ 349- (NSData *)dataRepresentationOfType:(NSString *)aType 350{ 351 Class imageRepClass = [NSImageRep imageRepClassForFileType:aType]; 352 353 if ( ! imageRepClass ) 354 { 355 return nil; 356 } 357 358 return [_image TIFFRepresentation]; 359} 360 361/** 362 * NSDocument subclass method 363 */ 364- (NSString *)fileType 365{ 366 return @"tiff"; 367} 368 369 370- (id)validRequestorForSendType:(NSString *)sendType 371 returnType:(NSString *)returnType 372{ 373 return self; 374} 375 376 377- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteBoard 378 types:(NSArray *)types 379{ 380 NSArray *pbTypeArray = [[NSArray alloc] initWithObjects:NSStringPboardType,NSFilenamesPboardType,NSTIFFPboardType,nil]; 381 BOOL ok = NO; 382 NSData *tiffRep = [_image TIFFRepresentation]; 383 384 [pasteBoard declareTypes:pbTypeArray owner:nil]; 385 386 if ( [types containsObject : NSStringPboardType] ) 387 { 388 if ( [pasteBoard setString: [super fileName] 389 forType: NSStringPboardType] ) 390 ok = YES; 391 } 392 if ( [types containsObject : NSFilenamesPboardType] ) 393 { 394 if ( [pasteBoard setPropertyList: [NSArray arrayWithObject:[super fileName]] 395 forType: NSFilenamesPboardType] ) 396 ok = YES; 397 } 398 399 if ( [types containsObject : NSTIFFPboardType] ) 400 { 401 if ([pasteBoard setData: tiffRep forType: NSTIFFPboardType] ) 402 ok = YES; 403 } 404 405 return ok; 406 407 408} 409 410/** 411 * 412 * This method copy NSTIFFPboardType, NSFilenamesPboardType or NSStringPboardType 413 * into the general Pasteboard 414 */ 415- (void) copy: (id) sender 416{ 417 NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; 418 NSData *tiffRep = [_image TIFFRepresentation]; 419 420 NSArray *pbTypeArray = [[NSArray alloc] initWithObjects:NSStringPboardType,NSFilenamesPboardType,NSTIFFPboardType,nil]; 421 422 [pasteBoard declareTypes: pbTypeArray owner:self]; 423 424 425 if ( ! [pasteBoard setPropertyList: [[NSArray alloc] initWithObjects:[super fileName],nil] 426 forType: NSStringPboardType] ) 427 NSLog(@"Problem : cannot copy NSStringPboardType"); 428 429 430 if (! [pasteBoard setPropertyList: [NSArray arrayWithObject:[super fileName]] 431 forType: NSFilenamesPboardType] ) 432 NSLog(@"Problem : cannot copy NSFilenamesPboardType"); 433 434 if (! [pasteBoard setData: tiffRep forType: NSTIFFPboardType] ) 435 NSLog(@"Problem : cannot copy NSTIFFPboardType"); 436} 437 438 439/** 440 * Action method 441 * 442 * 443 * 444 */ 445-(void) resize: (id) sender 446{ 447 unsigned tag; 448 NSSize newSize; 449 450 //Get Tag (sender comes from popUp or matrix or menu 451 { 452 if ( sender == popUp ) 453 tag = [sender indexOfSelectedItem]; //popUp 454 else if ( sender == matrix ) 455 { 456 tag = [[sender selectedCell] tag]; //matrix 457 } 458 else 459 tag = [sender tag]; //menu 460 } 461 462 463 //Deselect matrix cells if popPup is selected 464 { 465 if (tag <= HALF_SIZE) 466 { 467 if ( [matrix selectedCell] ) 468 [matrix deselectAllCells]; 469 470 [imageView setAutoresizingMask: NSViewNotSizable]; 471 } 472 } 473 474 switch (tag) 475 { 476 case HEIGHT_HUNDRED_PER_CENT: 477 newSize.width = [self _originalSize].width * 8; 478 newSize.height = [self _originalSize].height * 8; 479 break; 480 case FOUR_HUNDRED_PER_CENT: 481 newSize.width = [self _originalSize].width * 4; 482 newSize.height = [self _originalSize].height * 4; 483 break; 484 case DOUBLE_SIZE: 485 newSize.width = [self _originalSize].width * 2; 486 newSize.height = [self _originalSize].height * 2; 487 break; 488 case FULL_SIZE: 489 newSize.width = [self _originalSize].width ; 490 newSize.height = [self _originalSize].height; 491 break; 492 case HALF_SIZE: 493 newSize.width = [self _originalSize].width / 2; 494 newSize.height = [self _originalSize].height / 2; 495 break; 496 case FIT_WINDOW: 497 newSize.width = [scrollView contentSize].width; 498 newSize.height = [scrollView contentSize].height; 499 [imageView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; 500 if ( [self _isAlpha] ) 501 { 502 NSLog(@"isAlpha"); 503 [checkeredView setAutoresizingMask: 504 (NSViewWidthSizable|NSViewHeightSizable)]; 505 } 506 break; 507 case FIT_WIDTH: 508 newSize.width = [scrollView contentSize].width; 509 newSize.height = [imageView frame].size.height; 510 [imageView setAutoresizingMask: (NSViewWidthSizable)]; 511 if ( [self _isAlpha] ) 512 [checkeredView setAutoresizingMask: NSViewWidthSizable]; 513 break; 514 default: 515 printf("problem resize default \n"); 516 return; 517 } 518 519 //set autoresizing Mask 520 if ( tag < FIT_WINDOW ) 521 { 522 if ( [self _isAlpha] ) 523 [checkeredView setAutoresizingMask: NSViewNotSizable]; 524 525 [imageView setAutoresizingMask: NSViewNotSizable]; 526 } 527 528 529 //Resize 530 if ( [self _isAlpha] ) 531 { 532 [checkeredView setFrame:NSMakeRect(0,0,newSize.width,newSize.height) ]; 533 } 534 535 NSLog(@"apres newSize %@",NSStringFromSize(newSize)); 536 537 [imageView setFrame: NSMakeRect(0,0,newSize.width,newSize.height)]; 538 539 // why TODO FIXME !!! only need with FIT_WINDOW 540 [imageView setNeedsDisplay:YES]; 541 [checkeredView setNeedsDisplay:YES]; 542 [self _setCurrentItem: tag]; 543} 544 545-(void) zoomImage : (id) sender 546{ 547 unsigned tag; 548 tag = [sender tag]; 549 550 if ( tag == ZOOM_IN ) 551 { 552 [self _setScaleFactor: (1 + SCALEFACTOR)]; 553 [self _updateImage]; 554 } 555 else if ( tag == ZOOM_OUT ) 556 { 557 [self _setScaleFactor: (1 -SCALEFACTOR)]; 558 [self _updateImage]; 559 } 560 else 561 { 562 NSLog(@"zoomImage tag: %i",tag); 563 } 564} 565 566/** 567 * window delegate method. 568 * The mini icon is generate from _image 569 */ 570- (void)windowDidMiniaturize:(NSNotification *)aNotification 571{ 572 NSImage *miniImage = _image; 573 [miniImage setSize: NSMakeSize(48,48)]; 574 [window setMiniwindowImage:miniImage]; 575} 576 577/** 578 * window delegate method. 579 * This method is used to refresh the horizontalScroller width 580 */ 581- (void)windowDidResize:(NSNotification *)aNotification 582{ 583 NSRect scrollerRect = [[scrollView horizontalScroller] frame]; 584 585 scrollerRect.size.width = [window frame].size.width - 135; 586 [[scrollView horizontalScroller] setFrame:scrollerRect]; 587} 588 589 590//Validate Menu : 591- (BOOL) validateMenuItem: (id)menuItem 592{ 593 SEL action = [menuItem action]; 594 595 if ( sel_isEqual(action,@selector(resize:)) ) 596 { 597 if ( [menuItem tag] == [self _currentItem] ) 598 return NO; 599 } 600 601 return YES; 602} 603 604 605@end 606 607