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; }