From fa2386a7b9c928407413771c862cec28efcafba5 Mon Sep 17 00:00:00 2001 From: "stuart.morgan%alumni.case.edu" Date: Thu, 25 Sep 2008 04:58:40 +0000 Subject: [PATCH] Camino only - Bug 419578: Add a 'Recently Closed Pages' history submenu. r=ardisson sr=pink git-svn-id: svn://10.0.0.236/trunk@254421 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/camino/src/browser/BrowserWrapper.h | 2 + mozilla/camino/src/browser/BrowserWrapper.mm | 6 ++ mozilla/camino/src/browser/HistoryMenu.h | 1 + mozilla/camino/src/browser/HistoryMenu.mm | 77 +++++++++++++++++++- 4 files changed, 83 insertions(+), 3 deletions(-) diff --git a/mozilla/camino/src/browser/BrowserWrapper.h b/mozilla/camino/src/browser/BrowserWrapper.h index 6d21baea223..ae8534e16e3 100644 --- a/mozilla/camino/src/browser/BrowserWrapper.h +++ b/mozilla/camino/src/browser/BrowserWrapper.h @@ -48,6 +48,8 @@ class nsIMutableArray; class nsIArray; +extern NSString* const kBrowserInstanceClosedNotification; + // // The BrowserWrapper communicates with the UI via this delegate. // The delegate will be nil for background tabs. diff --git a/mozilla/camino/src/browser/BrowserWrapper.mm b/mozilla/camino/src/browser/BrowserWrapper.mm index 0ed5c1378a0..872f44c2366 100644 --- a/mozilla/camino/src/browser/BrowserWrapper.mm +++ b/mozilla/camino/src/browser/BrowserWrapper.mm @@ -99,6 +99,8 @@ enum StatusPriority { eStatusScriptDefault = 3, // javascript window.defaultStatus }; +NSString* const kBrowserInstanceClosedNotification = @"BrowserInstanceClosed"; + @interface BrowserWrapper(Private) - (void)ensureContentClickListeners; @@ -251,6 +253,10 @@ enum StatusPriority { - (void)browserClosed { + // Post a notification that we are closing, before the browser view is gone. + [[NSNotificationCenter defaultCenter] postNotificationName:kBrowserInstanceClosedNotification + object:self]; + // Break the cycle, but don't clear ourselves as the container // before we call |destroyWebBrowser| or onUnload handlers won't be // able to create new windows. The container will get cleared diff --git a/mozilla/camino/src/browser/HistoryMenu.h b/mozilla/camino/src/browser/HistoryMenu.h index 2feef2b745b..90a169d12f3 100644 --- a/mozilla/camino/src/browser/HistoryMenu.h +++ b/mozilla/camino/src/browser/HistoryMenu.h @@ -74,6 +74,7 @@ { IBOutlet NSMenuItem* mItemBeforeHistoryItems; // the item after which we add history items. HistoryItem* mTodayItem; // the "Today" history group + NSMenu* mRecentlyClosedMenu; // the folder of recently closed pages BOOL mAppLaunchDone; // has app launching completed? } diff --git a/mozilla/camino/src/browser/HistoryMenu.mm b/mozilla/camino/src/browser/HistoryMenu.mm index b6fee9e4f7a..8ec3e2b87e7 100644 --- a/mozilla/camino/src/browser/HistoryMenu.mm +++ b/mozilla/camino/src/browser/HistoryMenu.mm @@ -45,6 +45,7 @@ #import "MainController.h" #import "BrowserWindowController.h" +#import "BrowserWrapper.h" #import "CHBrowserService.h" #import "PreferenceManager.h" @@ -60,6 +61,9 @@ static const int kMaxNumHistoryItems = 50; // the maximum number of "today" items to show on the main menu static const unsigned int kMaxTodayItems = 12; +// the maximum number of recently closed pages to show +static const unsigned int kMaxRecentlyClosedItems = 20; + // the maximum number of characters in a menu title before cropping it static const unsigned int kMaxTitleLength = 50; @@ -331,9 +335,13 @@ static const unsigned int kMaxTitleLength = 50; - (void)openHistoryItem:(id)sender { id repObject = [sender representedObject]; - if ([repObject isKindOfClass:[HistoryItem class]]) { - NSString* itemURL = [repObject url]; + NSString* itemURL = nil; + if ([repObject isKindOfClass:[HistoryItem class]]) + itemURL = [repObject url]; + else if ([repObject isKindOfClass:[NSString class]]) + itemURL = repObject; + if (itemURL) { // XXX share this logic with MainController and HistoryOutlineViewDelegate BrowserWindowController* bwc = [(MainController *)[NSApp delegate] mainWindowBrowserController]; if (bwc) { @@ -389,11 +397,13 @@ static const unsigned int kMaxTitleLength = 50; { [[NSNotificationCenter defaultCenter] removeObserver:self]; [mTodayItem release]; + [mRecentlyClosedMenu release]; [super dealloc]; } - (void)awakeFromNib { + mRecentlyClosedMenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"RecentlyClosed", nil)]; [self setNeedsRebuild:YES]; // listen for app launch completion @@ -401,6 +411,12 @@ static const unsigned int kMaxTitleLength = 50; selector:@selector(appLaunchFinished:) name:NSApplicationDidFinishLaunchingNotification object:nil]; + + // listen for closing pages + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(browserClosed:) + name:kBrowserInstanceClosedNotification + object:nil]; } - (void)appLaunchFinished:(NSNotification*)inNotification @@ -411,6 +427,49 @@ static const unsigned int kMaxTitleLength = 50; [self performSelector:@selector(setupHistoryMenu) withObject:nil afterDelay:0]; } +- (void)browserClosed:(NSNotification*)inNotification +{ + BrowserWrapper* browser = [inNotification object]; + NSString* pageURI = [browser currentURI]; + + // Ignore empty pages, as well as things like Bookmarks and History. + if ([pageURI isBlankURL] || [pageURI hasCaseInsensitivePrefix:@"about:"]) + return; + + NSString* itemTitle = [browser pageTitle]; + if ([itemTitle length] == 0) + itemTitle = pageURI; + itemTitle = [itemTitle stringByTruncatingTo:kMaxTitleLength at:kTruncateAtMiddle]; + + // If this is the first item being added, mark the menu as needing a rebuild + // so that the folder will be added. + if ([mRecentlyClosedMenu numberOfItems] == 0) + [self setNeedsRebuild:YES]; + + NSMenuItem* newItem = [[[NSMenuItem alloc] initWithTitle:itemTitle + action:@selector(openHistoryItem:) + keyEquivalent:@""] autorelease]; + [newItem setImage:[browser siteIcon]]; + [newItem setTarget:self]; + [newItem setRepresentedObject:pageURI]; + + // Add the new item and its alternates at the top of the menu, and figure out + // how many menu items there are per entry so we can enforce the max correctly. + [mRecentlyClosedMenu insertItem:newItem atIndex:0]; + int itemsPerEntry = 1 + [mRecentlyClosedMenu addCommandKeyAlternatesForMenuItem:newItem]; + int maxItems = kMaxRecentlyClosedItems * itemsPerEntry; + + // Remove any previous entries with the same URL so we don't have duplicates, + // then enforce the limit. + for (int i = [mRecentlyClosedMenu numberOfItems] - 1; i >= itemsPerEntry; --i) { + if ([[[mRecentlyClosedMenu itemAtIndex:i] representedObject] isEqualToString:pageURI]) + [mRecentlyClosedMenu removeItemAtIndex:i]; + } + while ([mRecentlyClosedMenu numberOfItems] > maxItems) { + [mRecentlyClosedMenu removeItemAtIndex:maxItems]; + } +} + - (void)menuWillBeDisplayed { if (mAppLaunchDone) { @@ -493,10 +552,20 @@ static const unsigned int kMaxTitleLength = 50; - (void)addLastItems { - // at the bottom of the go menu, add a Clear History item if ([[mRootItem children] count] > 0) [self addItem:[NSMenuItem separatorItem]]; + // Add the recently closed items menu if there are any. + if ([mRecentlyClosedMenu numberOfItems] > 0) { + NSMenuItem* recentlyClosedItem = [self addItemWithTitle:NSLocalizedString(@"RecentlyClosed", nil) + action:nil + keyEquivalent:@""]; + [recentlyClosedItem setImage:[NSImage imageNamed:@"folder"]]; + [self setSubmenu:mRecentlyClosedMenu forItem:recentlyClosedItem]; + [self addItem:[NSMenuItem separatorItem]]; + } + + // at the bottom of the go menu, add a Clear History item NSMenuItem* clearHistoryItem = [[[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"ClearHistoryMenuItem", @"") action:@selector(clearHistory:) keyEquivalent:@""] autorelease]; @@ -509,6 +578,8 @@ static const unsigned int kMaxTitleLength = 50; // If rootChangedItem is nil, the whole history tree is being rebuilt. if (!rootChangedItem) { + [mRecentlyClosedMenu release]; + mRecentlyClosedMenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"RecentlyClosed", nil)]; [mTodayItem release]; mTodayItem = nil; }