diff --git a/camino/resources/localized/English.lproj/Localizable.strings b/camino/resources/localized/English.lproj/Localizable.strings
index 4bcdf1880815..5489ce23dd99 100644
Binary files a/camino/resources/localized/English.lproj/Localizable.strings and b/camino/resources/localized/English.lproj/Localizable.strings differ
diff --git a/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib b/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib
index 5e77fb27c917..d686a99e64f9 100644
--- a/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib
+++ b/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib
@@ -16,7 +16,13 @@
LANGUAGE = ObjC;
SUPERCLASS = NSObject;
},
- {CLASS = GoMenu; LANGUAGE = ObjC; SUPERCLASS = NSMenu; },
+ {CLASS = GoMenu; LANGUAGE = ObjC; SUPERCLASS = HistoryMenu; },
+ {
+ CLASS = HistoryMenu;
+ LANGUAGE = ObjC;
+ OUTLETS = {mItemBeforeHistoryItems = NSMenuItem; };
+ SUPERCLASS = NSMenu;
+ },
{
ACTIONS = {
aboutPlugins = id;
diff --git a/camino/resources/localized/English.lproj/MainMenu.nib/info.nib b/camino/resources/localized/English.lproj/MainMenu.nib/info.nib
index 62ea519131f7..fa7de0a16791 100644
--- a/camino/resources/localized/English.lproj/MainMenu.nib/info.nib
+++ b/camino/resources/localized/English.lproj/MainMenu.nib/info.nib
@@ -7,7 +7,7 @@
IBEditorPositions
29
- 199 682 433 44 0 0 1280 938
+ 274 731 433 44 0 0 1600 1002
494
726 607 116 61 0 0 1600 1002
670
@@ -15,11 +15,7 @@
IBFramework Version
364.0
- IBOpenObjects
-
- 29
-
IBSystem Version
- 7S215
+ 7W98
diff --git a/camino/resources/localized/English.lproj/MainMenu.nib/keyedobjects.nib b/camino/resources/localized/English.lproj/MainMenu.nib/keyedobjects.nib
index 2fe36544042d..b5daa8bc0b7f 100644
Binary files a/camino/resources/localized/English.lproj/MainMenu.nib/keyedobjects.nib and b/camino/resources/localized/English.lproj/MainMenu.nib/keyedobjects.nib differ
diff --git a/camino/src/application/MainController.mm b/camino/src/application/MainController.mm
index 527f692107b2..1f4ca514f429 100644
--- a/camino/src/application/MainController.mm
+++ b/camino/src/application/MainController.mm
@@ -108,6 +108,7 @@ const int kReuseWindowOnAE = 2;
@interface MainController(Private)
- (void)setupStartpage;
+- (void)setupRendezvous;
- (void)installBookmarksMenuEnableHandler;
- (NSMenu*)bookmarksMenu;
- (BOOL)bookmarksItemsEnabled;
@@ -245,11 +246,14 @@ const int kReuseWindowOnAE = 2;
-(void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
- [self installBookmarksMenuEnableHandler];
-
// initialize prefs if we haven't already.
PreferenceManager *pm = [PreferenceManager sharedInstance];
+ // register our app components with the embed layer
+ unsigned int numComps = 0;
+ const nsModuleComponentInfo* comps = GetAppComponents(&numComps);
+ CHBrowserService::RegisterAppComponents(comps, numComps);
+
// To work around a bug on Tiger where the view hookup order has been changed from postfix to prefix
// order, we need to set a user default to return to the old behavior.
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSViewSetAncestorsWindowFirst"];
@@ -261,6 +265,7 @@ const int kReuseWindowOnAE = 2;
[[NSFileManager defaultManager] removeFileAtPath:cacheDir handler:nil];
// register for window layering changes, so that we can update the bookmarks menu
+ [self installBookmarksMenuEnableHandler];
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:@selector(windowLayeringDidChange:) name:NSWindowDidBecomeKeyNotification object:nil];
[notificationCenter addObserver:self selector:@selector(windowLayeringDidChange:) name:NSWindowDidResignKeyNotification object:nil];
@@ -274,17 +279,6 @@ const int kReuseWindowOnAE = 2;
[self setupStartpage];
- // register our app components with the embed layer
- unsigned int numComps = 0;
- const nsModuleComponentInfo* comps = GetAppComponents(&numComps);
- CHBrowserService::RegisterAppComponents(comps, numComps);
-
- // don't open a new browser window if we already have one
- // (for example, from an GetURL Apple Event)
- NSWindow* browserWindow = [self getFrontmostBrowserWindow];
- if (!browserWindow)
- [self newWindow:self];
-
// Initialize offline mode.
mOffline = NO;
nsCOMPtr ioService(do_GetService(ioServiceContractID));
@@ -302,27 +296,17 @@ const int kReuseWindowOnAE = 2;
if ([pm getBooleanPref:"chimera.log_js_to_console" withSuccess:&success])
[JSConsole sharedJSConsole];
- BOOL doingRendezvous = NO;
-
- if ([pm getBooleanPref:"chimera.enable_rendezvous" withSuccess:&success]) {
- if ([MainController supportsBonjour]) {
- [notificationCenter addObserver:self selector:@selector(availableServicesChanged:) name:NetworkServicesAvailableServicesChanged object:nil];
- [notificationCenter addObserver:self selector:@selector(serviceResolved:) name:NetworkServicesResolutionSuccess object:nil];
- [notificationCenter addObserver:self selector:@selector(serviceResolutionFailed:) name:NetworkServicesResolutionFailure object:nil];
- doingRendezvous = YES;
- }
- }
-
- if (!doingRendezvous) {
- // remove rendezvous items
- int itemIndex;
- while ((itemIndex = [mGoMenu indexOfItemWithTag:kRendezvousRelatedItemTag]) != -1)
- [mGoMenu removeItemAtIndex:itemIndex];
- }
+ [self setupRendezvous];
// load up the charset dictionary with keys and menu titles.
NSString* charsetPath = [NSBundle pathForResource:@"Charset" ofType:@"dict" inDirectory:[[NSBundle mainBundle] bundlePath]];
mCharsets = [[NSDictionary dictionaryWithContentsOfFile:charsetPath] retain];
+
+ // open a new browser window if we don't already have one
+ // (for example, from an GetURL Apple Event)
+ NSWindow* browserWindow = [self getFrontmostBrowserWindow];
+ if (!browserWindow)
+ [self newWindow:self];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
@@ -390,6 +374,29 @@ const int kReuseWindowOnAE = 2;
}
}
+- (void)setupRendezvous // aka "Bonjour"
+{
+ BOOL doingRendezvous = NO;
+
+ PreferenceManager *pm = [PreferenceManager sharedInstance];
+ if ([pm getBooleanPref:"chimera.enable_rendezvous" withSuccess:NULL]) {
+ if ([MainController supportsBonjour]) {
+ NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
+ [notificationCenter addObserver:self selector:@selector(availableServicesChanged:) name:NetworkServicesAvailableServicesChanged object:nil];
+ [notificationCenter addObserver:self selector:@selector(serviceResolved:) name:NetworkServicesResolutionSuccess object:nil];
+ [notificationCenter addObserver:self selector:@selector(serviceResolutionFailed:) name:NetworkServicesResolutionFailure object:nil];
+ doingRendezvous = YES;
+ }
+ }
+
+ if (!doingRendezvous) {
+ // remove rendezvous items
+ int itemIndex;
+ while ((itemIndex = [mGoMenu indexOfItemWithTag:kRendezvousRelatedItemTag]) != -1)
+ [mGoMenu removeItemAtIndex:itemIndex];
+ }
+}
+
//
// setupBookmarkMenus
//
diff --git a/camino/src/bookmarks/BookmarkMenu.mm b/camino/src/bookmarks/BookmarkMenu.mm
index b4d688284c20..f5a37cb14e40 100644
--- a/camino/src/bookmarks/BookmarkMenu.mm
+++ b/camino/src/bookmarks/BookmarkMenu.mm
@@ -40,7 +40,9 @@
#import "BookmarkMenu.h"
#import "BookmarkFolder.h"
#import "Bookmark.h"
+
#import "NSString+Utils.h"
+#import "NSMenu+Utils.h"
// Definitions
#define MENU_TRUNCATION_CHARS 60
@@ -118,7 +120,7 @@ const long kOpenInTabsTag = 0xBEEF;
-(void)setFirstItemIndex:(int)anIndex
{
- mFirstItemIndex=anIndex;
+ mFirstItemIndex = anIndex;
}
//
@@ -128,9 +130,7 @@ const long kOpenInTabsTag = 0xBEEF;
- (void)flushMenu
{
int firstItemIndex = [self firstItemIndex];
- NSMenu *menu = [self menu];
- while ([menu numberOfItems] > firstItemIndex)
- [menu removeItemAtIndex:firstItemIndex];
+ [[self menu] removeItemsFromIndex:firstItemIndex];
}
//
diff --git a/camino/src/browser/BrowserTabBarView.mm b/camino/src/browser/BrowserTabBarView.mm
index f6da3006931e..bbe7e1a1c4bf 100644
--- a/camino/src/browser/BrowserTabBarView.mm
+++ b/camino/src/browser/BrowserTabBarView.mm
@@ -39,7 +39,9 @@
#import "BrowserTabBarView.h"
#import "BrowserTabViewItem.h"
#import "TabButtonCell.h"
+
#import "NSPasteboard+Utils.h"
+#import "NSMenu+Utils.h"
@interface BrowserTabBarView (PRIVATE)
-(void)layoutButtons;
@@ -410,9 +412,9 @@ static const int kOverflowButtonMargin = 1;
mOverflowMenu = [[NSMenu alloc] init];
[mOverflowMenu addItemWithTitle:@"" action:NULL keyEquivalent:@""];
}
+
// remove any items on the menu other than the dummy item
- for (int i = [mOverflowMenu numberOfItems]; i > 1; i--)
- [mOverflowMenu removeItemAtIndex:i-1];
+ [mOverflowMenu removeItemsFromIndex:1];
}
- (IBAction)overflowMenu:(id)sender
diff --git a/camino/src/browser/GoMenu.h b/camino/src/browser/GoMenu.h
index 4ad5cc93fcb9..f141f6d5273d 100644
--- a/camino/src/browser/GoMenu.h
+++ b/camino/src/browser/GoMenu.h
@@ -39,15 +39,38 @@
#import
-@interface GoMenu : NSMenu
+@class HistoryDataSource;
+@class HistoryItem;
+
+@interface HistoryMenu : NSMenu
{
- NSMutableDictionary* mBuckets; // cached history menu objects, rebuilt every time the menu is reopened, STRONG
+ IBOutlet NSMenuItem* mItemBeforeHistoryItems; // the item after which we add history items. Not retained.
+
+ HistoryItem* mRootItem; // root history item for this menu (retained)
+ HistoryItem* mAdditionalItemsParent; // may also contain children of this item (retained)
+
+ int mNumIgnoreItems; // if > 0, ignore the first N items (for "earlier today")
+ BOOL mHistoryItemsDirty; // whether we need to rebuild the items on next update
}
-- (void) emptyHistoryItems;
-- (void) addHistoryItems;
+- (void)setRootHistoryItem:(HistoryItem*)inRootItem;
+- (HistoryItem*)rootItem;
-// NSMenu
-- (void) update;
+- (void)setNumLeadingItemsToIgnore:(int)inIgnoreItems;
+- (int)numLeadingItemsToIgnore;
+
+// specify the item after which history items will be added
+// (they are assumed to go to the end of the menu). If nil,
+// the entire menu is full of history items.
+- (void)setItemBeforeHistoryItems:(NSMenuItem*)inItem;
+- (NSMenuItem*)itemBeforeHistoryItems;
+
+@end
+
+
+@interface GoMenu : HistoryMenu
+{
+ BOOL mAppLaunchDone; // has app launching completed?
+}
@end
diff --git a/camino/src/browser/GoMenu.mm b/camino/src/browser/GoMenu.mm
index 025a6c5b04e7..18563d1ff5df 100644
--- a/camino/src/browser/GoMenu.mm
+++ b/camino/src/browser/GoMenu.mm
@@ -39,295 +39,429 @@
#import "NSString+Utils.h"
#import "NSDate+Utils.h"
+#import "NSMenu+Utils.h"
-#import "GoMenu.h"
#import "MainController.h"
#import "BrowserWindowController.h"
#import "ChimeraUIConstants.h"
+#import "CHBrowserService.h"
+#import "PreferenceManager.h"
#include "nsCOMPtr.h"
#include "nsString.h"
-#define USE_GO_MENU 1
-
-#if USE_GO_MENU
#include "nsIWebBrowser.h"
#include "nsISHistory.h"
#include "nsIWebNavigation.h"
#include "nsIHistoryEntry.h"
#include "nsCRT.h"
-#else
-#include "nsIBrowserHistory.h"
-#include "nsIHistoryItems.h"
-#include "nsISimpleEnumerator.h"
-#include "nsIServiceManager.h"
-#endif
+
+#import "HistoryItem.h"
+#import "HistoryDataSource.h"
+
+#import "GoMenu.h"
+
+
// the maximum number of history entry menuitems to display
static const int kMaxItems = 15;
+
+// the maximum number of "today" items to show on the main menu
+static const int kMaxTodayItems = 12;
+
// the maximum number of characters in a menu title before cropping it
static const unsigned int kMaxTitleLength = 80;
-#if !USE_GO_MENU
-
-//
-// HistoryMenuItem
-//
-// An object that passes some data between the menu items and the history data source. This
-// item lives longer than the lifetime of the tracking of the menu.
-//
-
-@interface HistoryMenuItem : NSObject
+// this little class manages the singleton history data source, and takes
+// care of shutting it down at XPCOM shutdown time.
+@interface GoMenuHistoryDataSourceOwner : NSObject
{
-@private
- NSString* mURL; // strong
- NSString* mTitle; // strong
- PRTime mLastVisit;
+ HistoryDataSource* mHistoryDataSource;
}
--(id)initWithURL:(NSString*)inURL title:(NSString*)inTitle lastVisit:(PRTime)inLastVisit;
--(NSString*)url;
--(NSString*)title;
+
++ (GoMenuHistoryDataSourceOwner*)sharedGoMenuHistoryDataSourceOwner;
++ (HistoryDataSource*)sharedHistoryDataSource; // just a shortcut
+
+- (HistoryDataSource*)historyDataSource;
+
@end
-@implementation HistoryMenuItem
--(id)initWithURL:(NSString*)inURL title:(NSString*)inTitle lastVisit:(PRTime)inLastVisit
+@implementation GoMenuHistoryDataSourceOwner
+
++ (GoMenuHistoryDataSourceOwner*)sharedGoMenuHistoryDataSourceOwner
{
- if ((self = [super init])) {
- mURL = [inURL retain];
- mTitle = [inTitle retain];
- mLastVisit = inLastVisit;
+ static GoMenuHistoryDataSourceOwner* sHistoryOwner = nil;
+ if (!sHistoryOwner)
+ sHistoryOwner = [[GoMenuHistoryDataSourceOwner alloc] init];
+
+ return sHistoryOwner;
+}
+
++ (HistoryDataSource*)sharedHistoryDataSource
+{
+ return [[GoMenuHistoryDataSourceOwner sharedGoMenuHistoryDataSourceOwner] historyDataSource];
+}
+
+- (id)init
+{
+ if ((self = [super init]))
+ {
+ // register for xpcom shutdown
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(xpcomShutdownNotification:)
+ name:XPCOMShutDownNotificationName
+ object:nil];
}
return self;
}
- (void)dealloc
{
- [mURL release];
- [mTitle release];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [mHistoryDataSource release];
+ [super dealloc];
}
--(NSString*)url
+- (void)xpcomShutdownNotification:(NSNotification*)inNotification
{
- return mURL;
+ [mHistoryDataSource release];
+ mHistoryDataSource = nil;
}
--(NSString*)title
+- (HistoryDataSource*)historyDataSource
{
- return mTitle;
+ if (!mHistoryDataSource)
+ {
+ mHistoryDataSource = [[HistoryDataSource alloc] init];
+ [mHistoryDataSource setHistoryView:kHistoryViewByDate];
+ [mHistoryDataSource setSortColumnIdentifier:@"last_visit"]; // always sort by last visit
+ [mHistoryDataSource setSortDescending:YES];
+ }
+ return mHistoryDataSource;
}
-- (NSComparisonResult)compare:(HistoryMenuItem *)inItem
-{
- if (inItem->mLastVisit > mLastVisit)
- return NSOrderedAscending;
- if (inItem->mLastVisit < mLastVisit)
- return NSOrderedDescending;
- return NSOrderedSame;
-}
+@end // GoMenuHistoryDataSourceOwner
-@end
-
-#endif
#pragma mark -
-@implementation GoMenu
+@interface HistoryMenu(Private)
+
++ (NSString*)menuItemTitleForHistoryItem:(HistoryItem*)inItem;
+
+- (void)setupHistoryMenu;
+- (void)rebuildHistoryItems;
+- (void)historyChanged:(NSNotification*)inNotification;
+- (void)openHistoryItem:(id)sender;
+
+@end
+
+#pragma mark -
+
+@implementation HistoryMenu
+
++ (NSString*)menuItemTitleForHistoryItem:(HistoryItem*)inItem
+{
+ NSString* itemTitle = [inItem title];
+ if ([itemTitle length] == 0)
+ itemTitle = [inItem url];
+
+ return [itemTitle stringByTruncatingTo:kMaxTitleLength at:kTruncateAtMiddle];
+}
+
+- (id)initWithTitle:(NSString *)inTitle
+{
+ if ((self = [super initWithTitle:inTitle]))
+ {
+ mHistoryItemsDirty = YES;
+ // we're making the assumption here that the Go menu only gets awakeFromNib,
+ // and that other history submenus are allocated dynamically later on
+ [self setupHistoryMenu];
+ }
+ return self;
+}
+
+- (void)awakeFromNib
+{
+ mHistoryItemsDirty = YES;
+}
+
+// this should only be called after app launch, when the data source is available
+- (void)setupHistoryMenu
+{
+ // set ourselves up to listen for history changes
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(historyChanged:)
+ name:kNotificationNameHistoryDataSourceChanged
+ object:[GoMenuHistoryDataSourceOwner sharedHistoryDataSource]];
+}
-#if !USE_GO_MENU
- (void)dealloc
{
- [mBuckets autorelease];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [mRootItem release];
+ [mAdditionalItemsParent release];
[super dealloc];
}
-#endif
-- (void) update
+- (void)setRootHistoryItem:(HistoryItem*)inRootItem
{
- [self emptyHistoryItems];
- [self addHistoryItems];
+ [mRootItem autorelease];
+ mRootItem = [inRootItem retain];
+}
+- (HistoryItem*)rootItem
+{
+ return mRootItem;
+}
+
+- (void)setNumLeadingItemsToIgnore:(int)inIgnoreItems
+{
+ mNumIgnoreItems = inIgnoreItems;
+}
+
+- (int)numLeadingItemsToIgnore
+{
+ return mNumIgnoreItems;
+}
+
+- (void)setItemBeforeHistoryItems:(NSMenuItem*)inItem
+{
+ mItemBeforeHistoryItems = inItem;
+}
+
+- (NSMenuItem*)itemBeforeHistoryItems
+{
+ return mItemBeforeHistoryItems;
+}
+
+- (void)historyChanged:(NSNotification*)inNotification
+{
+ id rootChangedItem = [[inNotification userInfo] objectForKey:kNotificationHistoryDataSourceChangedUserInfoChangedItem];
+ // We could optimize by only changing single menu items if itemOnlyChanged is true. Normally this will also be a visit
+ // date change, which we can ignore.
+ //BOOL itemOnlyChanged = [[[inNotification userInfo] objectForKey:kNotificationHistoryDataSourceChangedUserInfoChangedItemOnly] boolValue];
+
+ // If rootChangedItem is nil, the whole history tree is being rebuilt.
+ // We need to clear our root item, because it will become invalid. We'll set it again when we rebuild.
+ if (!rootChangedItem)
+ {
+ [self setRootHistoryItem:nil];
+ [mAdditionalItemsParent release];
+ mAdditionalItemsParent = nil;
+ mHistoryItemsDirty = YES;
+ }
+ else
+ {
+ mHistoryItemsDirty = mRootItem == rootChangedItem ||
+ [mRootItem isDescendentOfItem:rootChangedItem] ||
+ [rootChangedItem isDescendentOfItem:mRootItem];
+
+ if (mAdditionalItemsParent)
+ mHistoryItemsDirty |= (rootChangedItem == mAdditionalItemsParent ||
+ [rootChangedItem parentItem] == mAdditionalItemsParent);
+ }
+}
+
+- (void)rebuildHistoryItems
+{
+ if (!mHistoryItemsDirty)
+ return;
+
+ // remove everything after the "before" item
+ [self removeItemsAfterItem:mItemBeforeHistoryItems];
+
+ // now iterate through the history items
+ NSEnumerator* childEnum = [[mRootItem children] objectEnumerator];
+
+ // skip the first mNumIgnoreItems items
+ for (int i = 0; i < mNumIgnoreItems; ++i)
+ [childEnum nextObject];
+
+ BOOL separatorPending = NO;
+
+ HistoryItem* curChild;
+ while ((curChild = [childEnum nextObject]))
+ {
+ NSMenuItem* newItem = nil;
+
+ // XXX should we impose a max number of items in any one menu, to avoid crazy 2000-item menus?
+ if ([curChild isKindOfClass:[HistorySiteItem class]])
+ {
+ newItem = [[[NSMenuItem alloc] initWithTitle:[HistoryMenu menuItemTitleForHistoryItem:curChild]
+ action:@selector(openHistoryItem:)
+ keyEquivalent:@""] autorelease];
+
+ [newItem setTarget:self];
+ [newItem setRepresentedObject:curChild];
+ }
+ else if ([curChild isKindOfClass:[HistoryCategoryItem class]] && ([curChild numberOfChildren] > 0))
+ {
+ // The "today" category is special, because we hoist the 10 most recent items up to the parent menu.
+ // This code assumes that we'll hit this first, by virtue of the last visit date sorting.
+ if ([curChild respondsToSelector:@selector(isTodayCategory)] && [(HistoryDateCategoryItem*)curChild isTodayCategory])
+ {
+ // take note of the fact that we're showing children of this item
+ [mAdditionalItemsParent autorelease];
+ mAdditionalItemsParent = [curChild retain];
+
+ NSMutableArray* menuTodayItems = [NSMutableArray arrayWithArray:[curChild children]];
+ while ((int)[menuTodayItems count] > kMaxTodayItems)
+ [menuTodayItems removeObjectAtIndex:kMaxTodayItems];
+
+ NSEnumerator* todayItemsEnum = [menuTodayItems objectEnumerator];
+ HistoryItem* curTodayItem;
+ while ((curTodayItem = [todayItemsEnum nextObject]))
+ {
+ NSMenuItem* todayMenuItem = [[[NSMenuItem alloc] initWithTitle:[HistoryMenu menuItemTitleForHistoryItem:curTodayItem]
+ action:@selector(openHistoryItem:)
+ keyEquivalent:@""] autorelease];
+
+ [todayMenuItem setTarget:self];
+ [todayMenuItem setRepresentedObject:curTodayItem];
+ [self addItem:todayMenuItem];
+ separatorPending = YES;
+ }
+
+ // make a submenu for "earlier today"
+ if ([curChild numberOfChildren] > kMaxTodayItems)
+ {
+ if (separatorPending)
+ {
+ [self addItem:[NSMenuItem separatorItem]];
+ separatorPending = NO;
+ }
+
+ NSString* itemTitle = NSLocalizedString(@"GoMenuEarlierToday", @"");
+ newItem = [[[NSMenuItem alloc] initWithTitle:itemTitle
+ action:nil
+ keyEquivalent:@""] autorelease];
+
+ HistoryMenu* newSubmenu = [[HistoryMenu alloc] initWithTitle:itemTitle];
+ [newSubmenu setRootHistoryItem:curChild];
+ [newSubmenu setNumLeadingItemsToIgnore:kMaxTodayItems];
+
+ [newItem setSubmenu:newSubmenu];
+ }
+ }
+ else
+ {
+ if (separatorPending)
+ {
+ [self addItem:[NSMenuItem separatorItem]];
+ separatorPending = NO;
+ }
+
+ // Not the "today" category, and has entries
+ NSString* itemTitle = [HistoryMenu menuItemTitleForHistoryItem:curChild];
+ newItem = [[[NSMenuItem alloc] initWithTitle:itemTitle
+ action:nil
+ keyEquivalent:@""] autorelease];
+
+ HistoryMenu* newSubmenu = [[HistoryMenu alloc] initWithTitle:itemTitle];
+ [newSubmenu setRootHistoryItem:curChild];
+
+ [newItem setSubmenu:newSubmenu];
+ }
+ }
+
+ if (newItem)
+ [self addItem:newItem];
+ }
+
+ mHistoryItemsDirty = NO;
+}
+
+- (void)update
+{
+ [self rebuildHistoryItems];
[super update];
}
-#if USE_GO_MENU
-
-- (nsIWebNavigation*) currentWebNavigation
+- (void)openHistoryItem:(id)sender
{
- // get controller for current window
- BrowserWindowController *controller = [(MainController *)[NSApp delegate] getMainWindowBrowserController];
- if (!controller) return nsnull;
- return [controller currentWebNavigation];
-}
-
-#endif
-
-- (void) historyItemAction:(id)sender
-{
-#if USE_GO_MENU
- // get web navigation for current browser
- nsIWebNavigation* webNav = [self currentWebNavigation];
- if (!webNav) return;
-
- // browse to the history entry for the menuitem that was selected
- PRInt32 historyIndex = ([sender tag] - 1) - kDividerTag;
- webNav->GotoIndex(historyIndex);
-#else
- NSString* urlToLoad = [[sender representedObject] url];
- BrowserWindowController* bwc = [(MainController *)[NSApp delegate] getMainWindowBrowserController];
- if (bwc)
- [bwc loadURL:urlToLoad referrer:nil activate:YES allowPopups:NO];
- else
- [(MainController *)[NSApp delegate] openNewWindowOrTabWithURL:urlToLoad andReferrer:nil];
-#endif
-}
-
-- (void) emptyHistoryItems
-{
- // remove every history item after the insertion point
- int insertionIndex = [self indexOfItemWithTag:kDividerTag];
- for (int i = [self numberOfItems]-1; i > insertionIndex ; --i) {
- [self removeItemAtIndex:i];
- }
-#if !USE_GO_MENU
- [mBuckets autorelease];
-#endif
-}
-
-- (void) addHistoryItems
-{
-#if USE_GO_MENU
- // get session history for current browser
- nsIWebNavigation* webNav = [self currentWebNavigation];
- if (!webNav) return;
- nsCOMPtr sessionHistory;
- webNav->GetSessionHistory(getter_AddRefs(sessionHistory));
-
- PRInt32 count;
- sessionHistory->GetCount(&count);
- PRInt32 currentIndex;
- sessionHistory->GetIndex(¤tIndex);
-
- // determine the range of items to display
- int rangeStart, rangeEnd;
- int above = kMaxItems/2;
- int below = (kMaxItems-above)-1;
- if (count <= kMaxItems) {
- // if the whole history fits within our menu, fit range to show all
- rangeStart = count-1;
- rangeEnd = 0;
- } else {
- // if the whole history is too large for menu, try to put current index as close to
- // the middle of the list as possible, so the user can see both back and forward in session
- rangeStart = currentIndex + above;
- rangeEnd = currentIndex - below;
- if (rangeStart >= count-1) {
- rangeEnd -= (rangeStart-count)+1; // shift overflow to the end
- rangeStart = count-1;
- } else if (rangeEnd < 0) {
- rangeStart -= rangeEnd; // shift overflow to the start
- rangeEnd = 0;
- }
- }
-
- // create a new menu item for each history entry (up to MAX_MENUITEM entries)
- for (PRInt32 i = rangeStart; i >= rangeEnd; --i) {
- nsCOMPtr entry;
- sessionHistory->GetEntryAtIndex(i, PR_FALSE, getter_AddRefs(entry));
-
- nsXPIDLString textStr;
- entry->GetTitle(getter_Copies(textStr));
- NSString* title = [[NSString stringWith_nsAString: textStr] stringByTruncatingTo:kMaxTitleLength at:kTruncateAtMiddle];
- NSMenuItem *newItem = [self addItemWithTitle:title action:@selector(historyItemAction:) keyEquivalent:@""];
- [newItem setTarget:self];
- [newItem setTag:kDividerTag+1+i];
- if (currentIndex == i)
- [newItem setState:NSOnState];
- }
-#else
- // first grab all the items in the history and put them into buckets based on
- // the last visit date. we'll then sort each bucket. each bucket becomes a menu.
- // XXX if there is just one menu and there are less than, say, 10 items, show them inline.
- // XXX optimize by building once, then saving the results and observing additions/removals
-
- // |mBuckets| is a dictionary of arrays. Each array represents a menu of all the
- // websites for a given day in sorted order. The key for the array is the corresponding
- // NSDate for that day. This lives until the menu is rebuilt so we don't have any
- // lifetime issues.
- mBuckets = [[NSMutableDictionary dictionary] retain];
-
- nsCOMPtr globalHist = do_GetService("@mozilla.org/browser/global-history;2");
- nsCOMPtr history = do_QueryInterface(globalHist);
- if (history) {
- // walk the list of history items placing them into buckets by day.
- nsCOMPtr items;
- history->GetItemEnumerator(getter_AddRefs(items));
- PRBool hasMore = PR_FALSE;
- while (NS_SUCCEEDED(items->HasMoreElements(&hasMore)) && hasMore) {
- nsCOMPtr supp;
- if (NS_FAILED(items->GetNext(getter_AddRefs(supp))))
- break;
- nsCOMPtr historyItem = do_QueryInterface(supp);
-
- // the key for the elements of |mBuckets| is the date with the hours/minutes/seconds
- // stripped off so that all visits that fall on the same day will map down to the same hash key.
- // we then map back to a date object so it can be used to display a pretty date and sorted below.
- PRTime lastVisit;
- historyItem->GetLastVisitDate(&lastVisit);
- NSDate* dateKey = [NSDate dateWithString:
- [[NSDate dateWithPRTime:lastVisit] descriptionWithCalendarFormat:@"%Y-%m-%d 00:00:00 +0000"
- timeZone:nil locale:nil]];
- NSMutableArray* bucket = [mBuckets objectForKey:dateKey];
- if (!bucket) {
- bucket = [NSMutableArray array];
- [mBuckets setObject:bucket forKey:dateKey];
+ id repObject = [sender representedObject];
+ if ([repObject isKindOfClass:[HistoryItem class]])
+ {
+ NSString* itemURL = [repObject url];
+
+ // XXX share this logic with MainController and HistoryOutlineViewDelegate
+ BrowserWindowController* bwc = [(MainController *)[NSApp delegate] getMainWindowBrowserController];
+ if (bwc)
+ {
+ if (GetCurrentKeyModifiers() & cmdKey)
+ {
+ BOOL backgroundLoad = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.loadInBackground" withSuccess:NULL];
+ if ([[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.opentabfor.middleclick" withSuccess:NULL])
+ [bwc openNewTabWithURL:itemURL referrer:nil loadInBackground:backgroundLoad allowPopups:NO];
+ else
+ [bwc openNewWindowWithURL:itemURL referrer: nil loadInBackground:backgroundLoad allowPopups:NO];
+ }
+ else
+ {
+ [bwc loadURL:itemURL referrer:nil activate:YES allowPopups:NO];
}
-
- // create the HistoryMenuItem which we store until the next time the menu is built. The ordering
- // of the array isn't really useful for us, we'll have to sort it later.
- nsCString url;
- historyItem->GetURL(url);
- NSString* urlStr = [NSString stringWith_nsACString:url];
- nsString title;
- historyItem->GetTitle(title);
- NSString* titleStr = [NSString stringWith_nsAString:title];
- HistoryMenuItem* menuObject = [[[HistoryMenuItem alloc] initWithURL:urlStr title:titleStr lastVisit:lastVisit] autorelease];
- [bucket addObject:menuObject];
}
+ else
+ [(MainController *)[NSApp delegate] openNewWindowOrTabWithURL:itemURL andReferrer:nil];
}
-
- // Now that the buckets of days are built, we need to build up the actual menu. First sort the keys then
- // walk them in order, building the top level items and their submenus
-
- NSArray* sortedKeys = [[mBuckets allKeys] sortedArrayUsingSelector:@selector(compare:)];
- NSEnumerator* e = [sortedKeys reverseObjectEnumerator]; // most recent at the top
- NSDate* dateKey = nil;
- while ((dateKey = [e nextObject])) {
- // we sort the items in the bucket which sorts them by the full last visit date. Since we want the
- // most recent (highest time) at the top, we need to use a reverse enumerator below as well.
- NSMutableArray* bucket = [[mBuckets objectForKey:dateKey] sortedArrayUsingSelector:@selector(compare:)];
-
- // create a toplevel menu with the date for |dateKey|
- NSString* menuTitle = [dateKey descriptionWithCalendarFormat:NSLocalizedString(@"HistoryMenuDateFormat",nil) timeZone:nil locale:nil];
- NSMenuItem* newItem = [self addItemWithTitle:menuTitle action:nil keyEquivalent:@""];
-
- // build the child menu with all the history urls for this day We tie back to the url for the action by
- // setting the represented object on the menu item (it's a weak ref, but means that the
- // |menuObject| must outlive the duration of the time the menu is being tracked, which it
- // certainly is).
- NSMenu* childMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@""] autorelease];
- NSEnumerator* e2 = [bucket reverseObjectEnumerator];
- HistoryMenuItem* menuObject = nil;
- while ((menuObject = [e2 nextObject])) {
- NSString* itemTitle = [[menuObject title] stringByTruncatingTo:kMaxTitleLength at:kTruncateAtMiddle];
- NSMenuItem* childMenuItem = [childMenu addItemWithTitle:itemTitle action:@selector(historyItemAction:) keyEquivalent:@""];
- [childMenuItem setRepresentedObject:menuObject];
- [childMenuItem setTarget:self];
- }
-
- [self setSubmenu:childMenu forItem:newItem];
- }
-#endif
+}
+
+@end
+
+
+#pragma mark -
+
+@interface GoMenu(Private)
+
+- (void)appLaunchFinished:(NSNotification*)inNotification;
+
+@end
+
+@implementation GoMenu
+
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)awakeFromNib
+{
+ [super awakeFromNib];
+
+ // listen for app launch completion
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(appLaunchFinished:)
+ name:NSApplicationDidFinishLaunchingNotification
+ object:nil];
+}
+
+- (void)appLaunchFinished:(NSNotification*)inNotification
+{
+ mAppLaunchDone = YES;
+ // setup the history menu after a delay, so that other app launch stuff
+ // finishes first
+ [self performSelector:@selector(setupHistoryMenu) withObject:nil afterDelay:0];
+}
+
+- (void)update
+{
+ if (mAppLaunchDone)
+ {
+ // the root item is nil at launch, and if the history gets totally rebuilt
+ if (!mRootItem)
+ {
+ HistoryDataSource* dataSource = [GoMenuHistoryDataSourceOwner sharedHistoryDataSource];
+ [dataSource loadLazily];
+
+ mRootItem = [[dataSource rootItem] retain];
+ }
+ }
+
+ [super update];
}
@end
diff --git a/camino/src/embedding/CHBrowserService.h b/camino/src/embedding/CHBrowserService.h
index 2f26c6a54f7c..bb13d985ba6d 100644
--- a/camino/src/embedding/CHBrowserService.h
+++ b/camino/src/embedding/CHBrowserService.h
@@ -47,6 +47,7 @@
// two shutdown notifcations exist to allow listeners to guarantee ordering of
// notifcations, such that they can save state before xpcom-reliant data structures
// are torn down.
+extern NSString* const InitEmbeddingNotificationName; // embedding was initted
extern NSString* const TermEmbeddingNotificationName; // someone called TermEmbedding
extern NSString* const XPCOMShutDownNotificationName; // XPCOM is about to shut down
diff --git a/camino/src/embedding/CHBrowserService.mm b/camino/src/embedding/CHBrowserService.mm
index 0021326d23eb..c06a04b04428 100644
--- a/camino/src/embedding/CHBrowserService.mm
+++ b/camino/src/embedding/CHBrowserService.mm
@@ -55,6 +55,7 @@
#include "nsIMIMEInfo.h"
#include "nsIPref.h"
+NSString* const InitEmbeddingNotificationName = @"InitEmebedding"; // this is actually broadcast from MainController
NSString* const TermEmbeddingNotificationName = @"TermEmbedding";
NSString* const XPCOMShutDownNotificationName = @"XPCOMShutDown";
@@ -109,8 +110,10 @@ CHBrowserService::InitEmbedding()
static NS_DEFINE_CID(kHelperDlgCID, NS_HELPERAPPLAUNCHERDIALOG_CID);
nsresult rv = cr->RegisterFactory(kHelperDlgCID, NS_IHELPERAPPLAUNCHERDLG_CLASSNAME, NS_IHELPERAPPLAUNCHERDLG_CONTRACTID,
sSingleton);
+ if (NS_FAILED(rv))
+ return rv;
- return rv;
+ return NS_OK;
}
/* static */
diff --git a/camino/src/extensions/NSMenu+Utils.h b/camino/src/extensions/NSMenu+Utils.h
index 41c697f8af4f..5ec07464b21f 100644
--- a/camino/src/extensions/NSMenu+Utils.h
+++ b/camino/src/extensions/NSMenu+Utils.h
@@ -53,6 +53,12 @@
// return the first item (if any) with the given target and action.
- (id)itemWithTarget:(id)anObject andAction:(SEL)actionSelector;
+// remove items after the given item, or all items if nil
+- (void)removeItemsAfterItem:(id)inItem;
+
+// remove all items including and after the given index (i.e. all items if index is 0)
+- (void)removeItemsFromIndex:(int)inItemIndex;
+
@end
diff --git a/camino/src/extensions/NSMenu+Utils.m b/camino/src/extensions/NSMenu+Utils.m
index c632dcde81df..82e823e37e22 100644
--- a/camino/src/extensions/NSMenu+Utils.m
+++ b/camino/src/extensions/NSMenu+Utils.m
@@ -90,6 +90,25 @@
return [self itemAtIndex:itemIndex];
}
+- (void)removeItemsAfterItem:(id)inItem
+{
+ int firstItemToRemoveIndex = 0;
+
+ if (inItem)
+ firstItemToRemoveIndex = [self indexOfItem:inItem] + 1;
+
+ [self removeItemsFromIndex:firstItemToRemoveIndex];
+}
+
+- (void)removeItemsFromIndex:(int)inItemIndex
+{
+ if (inItemIndex < 0)
+ inItemIndex = 0;
+
+ while ([self numberOfItems] > inItemIndex)
+ [self removeItemAtIndex:inItemIndex];
+}
+
@end
diff --git a/camino/src/history/HistoryDataSource.h b/camino/src/history/HistoryDataSource.h
index e73437152673..f38824bc2e8f 100644
--- a/camino/src/history/HistoryDataSource.h
+++ b/camino/src/history/HistoryDataSource.h
@@ -47,9 +47,9 @@
class nsIBrowserHistory;
class nsHistoryObserver;
-extern NSString* const kHistoryViewByDate;
-extern NSString* const kHistoryViewBySite;
-extern NSString* const kHistoryViewFlat;
+extern NSString* const kHistoryViewByDate; // grouped by last visit date
+extern NSString* const kHistoryViewBySite; // grouped by site
+extern NSString* const kHistoryViewFlat; // flat
// notification object is the data source.
extern NSString* const kNotificationNameHistoryDataSourceChanged;
@@ -91,6 +91,7 @@ extern NSString* const kNotificationHistoryDataSourceChangedUserInfoChangedItemO
// XXX remove?
- (void)loadLazily;
+- (HistoryItem*)rootItem;
// ideally sorting would be on the view, not the data source, but this keeps thing simpler
- (void)setSortColumnIdentifier:(NSString*)sortColumnIdentifier;
diff --git a/camino/src/history/HistoryDataSource.mm b/camino/src/history/HistoryDataSource.mm
index 601b21d5a52c..0e271081927a 100644
--- a/camino/src/history/HistoryDataSource.mm
+++ b/camino/src/history/HistoryDataSource.mm
@@ -92,9 +92,9 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
// base class for a 'builder' object. This one just builds a flat list
@interface HistoryTreeBuilder : NSObject
{
- HistoryItem* mRootItem;
- SEL mSortSelector;
- BOOL mSortDescending;
+ HistoryCategoryItem* mRootItem;
+ SEL mSortSelector;
+ BOOL mSortDescending;
}
// sets up the tree and sorts it
@@ -104,8 +104,6 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
- (HistoryItem*)addItem:(HistorySiteItem*)item;
- (HistoryItem*)removeItem:(HistorySiteItem*)item;
-- (HistoryItem*)parentOfItem:(HistorySiteItem*)item;
-
- (void)resortWithSelector:(SEL)sortSelector descending:(BOOL)descending;
// for internal use
@@ -130,7 +128,7 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
@interface HistoryByDateTreeBuilder : HistoryTreeBuilder
{
- NSMutableArray* mDateCategories; // array of HistoryCategoryItems ordered recent -> old
+ NSMutableArray* mDateCategories; // array of HistoryCategoryItems ordered recent -> old
}
- (void)setupDateCategories;
@@ -225,21 +223,16 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
return mRootItem;
}
-- (HistoryItem*)parentOfItem:(HistorySiteItem*)item
-{
- return mRootItem;
-}
-
- (HistoryItem*)addItem:(HistorySiteItem*)item
{
- [[mRootItem children] addObject:item];
+ [mRootItem addChild:item];
[self resortFromItem:mRootItem];
return mRootItem;
}
- (HistoryItem*)removeItem:(HistorySiteItem*)item
{
- [[mRootItem children] removeObject:item];
+ [mRootItem removeChild:item];
// no need to resort
return mRootItem;
}
@@ -248,7 +241,7 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
{
mRootItem = [[HistoryCategoryItem alloc] initWithTitle:@"" childCapacity:[items count]];
- [[mRootItem children] addObjectsFromArray:items];
+ [mRootItem addChildren:items];
[self resortFromItem:mRootItem];
}
@@ -294,11 +287,6 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
[super dealloc];
}
-- (HistoryItem*)parentOfItem:(HistorySiteItem*)item
-{
- return [mSiteDictionary objectForKey:[item hostname]];
-}
-
- (HistoryCategoryItem*)ensureHostCategoryForItem:(HistorySiteItem*)inItem
{
NSString* itemHostname = [inItem hostname];
@@ -311,7 +299,7 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
hostCategory = [[HistorySiteCategoryItem alloc] initWithSite:itemHostname title:itemTitle childCapacity:10];
[mSiteDictionary setObject:hostCategory forKey:itemHostname];
- [[mRootItem children] addObject:hostCategory];
+ [mRootItem addChild:hostCategory];
[hostCategory release];
}
return hostCategory;
@@ -320,7 +308,7 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
- (void)removeSiteCategory:(HistoryCategoryItem*)item forHostname:(NSString*)hostname
{
[mSiteDictionary removeObjectForKey:hostname];
- [[mRootItem children] removeObject:item];
+ [mRootItem removeChild:item];
}
- (HistoryItem*)addItem:(HistorySiteItem*)item
@@ -331,7 +319,7 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
if (!hostCategory)
hostCategory = [self ensureHostCategoryForItem:item];
- [[hostCategory children] addObject:item];
+ [hostCategory addChild:item];
[self resortFromItem:newHost ? mRootItem : hostCategory];
return hostCategory;
@@ -341,7 +329,7 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
{
NSString* itemHostname = [item hostname];
HistoryCategoryItem* hostCategory = [mSiteDictionary objectForKey:itemHostname];
- [[hostCategory children] removeObject:item];
+ [hostCategory removeChild:item];
// is the category is now empty, remove it
if ([hostCategory numberOfChildren] == 0)
@@ -368,7 +356,7 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
while ((item = [itemsEnum nextObject]))
{
HistoryCategoryItem* hostCategory = [self ensureHostCategoryForItem:item];
- [[hostCategory children] addObject:item];
+ [hostCategory addChild:item];
}
[self resortFromItem:mRootItem];
@@ -385,9 +373,9 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
{
if ((self = [super init]))
{
- mSortSelector = sortSelector;
- mSortDescending = descending;
-
+ mSortSelector = sortSelector;
+ mSortDescending = descending;
+
[self setupDateCategories];
[self buildTreeWithItems:items];
}
@@ -470,15 +458,10 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
return nil;
}
-- (HistoryItem*)parentOfItem:(HistorySiteItem*)item
-{
- return [self categoryItemForDate:[item lastVisit]];
-}
-
- (HistoryItem*)addItem:(HistorySiteItem*)item
{
HistoryCategoryItem* dateCategory = [self categoryItemForDate:[item lastVisit]];
- [[dateCategory children] addObject:item];
+ [dateCategory addChild:item];
[self resortFromItem:dateCategory];
return dateCategory;
@@ -487,7 +470,7 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
- (HistoryItem*)removeItem:(HistorySiteItem*)item
{
HistoryCategoryItem* dateCategory = [self categoryItemForDate:[item lastVisit]];
- [[dateCategory children] removeObject:item];
+ [dateCategory removeChild:item];
// no need to resort
return dateCategory;
}
@@ -499,11 +482,11 @@ static int HistoryItemSort(id firstItem, id secondItem, void* context)
while ((item = [itemsEnum nextObject]))
{
HistoryCategoryItem* dateCategory = [self categoryItemForDate:[item lastVisit]];
- [[dateCategory children] addObject:item];
+ [dateCategory addChild:item];
}
mRootItem = [[HistoryCategoryItem alloc] initWithTitle:@"" childCapacity:[mDateCategories count]];
- [[mRootItem children] addObjectsFromArray:mDateCategories];
+ [mRootItem addChildren:mDateCategories];
[self resortFromItem:mRootItem];
}
@@ -633,6 +616,7 @@ NS_IMPL_ISUPPORTS1(nsHistoryObserver, nsIHistoryObserver);
mGlobalHistory = globalHist;
if (!mGlobalHistory)
{
+ NSLog(@"Failed to initialize HistoryDataSource (couldn't get global history)");
[self autorelease];
return nil;
}
@@ -814,6 +798,11 @@ NS_IMPL_ISUPPORTS1(nsHistoryObserver, nsIHistoryObserver);
[self rebuildHistory];
}
+- (HistoryItem*)rootItem
+{
+ return [mTreeBuilder rootItem];
+}
+
- (void)notifyChanged:(HistoryItem*)changeRoot itemOnly:(BOOL)itemOnly
{
// if we are displaying search results, make sure that updates
diff --git a/camino/src/history/HistoryItem.h b/camino/src/history/HistoryItem.h
index a103010d1279..955207805857 100644
--- a/camino/src/history/HistoryItem.h
+++ b/camino/src/history/HistoryItem.h
@@ -44,6 +44,7 @@ class nsIHistoryItem;
@interface HistoryItem : NSObject
{
+ HistoryItem* mParentItem; // not retained
}
- (NSString*)title;
@@ -56,6 +57,10 @@ class nsIHistoryItem;
- (NSString*)hostname;
- (NSString*)identifier;
+- (void)setParentItem:(HistoryItem*)inParent;
+- (HistoryItem*)parentItem;
+- (BOOL)isDescendentOfItem:(HistoryItem*)inItem;
+
- (NSMutableArray*)children;
- (int)numberOfChildren;
- (HistoryItem*)childAtIndex:(int)inIndex;
@@ -83,6 +88,10 @@ class nsIHistoryItem;
- (NSString*)title;
- (NSString*)identifier; // return UUID for this folder
+- (void)addChild:(HistoryItem*)inChild;
+- (void)removeChild:(HistoryItem*)inChild;
+- (void)addChildren:(NSArray*)inChildren;
+
@end
@@ -106,6 +115,7 @@ class nsIHistoryItem;
- (id)initWithStartDate:(NSDate*)startDate ageInDays:(int)days title:(NSString*)title childCapacity:(int)capacity;
- (NSDate*)startDate;
+- (BOOL)isTodayCategory;
@end
diff --git a/camino/src/history/HistoryItem.mm b/camino/src/history/HistoryItem.mm
index 4f7845d9e84c..fdb70b86fb00 100644
--- a/camino/src/history/HistoryItem.mm
+++ b/camino/src/history/HistoryItem.mm
@@ -109,6 +109,24 @@ enum
return @"";
}
+- (void)setParentItem:(HistoryItem*)inParent
+{
+ mParentItem = inParent;
+}
+
+- (HistoryItem*)parentItem
+{
+ return mParentItem;
+}
+
+- (BOOL)isDescendentOfItem:(HistoryItem*)inItem
+{
+ if (inItem == mParentItem)
+ return YES;
+
+ return [mParentItem isDescendentOfItem:inItem];
+}
+
- (NSMutableArray*)children
{
return nil;
@@ -233,6 +251,36 @@ enum
return nil;
}
+- (void)addChild:(HistoryItem*)inChild
+{
+ [mChildren addObject:inChild];
+ [inChild setParentItem:self];
+}
+
+- (void)insertChild:(HistoryItem*)inChild atIndex:(unsigned int)inIndex
+{
+ [mChildren insertObject:inChild atIndex:inIndex];
+ [inChild setParentItem:self];
+}
+
+- (void)removeChild:(HistoryItem*)inChild
+{
+ [mChildren removeObject:inChild];
+ [inChild setParentItem:nil];
+}
+
+- (void)addChildren:(NSArray*)inChildren
+{
+ [inChildren makeObjectsPerformSelector:@selector(setParentItem:) withObject:self];
+ [mChildren addObjectsFromArray:inChildren];
+}
+
+- (void)removeAllChildren
+{
+ [mChildren makeObjectsPerformSelector:@selector(setParentItem:) withObject:nil];
+ [mChildren removeAllObjects];
+}
+
- (NSComparisonResult)compareURL:(HistoryItem *)aItem sortDescending:(NSNumber*)inDescending
{
// always sort categories before sites
@@ -314,6 +362,11 @@ enum
return [NSString stringWithFormat:@"site:%d", mSite];
}
+- (NSString*)description
+{
+ return [NSString stringWithFormat:@"HistorySiteCategoryItem %p, site %@", self, mSite];
+}
+
@end // HistorySiteCategoryItem
#pragma mark -
@@ -341,11 +394,21 @@ enum
return mStartDate;
}
+- (BOOL)isTodayCategory
+{
+ return (mAgeInDays == 0);
+}
+
- (NSString*)identifier
{
return [NSString stringWithFormat:@"age_in_days:%d", mAgeInDays];
}
+- (NSString*)description
+{
+ return [NSString stringWithFormat:@"HistoryDateCategoryItem %p, start date %@, age %d days", self, mStartDate, mAgeInDays];
+}
+
- (NSComparisonResult)startDateCompare:(HistoryItem *)aItem sortDescending:(NSNumber*)inDescending
{
// always sort categories before sites
@@ -378,7 +441,7 @@ enum
return NSOrderedAscending;
// sort category items on date, always ascending
- NSComparisonResult result = [[self startDate] compare:[aItem startDate]];
+ NSComparisonResult result = [[self startDate] compare:[(HistoryDateCategoryItem*)aItem startDate]];
return [inDescending boolValue] ? (NSComparisonResult)(-1 * (int)result) : result;
}
diff --git a/camino/src/preferences/PreferenceManager.mm b/camino/src/preferences/PreferenceManager.mm
index 69c690b15c31..7ea2255de98c 100644
--- a/camino/src/preferences/PreferenceManager.mm
+++ b/camino/src/preferences/PreferenceManager.mm
@@ -290,6 +290,10 @@ static BOOL gMadePrefManager;
NS_IF_ADDREF(mPrefs);
[self syncMozillaPrefs];
+
+ // send out initted notification
+ [[NSNotificationCenter defaultCenter] postNotificationName:InitEmbeddingNotificationName object:nil];
+
return YES;
}