Revision: 2915
          http://skim-app.svn.sourceforge.net/skim-app/?rev=2915&view=rev
Author:   hofman
Date:     2007-09-13 05:49:49 -0700 (Thu, 13 Sep 2007)

Log Message:
-----------
Folders for bookmarks. Shown using submenus in the Bookmarks menu, and 
displayed hierarchically in an outline view. 

Modified Paths:
--------------
    trunk/Dutch.lproj/BookmarksWindow.nib/classes.nib
    trunk/Dutch.lproj/BookmarksWindow.nib/keyedobjects.nib
    trunk/English.lproj/BookmarksWindow.nib/classes.nib
    trunk/English.lproj/BookmarksWindow.nib/keyedobjects.nib
    trunk/French.lproj/BookmarksWindow.nib/classes.nib
    trunk/French.lproj/BookmarksWindow.nib/keyedobjects.nib
    trunk/Italian.lproj/BookmarksWindow.nib/classes.nib
    trunk/Italian.lproj/BookmarksWindow.nib/keyedobjects.nib
    trunk/SKApplicationController.m
    trunk/SKBookmarkController.h
    trunk/SKBookmarkController.m

Modified: trunk/Dutch.lproj/BookmarksWindow.nib/classes.nib
===================================================================
--- trunk/Dutch.lproj/BookmarksWindow.nib/classes.nib   2007-09-13 08:57:04 UTC 
(rev 2914)
+++ trunk/Dutch.lproj/BookmarksWindow.nib/classes.nib   2007-09-13 12:49:49 UTC 
(rev 2915)
@@ -1,14 +1,27 @@
 {
     IBClasses = (
         {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
+        {CLASS = NSObject; LANGUAGE = ObjC; }, 
         {CLASS = SKBookmark; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
         {
+            ACTIONS = {insertBookmarkFolder = id; }; 
             CLASS = SKBookmarkController; 
             LANGUAGE = ObjC; 
-            OUTLETS = {statusBar = SKStatusBar; tableView = SKTableView; }; 
+            OUTLETS = {outlineView = SKOutlineView; statusBar = SKStatusBar; 
}; 
             SUPERCLASS = NSWindowController; 
         }, 
         {
+            ACTIONS = {
+                copy = id; 
+                delete = id; 
+                scrollToBeginningOfDocument = id; 
+                scrollToEndOfDocument = id; 
+            }; 
+            CLASS = SKOutlineView; 
+            LANGUAGE = ObjC; 
+            SUPERCLASS = NSOutlineView; 
+        }, 
+        {
             ACTIONS = {startAnimation = id; stopAnimation = id; }; 
             CLASS = SKStatusBar; 
             LANGUAGE = ObjC; 

Modified: trunk/Dutch.lproj/BookmarksWindow.nib/keyedobjects.nib
===================================================================
(Binary files differ)

Modified: trunk/English.lproj/BookmarksWindow.nib/classes.nib
===================================================================
--- trunk/English.lproj/BookmarksWindow.nib/classes.nib 2007-09-13 08:57:04 UTC 
(rev 2914)
+++ trunk/English.lproj/BookmarksWindow.nib/classes.nib 2007-09-13 12:49:49 UTC 
(rev 2915)
@@ -1,14 +1,27 @@
 {
     IBClasses = (
         {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
+        {CLASS = NSObject; LANGUAGE = ObjC; }, 
         {CLASS = SKBookmark; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
         {
+            ACTIONS = {insertBookmarkFolder = id; }; 
             CLASS = SKBookmarkController; 
             LANGUAGE = ObjC; 
-            OUTLETS = {statusBar = SKStatusBar; tableView = SKTableView; }; 
+            OUTLETS = {outlineView = SKOutlineView; statusBar = SKStatusBar; 
}; 
             SUPERCLASS = NSWindowController; 
         }, 
         {
+            ACTIONS = {
+                copy = id; 
+                delete = id; 
+                scrollToBeginningOfDocument = id; 
+                scrollToEndOfDocument = id; 
+            }; 
+            CLASS = SKOutlineView; 
+            LANGUAGE = ObjC; 
+            SUPERCLASS = NSOutlineView; 
+        }, 
+        {
             ACTIONS = {startAnimation = id; stopAnimation = id; }; 
             CLASS = SKStatusBar; 
             LANGUAGE = ObjC; 

Modified: trunk/English.lproj/BookmarksWindow.nib/keyedobjects.nib
===================================================================
(Binary files differ)

Modified: trunk/French.lproj/BookmarksWindow.nib/classes.nib
===================================================================
--- trunk/French.lproj/BookmarksWindow.nib/classes.nib  2007-09-13 08:57:04 UTC 
(rev 2914)
+++ trunk/French.lproj/BookmarksWindow.nib/classes.nib  2007-09-13 12:49:49 UTC 
(rev 2915)
@@ -1,14 +1,27 @@
 {
     IBClasses = (
         {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
+        {CLASS = NSObject; LANGUAGE = ObjC; }, 
         {CLASS = SKBookmark; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
         {
+            ACTIONS = {insertBookmarkFolder = id; }; 
             CLASS = SKBookmarkController; 
             LANGUAGE = ObjC; 
-            OUTLETS = {statusBar = SKStatusBar; tableView = SKTableView; }; 
+            OUTLETS = {outlineView = SKOutlineView; statusBar = SKStatusBar; 
}; 
             SUPERCLASS = NSWindowController; 
         }, 
         {
+            ACTIONS = {
+                copy = id; 
+                delete = id; 
+                scrollToBeginningOfDocument = id; 
+                scrollToEndOfDocument = id; 
+            }; 
+            CLASS = SKOutlineView; 
+            LANGUAGE = ObjC; 
+            SUPERCLASS = NSOutlineView; 
+        }, 
+        {
             ACTIONS = {startAnimation = id; stopAnimation = id; }; 
             CLASS = SKStatusBar; 
             LANGUAGE = ObjC; 

Modified: trunk/French.lproj/BookmarksWindow.nib/keyedobjects.nib
===================================================================
(Binary files differ)

Modified: trunk/Italian.lproj/BookmarksWindow.nib/classes.nib
===================================================================
--- trunk/Italian.lproj/BookmarksWindow.nib/classes.nib 2007-09-13 08:57:04 UTC 
(rev 2914)
+++ trunk/Italian.lproj/BookmarksWindow.nib/classes.nib 2007-09-13 12:49:49 UTC 
(rev 2915)
@@ -1,14 +1,27 @@
 {
     IBClasses = (
         {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
+        {CLASS = NSObject; LANGUAGE = ObjC; }, 
         {CLASS = SKBookmark; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, 
         {
+            ACTIONS = {insertBookmarkFolder = id; }; 
             CLASS = SKBookmarkController; 
             LANGUAGE = ObjC; 
-            OUTLETS = {statusBar = SKStatusBar; tableView = SKTableView; }; 
+            OUTLETS = {outlineView = SKOutlineView; statusBar = SKStatusBar; 
}; 
             SUPERCLASS = NSWindowController; 
         }, 
         {
+            ACTIONS = {
+                copy = id; 
+                delete = id; 
+                scrollToBeginningOfDocument = id; 
+                scrollToEndOfDocument = id; 
+            }; 
+            CLASS = SKOutlineView; 
+            LANGUAGE = ObjC; 
+            SUPERCLASS = NSOutlineView; 
+        }, 
+        {
             ACTIONS = {startAnimation = id; stopAnimation = id; }; 
             CLASS = SKStatusBar; 
             LANGUAGE = ObjC; 

Modified: trunk/Italian.lproj/BookmarksWindow.nib/keyedobjects.nib
===================================================================
(Binary files differ)

Modified: trunk/SKApplicationController.m
===================================================================
--- trunk/SKApplicationController.m     2007-09-13 08:57:04 UTC (rev 2914)
+++ trunk/SKApplicationController.m     2007-09-13 12:49:49 UTC (rev 2915)
@@ -239,19 +239,31 @@
 
 #pragma mark Support
 
+- (void)addMenuItemsForBookmarks:(NSArray *)bookmarks toMenu:(NSMenu *)menu {
+    int i, iMax = [bookmarks count];
+    for (i = 0; i < iMax; i++) {
+        SKBookmark *bm = [bookmarks objectAtIndex:i];
+        if ([bm bookmarkType] == SKBookmarkTypeFolder) {
+            NSMenu *submenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] 
initWithTitle:[bm label]] autorelease];
+            NSMenuItem *item = [menu addItemWithTitle:[bm label] action:NULL 
keyEquivalent:@""];
+            [item setSubmenu:submenu];
+            [self addMenuItemsForBookmarks:[bm children] toMenu:submenu];
+        } else {
+            NSMenuItem *item = [menu addItemWithTitle:[bm label] 
action:@selector(openBookmark:)  keyEquivalent:@""];
+            [item setTarget:self];
+            [item setRepresentedObject:bm];
+        }
+    }
+}
+
 - (void)menuNeedsUpdate:(NSMenu *)menu {
     NSArray *bookmarks = [[SKBookmarkController sharedBookmarkController] 
bookmarks];
-    int i = [menu numberOfItems], iMax = [bookmarks count];
+    int i = [menu numberOfItems];
     while (--i > 1)
         [menu removeItemAtIndex:i];
-    if (iMax > 0)
+    if ([bookmarks count] > 0)
         [menu addItem:[NSMenuItem separatorItem]];
-    for (i = 0; i < iMax; i++) {
-        SKBookmark *bm = [bookmarks objectAtIndex:i];
-        NSMenuItem *item = [menu addItemWithTitle:[bm label] 
action:@selector(openBookmark:)  keyEquivalent:@""];
-        [item setTarget:self];
-        [item setRepresentedObject:bm];
-    }
+    [self addMenuItemsForBookmarks:bookmarks toMenu:menu];
 }
 
 - (void)appleRemoteButton:(AppleRemoteEventIdentifier)buttonIdentifier 
pressedDown:(BOOL)pressedDown {

Modified: trunk/SKBookmarkController.h
===================================================================
--- trunk/SKBookmarkController.h        2007-09-13 08:57:04 UTC (rev 2914)
+++ trunk/SKBookmarkController.h        2007-09-13 12:49:49 UTC (rev 2915)
@@ -38,10 +38,15 @@
 
 #import <Cocoa/Cocoa.h>
 
[EMAIL PROTECTED] SKTableView, SKStatusBar;
[EMAIL PROTECTED] SKOutlineView, SKTableView, SKStatusBar;
 
+enum {
+    SKBookmarkTypeBookmark,
+    SKBookmarkTypeFolder
+};
+
 @interface SKBookmarkController : NSWindowController {
-    IBOutlet SKTableView *tableView;
+    IBOutlet SKOutlineView *outlineView;
     IBOutlet SKStatusBar *statusBar;
     NSMutableArray *bookmarks;
     NSMutableArray *recentDocuments;
@@ -63,6 +68,8 @@
 - (NSString *)bookmarksFilePath;
 - (void)openBookmarks:(NSArray *)items;
 
+- (IBAction)insertBookmarkFolder:(id)sender;
+
 - (NSArray *)recentDocuments;
 - (void)addRecentDocumentForPath:(NSString *)path 
pageIndex:(unsigned)pageIndex snapshots:(NSArray *)setups;
 - (unsigned int)pageIndexForRecentDocumentAtPath:(NSString *)path;
@@ -78,14 +85,21 @@
     NSData *aliasData;
     NSString *label;
     unsigned int pageIndex;
+    NSMutableArray *children;
+    SKBookmark *parent;
+    int bookmarkType;
 }
 
 - (id)initWithPath:(NSString *)aPath aliasData:(NSData *)aData 
pageIndex:(unsigned)aPageIndex label:(NSString *)aLabel;
 - (id)initWithPath:(NSString *)aPath pageIndex:(unsigned)aPageIndex 
label:(NSString *)aLabel;
+- (id)initFolderWithChildren:(NSArray *)aChildren label:(NSString *)aLabel;
+- (id)initFolderWithLabel:(NSString *)aLabel;
 - (id)initWithDictionary:(NSDictionary *)dictionary;
 
 - (NSDictionary *)dictionaryValue;
 
+- (int)bookmarkType;
+
 - (NSString *)path;
 - (NSData *)aliasData;
 - (NSString *)resolvedPath;
@@ -94,4 +108,13 @@
 - (NSString *)label;
 - (void)setLabel:(NSString *)newLabel;
 
+- (SKBookmark *)parent;
+- (void)setParent:(SKBookmark *)newParent;
+- (NSArray *)children;
+- (void)insertChild:(SKBookmark *)child atIndex:(unsigned int)index;
+- (void)addChild:(SKBookmark *)child;
+- (void)removeChild:(SKBookmark *)child;
+
+- (BOOL)isDescendantOf:(SKBookmark *)bookmark;
+
 @end

Modified: trunk/SKBookmarkController.m
===================================================================
--- trunk/SKBookmarkController.m        2007-09-13 08:57:04 UTC (rev 2914)
+++ trunk/SKBookmarkController.m        2007-09-13 12:49:49 UTC (rev 2915)
@@ -41,6 +41,7 @@
 #import "SKDocument.h"
 #import "SKMainWindowController.h"
 #import "Files_SKExtensions.h"
+#import "SKOutlineView.h"
 #import "SKTableView.h"
 #import "SKTypeSelectHelper.h"
 #import "SKStatusBar.h"
@@ -116,9 +117,9 @@
     
     SKTypeSelectHelper *typeSelectHelper = [[[SKTypeSelectHelper alloc] init] 
autorelease];
     [typeSelectHelper setDataSource:self];
-    [tableView setTypeSelectHelper:typeSelectHelper];
+    [outlineView setTypeSelectHelper:typeSelectHelper];
     
-    [tableView registerForDraggedTypes:[NSArray 
arrayWithObjects:SKBookmarkRowsPboardType, nil]];
+    [outlineView registerForDraggedTypes:[NSArray 
arrayWithObjects:SKBookmarkRowsPboardType, nil]];
 }
 
 #pragma mark Bookmarks
@@ -143,13 +144,13 @@
 - (void)insertObject:(id)obj inBookmarksAtIndex:(unsigned)index {
     [[[self undoManager] prepareWithInvocationTarget:self] 
removeObjectFromBookmarksAtIndex:index];
     [bookmarks insertObject:obj atIndex:index];
-    [self saveBookmarks];
+    [self handleBookmarkChangedNotification:nil];
 }
 
 - (void)removeObjectFromBookmarksAtIndex:(unsigned)index {
     [[[self undoManager] prepareWithInvocationTarget:self] 
insertObject:[bookmarks objectAtIndex:index] inBookmarksAtIndex:index];
     [bookmarks removeObjectAtIndex:index];
-    [self saveBookmarks];
+    [self handleBookmarkChangedNotification:nil];
 }
 
 - (void)addBookmarkForPath:(NSString *)path pageIndex:(unsigned)pageIndex 
label:(NSString *)label {
@@ -160,6 +161,31 @@
     [bookmark release];
 }
 
+- (NSArray *)childrenOfBookmark:(SKBookmark *)bookmark {
+    return bookmark ? [bookmark children] : bookmarks;
+}
+
+- (unsigned int)indexOfChildBookmark:(SKBookmark *)bookmark {
+    SKBookmark *parent = [bookmark parent];
+    NSArray *children = parent ? [parent children] : bookmarks;
+    return [children indexOfObject:bookmark];
+}
+
+- (void)bookmark:(SKBookmark *)bookmark insertChildBookmark:(SKBookmark 
*)child atIndex:(unsigned int)index {
+    if (bookmark)
+        [bookmark insertChild:child atIndex:index];
+    else
+        [self insertObject:child inBookmarksAtIndex:index];
+}
+
+- (void)removeChildBookmark:(SKBookmark *)bookmark {
+    SKBookmark *parent = [bookmark parent];
+    if (parent)
+        [parent removeChild:bookmark];
+    else
+        [[self mutableArrayValueForKey:@"bookmarks"] removeObject:bookmark];
+}
+
 #pragma mark Recent Documents
 
 - (NSArray *)recentDocuments {
@@ -229,6 +255,7 @@
 
 - (void)handleBookmarkChangedNotification:(NSNotification *)notification {
     [self saveBookmarks];
+    [outlineView reloadData];
 }
 
 - (NSString *)bookmarksFilePath {
@@ -281,6 +308,31 @@
     }
 }
 
+- (IBAction)insertBookmarkFolder:(id)sender {
+    SKBookmark *folder = [[[SKBookmark alloc] initFolderWithLabel:@"Folder"] 
autorelease];
+    int rowIndex = [[outlineView selectedRowIndexes] lastIndex];
+    SKBookmark *item = nil;
+    unsigned int index = [bookmarks count];
+    
+    if (rowIndex != NSNotFound) {
+        SKBookmark *selectedItem = [outlineView itemAtRow:rowIndex];
+        if ([outlineView isItemExpanded:selectedItem]) {
+            item = [selectedItem parent];
+            if (item)
+                index = [[item children] indexOfObject:selectedItem] + 1;
+            else
+                index = [bookmarks indexOfObject:selectedItem] + 1;
+        } else {
+            item = selectedItem;
+            index = [[item children] count];
+        }
+    }
+    if (item)
+        [item insertChild:folder atIndex:index];
+    else
+        [self insertObject:folder inBookmarksAtIndex:index];
+}
+
 #pragma mark Undo support
 
 - (NSUndoManager *)undoManager {
@@ -293,83 +345,131 @@
     return [self undoManager];
 }
 
-#pragma mark NSTableView datasource methods
+#pragma mark NSOutlineView datasource methods
 
-- (int)numberOfRowsInTableView:(NSTableView *)tv { return 0; }
+- (int)outlineView:(NSOutlineView *)ov numberOfChildrenOfItem:(id)item {
+    return [[self childrenOfBookmark:item] count];
+}
 
-- (id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn 
*)tableColumn row:(int)row { return nil; }
+- (BOOL)outlineView:(NSOutlineView *)ov isItemExpandable:(id)item {
+    return [item bookmarkType] == SKBookmarkTypeFolder;
+}
 
-- (BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet 
*)rowIndexes toPasteboard:(NSPasteboard *)pboard {
+- (id)outlineView:(NSOutlineView *)ov child:(int)index ofItem:(id)item {
+    return [[self childrenOfBookmark:item] objectAtIndex:index];
+}
+
+- (id)outlineView:(NSOutlineView *)ov objectValueForTableColumn:(NSTableColumn 
*)tableColumn byItem:(id)item {
+    NSString *tcID = [tableColumn identifier];
+    if ([tcID isEqualToString:@"label"]) {
+        return [item label];
+    } else if ([tcID isEqualToString:@"file"]) {
+        return [item resolvedPath];
+    } else if ([tcID isEqualToString:@"page"]) {
+        return [[item pageNumber] stringValue];
+    }
+    return nil;
+}
+
+- (void)outlineView:(NSOutlineView *)ov setObjectValue:(id)object 
forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
+    NSString *tcID = [tableColumn identifier];
+    if ([tcID isEqualToString:@"label"]) {
+        [item setLabel:object];
+    }
+}
+
+- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray *)items 
toPasteboard:(NSPasteboard *)pboard {
+    SKBookmark *item = [items objectAtIndex:0];
     [pboard declareTypes:[NSArray arrayWithObjects:SKBookmarkRowsPboardType, 
nil] owner:nil];
-    [pboard setPropertyList:[NSNumber numberWithUnsignedInt:[rowIndexes 
firstIndex]] forType:SKBookmarkRowsPboardType];
+    [pboard setPropertyList:[NSNumber numberWithUnsignedInt:[outlineView 
rowForItem:item]] forType:SKBookmarkRowsPboardType];
     return YES;
 }
 
-- (NSDragOperation)tableView:(NSTableView *)tv validateDrop:(id 
<NSDraggingInfo>)info proposedRow:(int)row 
proposedDropOperation:(NSTableViewDropOperation)op {
+- (NSDragOperation)outlineView:(NSOutlineView *)ov validateDrop:(id 
<NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index {
     NSPasteboard *pboard = [info draggingPasteboard];
     NSString *type = [pboard availableTypeFromArray:[NSArray 
arrayWithObjects:SKBookmarkRowsPboardType, nil]];
     
     if (type) {
-        [tv setDropRow:row == -1 ? [tv numberOfRows] : row 
dropOperation:NSTableViewDropAbove];
+        if (index == NSOutlineViewDropOnItemIndex) {
+            if ([item bookmarkType] == SKBookmarkTypeFolder && [outlineView 
isItemExpanded:item]) {
+                [ov setDropItem:item dropChildIndex:0];
+            } else if ([item parent]) {
+                [ov setDropItem:[item parent] dropChildIndex:[[[item parent] 
children] indexOfObject:item] + 1];
+            } else if (item) {
+                [ov setDropItem:nil dropChildIndex:[bookmarks 
indexOfObject:item] + 1];
+            } else {
+                [ov setDropItem:nil dropChildIndex:[bookmarks count]];
+            }
+        }
         return NSDragOperationMove;
     }
     return NSDragOperationNone;
 }
 
-- (BOOL)tableView:(NSTableView *)tv acceptDrop:(id <NSDraggingInfo>)info 
row:(int)row dropOperation:(NSTableViewDropOperation)op {
+- (BOOL)outlineView:(NSOutlineView *)ov acceptDrop:(id <NSDraggingInfo>)info 
item:(id)item childIndex:(int)index {
     NSPasteboard *pboard = [info draggingPasteboard];
     NSString *type = [pboard availableTypeFromArray:[NSArray 
arrayWithObjects:SKBookmarkRowsPboardType, nil]];
     
     if (type) {
         int draggedRow = [[pboard 
propertyListForType:SKBookmarkRowsPboardType] intValue];
-        SKBookmark *bookmark = [[bookmarks objectAtIndex:draggedRow] retain];
-        [self removeObjectFromBookmarksAtIndex:draggedRow];
-        [self insertObject:bookmark inBookmarksAtIndex:row < draggedRow ? row 
: row - 1];
+        SKBookmark *bookmark = [outlineView itemAtRow:draggedRow];
+        if ([(SKBookmark *)item isDescendantOf:bookmark])
+            return NO;
+        if ([bookmark parent] == item && index > (int)[self 
indexOfChildBookmark:bookmark])
+            index--;
+        [bookmark retain];
+        [self removeChildBookmark:bookmark];
+        [self bookmark:item insertChildBookmark:bookmark atIndex:index];
         [bookmark release];
-        [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] 
byExtendingSelection:NO];
+        [outlineView selectRowIndexes:[NSIndexSet 
indexSetWithIndex:[outlineView rowForItem:bookmark]] byExtendingSelection:NO];
         return YES;
     }
     return NO;
 }
 
-#pragma mark NSTableView delegate methods
+#pragma mark NSOutlineView delegate methods
 
-- (NSString *)tableView:(NSTableView *)tv toolTipForCell:(NSCell *)cell 
rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)tableColumn row:(int)row 
mouseLocation:(NSPoint)mouseLocation {
-    NSString *tcID = [tableColumn identifier];
-    SKBookmark *bookmark = [self objectInBookmarksAtIndex:row];
+- (NSString *)outlineView:(NSOutlineView *)ov toolTipForCell:(NSCell *)cell 
rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)tc item:(id)item 
mouseLocation:(NSPoint)mouseLocation {
+    NSString *tcID = [tc identifier];
     
     if ([tcID isEqualToString:@"label"]) {
-        return [bookmark label];
+        return [item label];
     } else if ([tcID isEqualToString:@"file"]) {
-        return [bookmark resolvedPath];
+        return [item resolvedPath];
     } else if ([tcID isEqualToString:@"page"]) {
-        return [[bookmark pageNumber] stringValue];
+        return [[item pageNumber] stringValue];
     }
     return nil;
 }
 
-- (void)tableView:(NSTableView *)aTableView deleteRowsWithIndexes:(NSIndexSet 
*)rowIndexes {
-    int row = [rowIndexes firstIndex];
-    [self removeObjectFromBookmarksAtIndex:row];
+- (void)outlineView:(NSOutlineView *)ov deleteItems:(NSArray *)items {
+    SKBookmark *item = [items objectAtIndex:0];
+    [self removeChildBookmark:item];
 }
 
-- (BOOL)tableView:(NSTableView *)aTableView 
canDeleteRowsWithIndexes:(NSIndexSet *)rowIndexes {
-    return YES;
+- (BOOL)outlineView:(NSOutlineView *)ov canDeleteItems:(NSArray *)items {
+    return [items count] > 0;
 }
 
 #pragma mark SKTypeSelectHelper datasource protocol
 
 - (NSArray *)typeSelectHelperSelectionItems:(SKTypeSelectHelper 
*)typeSelectHelper {
-    return [bookmarks valueForKey:@"label"];
+    int i, count = [outlineView numberOfRows];
+    NSMutableArray *labels = [NSMutableArray arrayWithCapacity:count];
+    for (i = 0; i < count; i++) {
+        NSString *label = [[outlineView itemAtRow:i] label];
+        [labels addObject:label ? label : @""];
+    }
+    return labels;
 }
 
 - (unsigned int)typeSelectHelperCurrentlySelectedIndex:(SKTypeSelectHelper 
*)typeSelectHelper {
-    return [[tableView selectedRowIndexes] lastIndex];
+    return [[outlineView selectedRowIndexes] lastIndex];
 }
 
 - (void)typeSelectHelper:(SKTypeSelectHelper *)typeSelectHelper 
selectItemAtIndex:(unsigned int)itemIndex {
-    [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:itemIndex] 
byExtendingSelection:NO];
-    [tableView scrollRowToVisible:itemIndex];
+    [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:itemIndex] 
byExtendingSelection:NO];
+    [outlineView scrollRowToVisible:itemIndex];
 }
 
 - (void)typeSelectHelper:(SKTypeSelectHelper *)typeSelectHelper 
didFailToFindMatchForSearchString:(NSString *)searchString {
@@ -391,10 +491,12 @@
 
 - (id)initWithPath:(NSString *)aPath aliasData:(NSData *)aData 
pageIndex:(unsigned)aPageIndex label:(NSString *)aLabel {
     if (self = [super init]) {
+        bookmarkType = SKBookmarkTypeBookmark;
         path = [aPath copy];
         aliasData = [aData copy];
         pageIndex = aPageIndex;
         label = [aLabel copy];
+        children = nil;
     }
     return self;
 }
@@ -403,12 +505,41 @@
     return [self initWithPath:aPath aliasData:[[BDAlias aliasWithPath:aPath] 
aliasData] pageIndex:aPageIndex label:aLabel];
 }
 
+- (id)initFolderWithChildren:(NSArray *)aChildren label:(NSString *)aLabel {
+    if (self = [super init]) {
+        bookmarkType = SKBookmarkTypeFolder;
+        path = nil;
+        aliasData = nil;
+        pageIndex = NSNotFound;
+        label = [aLabel copy];
+        children = [aChildren mutableCopy];
+        [children makeObjectsPerformSelector:@selector(setParent:) 
withObject:self];
+    }
+    return self;
+}
+
+- (id)initFolderWithLabel:(NSString *)aLabel {
+    return [self initFolderWithChildren:[NSArray array] label:aLabel];
+}
+
 - (id)initWithDictionary:(NSDictionary *)dictionary {
-    return [self initWithPath:[dictionary objectForKey:@"path"] 
aliasData:[dictionary objectForKey:@"_BDAlias"] pageIndex:[[dictionary 
objectForKey:@"pageIndex"] unsignedIntValue] label:[dictionary 
objectForKey:@"label"]];
+    if ([[dictionary objectForKey:@"type"] isEqualToString:@"folder"]) {
+        NSEnumerator *dictEnum = [[dictionary objectForKey:@"children"] 
objectEnumerator];
+        NSDictionary *dict;
+        NSMutableArray *newChildren = [NSMutableArray array];
+        while (dict = [dictEnum nextObject])
+            [newChildren addObject:[[[[self class] alloc] 
initWithDictionary:dict] autorelease]];
+        return [self initFolderWithChildren:newChildren label:[dictionary 
objectForKey:@"label"]];
+    } else {
+        return [self initWithPath:[dictionary objectForKey:@"path"] 
aliasData:[dictionary objectForKey:@"_BDAlias"] pageIndex:[[dictionary 
objectForKey:@"pageIndex"] unsignedIntValue] label:[dictionary 
objectForKey:@"label"]];
+    }
 }
 
 - (id)copyWithZone:(NSZone *)aZone {
-    return [[[self class] allocWithZone:aZone] initWithPath:path 
aliasData:aliasData pageIndex:pageIndex label:label];
+    if (bookmarkType == SKBookmarkTypeFolder)
+        return [[[self class] allocWithZone:aZone] 
initFolderWithChildren:[[[NSArray alloc] initWithArray:children copyItems:YES] 
autorelease] label:label];
+    else
+        return [[[self class] allocWithZone:aZone] initWithPath:path 
aliasData:aliasData pageIndex:pageIndex label:label];
 }
 
 - (void)dealloc {
@@ -416,13 +547,21 @@
     [path release];
     [aliasData release];
     [label release];
+    [children release];
     [super dealloc];
 }
 
 - (NSDictionary *)dictionaryValue {
-    return [NSDictionary dictionaryWithObjectsAndKeys:path, @"path", 
aliasData, @"_BDAlias", [NSNumber numberWithUnsignedInt:pageIndex], 
@"pageIndex", label, @"label", nil];
+    if (bookmarkType == SKBookmarkTypeFolder)
+        return [NSDictionary dictionaryWithObjectsAndKeys:@"folder", @"type", 
[children valueForKey:@"dictionaryValue"], @"children", label, @"label", nil];
+    else
+        return [NSDictionary dictionaryWithObjectsAndKeys:@"bookmark", 
@"type", path, @"path", aliasData, @"_BDAlias", [NSNumber 
numberWithUnsignedInt:pageIndex], @"pageIndex", label, @"label", nil];
 }
 
+- (int)bookmarkType {
+    return bookmarkType;
+}
+
 - (NSString *)path {
     return [[path retain] autorelease];
 }
@@ -443,7 +582,7 @@
 }
 
 - (NSNumber *)pageNumber {
-    return [NSNumber numberWithUnsignedInt:pageIndex + 1];
+    return pageIndex == NSNotFound ? nil : [NSNumber 
numberWithUnsignedInt:pageIndex + 1];
 }
 
 - (NSString *)label {
@@ -460,4 +599,47 @@
     }
 }
 
+- (SKBookmark *)parent {
+    return parent;
+}
+
+- (void)setParent:(SKBookmark *)newParent {
+    parent = newParent;
+}
+
+- (NSArray *)children {
+    return children;
+}
+
+- (void)insertChild:(SKBookmark *)child atIndex:(unsigned int)index {
+    NSUndoManager *undoManager = [[SKBookmarkController 
sharedBookmarkController] undoManager];
+    [(SKBookmark *)[undoManager prepareWithInvocationTarget:self] 
removeChild:child];
+    [children insertObject:child atIndex:index];
+    [child setParent:self];
+    [[NSNotificationCenter defaultCenter] 
postNotificationName:SKBookmarkChangedNotification object:self];
+}
+
+- (void)addChild:(SKBookmark *)child {
+    [self insertChild:child atIndex:[children count]];
+}
+
+- (void)removeChild:(SKBookmark *)child {
+    NSUndoManager *undoManager = [[SKBookmarkController 
sharedBookmarkController] undoManager];
+    [(SKBookmark *)[undoManager prepareWithInvocationTarget:self] 
insertChild:child atIndex:[[self children] indexOfObject:child]];
+    [children removeObject:child];
+    [[NSNotificationCenter defaultCenter] 
postNotificationName:SKBookmarkChangedNotification object:self];
+}
+
+- (BOOL)isDescendantOf:(SKBookmark *)bookmark {
+    if (self == bookmark)
+        return YES;
+    NSEnumerator *childEnum = [[bookmark children] objectEnumerator];
+    SKBookmark *child;
+    while (child = [childEnum nextObject]) {
+        if ([self isDescendantOf:child])
+            return YES;
+    }
+    return NO;
+}
+
 @end


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Skim-app-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/skim-app-commit

Reply via email to