Fix bug 169816: implement bookmark sorting (really arranging) in Camino. Selecting a single folder will sort its children. Selecting two or more items will sort them together. Holding down the Option key will do a deep sort of all selected items. If nothing is selected, the current collection is sorted (if allowed).

Fix bug 322809: bookmarks toolbar and menu folders should have localized names.
Other fixes:
Re-order the bookmarks and history context menus slightly to reduce the number of separators.
Fix the bookmarks toolbar to not respond to every bookmark update by looking for a button with the changed bookmark.
Fix the bookmarks toolbar to notice child re-orderings and update appropriately.
Clean up the key handling code in ExtendedOutlineView and ExtendedTableView, and make our outline and table views respond to the home and end keys by scrolling to top/bottom.
This commit is contained in:
smfr%smfr.org 2006-01-15 21:03:32 +00:00
Родитель 226f5ad779
Коммит dc67e36797
18 изменённых файлов: 531 добавлений и 157 удалений

Просмотреть файл

@ -10,7 +10,9 @@
addBookmarkFolder = id;
addBookmarkSeparator = id;
addCollection = id;
arrange = id;
copy = id;
copyURLs = id;
cut = id;
delete = id;
deleteBookmarks = id;
@ -50,7 +52,12 @@
};
SUPERCLASS = NSObject;
},
{CLASS = BookmarksEditingView; LANGUAGE = ObjC; SUPERCLASS = NSView; },
{
CLASS = BookmarksEditingView;
LANGUAGE = ObjC;
OUTLETS = {mDelegate = id; };
SUPERCLASS = NSView;
},
{CLASS = ExtendedOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; },
{CLASS = ExtendedTableView; LANGUAGE = ObjC; SUPERCLASS = NSTableView; },
{

Просмотреть файл

@ -23,15 +23,15 @@
<key>302</key>
<string>17 392 130 49 0 0 1600 1002 </string>
<key>64</key>
<string>367 446 170 118 0 0 1600 1002 </string>
<string>367 446 180 118 0 0 1600 1002 </string>
<key>68</key>
<string>174 384 142 87 0 0 1600 1002 </string>
<key>70</key>
<string>206 320 138 68 0 0 1600 1002 </string>
<string>210 319 186 118 0 0 1600 1002 </string>
</dict>
<key>IBFramework Version</key>
<string>437.0</string>
<key>IBSystem Version</key>
<string>8C46</string>
<string>8F46</string>
</dict>
</plist>

Двоичные данные
camino/resources/localized/English.lproj/BookmarksEditing.nib/keyedobjects.nib сгенерированный

Двоичный файл не отображается.

Двоичный файл не отображается.

Просмотреть файл

@ -125,10 +125,11 @@ enum {
-(void) deleteFromSmartFolderChildAtIndex:(unsigned)index;
// sorting
- (void)sortChildrenUsingSelector:(SEL)inSelector reverseSort:(BOOL)inReverse sortDeep:(BOOL)inDeep;
- (void)sortChildrenUsingPrimarySelector:(SEL)inSelector primaryReverseSort:(BOOL)inReverse
secondarySelector:(SEL)inSecondarySelector secondaryReverseSort:(BOOL)inSecondaryReverse
sortDeep:(BOOL)inDeep;
// Arrange the given items (which must be children of this folder) next to eachother and in
// the order determined by the selector. Undoable.
- (void)arrangeChildItems:(NSArray*)inChildItems usingSelector:(SEL)inSelector reverseSort:(BOOL)inReverse;
// Sort the children of this folder, optionally sorting deep. Optionally undoable.
- (void)sortChildrenUsingSelector:(SEL)inSelector reverseSort:(BOOL)inReverse sortDeep:(BOOL)inDeep undoable:(BOOL)inUndoable;
// generation menus
-(void) buildFlatFolderList:(NSMenu *)menu depth:(unsigned)pad;

Просмотреть файл

@ -121,6 +121,9 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
- (NSString*)expandKeyword:(NSString*)keyword inString:(NSString*)location;
- (NSArray *)folderItemsWithClass:(Class)theClass;
// used for undo
- (void)arrangeChildrenWithOrder:(NSArray*)inChildArray;
@end
#pragma mark -
@ -478,14 +481,16 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
[self insertChild:aChild atIndex:[self count] isMove:NO];
}
-(void) insertChild:(BookmarkItem *)aChild atIndex:(unsigned)aPosition isMove:(BOOL)aBool
-(void) insertChild:(BookmarkItem *)aChild atIndex:(unsigned)aPosition isMove:(BOOL)inIsMove
{
[aChild setParent:self];
unsigned insertPoint = [mChildArray count];
if (insertPoint > aPosition)
insertPoint = aPosition;
[mChildArray insertObject:aChild atIndex:insertPoint];
if (!aBool && ![self isSmartFolder]) {
if (!inIsMove && ![self isSmartFolder])
{
NSUndoManager* undoManager = [[BookmarkManager sharedBookmarkManager] undoManager];
[[undoManager prepareWithInvocationTarget:self] deleteChild:aChild];
if (![undoManager isUndoing]) {
@ -532,8 +537,39 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
}
}
- (void)sortChildrenUsingSelector:(SEL)inSelector reverseSort:(BOOL)inReverse sortDeep:(BOOL)inDeep
// move the given items together, sorted according to the sort selector.
// inChildItems is assumed to be in the same order as the children
- (void)arrangeChildItems:(NSArray*)inChildItems usingSelector:(SEL)inSelector reverseSort:(BOOL)inReverse
{
NSMutableArray* orderedItems = [NSMutableArray arrayWithArray:inChildItems];
BookmarkSortData sortData = { inSelector, [NSNumber numberWithBool:inReverse], NULL, nil };
[orderedItems sortUsingFunction:BookmarkItemSort context:&sortData];
// now build a new child array
NSMutableArray* newChildOrder = [[mChildArray mutableCopy] autorelease];
// save the index of the first (which won't change, since it's the first)
int firstChangedIndex = [newChildOrder indexOfObject:[inChildItems firstObject]];
if (firstChangedIndex == -1) return; // something went wrong
[newChildOrder removeObjectsInArray:inChildItems];
[newChildOrder replaceObjectsInRange:NSMakeRange(firstChangedIndex, 0) withObjectsFromArray:orderedItems];
// this makes it undoable
[self arrangeChildrenWithOrder:newChildOrder];
}
- (void)sortChildrenUsingSelector:(SEL)inSelector reverseSort:(BOOL)inReverse sortDeep:(BOOL)inDeep undoable:(BOOL)inUndoable
{
NSUndoManager* undoManager = [[BookmarkManager sharedBookmarkManager] undoManager];
if (inUndoable)
{
[undoManager beginUndoGrouping];
// record undo, back to existing order
[[undoManager prepareWithInvocationTarget:self] arrangeChildrenWithOrder:[NSArray arrayWithArray:mChildArray]];
}
BookmarkSortData sortData = { inSelector, [NSNumber numberWithBool:inReverse], NULL, nil };
[mChildArray sortUsingFunction:BookmarkItemSort context:&sortData];
@ -547,37 +583,42 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
while ((childItem = [enumerator nextObject]))
{
if ([childItem isKindOfClass:[BookmarkFolder class]])
[childItem sortChildrenUsingSelector:inSelector reverseSort:inReverse sortDeep:inDeep];
[childItem sortChildrenUsingSelector:inSelector reverseSort:inReverse sortDeep:inDeep undoable:inUndoable];
}
}
if (inUndoable)
{
[undoManager endUndoGrouping];
[undoManager setActionName:NSLocalizedString(@"Arrange Bookmarks", @"")];
}
}
- (void)sortChildrenUsingPrimarySelector:(SEL)inSelector primaryReverseSort:(BOOL)inReverse
secondarySelector:(SEL)inSecondarySelector secondaryReverseSort:(BOOL)inSecondaryReverse
sortDeep:(BOOL)inDeep
// used for undo
- (void)arrangeChildrenWithOrder:(NSArray*)inChildArray
{
BookmarkSortData sortData = { inSelector, [NSNumber numberWithBool:inReverse],
inSecondarySelector, [NSNumber numberWithBool:inSecondaryReverse]
};
[mChildArray sortUsingFunction:BookmarkItemSort context:&sortData];
// The undo manager automatically puts redo items in a group, so we don't have to
// (undoing sorting of nested folders will work OK)
NSUndoManager* undoManager = [[BookmarkManager sharedBookmarkManager] undoManager];
// record undo, back to existing order
[[undoManager prepareWithInvocationTarget:self] arrangeChildrenWithOrder:[NSArray arrayWithArray:mChildArray]];
if ([mChildArray count] != [inChildArray count])
{
NSLog(@"arrangeChildrenWithOrder: unmatched child array sizes");
return;
}
// Cheating here. The in array simply contains the items in the order we want,
// so use it.
[mChildArray removeAllObjects];
[mChildArray addObjectsFromArray:inChildArray];
// notify
[self itemChangedNote:self];
if (inDeep)
{
NSEnumerator *enumerator = [mChildArray objectEnumerator];
id childItem;
while ((childItem = [enumerator nextObject]))
{
if ([childItem isKindOfClass:[BookmarkFolder class]])
[childItem sortChildrenUsingPrimarySelector:inSelector
primaryReverseSort:inReverse
secondarySelector:inSecondarySelector
secondaryReverseSort:inSecondaryReverse
sortDeep:inDeep];
}
}
[undoManager setActionName:NSLocalizedString(@"Arrange Bookmarks", @"")];
}
//
@ -719,15 +760,20 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
return;
BOOL isSeparator = NO;
// Couple of sanity checks
if ([aChild isKindOfClass:[BookmarkFolder class]]) {
// A few of sanity checks
if ([aChild isKindOfClass:[BookmarkFolder class]])
{
if ([aNewParent isChildOfItem:aChild])
return;
else if ([(BookmarkFolder *)aChild isToolbar] && ![aNewParent isRoot])
if ([(BookmarkFolder *)aChild isToolbar] && ![aNewParent isRoot])
return;
else if ([(BookmarkFolder *)aChild isSmartFolder] && ![aNewParent isRoot])
if ([(BookmarkFolder *)aChild isSmartFolder] && ![aNewParent isRoot])
return;
} else if ([aChild isKindOfClass:[Bookmark class]]){
}
else if ([aChild isKindOfClass:[Bookmark class]])
{
if ([aNewParent isRoot])
return;
isSeparator = [(Bookmark *)aChild isSeparator];
@ -796,15 +842,20 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
-(BOOL) deleteChild:(BookmarkItem *)aChild
{
BOOL itsDead = NO;
if ([[self childArray] indexOfObjectIdenticalTo:aChild] != NSNotFound) {
if ([[self childArray] indexOfObjectIdenticalTo:aChild] != NSNotFound)
{
if ([aChild isKindOfClass:[Bookmark class]])
itsDead = [self deleteBookmark:(Bookmark *)aChild];
else if ([aChild isKindOfClass:[BookmarkFolder class]])
itsDead = [self deleteBookmarkFolder:(BookmarkFolder *)aChild];
} else { //with current setup, shouldn't ever hit this code path.
}
else
{
//with current setup, shouldn't ever hit this code path.
NSEnumerator *enumerator = [[self childArray] objectEnumerator];
id anObject;
while (!itsDead && (anObject = [enumerator nextObject])) {
while (!itsDead && (anObject = [enumerator nextObject]))
{
if ([anObject isKindOfClass:[BookmarkFolder class]])
itsDead = [anObject deleteChild:aChild];
}
@ -847,7 +898,7 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
while (numChildren > 0)
[aChild deleteChild:[aChild objectAtIndex:--numChildren]];
//record undo
// record undo
[[undoManager prepareWithInvocationTarget:self] insertChild:aChild atIndex:[[self childArray] indexOfObjectIdenticalTo:aChild] isMove:NO];
[undoManager endUndoGrouping];

Просмотреть файл

@ -148,9 +148,12 @@ enum
// we put sort comparators on the base class for convenience
- (NSComparisonResult)compareURL:(BookmarkItem *)aItem sortDescending:(NSNumber*)inDescending;
- (NSComparisonResult)compareTitle:(BookmarkItem *)aItem sortDescending:(NSNumber*)inDescending;
- (NSComparisonResult)compareKeyword:(BookmarkItem *)aItem sortDescending:(NSNumber*)inDescending;
- (NSComparisonResult)compareDescription:(BookmarkItem *)aItem sortDescending:(NSNumber*)inDescending;
- (NSComparisonResult)compareType:(BookmarkItem *)aItem sortDescending:(NSNumber*)inDescending;
- (NSComparisonResult)compareVisitCount:(BookmarkItem *)aItem sortDescending:(NSNumber*)inDescending;
- (NSComparisonResult)compareLastVisitDate:(BookmarkItem *)aItem sortDescending:(NSNumber*)inDescending;
- (NSComparisonResult)compareForTop10:(BookmarkItem *)aItem sortDescending:(NSNumber*)inDescending;
@end

Просмотреть файл

@ -51,6 +51,8 @@ extern NSString* const kBookmarkManagerStartedNotification;
extern NSString* const kBookmarksToolbarFolderIdentifier;
extern NSString* const kBookmarksMenuFolderIdentifier;
const int kBookmarksContextMenuArrangeSeparatorTag = 100;
@interface BookmarkManager : NSObject <BookmarksClient>
{
@ -107,6 +109,9 @@ extern NSString* const kBookmarksMenuFolderIdentifier;
- (BookmarkItem*)containerItemAtIndex:(unsigned)inIndex;
- (BookmarkFolder*)rootBookmarkFolderWithIdentifier:(NSString*)inIdentifier;
- (BOOL)itemsShareCommonParent:(NSArray*)inItems;
// get/set folder last used by "Add Bookmarks"
- (BookmarkFolder*)lastUsedBookmarkFolder;
- (void)setLastUsedBookmarkFolder:(BookmarkFolder*)inFolder;

Просмотреть файл

@ -45,6 +45,7 @@
#include "nsAppDirectoryServiceDefs.h"
#import "NSString+Utils.h"
#import "NSArray+Utils.h"
#import "NSThread+Utils.h"
#import "NSFileManager+Utils.h"
#import "NSWorkspace+Utils.h"
@ -310,13 +311,9 @@ static BookmarkManager* gBookmarkManager = nil;
mSmartFolderManager = [[KindaSmartFolderManager alloc] initWithBookmarkManager:self];
#if 0
// at some point, f'd up setting the bookmark toolbar folder special flag.
// this'll handle that little boo-boo for the time being
[[self toolbarFolder] setIsToolbar:YES];
// set the localized titles of these folders
[[self toolbarFolder] setTitle:NSLocalizedString(@"Bookmark Bar", @"")];
[[self bookmarkMenuFolder] setTitle:NSLocalizedString(@"Bookmark Menu", @"")];
#endif
// don't do this until after we've read in the bookmarks
mUndoManager = [[NSUndoManager alloc] init];
@ -485,6 +482,28 @@ static BookmarkManager* gBookmarkManager = nil;
return nil;
}
- (BOOL)itemsShareCommonParent:(NSArray*)inItems
{
NSEnumerator* itemsEnum = [inItems objectEnumerator];
id commonParent = nil;
BookmarkItem* curItem;
while ((curItem = [itemsEnum nextObject]))
{
if (curItem == [inItems firstObject])
{
commonParent = [curItem parent];
if (!commonParent) return NO;
}
if ([curItem parent] != commonParent)
return NO;
}
return YES;
}
-(BookmarkFolder *)top10Folder
{
return mTop10Container;
@ -702,6 +721,13 @@ static BookmarkManager* gBookmarkManager = nil;
[menuItem setTarget:target];
[contextMenu addItem:menuItem];
if (!outlineView || ([items count] == 1)) {
menuTitle = NSLocalizedString(@"Get Info", @"");
menuItem = [[[NSMenuItem alloc] initWithTitle:menuTitle action:@selector(showBookmarkInfo:) keyEquivalent:@""] autorelease];
[menuItem setTarget:target];
[contextMenu addItem:menuItem];
}
[contextMenu addItem:[NSMenuItem separatorItem]];
// copy URL(s) to clipboard
@ -712,14 +738,6 @@ static BookmarkManager* gBookmarkManager = nil;
menuItem = [[[NSMenuItem alloc] initWithTitle:menuTitle action:@selector(copyURLs:) keyEquivalent:@""] autorelease];
[menuItem setTarget:target];
[contextMenu addItem:menuItem];
if (!outlineView || ([items count] == 1)) {
[contextMenu addItem:[NSMenuItem separatorItem]];
menuTitle = NSLocalizedString(@"Get Info", @"");
menuItem = [[[NSMenuItem alloc] initWithTitle:menuTitle action:@selector(showBookmarkInfo:) keyEquivalent:@""] autorelease];
[menuItem setTarget:target];
[contextMenu addItem:menuItem];
}
if (([items count] == 1) && itemsContainsFolder) {
menuTitle = NSLocalizedString(@"Use as Dock Menu", @"");
@ -732,16 +750,6 @@ static BookmarkManager* gBookmarkManager = nil;
if ([target isKindOfClass:[BookmarkViewController class]])
allowNewFolder = ![[target activeCollection] isSmartFolder];
if (allowNewFolder) {
// space
[contextMenu addItem:[NSMenuItem separatorItem]];
// create new folder
menuTitle = NSLocalizedString(@"Create New Folder...", @"");
menuItem = [[[NSMenuItem alloc] initWithTitle:menuTitle action:@selector(addBookmarkFolder:) keyEquivalent:@""] autorelease];
[menuItem setTarget:target];
[contextMenu addItem:menuItem];
}
// if we're not in a smart collection (other than history)
if (!outlineView ||
![target isKindOfClass:[BookmarkViewController class]] ||
@ -755,6 +763,67 @@ static BookmarkManager* gBookmarkManager = nil;
[menuItem setTarget:target];
[contextMenu addItem:menuItem];
}
if (allowNewFolder) {
// space
[contextMenu addItem:[NSMenuItem separatorItem]];
// create new folder
menuTitle = NSLocalizedString(@"Create New Folder...", @"");
menuItem = [[[NSMenuItem alloc] initWithTitle:menuTitle action:@selector(addBookmarkFolder:) keyEquivalent:@""] autorelease];
[menuItem setTarget:target];
[contextMenu addItem:menuItem];
}
// Arrange bookmarks items. these may get removed again by the caller, so
// we tag them.
if ([target isKindOfClass:[BookmarkViewController class]] &&
![[target activeCollection] isSmartFolder])
{
NSMenuItem* separatorItem = [NSMenuItem separatorItem];
[separatorItem setTag:kBookmarksContextMenuArrangeSeparatorTag];
[contextMenu addItem:separatorItem];
menuTitle = NSLocalizedString(@"Arrange Bookmarks", @"");
menuItem = [[[NSMenuItem alloc] initWithTitle:menuTitle action:NULL keyEquivalent:@""] autorelease];
[menuItem setTarget:target];
[contextMenu addItem:menuItem];
// create submenu
NSMenu* arrangeSubmenu = [[[NSMenu alloc] initWithTitle:@"notitle"] autorelease];
NSMenuItem* subMenuItem = [[[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Arrange Increasing by title", @"")
action:@selector(arrange:)
keyEquivalent:@""] autorelease];
[subMenuItem setTarget:target];
[subMenuItem setTag:(kArrangeBookmarksByTitleMask | kArrangeBookmarksAscendingMask)];
[arrangeSubmenu addItem:subMenuItem];
subMenuItem = [[[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Arrange Decreasing by title", @"")
action:@selector(arrange:)
keyEquivalent:@""] autorelease];
[subMenuItem setTarget:target];
[subMenuItem setTag:(kArrangeBookmarksByTitleMask | kArrangeBookmarksDescendingMask)];
[arrangeSubmenu addItem:subMenuItem];
[arrangeSubmenu addItem:[NSMenuItem separatorItem]];
subMenuItem = [[[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Arrange Increasing by location", @"")
action:@selector(arrange:)
keyEquivalent:@""] autorelease];
[subMenuItem setTarget:target];
[subMenuItem setTag:(kArrangeBookmarksByLocationMask | kArrangeBookmarksAscendingMask)];
[arrangeSubmenu addItem:subMenuItem];
subMenuItem = [[[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Arrange Decreasing by location", @"")
action:@selector(arrange:)
keyEquivalent:@""] autorelease];
[subMenuItem setTarget:target];
[subMenuItem setTag:(kArrangeBookmarksByLocationMask | kArrangeBookmarksDescendingMask)];
[arrangeSubmenu addItem:subMenuItem];
[contextMenu setSubmenu:arrangeSubmenu forItem:menuItem];
}
return contextMenu;
}

Просмотреть файл

@ -51,10 +51,11 @@
int mDragInsertionPosition;
BOOL mIsShowing;
BOOL mDrawBorder;
BOOL mButtonListDirty; // do we need a full rebuild of the button list?
}
// Called to construct & edit the initial set of personal toolbar buttons.
-(void)buildButtonList;
-(void)rebuildButtonList;
-(void)addButton:(BookmarkItem*)aItem atIndex:(int)aIndex;
-(void)updateButton:(BookmarkItem*)aItem;
-(void)removeButton:(BookmarkItem*)aItem;

Просмотреть файл

@ -38,6 +38,8 @@
*
* ***** END LICENSE BLOCK ***** */
#import "NSView+Utils.h"
#import "BookmarkToolbar.h"
#import "CHBrowserService.h"
@ -60,14 +62,18 @@ static const float kButtonRectVPadding = 4.0f;
@interface BookmarkToolbar(Private)
-(void)rebuildButtonList;
- (void)setButtonInsertionPoint:(id <NSDraggingInfo>)sender;
- (NSRect)insertionHiliteRectForButton:(NSView*)aButton position:(int)aPosition;
- (BookmarkButton*)makeNewButtonWithItem:(BookmarkItem*)aItem;
- (void)managerStarted:(NSNotification*)inNotify;
- (BOOL)anchorFoundAtPoint:(NSPoint)testPoint forButton:(NSButton*)sourceButton;
- (BOOL)anchorFoundScanningFromPoint:(NSPoint)testPoint withStep:(int)step;
@end
#pragma mark -
@implementation BookmarkToolbar
static const int kBMBarScanningStep = 5;
@ -80,8 +86,12 @@ static const int kBMBarScanningStep = 5;
mDragInsertionButton = nil;
mDragInsertionPosition = CHInsertNone;
mDrawBorder = YES;
[self registerForDraggedTypes:[NSArray arrayWithObjects: kCaminoBookmarkListPBoardType, kWebURLsWithTitlesPboardType, NSStringPboardType, NSURLPboardType, nil]];
mIsShowing = YES;
mButtonListDirty = YES;
// Generic notifications for Bookmark Client
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(bookmarkAdded:) name:BookmarkFolderAdditionNotification object:nil];
@ -112,7 +122,7 @@ static const int kBMBarScanningStep = 5;
//
- (void)managerStarted:(NSNotification*)inNotify
{
[self buildButtonList];
[self rebuildButtonList];
}
static void VerticalGrayGradient(void* inInfo, float const* inData, float* outData)
@ -218,44 +228,38 @@ static void VerticalGrayGradient(void* inInfo, float const* inData, float* outDa
}
//
// -buildButtonList
// -rebuildButtonList
//
// this only gets called on startup OR window creation. on the off chance that
// we're starting due to an appleevent from another program, we might call it twice.
// make sure nothing bad happens if we do that.
//
-(void)buildButtonList
-(void)rebuildButtonList
{
BookmarkFolder* toolbar = [[BookmarkManager sharedBookmarkManager] toolbarFolder];
// check if we've built the toolbar already and bail if we have
const unsigned long count = [toolbar count];
if ([mButtons count] == count)
if (!mButtonListDirty)
return;
for (unsigned int i = 0; i < count; i++) {
BookmarkButton* button = [self makeNewButtonWithItem:[toolbar objectAtIndex:i]];
BookmarkFolder* toolbarFolder = [[BookmarkManager sharedBookmarkManager] toolbarFolder];
[mButtons removeAllObjects];
[self removeAllSubviews];
unsigned int numItems = [toolbarFolder count];
for (unsigned int i = 0; i < numItems; i++)
{
BookmarkButton* button = [self makeNewButtonWithItem:[toolbarFolder objectAtIndex:i]];
if (button) {
[self addSubview:button];
[mButtons addObject:button];
}
}
mButtonListDirty = NO;
if ([self isShown])
[self reflowButtons];
}
- (void)resetButtonList
{
int count = [mButtons count];
for (int i = 0; i < count; i++)
{
BookmarkButton* button = [mButtons objectAtIndex: i];
[button removeFromSuperview];
}
[mButtons removeAllObjects];
[self setNeedsDisplay:YES];
}
-(void)addButton:(BookmarkItem*)aItem atIndex:(int)aIndex
{
BookmarkButton* button = [self makeNewButtonWithItem:aItem];
@ -315,7 +319,7 @@ static void VerticalGrayGradient(void* inInfo, float const* inData, float* outDa
#define kBookmarkButtonVerticalPadding 1.0
#define kBookmarkToolbarBottomPadding 2.0
-(void)reflowButtonsStartingAtIndex: (int)aIndex
-(void)reflowButtonsStartingAtIndex:(int)aIndex
{
if (![self isShown])
return;
@ -718,33 +722,62 @@ static void VerticalGrayGradient(void* inInfo, float const* inData, float* outDa
- (BookmarkButton*)makeNewButtonWithItem:(BookmarkItem*)aItem
{
return [[[BookmarkButton alloc] initWithFrame: NSMakeRect(2.0f, 1.0f, 100.0f, 17.0f) item:aItem] autorelease];
return [[[BookmarkButton alloc] initWithFrame: NSMakeRect(0.0f, 0.0f, kMaxBookmarkButtonWidth, kBookmarkButtonHeight) item:aItem] autorelease];
}
#pragma mark -
- (void)bookmarkAdded:(NSNotification *)aNote
{
BookmarkFolder *anArray = [aNote object];
if (![anArray isEqual:[[BookmarkManager sharedBookmarkManager] toolbarFolder]])
BookmarkItem* changedItem = [aNote object];
if (changedItem != [[BookmarkManager sharedBookmarkManager] toolbarFolder])
return;
NSDictionary *dict = [aNote userInfo];
[self addButton:[dict objectForKey:BookmarkFolderChildKey] atIndex:[[dict objectForKey:BookmarkFolderChildIndexKey] unsignedIntValue]];
}
- (void)bookmarkRemoved:(NSNotification *)aNote
{
BookmarkFolder *aFolder = [aNote object];
if (![aFolder isEqual:[[BookmarkManager sharedBookmarkManager] toolbarFolder]])
BookmarkItem* changedItem = [aNote object];
if (changedItem != [[BookmarkManager sharedBookmarkManager] toolbarFolder])
return;
NSDictionary *dict = [aNote userInfo];
[self removeButton:[dict objectForKey:BookmarkFolderChildKey]];
}
- (void)bookmarkChanged:(NSNotification *)aNote
{
// XXX look at change flags
[self updateButton:[aNote object]];
BookmarkItem* changedItem = [aNote object];
BookmarkFolder* toolbarFolder = [[BookmarkManager sharedBookmarkManager] toolbarFolder];
if (changedItem == toolbarFolder)
{
const unsigned int kSignificantRootChangeFlags = (kBookmarkItemTitleChangedMask |
kBookmarkItemStatusChangedMask |
kBookmarkItemChildrenChangedMask);
if ([BookmarkItem bookmarkChangedNotificationUserInfo:[aNote userInfo] containsFlags:kSignificantRootChangeFlags])
{
mButtonListDirty = YES;
[self rebuildButtonList];
}
}
else if ([changedItem parent] == toolbarFolder)
{
const unsigned int kSignificantItemChangeFlags = (kBookmarkItemTitleChangedMask |
kBookmarkItemIconChangedMask |
kBookmarkItemStatusChangedMask |
kBookmarkItemChildrenChangedMask);
if ([BookmarkItem bookmarkChangedNotificationUserInfo:[aNote userInfo] containsFlags:kSignificantItemChangeFlags])
{
// note that this gets called as we're building the toolbar for the first time, since that's
// setting the icons on the bookmarks. It's slightly expensive, but harmless.
[self updateButton:changedItem];
}
}
}
@end

Просмотреть файл

@ -59,6 +59,25 @@
@class SearchTextField;
// Tags for arrange menu items
enum
{
kArrangeBookmarksByLocationMask = (1 << 0),
kArrangeBookmarksByTitleMask = (1 << 1),
// currently unused (but implemented)
kArrangeBookmarksByKeywordMask = (1 << 2),
kArrangeBookmarksByDescriptionMask = (1 << 3),
kArrangeBookmarksByLastVisitMask = (1 << 4),
kArrangeBookmarksByVisitCountMask = (1 << 5),
kArrangeBookmarksByTypeMask = (1 << 6), // folder < item < separator
kArrangeBookmarksAscendingMask = (0),
kArrangeBookmarksDescendingMask = (1 << 7),
kArrangeBookmarksFieldMask = kArrangeBookmarksDescendingMask - 1
};
// a simple view subclass that allows us to override viewDidMoveToWindow
@interface BookmarksEditingView : NSView
@ -151,6 +170,9 @@
-(IBAction) paste:(id)aSender;
-(IBAction) delete:(id)aSender;
// uses the tag of the sender to determine the sort order
-(IBAction) arrange:(id)aSender;
-(IBAction) copyURLs:(id)aSender;
-(IBAction) quicksearchPopupChanged:(id)aSender;

Просмотреть файл

@ -43,10 +43,12 @@
#import "BookmarkViewController.h"
#import "NSArray+Utils.h"
#import "NSString+Utils.h"
#import "NSPasteboard+Utils.h"
#import "NSSplitView+Utils.h"
#import "NSView+Utils.h"
#import "NSMenu+Utils.h"
#import "BookmarkManager.h"
#import "BookmarkInfoController.h"
@ -123,6 +125,8 @@ static const int kDisabledQuicksearchPopupItemTag = 9999;
- (void)selectItems:(NSArray*)items expandingContainers:(BOOL)expandContainers scrollIntoView:(BOOL)scroll;
- (BookmarkItem*)selectedBookmarkItem;
- (SEL)sortSelectorFromItemTag:(int)inTag;
- (id)itemTreeRootContainer; // something that responds to NSArray-like selectors
- (NSOutlineView*)activeOutlineView; // return the outline view of the visible tab
@ -143,6 +147,7 @@ static const int kDisabledQuicksearchPopupItemTag = 9999;
-(void)pasteBookmarks:(NSPasteboard*)aPasteboard intoFolder:(BookmarkFolder *)dropFolder index:(int)index copying:(BOOL)isCopy;
-(void)pasteBookmarksFromURLsAndTitles:(NSPasteboard*)aPasteboard intoFolder:(BookmarkFolder*)dropFolder index:(int)index;
@end
@ -679,6 +684,67 @@ static const int kDisabledQuicksearchPopupItemTag = 9999;
[self deleteBookmarks:aSender];
}
//
// the logic of what to sort here is somewhat subtle.
//
// If a single folder is selected, we sort its children.
// If > 1 items are selected, we just re-order them.
// If the option key is down, we sort deep
//
-(IBAction) arrange:(id)aSender
{
BookmarkFolder* activeCollection = [self activeCollection];
if ([activeCollection isRoot] || [activeCollection isSmartFolder])
return;
int tag = [aSender tag];
BOOL reverseSort = ((tag & kArrangeBookmarksDescendingMask) != 0);
SEL sortSelector = [self sortSelectorFromItemTag:tag];
if (!sortSelector)
return; // all UI items that call this should have the appropriate tags set
// sort deep if the option key is down
BOOL sortDeep = (([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0);
NSArray* bmItems = [mBookmarksOutlineView selectedItems];
if ([bmItems count] == 0)
{
// if nothing is selected, sort the whole container
bmItems = [NSArray arrayWithObject:[self activeCollection]];
}
// if the items don't have a common parent, bail.
if (![[BookmarkManager sharedBookmarkManager] itemsShareCommonParent:bmItems])
return;
// first arrange the items at the top level
if ([bmItems count] > 1)
{
BookmarkFolder* itemsParent = [[bmItems firstObject] parent];
[itemsParent arrangeChildItems:bmItems usingSelector:sortSelector reverseSort:reverseSort];
}
// now sort the children if a single folder is selected,
// or sort deep if we are doing so
if ([bmItems count] == 1 || sortDeep)
{
NSEnumerator* itemsEnum = [bmItems objectEnumerator];
BookmarkItem* curItem;
while ((curItem = [itemsEnum nextObject]))
{
if ([curItem isKindOfClass:[BookmarkFolder class]])
{
BookmarkFolder* curFolder = (BookmarkFolder*)curItem;
[curFolder sortChildrenUsingSelector:sortSelector reverseSort:reverseSort sortDeep:sortDeep undoable:YES];
}
}
}
// reselect them
[self selectItems:bmItems expandingContainers:NO scrollIntoView:YES];
}
- (IBAction)copyURLs:(id)aSender
{
[[BookmarkManager sharedBookmarkManager] copyBookmarksURLs:[mBookmarksOutlineView selectedItems] toPasteboard:[NSPasteboard generalPasteboard]];
@ -833,7 +899,7 @@ static const int kDisabledQuicksearchPopupItemTag = 9999;
if (itemRow == -1) return;
if (inSelectItem)
[mBookmarksOutlineView selectRow:itemRow byExtendingSelection:NO];
[mBookmarksOutlineView selectRow:itemRow byExtendingSelection:inExtendSelection];
if (inScroll)
[mBookmarksOutlineView scrollRowToVisible:itemRow];
@ -1563,6 +1629,18 @@ static const int kDisabledQuicksearchPopupItemTag = 9999;
if (action == @selector(showBookmarkInfo:))
return (selItem != nil);
if (action == @selector(arrange:))
{
BookmarkFolder* activeCollection = [self activeCollection];
if ([activeCollection isRoot] || [activeCollection isSmartFolder])
return NO;
NSArray* selectedBMs = [mBookmarksOutlineView selectedItems];
return ([selectedBMs count] == 0) ||
([selectedBMs count] == 1 && [[selectedBMs firstObject] isKindOfClass:[BookmarkFolder class]]) ||
(([selectedBMs count] > 1) && [[BookmarkManager sharedBookmarkManager] itemsShareCommonParent:selectedBMs]);
}
}
else // history visible
{
@ -1704,6 +1782,39 @@ static const int kDisabledQuicksearchPopupItemTag = 9999;
return (BookmarkItem*)[mBookmarksOutlineView itemAtRow:index];
}
- (SEL)sortSelectorFromItemTag:(int)inTag
{
switch (inTag & kArrangeBookmarksFieldMask)
{
default:
NSLog(@"Unknown sort tag mask");
// fall through
case kArrangeBookmarksByLocationMask:
return @selector(compareURL:sortDescending:);
case kArrangeBookmarksByTitleMask:
return @selector(compareTitle:sortDescending:);
case kArrangeBookmarksByKeywordMask:
return @selector(compareKeyword:sortDescending:);
case kArrangeBookmarksByDescriptionMask:
return @selector(compareDescription:sortDescending:);
case kArrangeBookmarksByLastVisitMask:
return @selector(compareLastVisitDate:sortDescending:);
case kArrangeBookmarksByVisitCountMask:
return @selector(compareVisitCount:sortDescending:);
case kArrangeBookmarksByTypeMask:
return @selector(compareType:sortDescending:);
}
return NULL; // keep compiler quiet
}
- (id)itemTreeRootContainer
{
if (mSearchResultArray)
@ -1754,7 +1865,11 @@ static const int kDisabledQuicksearchPopupItemTag = 9999;
{
NSArray* selectedBMs = [mBookmarksOutlineView selectedItems];
if ([selectedBMs count] > 0)
{
actionMenu = [[BookmarkManager sharedBookmarkManager] contextMenuForItems:selectedBMs fromView:mBookmarksOutlineView target:self];
// remove the arrange stuff, because it's on the sort button too
[actionMenu removeItemsFromIndex:[actionMenu indexOfItemWithTag:kBookmarksContextMenuArrangeSeparatorTag]];
}
else
actionMenu = mActionMenuBookmarks;
}

Просмотреть файл

@ -173,7 +173,8 @@ const unsigned kNumTop10Items = 10; // well, 10, duh!
// just resort
[mTop10Folder sortChildrenUsingSelector:@selector(compareForTop10:sortDescending:)
reverseSort:YES
sortDeep:NO];
sortDeep:NO
undoable:NO];
}
}
else if (visitCount >= currentMinVisits)

Просмотреть файл

@ -841,7 +841,7 @@ enum BWCOpenDest {
mPendingURL = mPendingReferrer = nil;
}
[mPersonalToolbar buildButtonList];
[mPersonalToolbar rebuildButtonList];
BOOL chromeHidesToolbar = (mChromeMask != 0) && !(mChromeMask & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
if (chromeHidesToolbar || ![self shouldShowBookmarkToolbar])

Просмотреть файл

@ -139,53 +139,99 @@ static NSString* const kAutosaveSortDirectionKey = @"sort_descending";
// check each char in the event array. it should be just 1 char, but
// just in case we use a loop.
int len = [[aEvent characters] length];
for ( int i = 0; i < len; ++i ) {
BOOL handled = NO;
for (int i = 0; i < len; ++i)
{
unichar c = [[aEvent characters] characterAtIndex:i];
// Check for a certain set of special keys.
if (c == NSDeleteCharacter || c == NSBackspaceCharacter || c == NSDeleteFunctionKey) {
// delete the bookmark
if (mDeleteAction)
[NSApp sendAction: mDeleteAction to: [self target] from: self];
return;
}
else if (c == NSCarriageReturnCharacter) {
// Start editing
if ([self numberOfSelectedRows] == 1) {
[self editColumn:0 row:[self selectedRow] withEvent:aEvent select:YES];
return;
}
}
else if (c == NSEnterCharacter
|| ([aEvent modifierFlags] & NSCommandKeyMask && c == NSDownArrowFunctionKey)) {
// on enter or cmd-downArrow, open the item as a double-click
[NSApp sendAction:[self doubleAction] to:[self target] from:self];
return;
}
else if (c == NSLeftArrowFunctionKey || c == NSRightArrowFunctionKey)
// Check for a certain set of special keys.
switch (c)
{
BOOL expand = (c == NSRightArrowFunctionKey);
if ([self numberOfSelectedRows] == 1) {
int index = [self selectedRow];
if (index == -1)
return;
id item = [self itemAtRow: index];
if (!item)
return;
if (![self isExpandable: item])
return;
case NSDeleteCharacter:
case NSBackspaceCharacter:
case NSDeleteFunctionKey:
if (mDeleteAction)
{
[NSApp sendAction:mDeleteAction to:[self target] from:self];
handled = YES;
}
break;
if (![self isItemExpanded: item] && expand)
[self expandItem: item];
else if ([self isItemExpanded: item] && !expand)
[self collapseItem: item];
}
case NSCarriageReturnCharacter:
// Start editing
if ([self numberOfSelectedRows] == 1)
{
[self editColumn:0 row:[self selectedRow] withEvent:aEvent select:YES];
handled = YES;
}
break;
case NSEnterCharacter:
[NSApp sendAction:[self doubleAction] to:[self target] from:self];
handled = YES;
break;
case NSDownArrowFunctionKey:
// Command-down arrow opens an item
if ([aEvent modifierFlags] & NSCommandKeyMask)
{
[NSApp sendAction:[self doubleAction] to:[self target] from:self];
handled = YES;
}
break;
case NSLeftArrowFunctionKey:
case NSRightArrowFunctionKey:
{
BOOL expand = (c == NSRightArrowFunctionKey);
BOOL changeChildren = (([aEvent modifierFlags] & NSAlternateKeyMask) != 0);
if ([self numberOfSelectedRows] == 1)
{
int index = [self selectedRow];
if (index == -1)
break;
id item = [self itemAtRow:index];
if (!item)
break;
if (![self isExpandable:item])
break;
if (expand)
{
if (![self isItemExpanded:item])
[self expandItem:item expandChildren:changeChildren];
}
else // collapse
{
if ([self isItemExpanded:item])
[self collapseItem:item collapseChildren:changeChildren]; // doesn't seem to work for children
}
handled = YES;
}
}
break;
// AppKit doesn't seem to call -interpretKeyEvents for table views, so we can't just
// override the standard NSResponder methods like -moveToBeginningOfDocument: and expect them to work
case NSHomeFunctionKey:
[self scrollRowToVisible:0];
handled = YES;
break;
case NSEndFunctionKey:
[self scrollRowToVisible:[self numberOfRows] - 1];
handled = YES;
break;
}
} // foreach character
[super keyDown: aEvent];
if (!handled)
[super keyDown:aEvent];
}
/*

Просмотреть файл

@ -56,19 +56,39 @@
// check each char in the event array. it should be just 1 char, but
// just in case we use a loop.
int len = [[aEvent characters] length];
for ( int i = 0; i < len; ++i ) {
BOOL handled = NO;
for (int i = 0; i < len; ++i)
{
unichar c = [[aEvent characters] characterAtIndex:i];
// Check for a certain set of special keys.
if (c == NSDeleteCharacter || c == NSBackspaceCharacter || c == NSDeleteFunctionKey) {
// delete the bookmark
if (mDeleteAction)
[NSApp sendAction: mDeleteAction to: [self target] from: self];
return;
switch (c)
{
case NSDeleteCharacter:
case NSBackspaceCharacter:
case NSDeleteFunctionKey:
if (mDeleteAction)
{
[NSApp sendAction:mDeleteAction to:[self target] from:self];
handled = YES;
}
break;
case NSHomeFunctionKey:
[self scrollRowToVisible:0];
handled = YES;
break;
case NSEndFunctionKey:
[self scrollRowToVisible:[self numberOfRows] - 1];
handled = YES;
break;
}
}
[super keyDown: aEvent];
if (!handled)
[super keyDown:aEvent];
}
-(NSMenu *)menuForEvent:(NSEvent *)theEvent

Просмотреть файл

@ -429,20 +429,20 @@ static NSString* const kExpandedHistoryStatesDefaultsKey = @"history_expand_stat
// space
[contextMenu addItem:[NSMenuItem separatorItem]];
if (numSiteItems > 1)
menuTitle = NSLocalizedString(@"Copy URLs to Clipboard", @"");
else
menuTitle = NSLocalizedString(@"Copy URL to Clipboard", @"");
menuItem = [[[NSMenuItem alloc] initWithTitle:menuTitle action:@selector(copyURLs:) keyEquivalent:@""] autorelease];
// delete
menuTitle = NSLocalizedString(@"Delete", @"");
menuItem = [[[NSMenuItem alloc] initWithTitle:menuTitle action:@selector(deleteHistoryItems:) keyEquivalent:@""] autorelease];
[menuItem setTarget:self];
[contextMenu addItem:menuItem];
// space
[contextMenu addItem:[NSMenuItem separatorItem]];
// delete
menuTitle = NSLocalizedString(@"Delete", @"");
menuItem = [[[NSMenuItem alloc] initWithTitle:menuTitle action:@selector(deleteHistoryItems:) keyEquivalent:@""] autorelease];
if (numSiteItems > 1)
menuTitle = NSLocalizedString(@"Copy URLs to Clipboard", @"");
else
menuTitle = NSLocalizedString(@"Copy URL to Clipboard", @"");
menuItem = [[[NSMenuItem alloc] initWithTitle:menuTitle action:@selector(copyURLs:) keyEquivalent:@""] autorelease];
[menuItem setTarget:self];
[contextMenu addItem:menuItem];