1/** <title>NSTextAttachment</title> 2 3 <abstract>Classes to represent text attachments.</abstract> 4 5 NSTextAttachment is used to represent text attachments. When inline, 6 text attachments appear as the value of the NSAttachmentAttributeName 7 attached to the special character NSAttachmentCharacter. 8 9 NSTextAttachment uses an object obeying the NSTextAttachmentCell 10 protocol to get input from the user and to display an image. 11 12 NSTextAttachmentCell is a simple subclass of NSCell which provides 13 the NSTextAttachment protocol. 14 15 Copyright (C) 2000 Free Software Foundation, Inc. 16 17 Author: Fred Kiefer <FredKiefer@gmx.de> 18 Date: June 2000 19 20 This file is part of the GNUstep GUI Library. 21 22 This library is free software; you can redistribute it and/or 23 modify it under the terms of the GNU Lesser General Public 24 License as published by the Free Software Foundation; either 25 version 2 of the License, or (at your option) any later version. 26 27 This library is distributed in the hope that it will be useful, 28 but WITHOUT ANY WARRANTY; without even the implied warranty of 29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 30 Lesser General Public License for more details. 31 32 You should have received a copy of the GNU Lesser General Public 33 License along with this library; see the file COPYING.LIB. 34 If not, see <http://www.gnu.org/licenses/> or write to the 35 Free Software Foundation, 51 Franklin Street, Fifth Floor, 36 Boston, MA 02110-1301, USA. 37*/ 38 39#import "AppKit/NSCell.h" 40#import "AppKit/NSFileWrapper.h" 41#import "AppKit/NSFileWrapperExtensions.h" 42#import "AppKit/NSImage.h" 43#import "AppKit/NSEvent.h" 44#import "AppKit/NSTextContainer.h" 45#import "AppKit/NSTextAttachment.h" 46#import "AppKit/NSTextView.h" 47 48 49@implementation NSTextAttachmentCell 50 51- (void)drawWithFrame: (NSRect)cellFrame 52 inView: (NSView *)controlView 53 characterIndex: (NSUInteger)charIndex 54{ 55 // cellFrame.origin.y -= cellFrame.size.height; 56 [self drawWithFrame: cellFrame 57 inView: controlView]; 58} 59 60- (void)drawWithFrame: (NSRect)cellFrame 61 inView: (NSView *)controlView 62 characterIndex: (NSUInteger)charIndex 63 layoutManager: (NSLayoutManager *)layoutManager 64{ 65 [self drawWithFrame: cellFrame 66 inView: controlView 67 characterIndex: charIndex]; 68} 69 70- (NSPoint)cellBaselineOffset 71{ 72 return NSZeroPoint; 73} 74 75- (NSRect)cellFrameForTextContainer: (NSTextContainer *)textContainer 76 proposedLineFragment: (NSRect)lineFrag 77 glyphPosition: (NSPoint)position 78 characterIndex: (NSUInteger)charIndex 79{ 80 NSRect aRect; 81 82 aRect.origin = [self cellBaselineOffset]; 83 aRect.size = [self cellSize]; 84 return aRect; 85} 86 87- (BOOL)wantsToTrackMouse 88{ 89 return YES; 90} 91 92- (BOOL)wantsToTrackMouseForEvent: (NSEvent *)theEvent 93 inRect: (NSRect)cellFrame 94 ofView: (NSView *)controlView 95 atCharacterIndex: (NSUInteger)charIndex 96{ 97 return [self wantsToTrackMouse]; 98} 99 100- (BOOL)trackMouse: (NSEvent *)theEvent 101 inRect: (NSRect)cellFrame 102 ofView: (NSView *)controlView 103 untilMouseUp: (BOOL)flag 104{ 105 if ([controlView respondsToSelector: @selector(delegate)]) 106 { 107 NSTextView *textView = (NSTextView*)controlView; 108 id delegate = [textView delegate]; 109 NSEventType type = [theEvent type]; 110 111 if (type == NSLeftMouseUp) 112 { 113 if ([theEvent clickCount] == 2) 114 { 115 if (delegate != nil && [delegate respondsToSelector: 116 @selector(textView:doubleClickedOnCell:inRect:)]) 117 { 118 [delegate textView: textView 119 doubleClickedOnCell: self 120 inRect: cellFrame]; 121 return YES; 122 } 123 } 124 else 125 { 126 if (delegate != nil && [delegate respondsToSelector: 127 @selector(textView:clickedOnCell:inRect:)]) 128 { 129 [delegate textView: textView 130 clickedOnCell: self 131 inRect: cellFrame]; 132 return YES; 133 } 134 } 135 } 136 else if (type == NSLeftMouseDragged) 137 { 138 if (delegate != nil && [delegate respondsToSelector: 139 @selector(textView:draggedCell:inRect:event:)]) 140 { 141 [delegate textView: textView 142 draggedCell: self 143 inRect: cellFrame 144 event: theEvent]; 145 return YES; 146 } 147 } 148 } 149 150 return [super trackMouse: theEvent 151 inRect: cellFrame 152 ofView: controlView 153 untilMouseUp: flag]; 154} 155 156- (BOOL)trackMouse: (NSEvent *)theEvent 157 inRect: (NSRect)cellFrame 158 ofView: (NSView *)controlView 159 atCharacterIndex: (NSUInteger)charIndex 160 untilMouseUp: (BOOL)flag 161{ 162 if ([controlView respondsToSelector: @selector(delegate)]) 163 { 164 NSTextView *textView = (NSTextView*)controlView; 165 id delegate = [textView delegate]; 166 NSEventType type = [theEvent type]; 167 168 if (type == NSLeftMouseDown) 169 { 170 if ([theEvent clickCount] == 2) 171 { 172 if (delegate != nil) 173 { 174 if ([delegate respondsToSelector: 175 @selector(textView:doubleClickedOnCell:inRect:atIndex:)]) 176 { 177 [delegate textView: textView 178 doubleClickedOnCell: self 179 inRect: cellFrame 180 atIndex: charIndex]; 181 return YES; 182 } 183 else if ([delegate respondsToSelector: 184 @selector(textView:doubleClickedOnCell:inRect:)]) 185 { 186 [delegate textView: textView 187 doubleClickedOnCell: self 188 inRect: cellFrame]; 189 return YES; 190 } 191 } 192 } 193 else 194 { 195 if (delegate != nil) 196 { 197 if ([delegate respondsToSelector: 198 @selector(textView:clickedOnCell:inRect:atIndex:)]) 199 { 200 [delegate textView: textView 201 clickedOnCell: self 202 inRect: cellFrame 203 atIndex: charIndex]; 204 return YES; 205 } 206 else if ([delegate respondsToSelector: 207 @selector(textView:clickedOnCell:inRect:)]) 208 { 209 [delegate textView: textView 210 clickedOnCell: self 211 inRect: cellFrame]; 212 return YES; 213 } 214 } 215 } 216 } 217 else if (type == NSLeftMouseDragged) 218 { 219 if (delegate != nil && [delegate respondsToSelector: 220 @selector(textView:draggedCell:inRect:event:atIndex:)]) 221 { 222 [delegate textView: textView 223 draggedCell: self 224 inRect: cellFrame 225 event: theEvent 226 atIndex: charIndex]; 227 return YES; 228 } 229 } 230 } 231 232 return [self trackMouse: theEvent 233 inRect: cellFrame 234 ofView: controlView 235 untilMouseUp: flag]; 236} 237 238- (void)setAttachment: (NSTextAttachment *)anObject 239{ 240 // Do not retain the attachment 241 _attachment = anObject; 242} 243 244- (NSTextAttachment *)attachment 245{ 246 return _attachment; 247} 248 249//FIXME: I had to add those methods to keep the compiler quite. 250// This are already defined on the super class and should be taken from there. 251 252- (NSSize)cellSize 253{ 254 return [super cellSize]; 255} 256 257- (void)highlight: (BOOL)flag 258 withFrame: (NSRect)cellFrame 259 inView: (NSView *)controlView 260{ 261 [super highlight: flag 262 withFrame: cellFrame 263 inView: controlView]; 264} 265 266- (void)drawWithFrame: (NSRect)cellFrame inView: (NSView *)controlView 267{ 268 [super drawWithFrame: cellFrame inView: controlView]; 269} 270 271@end 272 273 274@implementation NSTextAttachment 275 276- (id) init 277{ 278 return [self initWithFileWrapper: nil]; 279} 280 281- (void) dealloc 282{ 283 DESTROY(_fileWrapper); 284 DESTROY(_cell); 285 [super dealloc]; 286} 287 288- (id) initWithFileWrapper: (NSFileWrapper *)fileWrapper 289{ 290 self = [super init]; 291 if (self != nil) 292 { 293 _cell = [[NSTextAttachmentCell alloc ] init]; 294 [self setFileWrapper: fileWrapper]; 295 } 296 return self; 297} 298 299- (void)setFileWrapper: (NSFileWrapper *)fileWrapper 300{ 301 ASSIGN(_fileWrapper, fileWrapper); 302 // Reset the cell, so it shows the new attachment 303 if ([_cell respondsToSelector: @selector(setAttachment:)] == YES) 304 { 305 [_cell setAttachment: self]; 306 } 307 if (_taflags.cell_explicitly_set == 0) 308 { 309 if (fileWrapper != nil) 310 { 311 NSImage *icon = nil; 312 NSString *fileName = [fileWrapper filename]; 313 314 if (fileName != nil) 315 { 316 // Try to set the image to the file wrapper content 317 icon = [[NSImage alloc] initByReferencingFile: fileName]; 318 } 319 if (icon == nil) 320 icon = RETAIN([fileWrapper icon]); 321 322 [(NSTextAttachmentCell*)_cell setImage: icon]; 323 RELEASE(icon); 324 } 325 } 326} 327 328- (NSFileWrapper *)fileWrapper 329{ 330 return _fileWrapper; 331} 332 333- (id <NSTextAttachmentCell>)attachmentCell 334{ 335 return _cell; 336} 337 338- (void)setAttachmentCell: (id <NSTextAttachmentCell>)cell 339{ 340 ASSIGN(_cell, cell); 341 _taflags.cell_explicitly_set = 1; 342 if ([_cell respondsToSelector: @selector(setAttachment:)] == YES) 343 { 344 [_cell setAttachment: self]; 345 } 346} 347 348/* 349 * NSCoding protocol 350 */ 351- (void) encodeWithCoder: (NSCoder*)aCoder 352{ 353 if ([aCoder allowsKeyedCoding]) 354 { 355 [aCoder encodeObject: [self fileWrapper] forKey: @"NSFileWrapper"]; 356 if (_cell != nil) 357 { 358 [aCoder encodeObject: _cell forKey: @"NSCell"]; 359 } 360 } 361 else 362 { 363 [aCoder encodeObject: _fileWrapper]; 364 [aCoder encodeObject: _cell]; 365 } 366} 367 368- (id) initWithCoder: (NSCoder*)aDecoder 369{ 370 if ([aDecoder allowsKeyedCoding]) 371 { 372 [self setFileWrapper: [aDecoder decodeObjectForKey: @"NSFileWrapper"]]; 373 [self setAttachmentCell: [aDecoder decodeObjectForKey: @"NSCell"]]; 374 } 375 else 376 { 377 [aDecoder decodeValueOfObjCType: @encode(id) at: &_fileWrapper]; 378 [aDecoder decodeValueOfObjCType: @encode(id) at: &_cell]; 379 380 // Reconnect the cell, so the cell does not have to store the attachment 381 if ([_cell respondsToSelector: @selector(setAttachment:)] == YES) 382 { 383 [_cell setAttachment: self]; 384 } 385 } 386 return self; 387} 388 389@end 390