1/** <title>NSDataLink</title> 2 3 Copyright (C) 1996, 2005 Free Software Foundation, Inc. 4 5 Author: Gregory John Casamento <greg_casamento@yahoo.com> 6 Date: 2005 7 Author: Scott Christley <scottc@net-community.com> 8 Date: 1996 9 10 This file is part of the GNUstep GUI Library. 11 12 This library is free software; you can redistribute it and/or 13 modify it under the terms of the GNU Lesser General Public 14 License as published by the Free Software Foundation; either 15 version 2 of the License, or (at your option) any later version. 16 17 This library is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public 23 License along with this library; see the file COPYING.LIB. 24 If not, see <http://www.gnu.org/licenses/> or write to the 25 Free Software Foundation, 51 Franklin Street, Fifth Floor, 26 Boston, MA 02110-1301, USA. 27*/ 28 29#include "config.h" 30#import <Foundation/NSFileManager.h> 31#import <Foundation/NSArchiver.h> 32#import <Foundation/NSData.h> 33#import "AppKit/NSDataLink.h" 34#import "AppKit/NSDataLinkManager.h" 35#import "AppKit/NSPasteboard.h" 36#import "AppKit/NSSavePanel.h" 37#import "AppKit/NSSelection.h" 38 39@implementation NSDataLink 40 41// 42// Class methods 43// 44+ (void)initialize 45{ 46 if (self == [NSDataLink class]) 47 { 48 // Initial version 49 [self setVersion: 0]; 50 } 51} 52 53// 54// 55// Instance methods 56// 57// Initializing a Link 58// 59- (id)initLinkedToFile:(NSString *)filename 60{ 61 if ((self = [self init]) != nil) 62 { 63 NSData *data = [NSData dataWithBytes: [filename cString] length: [filename cStringLength]]; 64 NSSelection *selection = [NSSelection selectionWithDescriptionData: data]; 65 ASSIGN(sourceSelection, selection); 66 } 67 return self; 68} 69 70- (id)initLinkedToSourceSelection:(NSSelection *)selection 71 managedBy:(NSDataLinkManager *)linkManager 72 supportingTypes:(NSArray *)newTypes 73{ 74 if ((self = [self init]) != nil) 75 { 76 ASSIGN(sourceSelection,selection); 77 ASSIGN(sourceManager,linkManager); 78 ASSIGN(types,newTypes); 79 } 80 return self; 81} 82 83- (id)initWithContentsOfFile:(NSString *)filename 84{ 85 NSData *data = [[NSData alloc] initWithContentsOfFile: filename]; 86 id object = [NSUnarchiver unarchiveObjectWithData: data]; 87 88 RELEASE(data); 89 RELEASE(self); 90 return RETAIN(object); 91} 92 93- (id)initWithPasteboard:(NSPasteboard *)pasteboard 94{ 95 NSData *data = [pasteboard dataForType: NSDataLinkPboardType]; 96 id object = [NSUnarchiver unarchiveObjectWithData: data]; 97 98 RELEASE(self); 99 return RETAIN(object); 100} 101 102// 103// Exporting a Link 104// 105- (BOOL)saveLinkIn:(NSString *)directoryName 106{ 107 NSSavePanel *sp; 108 int result; 109 110 sp = [NSSavePanel savePanel]; 111 [sp setRequiredFileType: NSDataLinkFilenameExtension]; 112 result = [sp runModalForDirectory: directoryName file: @""]; 113 if (result == NSOKButton) 114 { 115 NSFileManager *mgr = [NSFileManager defaultManager]; 116 NSString *path = [sp filename]; 117 118 if ([mgr fileExistsAtPath: path] == YES) 119 { 120 /* NSSavePanel has already asked if it's ok to replace */ 121 NSString *bPath = [path stringByAppendingString: @"~"]; 122 123 [mgr removeFileAtPath: bPath handler: nil]; 124 [mgr movePath: path toPath: bPath handler: nil]; 125 } 126 127 // save it. 128 return [self writeToFile: path]; 129 } 130 return NO; 131} 132 133- (BOOL)writeToFile:(NSString *)filename 134{ 135 NSString *path = filename; 136 137 if ([[path pathExtension] isEqual: NSDataLinkFilenameExtension] == NO) 138 { 139 path = [filename stringByAppendingPathExtension: NSDataLinkFilenameExtension]; 140 } 141 142 return [NSArchiver archiveRootObject: self toFile: path]; 143} 144 145- (void)writeToPasteboard:(NSPasteboard *)pasteboard 146{ 147 NSData *data = [NSArchiver archivedDataWithRootObject: self]; 148 [pasteboard setData: data forType: NSDataLinkPboardType]; 149} 150 151// 152// Information about the Link 153// 154- (NSDataLinkDisposition)disposition 155{ 156 return disposition; 157} 158 159- (NSDataLinkNumber)linkNumber 160{ 161 return linkNumber; 162} 163 164- (NSDataLinkManager *)manager 165{ 166 return sourceManager; 167} 168 169// 170// Information about the Link's Source 171// 172- (NSDate *)lastUpdateTime 173{ 174 return lastUpdateTime; 175} 176 177- (BOOL)openSource 178{ 179 return NO; 180} 181 182- (NSString *)sourceApplicationName 183{ 184 return sourceApplicationName; 185} 186 187- (NSString *)sourceFilename 188{ 189 return sourceFilename; 190} 191 192- (NSSelection *)sourceSelection 193{ 194 return sourceSelection; 195} 196 197- (NSArray *)types 198{ 199 return types; 200} 201 202// 203// Information about the Link's Destination 204// 205- (NSString *)destinationApplicationName 206{ 207 return destinationApplicationName; 208} 209 210- (NSString *)destinationFilename 211{ 212 return destinationFilename; 213} 214 215- (NSSelection *)destinationSelection 216{ 217 return destinationSelection; 218} 219 220// 221// Changing the Link 222// 223- (BOOL)break 224{ 225 id srcDelegate = [sourceManager delegate]; 226 id dstDelegate = [destinationManager delegate]; 227 228 // The spec is quite vague here. I don't know under what 229 // circumstances a link cannot be broken, so this method 230 // always returns YES. 231 232 if ([srcDelegate respondsToSelector: @selector(dataLinkManager:didBreakLink:)]) 233 { 234 [srcDelegate dataLinkManager: sourceManager didBreakLink: self]; 235 } 236 237 if ([dstDelegate respondsToSelector: @selector(dataLinkManager:didBreakLink:)]) 238 { 239 [dstDelegate dataLinkManager: destinationManager didBreakLink: self]; 240 } 241 242 return (_flags.broken = YES); 243} 244 245- (void)noteSourceEdited 246{ 247 _flags.isDirty = YES; 248 249 if (updateMode != NSUpdateNever) 250 { 251 [sourceManager noteDocumentEdited]; 252 } 253} 254 255- (void)setUpdateMode:(NSDataLinkUpdateMode)mode 256{ 257 updateMode = mode; 258} 259 260- (BOOL)updateDestination 261{ 262 return NO; 263} 264 265- (NSDataLinkUpdateMode)updateMode 266{ 267 return updateMode; 268} 269 270// 271// NSCoding protocol 272// 273- (void) encodeWithCoder: (NSCoder*)aCoder 274{ 275 BOOL flag = NO; 276 277 if ([aCoder allowsKeyedCoding]) 278 { 279 [aCoder encodeInt: linkNumber forKey: @"GSLinkNumber"]; 280 [aCoder encodeInt: disposition forKey: @"GSUpdateMode"]; 281 [aCoder encodeInt: updateMode forKey: @"GSLastUpdateMode"]; 282 283 [aCoder encodeObject: lastUpdateTime forKey: @"GSLastUpdateTime"]; 284 285 [aCoder encodeObject: sourceApplicationName forKey: @"GSSourceApplicationName"]; 286 [aCoder encodeObject: sourceFilename forKey: @"GSSourceFilename"]; 287 [aCoder encodeObject: sourceSelection forKey: @"GSSourceSelection"]; 288 [aCoder encodeObject: sourceManager forKey: @"GSSourceManager"]; 289 290 [aCoder encodeObject: destinationApplicationName forKey: @"GSDestinationApplicationName"]; 291 [aCoder encodeObject: destinationFilename forKey: @"GSDestinationFilename"]; 292 [aCoder encodeObject: destinationSelection forKey: @"GSDestinationSelection"]; 293 [aCoder encodeObject: destinationManager forKey: @"GSDestinationManager"]; 294 295 [aCoder encodeObject: types forKey: @"GSTypes"]; 296 297 // flags... 298 flag = _flags.appVerifies; 299 [aCoder encodeBool: flag forKey: @"GSAppVerifies"]; 300 flag = _flags.canUpdateContinuously; 301 [aCoder encodeBool: flag forKey: @"GSCanUpdateContinuously"]; 302 flag = _flags.isDirty; 303 [aCoder encodeBool: flag forKey: @"GSIsDirty"]; 304 flag = _flags.willOpenSource; 305 [aCoder encodeBool: flag forKey: @"GSWillOpenSource"]; 306 flag = _flags.willUpdate; 307 [aCoder encodeBool: flag forKey: @"GSWillUpdate"]; 308 } 309 else 310 { 311 [aCoder encodeValueOfObjCType: @encode(int) at: &linkNumber]; 312 [aCoder encodeValueOfObjCType: @encode(int) at: &disposition]; 313 [aCoder encodeValueOfObjCType: @encode(int) at: &updateMode]; 314 [aCoder encodeValueOfObjCType: @encode(id) at: &lastUpdateTime]; 315 316 [aCoder encodeValueOfObjCType: @encode(id) at: &sourceApplicationName]; 317 [aCoder encodeValueOfObjCType: @encode(id) at: &sourceFilename]; 318 [aCoder encodeValueOfObjCType: @encode(id) at: &sourceSelection]; 319 [aCoder encodeValueOfObjCType: @encode(id) at: &sourceManager]; 320 321 [aCoder encodeValueOfObjCType: @encode(id) at: &destinationApplicationName]; 322 [aCoder encodeValueOfObjCType: @encode(id) at: &destinationFilename]; 323 [aCoder encodeValueOfObjCType: @encode(id) at: &destinationSelection]; 324 [aCoder encodeValueOfObjCType: @encode(id) at: &destinationManager]; 325 326 [aCoder encodeValueOfObjCType: @encode(id) at: &types]; 327 328 // flags... 329 flag = _flags.appVerifies; 330 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 331 flag = _flags.canUpdateContinuously; 332 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 333 flag = _flags.isDirty; 334 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 335 flag = _flags.willOpenSource; 336 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 337 flag = _flags.willUpdate; 338 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &flag]; 339 } 340} 341 342- (id) initWithCoder: (NSCoder*)aCoder 343{ 344 if ([aCoder allowsKeyedCoding]) 345 { 346 id obj; 347 348 linkNumber = [aCoder decodeIntForKey: @"GSLinkNumber"]; 349 disposition = [aCoder decodeIntForKey: @"GSDisposition"]; 350 updateMode = [aCoder decodeIntForKey: @"GSUpdateMode"]; 351 352 obj = [aCoder decodeObjectForKey: @"GSSourceManager"]; 353 ASSIGN(sourceManager,obj); 354 obj = [aCoder decodeObjectForKey: @"GSDestinationManager"]; 355 ASSIGN(destinationManager,obj); 356 obj = [aCoder decodeObjectForKey: @"GSLastUpdateTime"]; 357 ASSIGN(lastUpdateTime, obj); 358 obj = [aCoder decodeObjectForKey: @"GSSourceApplicationName"]; 359 ASSIGN(sourceApplicationName,obj); 360 obj = [aCoder decodeObjectForKey: @"GSSourceFilename"]; 361 ASSIGN(sourceFilename,obj); 362 obj = [aCoder decodeObjectForKey: @"GSSourceSelection"]; 363 ASSIGN(sourceSelection,obj); 364 obj = [aCoder decodeObjectForKey: @"GSSourceManager"]; 365 ASSIGN(sourceManager,obj); 366 obj = [aCoder decodeObjectForKey: @"GSDestinationApplicationName"]; 367 ASSIGN(destinationApplicationName,obj); 368 obj = [aCoder decodeObjectForKey: @"GSDestinationFilename"]; 369 ASSIGN(destinationFilename,obj); 370 obj = [aCoder decodeObjectForKey: @"GSDestinationSelection"]; 371 ASSIGN(destinationSelection,obj); 372 obj = [aCoder decodeObjectForKey: @"GSDestinationManager"]; 373 ASSIGN(destinationManager,obj); 374 obj = [aCoder decodeObjectForKey: @"GSTypes"]; 375 ASSIGN(types,obj); 376 377 // flags... 378 _flags.appVerifies = [aCoder decodeBoolForKey: @"GSAppVerifies"]; 379 _flags.canUpdateContinuously = [aCoder decodeBoolForKey: @"GSCanUpdateContinuously"]; 380 _flags.isDirty = [aCoder decodeBoolForKey: @"GSIsDirty"]; 381 _flags.willOpenSource = [aCoder decodeBoolForKey: @"GSWillOpenSource"]; 382 _flags.willUpdate = [aCoder decodeBoolForKey: @"GSWillUpdate"]; 383 } 384 else 385 { 386 int version = [aCoder versionForClassName: @"NSDataLink"]; 387 if (version == 0) 388 { 389 BOOL flag = NO; 390 391 [aCoder decodeValueOfObjCType: @encode(int) at: &linkNumber]; 392 [aCoder decodeValueOfObjCType: @encode(int) at: &disposition]; 393 [aCoder decodeValueOfObjCType: @encode(int) at: &updateMode]; 394 [aCoder decodeValueOfObjCType: @encode(id) at: &sourceManager]; 395 [aCoder decodeValueOfObjCType: @encode(id) at: &destinationManager]; 396 [aCoder decodeValueOfObjCType: @encode(id) at: &lastUpdateTime]; 397 398 [aCoder decodeValueOfObjCType: @encode(id) at: &sourceApplicationName]; 399 [aCoder decodeValueOfObjCType: @encode(id) at: &sourceFilename]; 400 [aCoder decodeValueOfObjCType: @encode(id) at: &sourceSelection]; 401 [aCoder decodeValueOfObjCType: @encode(id) at: &sourceManager]; 402 403 [aCoder decodeValueOfObjCType: @encode(id) at: &destinationApplicationName]; 404 [aCoder decodeValueOfObjCType: @encode(id) at: &destinationFilename]; 405 [aCoder decodeValueOfObjCType: @encode(id) at: &destinationSelection]; 406 [aCoder decodeValueOfObjCType: @encode(id) at: &destinationManager]; 407 408 [aCoder decodeValueOfObjCType: @encode(id) at: &types]; 409 410 // flags... 411 [aCoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 412 _flags.appVerifies = flag; 413 [aCoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 414 _flags.canUpdateContinuously = flag; 415 [aCoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 416 _flags.isDirty = flag; 417 [aCoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 418 _flags.willOpenSource = flag; 419 [aCoder decodeValueOfObjCType: @encode(BOOL) at: &flag]; 420 _flags.willUpdate = flag; 421 } 422 else 423 return nil; 424 } 425 426 return self; 427} 428 429@end 430