/* BKBookmarkStore.m BKBookmarkStore is the core BookmarkKit class to interact with the bookmarks Copyright (C) 2004 Quentin Mathe Copyright (C) 2006 Yen-Ju Chen Author: Quentin Mathe Date: April 2004 Author: Yen-Ju Chen Date: October 2006 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #import #import #import #import #import #import #import #import "GNUstep.h" NSString *const BKDefaultBookmarkStore = @"BKDefaultBookmarkStore"; NSString *const BKRecentFilesBookmarkStore = @"BKRecentFilesBookmarkStore"; NSString *const BKRecentApplicationsBookmarkStore = @"BKRecentApplicationsBookmarkStore"; NSString *const BKWebBrowserBookmarkStore = @"BKWebBrowserBookmarkStore"; NSString *const BKRSSBookmarkStore = @"BKRSSBookmarkStore"; NSString *const BKBookmarkDirectory = @"Bookmark"; NSString *const BKBookmarkExtension = @"bookmark"; NSString *const kBKTopLevelOrderProperty = @"kBKTopLevelOrderProperty"; @implementation BKBookmarkStore + (BKBookmarkStore *) sharedBookmarkStore { return [BKBookmarkStore sharedBookmarkWithDomain: BKDefaultBookmarkStore]; } + (BKBookmarkStore *) sharedBookmarkWithDomain: (NSString *) domain { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); if ([paths count] == 0) return nil; NSString *path = [paths objectAtIndex: 0]; path = [path stringByAppendingPathComponent: BKBookmarkDirectory]; path = [path stringByAppendingPathComponent: domain]; path = [path stringByAppendingPathExtension: BKBookmarkExtension]; return [BKBookmarkStore sharedBookmarkAtPath: path]; } // support native format or XBEL format + (BKBookmarkStore *) sharedBookmarkAtPath: (NSString *)path { return AUTORELEASE([[BKBookmarkStore alloc] initWithLocation: path]); } + (BKBookmarkStore *) sharedBookmarkAtURL: (NSURL *)url // support native format or XBEL format { return nil; } - (NSString *) path { return [self location]; } // FIXME: roles idea must be used here to have a better method interface and // implementation. "relatedToProtocols" is here to support protocol variants // like "protocols combo" to be short, I mean http/web, http/webdav, ssh/svn // etc. - (void) addProtocol: (BKBookmarkProtocol)bookmarkProtocol relativeToResourceSpecifier: (NSString *)resourceSpecifier relatedToProcotols: (NSArray *)bookmarkProtocols; { } - (void) removeProtocol: (BKBookmarkProtocol)bookmarkProtocol { } - (void) addBookmark: (BKBookmark *)bookmark { [self addRecord: bookmark]; } - (void) removeBookmark: (BKBookmark *)bookmark { [self removeRecord: bookmark]; } - (BKBookmarkSearchResult *) searchWithQuery: (BKBookmarkQuery *)query { return nil; } - (void) save { /* Go through all top level records and put an order number of it */ NSEnumerator *e = [_topLevelRecords objectEnumerator]; CKRecord *r; int i = 0; while ((r = [e nextObject])) { [r setValue: [NSNumber numberWithInt: i++] forProperty: kBKTopLevelOrderProperty]; } [super save]; } - (BOOL) hasUnsavedChanges { return [super hasUnsavedChanges]; } - (NSMutableArray *) topLevelRecords { return _topLevelRecords; } - (NSString *) transformToXBEL // aspect { return nil; } - (NSString *) transformToXMLNativeFormat // aspect { return nil; } /** override super class */ - (BOOL) addRecord: (CKRecord *) record { if ([super addRecord: record]) { [_topLevelRecords addObject: record]; return YES; } return NO; } - (BOOL) removeRecord: (CKRecord *) record { if ([super removeRecord: record]) { [_topLevelRecords removeObject: record]; return YES; } return NO; } - (BOOL) addItem: (CKItem *) it forGroup: (CKGroup*) group { BKBookmark *item = (BKBookmark *) it; if ([item isTopLevel] == BKNotTopLevel) { /* Has parent already. */ return NO; } if ([super addItem: item forGroup: group] == YES) { [item setTopLevel: BKNotTopLevel]; [_topLevelRecords removeObject: item]; return YES; } else { [item setTopLevel: BKUndecidedTopLevel]; return NO; } } - (BOOL) removeItem: (CKItem *) it forGroup: (CKGroup*) group { BKBookmark *item = (BKBookmark *) it; if ([super removeItem: item forGroup: group] == YES) { /* In BookmarkKit, an item can have only one parent. * If it is remove from a group, it should be at top level. */ [item setTopLevel: BKTopLevel]; [_topLevelRecords addObject: item]; return YES; } else { [item setTopLevel: BKUndecidedTopLevel]; return NO; } } - (BOOL) addSubgroup: (CKGroup*) g forGroup: (CKGroup*) g2 { BKGroup *g1 = (BKGroup *) g; if ([g1 isTopLevel] == BKNotTopLevel) { /* Has parent already. */ return NO; } if ([super addSubgroup: g1 forGroup: g2] == YES) { [g1 setTopLevel: BKNotTopLevel]; [_topLevelRecords removeObject: g1]; return YES; } else { [g1 setTopLevel: BKUndecidedTopLevel]; return NO; } } - (BOOL) removeSubgroup: (CKGroup*) g forGroup: (CKGroup*) g2 { BKGroup *g1 = (BKGroup *) g; if ([super removeSubgroup: g1 forGroup: g2] == YES) { /* In BookmarkKit, an item can have only one parent. * If it is remove from a group, it should be at top level. */ [g1 setTopLevel: BKTopLevel]; [_topLevelRecords addObject: g1]; return YES; } else { [g1 setTopLevel: BKUndecidedTopLevel]; return NO; } } - (id) initWithLocation: (NSString *) location { self = [self initWithLocation: location itemClass: [BKBookmark class] groupClass: [BKGroup class]]; /* Found all top level records */ _topLevelRecords = [[NSMutableArray alloc] init]; NSEnumerator *e = [[self items] objectEnumerator]; CKRecord *r; NSNumber *n; while ((r = [e nextObject])) { n = [r valueForProperty: kBKTopLevelOrderProperty]; if (n) { [_topLevelRecords addObject: r]; } } e = [[self groups] objectEnumerator]; while ((r = [e nextObject])) { n = [r valueForProperty: kBKTopLevelOrderProperty]; if (n) { [_topLevelRecords addObject: r]; } } [_topLevelRecords sortUsingSelector: @selector(compareTopLevelOrder:)]; e = [_topLevelRecords objectEnumerator]; while ((r = [e nextObject])) { [r removeValueForProperty: kBKTopLevelOrderProperty]; } return self; } - (void) dealloc { DESTROY(_topLevelRecords); [super dealloc]; } @end