Reviewed by Dave Harrison.
[WebKit-https.git] / WebKit / WebView.subproj / WebPreferences.m
1 /*        
2         WebPreferences.m
3         Copyright 2001, 2002, Apple Computer, Inc. All rights reserved.
4 */
5
6 #import <WebKit/WebPreferencesPrivate.h>
7 #import <WebKit/WebPreferenceKeysPrivate.h>
8
9 #import <WebKit/WebKitLogging.h>
10 #import <WebKit/WebKitNSStringExtras.h>
11 #import <WebKit/WebNSURLExtras.h>
12
13 #import <Foundation/NSDictionary_NSURLExtras.h>
14 #import <Foundation/NSString_NSURLExtras.h>
15
16 #import <WebCore/WebCoreSettings.h>
17
18 #import <Carbon/Carbon.h>                           // For TEC
19 #import <CoreFoundation/CFStringDefaultEncoding.h>  // For __CFStringGetUserDefaultEncoding
20
21 NSString *WebPreferencesChangedNotification = @"WebPreferencesChangedNotification";
22
23 #define KEY(x) (_private->identifier ? [_private->identifier stringByAppendingString:(x)] : (x))
24
25 enum { WebPreferencesVersion = 1 };
26
27 @interface WebPreferencesPrivate : NSObject
28 {
29 @public
30     NSMutableDictionary *values;
31     NSString *identifier;
32     NSString *IBCreatorID;
33     BOOL autosaves;
34 }
35 @end
36
37 @implementation WebPreferencesPrivate
38 - (void)dealloc
39 {
40     [values release];
41     [identifier release];
42     [IBCreatorID release];
43     [super dealloc];
44 }
45 @end
46
47 @interface WebPreferences (WebInternal)
48 + (NSString *)_concatenateKeyWithIBCreatorID:(NSString *)key;
49 + (NSString *)_IBCreatorID;
50 @end
51
52 @interface WebPreferences (WebForwardDeclarations)
53 // This pseudo-category is needed so these methods can be used from within other category implementations
54 // without being in the public header file.
55 - (BOOL)_boolValueForKey:(NSString *)key;
56 - (void)_setBoolValue:(BOOL)value forKey:(NSString *)key;
57 @end
58
59 @implementation WebPreferences
60
61 - init
62 {
63     // Create fake identifier
64     static int instanceCount = 1;
65     NSString *fakeIdentifier;
66     
67     // At least ensure that identifier hasn't been already used.  
68     fakeIdentifier = [NSString stringWithFormat:@"WebPreferences%d", instanceCount++];
69     while ([[self class] _getInstanceForIdentifier:fakeIdentifier]){
70         fakeIdentifier = [NSString stringWithFormat:@"WebPreferences%d", instanceCount++];
71     }
72     
73     return [self initWithIdentifier:fakeIdentifier];
74 }
75
76 static WebPreferences *_standardPreferences = nil;
77
78 - (id)initWithIdentifier:(NSString *)anIdentifier
79 {
80     [super init];
81
82     _private = [[WebPreferencesPrivate alloc] init];
83     _private->IBCreatorID = [[WebPreferences _IBCreatorID] retain];
84
85     WebPreferences *instance = [[self class] _getInstanceForIdentifier:anIdentifier];
86     if (instance){
87         [self release];
88         return [instance retain];
89     }
90
91     _private->values = [[NSMutableDictionary alloc] init];
92     _private->identifier = [anIdentifier copy];
93     
94     [[self class] _setInstance:self forIdentifier:_private->identifier];
95
96     [[NSNotificationCenter defaultCenter]
97        postNotificationName:WebPreferencesChangedNotification object:self userInfo:nil];
98
99     return self;
100 }
101
102 - (id)initWithCoder:(NSCoder *)decoder
103 {
104     volatile id result = nil;
105
106 NS_DURING
107
108     int version;
109
110     _private = [[WebPreferencesPrivate alloc] init];
111     _private->IBCreatorID = [[WebPreferences _IBCreatorID] retain];
112     
113     if ([decoder allowsKeyedCoding]){
114         _private->identifier = [[decoder decodeObjectForKey:@"Identifier"] retain];
115         _private->values = [[decoder decodeObjectForKey:@"Values"] retain];
116         LOG (Encoding, "Identifier = %@, Values = %@\n", _private->identifier, _private->values);
117     }
118     else {
119         [decoder decodeValueOfObjCType:@encode(int) at:&version];
120         if (version == 1){
121             _private->identifier = [[decoder decodeObject] retain];
122             _private->values = [[decoder decodeObject] retain];
123         }
124     }
125     
126     // If we load a nib multiple times, or have instances in multiple
127     // nibs with the same name, the first guy up wins.
128     WebPreferences *instance = [[self class] _getInstanceForIdentifier:_private->identifier];
129     if (instance){
130         [self release];
131         result = [instance retain];
132     }
133     else {
134         [[self class] _setInstance:self forIdentifier:_private->identifier];
135         result = self;
136     }
137     
138 NS_HANDLER
139
140     result = nil;
141     [self release];
142     
143 NS_ENDHANDLER
144
145     return result;
146 }
147
148 - (void)encodeWithCoder:(NSCoder *)encoder
149 {
150     if ([encoder allowsKeyedCoding]){
151         [encoder encodeObject:_private->identifier forKey:@"Identifier"];
152         [encoder encodeObject:_private->values forKey:@"Values"];
153         LOG (Encoding, "Identifier = %@, Values = %@\n", _private->identifier, _private->values);
154     }
155     else {
156         int version = WebPreferencesVersion;
157         [encoder encodeValueOfObjCType:@encode(int) at:&version];
158         [encoder encodeObject:_private->identifier];
159         [encoder encodeObject:_private->values];
160     }
161 }
162
163 + (WebPreferences *)standardPreferences
164 {
165     if (_standardPreferences == nil) {
166         _standardPreferences = [[WebPreferences alloc] initWithIdentifier:nil];
167         [_standardPreferences setAutosaves:YES];
168         [_standardPreferences _postPreferencesChangesNotification];
169     }
170
171     return _standardPreferences;
172 }
173
174 // if we ever have more than one WebPreferences object, this would move to init
175 + (void)initialize
176 {
177     NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
178         @"0x0",                         WebKitLogLevelPreferenceKey,
179         @"Times",                       WebKitStandardFontPreferenceKey,
180         @"Courier",                     WebKitFixedFontPreferenceKey,
181         @"Times",                       WebKitSerifFontPreferenceKey,
182         @"Helvetica",                   WebKitSansSerifFontPreferenceKey,
183         @"Apple Chancery",              WebKitCursiveFontPreferenceKey,
184         @"Papyrus",                     WebKitFantasyFontPreferenceKey,
185         @"1",                           WebKitMinimumFontSizePreferenceKey,
186         @"9",                           WebKitMinimumLogicalFontSizePreferenceKey, 
187         @"16",                          WebKitDefaultFontSizePreferenceKey,
188         @"13",                          WebKitDefaultFixedFontSizePreferenceKey,
189         @"ISO-8859-1",                  WebKitDefaultTextEncodingNamePreferenceKey,
190         @"4",                           WebKitPageCacheSizePreferenceKey,
191         @"8388608",                     WebKitObjectCacheSizePreferenceKey,
192         [NSNumber numberWithBool:NO],   WebKitUserStyleSheetEnabledPreferenceKey,
193         @"",                            WebKitUserStyleSheetLocationPreferenceKey,
194         [NSNumber numberWithBool:NO],   WebKitShouldPrintBackgroundsPreferenceKey,
195         [NSNumber numberWithBool:YES],  WebKitJavaEnabledPreferenceKey,
196         [NSNumber numberWithBool:YES],  WebKitJavaScriptEnabledPreferenceKey,
197         [NSNumber numberWithBool:YES],  WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey,
198         [NSNumber numberWithBool:YES],  WebKitPluginsEnabledPreferenceKey,
199         [NSNumber numberWithBool:YES],  WebKitAllowAnimatedImagesPreferenceKey,
200         [NSNumber numberWithBool:YES],  WebKitAllowAnimatedImageLoopingPreferenceKey,
201         [NSNumber numberWithBool:YES],  WebKitDisplayImagesKey,
202         @"1800",                        WebKitBackForwardCacheExpirationIntervalKey,
203         [NSNumber numberWithBool:NO],   WebKitTabToLinksPreferenceKey,
204         [NSNumber numberWithBool:NO],   WebKitPrivateBrowsingEnabledPreferenceKey,
205         [NSNumber numberWithBool:NO],   WebKitRespectStandardStyleKeyEquivalentsPreferenceKey,
206         [NSNumber numberWithBool:NO],   WebKitShowsURLsInToolTipsPreferenceKey,
207         nil];
208
209     [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
210 }
211
212 - (void)dealloc
213 {
214     [_private release];
215     [super dealloc];
216 }
217
218 - (NSString *)identifier
219 {
220     return _private->identifier;
221 }
222
223 - (id)_valueForKey:(NSString *)key
224 {
225     NSString *_key = KEY(key);
226     id o = [_private->values objectForKey:_key];
227     if (o)
228         return o;
229     o = [[NSUserDefaults standardUserDefaults] objectForKey:_key];
230     if (!o && key != _key)
231         o = [[NSUserDefaults standardUserDefaults] objectForKey:key];
232     return o;
233 }
234
235 - (NSString *)_stringValueForKey:(NSString *)key
236 {
237     id s = [self _valueForKey:key];
238     return [s isKindOfClass:[NSString class]] ? (NSString *)s : nil;
239 }
240
241 - (void)_setStringValue:(NSString *)value forKey:(NSString *)key
242 {
243     NSString *_key = KEY(key);
244     [_private->values setObject:value forKey:_key];
245     if (_private->autosaves)
246         [[NSUserDefaults standardUserDefaults] setObject:value forKey:_key];
247     [self _postPreferencesChangesNotification];
248 }
249
250 - (int)_integerValueForKey:(NSString *)key
251 {
252     id o = [self _valueForKey:key];
253     // 
254     return [o respondsToSelector:@selector(intValue)] ? [o intValue] : 0;
255 }
256
257 - (void)_setIntegerValue:(int)value forKey:(NSString *)key
258 {
259     NSString *_key = KEY(key);
260     [_private->values _web_setInt:value forKey:_key];
261     if (_private->autosaves)
262         [[NSUserDefaults standardUserDefaults] setInteger:value forKey:_key];
263     [self _postPreferencesChangesNotification];
264 }
265
266 - (BOOL)_boolValueForKey:(NSString *)key
267 {
268     return [self _integerValueForKey:key] != 0;
269 }
270
271 - (void)_setBoolValue:(BOOL)value forKey:(NSString *)key
272 {
273     NSString *_key = KEY(key);
274     [_private->values _web_setBool:value forKey:_key];
275     if (_private->autosaves)
276         [[NSUserDefaults standardUserDefaults] setBool:value forKey:_key];
277     [self _postPreferencesChangesNotification];
278 }
279
280 - (NSString *)standardFontFamily
281 {
282     return [self _stringValueForKey: WebKitStandardFontPreferenceKey];
283 }
284
285 - (void)setStandardFontFamily:(NSString *)family
286 {
287     [self _setStringValue: family forKey: WebKitStandardFontPreferenceKey];
288 }
289
290 - (NSString *)fixedFontFamily
291 {
292     return [self _stringValueForKey: WebKitFixedFontPreferenceKey];
293 }
294
295 - (void)setFixedFontFamily:(NSString *)family
296 {
297     [self _setStringValue: family forKey: WebKitFixedFontPreferenceKey];
298 }
299
300 - (NSString *)serifFontFamily
301 {
302     return [self _stringValueForKey: WebKitSerifFontPreferenceKey];
303 }
304
305 - (void)setSerifFontFamily:(NSString *)family 
306 {
307     [self _setStringValue: family forKey: WebKitSerifFontPreferenceKey];
308 }
309
310 - (NSString *)sansSerifFontFamily
311 {
312     return [self _stringValueForKey: WebKitSansSerifFontPreferenceKey];
313 }
314
315 - (void)setSansSerifFontFamily:(NSString *)family
316 {
317     [self _setStringValue: family forKey: WebKitSansSerifFontPreferenceKey];
318 }
319
320 - (NSString *)cursiveFontFamily
321 {
322     return [self _stringValueForKey: WebKitCursiveFontPreferenceKey];
323 }
324
325 - (void)setCursiveFontFamily:(NSString *)family
326 {
327     [self _setStringValue: family forKey: WebKitCursiveFontPreferenceKey];
328 }
329
330 - (NSString *)fantasyFontFamily
331 {
332     return [self _stringValueForKey: WebKitFantasyFontPreferenceKey];
333 }
334
335 - (void)setFantasyFontFamily:(NSString *)family
336 {
337     [self _setStringValue: family forKey: WebKitFantasyFontPreferenceKey];
338 }
339
340 - (int)defaultFontSize
341 {
342     return [self _integerValueForKey: WebKitDefaultFontSizePreferenceKey];
343 }
344
345 - (void)setDefaultFontSize:(int)size
346 {
347     [self _setIntegerValue: size forKey: WebKitDefaultFontSizePreferenceKey];
348 }
349
350 - (int)defaultFixedFontSize
351 {
352     return [self _integerValueForKey: WebKitDefaultFixedFontSizePreferenceKey];
353 }
354
355 - (void)setDefaultFixedFontSize:(int)size
356 {
357     [self _setIntegerValue: size forKey: WebKitDefaultFixedFontSizePreferenceKey];
358 }
359
360 - (int)minimumFontSize
361 {
362     return [self _integerValueForKey: WebKitMinimumFontSizePreferenceKey];
363 }
364
365 - (void)setMinimumFontSize:(int)size
366 {
367     [self _setIntegerValue: size forKey: WebKitMinimumFontSizePreferenceKey];
368 }
369
370 - (int)minimumLogicalFontSize
371 {
372   return [self _integerValueForKey: WebKitMinimumLogicalFontSizePreferenceKey];
373 }
374
375 - (void)setMinimumLogicalFontSize:(int)size
376 {
377   [self _setIntegerValue: size forKey: WebKitMinimumLogicalFontSizePreferenceKey];
378 }
379
380 - (NSString *)defaultTextEncodingName
381 {
382     return [self _stringValueForKey: WebKitDefaultTextEncodingNamePreferenceKey];
383 }
384
385 - (void)setDefaultTextEncodingName:(NSString *)encoding
386 {
387     [self _setStringValue: encoding forKey: WebKitDefaultTextEncodingNamePreferenceKey];
388 }
389
390 - (BOOL)userStyleSheetEnabled
391 {
392     return [self _boolValueForKey: WebKitUserStyleSheetEnabledPreferenceKey];
393 }
394
395 - (void)setUserStyleSheetEnabled:(BOOL)flag
396 {
397     [self _setBoolValue: flag forKey: WebKitUserStyleSheetEnabledPreferenceKey];
398 }
399
400 - (NSURL *)userStyleSheetLocation
401 {
402     NSString *locationString = [self _stringValueForKey: WebKitUserStyleSheetLocationPreferenceKey];
403     
404     if ([locationString _web_looksLikeAbsoluteURL]) {
405         return [NSURL _web_URLWithDataAsString:locationString];
406     } else {
407         locationString = [locationString stringByExpandingTildeInPath];
408         return [NSURL fileURLWithPath:locationString];
409     }
410 }
411
412 - (void)setUserStyleSheetLocation:(NSURL *)URL
413 {
414     NSString *locationString;
415     
416     if ([URL isFileURL]) {
417         locationString = [[URL path] _web_stringByAbbreviatingWithTildeInPath];
418     } else {
419         locationString = [URL _web_originalDataAsString];
420     }
421     
422     [self _setStringValue:locationString forKey: WebKitUserStyleSheetLocationPreferenceKey];
423 }
424
425 - (BOOL)shouldPrintBackgrounds
426 {
427     return [self _boolValueForKey: WebKitShouldPrintBackgroundsPreferenceKey];
428 }
429
430 - (void)setShouldPrintBackgrounds:(BOOL)flag
431 {
432     [self _setBoolValue: flag forKey: WebKitShouldPrintBackgroundsPreferenceKey];
433 }
434
435 - (BOOL)isJavaEnabled
436 {
437     return [self _boolValueForKey: WebKitJavaEnabledPreferenceKey];
438 }
439
440 - (void)setJavaEnabled:(BOOL)flag
441 {
442     [self _setBoolValue: flag forKey: WebKitJavaEnabledPreferenceKey];
443 }
444
445 - (BOOL)isJavaScriptEnabled
446 {
447     return [self _boolValueForKey: WebKitJavaScriptEnabledPreferenceKey];
448 }
449
450 - (void)setJavaScriptEnabled:(BOOL)flag
451 {
452     [self _setBoolValue: flag forKey: WebKitJavaScriptEnabledPreferenceKey];
453 }
454
455 - (BOOL)javaScriptCanOpenWindowsAutomatically
456 {
457     return [self _boolValueForKey: WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey];
458 }
459
460 - (void)setJavaScriptCanOpenWindowsAutomatically:(BOOL)flag
461 {
462     [self _setBoolValue: flag forKey: WebKitJavaScriptCanOpenWindowsAutomaticallyPreferenceKey];
463 }
464
465 - (BOOL)arePlugInsEnabled
466 {
467     return [self _boolValueForKey: WebKitPluginsEnabledPreferenceKey];
468 }
469
470 - (void)setPlugInsEnabled:(BOOL)flag
471 {
472     [self _setBoolValue: flag forKey: WebKitPluginsEnabledPreferenceKey];
473 }
474
475 - (BOOL)allowsAnimatedImages
476 {
477     return [self _boolValueForKey: WebKitAllowAnimatedImagesPreferenceKey];
478 }
479
480 - (void)setAllowsAnimatedImages:(BOOL)flag;
481 {
482     [self _setBoolValue: flag forKey: WebKitAllowAnimatedImagesPreferenceKey];
483 }
484
485 - (BOOL)allowsAnimatedImageLooping
486 {
487     return [self _boolValueForKey: WebKitAllowAnimatedImageLoopingPreferenceKey];
488 }
489
490 - (void)setAllowsAnimatedImageLooping: (BOOL)flag
491 {
492     [self _setBoolValue: flag forKey: WebKitAllowAnimatedImageLoopingPreferenceKey];
493 }
494
495 - (void)setLoadsImagesAutomatically: (BOOL)flag
496 {
497     [self _setBoolValue: flag forKey: WebKitDisplayImagesKey];
498 }
499
500 - (BOOL)loadsImagesAutomatically
501 {
502     return [self _boolValueForKey: WebKitDisplayImagesKey];
503 }
504
505 - (void)setAutosaves:(BOOL)flag;
506 {
507     _private->autosaves = flag;
508 }
509
510 - (BOOL)autosaves
511 {
512     return _private->autosaves;
513 }
514
515 - (void)setTabsToLinks:(BOOL)flag
516 {
517     [self _setBoolValue: flag forKey: WebKitTabToLinksPreferenceKey];
518 }
519
520 - (BOOL)tabsToLinks
521 {
522     return [self _boolValueForKey:WebKitTabToLinksPreferenceKey];
523 }
524
525 - (void)setPrivateBrowsingEnabled:(BOOL)flag
526 {
527     [self _setBoolValue:flag forKey:WebKitPrivateBrowsingEnabledPreferenceKey];
528 }
529
530 - (BOOL)privateBrowsingEnabled
531 {
532     return [self _boolValueForKey:WebKitPrivateBrowsingEnabledPreferenceKey];
533 }
534
535 @end
536
537 @implementation WebPreferences (WebPrivate)
538
539 - (BOOL)respectStandardStyleKeyEquivalents
540 {
541     return [self _boolValueForKey:WebKitRespectStandardStyleKeyEquivalentsPreferenceKey];
542 }
543
544 - (void)setRespectStandardStyleKeyEquivalents:(BOOL)flag
545 {
546     [self _setBoolValue:flag forKey:WebKitRespectStandardStyleKeyEquivalentsPreferenceKey];
547 }
548
549 - (BOOL)showsURLsInToolTips
550 {
551     return [self _boolValueForKey:WebKitShowsURLsInToolTipsPreferenceKey];
552 }
553
554 - (void)setShowsURLsInToolTips:(BOOL)flag
555 {
556     [self _setBoolValue:flag forKey:WebKitShowsURLsInToolTipsPreferenceKey];
557 }
558
559 - (int)_pageCacheSize
560 {
561     return [[NSUserDefaults standardUserDefaults] integerForKey:WebKitPageCacheSizePreferenceKey];
562 }
563
564 - (int)_objectCacheSize
565 {
566     return [[NSUserDefaults standardUserDefaults] integerForKey:WebKitObjectCacheSizePreferenceKey];
567 }
568
569 - (NSTimeInterval)_backForwardCacheExpirationInterval
570 {
571     return (NSTimeInterval)[[NSUserDefaults standardUserDefaults] floatForKey:WebKitBackForwardCacheExpirationIntervalKey];
572 }
573
574 static NSMutableDictionary *webPreferencesInstances = nil;
575
576 + (WebPreferences *)_getInstanceForIdentifier:(NSString *)ident
577 {
578         LOG (Encoding, "requesting for %@\n", ident);
579
580     if (!ident){
581         if(_standardPreferences)
582             return _standardPreferences;
583         return nil;
584     }    
585     
586     WebPreferences *instance = [webPreferencesInstances objectForKey:[self _concatenateKeyWithIBCreatorID:ident]];
587
588     return instance;
589 }
590
591 + (void)_setInstance:(WebPreferences *)instance forIdentifier:(NSString *)ident
592 {
593     if (!webPreferencesInstances)
594         webPreferencesInstances = [[NSMutableDictionary alloc] init];
595     if (ident) {
596         [webPreferencesInstances setObject:instance forKey:[self _concatenateKeyWithIBCreatorID:ident]];
597         LOG (Encoding, "recording %p for %@\n", instance, [self _concatenateKeyWithIBCreatorID:ident]);
598     }
599 }
600
601 + (void)_removeReferenceForIdentifier:(NSString *)ident
602 {
603     if (ident != nil) {
604         [webPreferencesInstances performSelector:@selector(_web_checkLastReferenceForIdentifier:) withObject: [self _concatenateKeyWithIBCreatorID:ident] afterDelay:.1];
605     }
606 }
607
608 - (void)_postPreferencesChangesNotification
609 {
610     [[NSNotificationCenter defaultCenter]
611         postNotificationName:WebPreferencesChangedNotification object:self
612                     userInfo:nil];
613 }
614
615 + (CFStringEncoding)_systemCFStringEncoding
616 {
617 #if OMIT_TIGER_FEATURES
618     CFStringEncoding encoding = CFStringGetSystemEncoding();
619
620     // Map from system encodings to the appropriate default web encoding.
621     // Web pages that are not labeled will be decoded assuming this encoding,
622     // so it's important that this be the most likely encoding to encounter
623     // on a web page. MacArabic, MacHebrew, and MacRoman are not common on
624     // the web, so instead we map to the most common similar encoding actually used.
625     switch (encoding) {
626         case kCFStringEncodingMacArabic:
627             encoding = kCFStringEncodingDOSArabic;
628             break;
629         case kCFStringEncodingMacHebrew:
630             encoding = kCFStringEncodingDOSHebrew;
631             break;
632         case kCFStringEncodingMacRoman:
633             encoding = kCFStringEncodingISOLatin1;
634             break;
635     }
636
637     // We must not use any encoding that has no IANA character set name.
638     if (CFStringConvertEncodingToIANACharSetName(encoding) == NULL)
639         return kCFStringEncodingISOLatin1;
640 #else
641     UInt32 script = 0;
642     UInt32 region = 0;
643     TextEncoding encoding;
644     OSErr err;
645     ItemCount dontcare;
646
647     // We can't use the Script Manager as it will not return things that use
648     // a script that is not supported on Mac OS X.
649     __CFStringGetUserDefaultEncoding(&script, &region);
650     err = TECGetWebTextEncodings(region, &encoding, 1, &dontcare);
651     if (err != noErr)
652         encoding = kCFStringEncodingISOLatin1;
653 #endif
654
655     return encoding;
656 }
657
658 + (void)_setInitialDefaultTextEncodingToSystemEncoding
659 {
660     [[NSUserDefaults standardUserDefaults] registerDefaults:
661         [NSDictionary dictionaryWithObject:(NSString *)CFStringConvertEncodingToIANACharSetName([self _systemCFStringEncoding])
662                                     forKey:WebKitDefaultTextEncodingNamePreferenceKey]];
663 }
664
665 static NSString *classIBCreatorID = nil;
666
667 + (void)_setIBCreatorID:(NSString *)string
668 {
669     NSString *old = classIBCreatorID;
670     classIBCreatorID = [string copy];
671     [old release];
672 }
673
674 @end
675
676 @implementation WebPreferences (WebInternal)
677
678 + (NSString *)_IBCreatorID
679 {
680     return classIBCreatorID;
681 }
682
683 + (NSString *)_concatenateKeyWithIBCreatorID:(NSString *)key
684 {
685     NSString *IBCreatorID = [WebPreferences _IBCreatorID];
686     if (!IBCreatorID)
687         return key;
688     return [IBCreatorID stringByAppendingString:key];
689 }
690
691 @end
692
693 @implementation NSMutableDictionary (WebInternal)
694
695 - (void)_web_checkLastReferenceForIdentifier:(NSString *)identifier
696 {
697     WebPreferences *instance = [webPreferencesInstances objectForKey:identifier];
698     if ([instance retainCount] == 1)
699         [webPreferencesInstances removeObjectForKey:identifier];
700 }
701
702 @end