OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "chrome/browser/ui/cocoa/share_menu/share_menu_controller.h" |
| 6 |
| 7 #include "base/strings/sys_string_conversions.h" |
| 8 #include "base/strings/utf_string_conversions.h" |
| 9 #include "chrome/app/chrome_command_ids.h" |
| 10 #import "chrome/browser/app_controller_mac.h" |
| 11 #include "chrome/browser/ui/browser_commands.h" |
| 12 #include "chrome/browser/ui/browser_finder.h" |
| 13 #include "chrome/browser/ui/browser_list.h" |
| 14 #include "chrome/browser/ui/browser_list_observer.h" |
| 15 #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h" |
| 16 #include "chrome/browser/ui/cocoa/share_menu/share_menu_manager.h" |
| 17 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 18 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" |
| 19 #include "chrome/grit/generated_resources.h" |
| 20 #include "skia/ext/image_operations.h" |
| 21 #include "ui/base/l10n/l10n_util.h" |
| 22 #include "ui/base/l10n/l10n_util_mac.h" |
| 23 #include "ui/gfx/geometry/size_conversions.h" |
| 24 #include "ui/gfx/geometry/vector2d_conversions.h" |
| 25 #include "ui/gfx/skbitmap_operations.h" |
| 26 #include "ui/snapshot/snapshot.h" |
| 27 #include "net/base/escape.h" |
| 28 |
| 29 @interface ShareMenuController() <NSSharingServiceDelegate, NSMenuDelegate> |
| 30 - (void)buildShareItemsFor:(Browser* )browser; |
| 31 - (NSMenuItem*)createItemWithTitle:(NSString*)title action:(SEL)sel; |
| 32 - (void)enableShareMenuItemsFor:(Browser*)browser; |
| 33 // Retrieve the list of possible sharing options and create menu item for each. |
| 34 - (NSArray*)shareMenuItemsFor:(NSArray*)items; |
| 35 - (void)setPageScreenShotFor:(content::WebContents*)contents; |
| 36 - (void)setPageUrlFor:(content::WebContents*)contents; |
| 37 @end |
| 38 |
| 39 namespace ShareMenuControllerInternal { |
| 40 |
| 41 class Observer : public chrome::BrowserListObserver,TabStripModelObserver { |
| 42 public: |
| 43 Observer(ShareMenuController* controller) : controller_(controller) { |
| 44 BrowserList::AddObserver(this); |
| 45 } |
| 46 |
| 47 ~Observer() override { |
| 48 BrowserList::RemoveObserver(this); |
| 49 } |
| 50 |
| 51 void OnBrowserAdded(Browser* browser) override { |
| 52 tab_strip_ = browser->tab_strip_model(); |
| 53 tab_strip_->AddObserver(this); |
| 54 } |
| 55 |
| 56 void OnBrowserRemoved(Browser* browser) override { |
| 57 tab_strip_->RemoveObserver(this); |
| 58 } |
| 59 |
| 60 // Wait for a browser tab to become active before building the share menu. |
| 61 void OnBrowserSetLastActive(Browser* browser) override { |
| 62 [controller_ setActiveBrowser:browser]; |
| 63 if (browser && ![controller_ menuItemsLoaded]) { |
| 64 [controller_ initShareMenuItem]; |
| 65 [controller_ buildShareItemsFor:browser]; |
| 66 } |
| 67 LOG(ERROR) << "page refreshed"; |
| 68 [controller_ enableShareMenuItemsFor:browser]; |
| 69 [controller_ setPageContents:tab_strip_->GetActiveWebContents()]; |
| 70 } |
| 71 // When a detached tab / or a NTP is added to the tabstrip update webcontents. |
| 72 void TabInsertedAt(content::WebContents* contents, |
| 73 int index, |
| 74 bool foreground) override { |
| 75 [controller_ setPageUrlFor:contents]; |
| 76 [controller_ setPageContents:contents]; |
| 77 } |
| 78 |
| 79 // When tabs are switched update webcontents. |
| 80 void TabSelectionChanged(TabStripModel* tab_strip_model, |
| 81 const ui::ListSelectionModel& old_model) override { |
| 82 [controller_ setPageContents:tab_strip_->GetActiveWebContents()]; |
| 83 Browser* browser = chrome::GetLastActiveBrowser(); |
| 84 [controller_ enableShareMenuItemsFor:browser]; |
| 85 LOG(ERROR) << "Tabs switched"; |
| 86 } |
| 87 |
| 88 void TabChangedAt(content::WebContents* contents, |
| 89 int index, |
| 90 TabChangeType change_type) override { |
| 91 LOG(ERROR) << "Tab contents changed"; |
| 92 [controller_ setPageContents:contents]; |
| 93 } |
| 94 |
| 95 private: |
| 96 ShareMenuController* controller_; // Weak; owns this. |
| 97 TabStripModel* tab_strip_; |
| 98 }; |
| 99 |
| 100 } // namespace ShareMenuControllerInternal |
| 101 |
| 102 //////////////////////////////////////////////////////////////////////////////// |
| 103 |
| 104 @implementation ShareMenuController |
| 105 |
| 106 - (id)initWithMainMenu:(NSMenu*)menu { |
| 107 if (self = [super init]) { |
| 108 mainMenu_ = menu; |
| 109 shareItems_.reset([[NSMutableArray alloc] init]); |
| 110 pageInfo_.reset([[NSMutableDictionary alloc] init]); |
| 111 menuItemsLoaded_ = NO; |
| 112 observer_.reset(new ShareMenuControllerInternal::Observer(self)); |
| 113 } |
| 114 return self; |
| 115 } |
| 116 |
| 117 - (BOOL) menuItemsLoaded { |
| 118 return menuItemsLoaded_; |
| 119 } |
| 120 |
| 121 - (void)setPageContents:(content::WebContents*)contents { |
| 122 pageContents_ = contents; |
| 123 } |
| 124 |
| 125 - (void)setActiveBrowser:(Browser*)browser { |
| 126 lastActiveBrowser_ = browser; |
| 127 } |
| 128 |
| 129 - (void)rebuildShareMenu { |
| 130 //[shareSubMenu_ removeAllItems]; |
| 131 //[self buildShareItemsFor:lastActiveBrowser_]; |
| 132 } |
| 133 |
| 134 // Create a submenu for displaying various system wide sharing options. |
| 135 - (void)initShareMenuItem { |
| 136 shareSubMenu_.reset([[NSMenu alloc] initWithTitle:@"ShareSubMenu"]); |
| 137 fileMenuItem_ = [mainMenu_ itemWithTag:IDC_FILE_MENU]; |
| 138 NSString* shareMenuName = |
| 139 l10n_util::GetNSStringWithFixup(IDS_SHARE_MENU_MAC); |
| 140 shareMenuItem_ = [self createItemWithTitle:shareMenuName action:nil]; |
| 141 [shareMenuItem_ setTag:IDC_SHARE_MENU]; |
| 142 } |
| 143 |
| 144 - (NSMenu*)shareSubMenu { |
| 145 return shareSubMenu_; |
| 146 } |
| 147 |
| 148 - (NSMenuItem*)shareSubMenuItem { |
| 149 return shareMenuItem_; |
| 150 } |
| 151 |
| 152 - (void)buildShareItemsFor:(Browser*)browser { |
| 153 if (!shareSubMenu_) |
| 154 return; |
| 155 |
| 156 [shareItems_ addObject:pageUrlForCurrentTab_]; |
| 157 NSArray* menuItems = [self shareMenuItemsFor:shareItems_]; |
| 158 for (NSMenuItem* item in menuItems) { |
| 159 [shareSubMenu_ addItem:item]; |
| 160 } |
| 161 |
| 162 // Add the Share Menu Item. |
| 163 NSMenuItem* savePageItem = [[fileMenuItem_ submenu] |
| 164 itemWithTag:IDC_SAVE_PAGE]; |
| 165 NSInteger idxSavePage = [[fileMenuItem_ submenu] indexOfItem:savePageItem]; |
| 166 [[fileMenuItem_ submenu] insertItem:shareMenuItem_ atIndex:idxSavePage + 2]; |
| 167 |
| 168 // Remove the Email Page location Menu Item. |
| 169 NSMenuItem* emailPageItem = [[fileMenuItem_ submenu] |
| 170 itemWithTag:IDC_EMAIL_PAGE_LOCATION]; |
| 171 [[fileMenuItem_ submenu] removeItem:emailPageItem]; |
| 172 |
| 173 [[fileMenuItem_ submenu] setSubmenu:shareSubMenu_ forItem:shareMenuItem_]; |
| 174 menuItemsLoaded_ = YES; |
| 175 } |
| 176 |
| 177 - (NSMenuItem*)createItemWithTitle:(NSString*)title action:(SEL)sel { |
| 178 NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title action:sel |
| 179 keyEquivalent:@""] |
| 180 autorelease]; |
| 181 [item setTarget:self]; |
| 182 return item; |
| 183 } |
| 184 |
| 185 - (void)enableShareMenuItemsFor:(Browser*)browser { |
| 186 [shareSubMenu_ setAutoenablesItems:NO]; |
| 187 for (NSMenuItem* item in [shareSubMenu_ itemArray]) { |
| 188 BOOL enabled = chrome::CanEmailPageLocation(browser) ? |
| 189 [self validateMenuItem:item] : NO; |
| 190 [item setEnabled:enabled]; |
| 191 } |
| 192 } |
| 193 |
| 194 - (NSArray*)shareMenuItemsFor:(NSArray*)items { |
| 195 base::scoped_nsobject<NSMutableArray> |
| 196 menuItems([[NSMutableArray alloc] init]); |
| 197 NSArray *sharingServices = [NSSharingService sharingServicesForItems:items]; |
| 198 //originalSharableItems_.reset([[NSArray alloc] initWithArray:sharingServices]
); |
| 199 for (NSSharingService* currentService in sharingServices) { |
| 200 NSString* titleText = nil; |
| 201 if ([currentService isEqualTo:[NSSharingService sharingServiceNamed |
| 202 : NSSharingServiceNameComposeEmail]]) { |
| 203 titleText = l10n_util::GetNSString(IDS_EMAIL_PAGE_LOCATION_MAC); |
| 204 } else { |
| 205 titleText = currentService.title; |
| 206 } |
| 207 NSMenuItem* item = [self createItemWithTitle:titleText |
| 208 action:@selector( |
| 209 systemShareService:)]; |
| 210 item.image = currentService.image; |
| 211 item.representedObject = currentService; |
| 212 [item setTarget:self]; |
| 213 currentService.delegate = self; |
| 214 [menuItems addObject:item]; |
| 215 } |
| 216 |
| 217 // Add the AirDrop menu item. |
| 218 NSMenuItem* item = nil; |
| 219 NSSharingService* customService = nil; |
| 220 customService = [NSSharingService sharingServiceNamed |
| 221 :NSSharingServiceNameSendViaAirDrop]; |
| 222 item = [self createItemWithTitle:customService.title |
| 223 action:@selector( |
| 224 systemShareService:)]; |
| 225 item.image = customService.image; |
| 226 item.representedObject = customService; |
| 227 [item setTarget:self]; |
| 228 customService.delegate = self; |
| 229 [menuItems addObject:item]; |
| 230 |
| 231 // Add a menu item to open up system share panel. |
| 232 customService = [[NSSharingService alloc] initWithTitle:@"More" |
| 233 image:nil |
| 234 alternateImage:nil |
| 235 handler:nil]; |
| 236 item = [self createItemWithTitle:customService.title |
| 237 action:@selector( |
| 238 systemShareService:)]; |
| 239 item.representedObject = customService; |
| 240 [item setTarget:self]; |
| 241 customService.delegate = self; |
| 242 [menuItems addObject:item]; |
| 243 |
| 244 return [NSArray arrayWithArray:menuItems]; |
| 245 } |
| 246 |
| 247 - (void)setPageScreenShotFor:(content::WebContents*)contents { |
| 248 scoped_ptr<std::vector<unsigned char> > png_representation( |
| 249 new std::vector<unsigned char>); |
| 250 NSView* webView = contents->GetNativeView(); |
| 251 NSRect frame = [webView frame]; |
| 252 gfx::Rect bounds(frame.origin.x, frame.origin.y, frame.size.width, |
| 253 frame.size.height); |
| 254 if (ui::GrabViewSnapshot( |
| 255 contents->GetNativeView(), png_representation.get(), bounds)) { |
| 256 base::scoped_nsobject<NSData> image_data( |
| 257 [[NSData alloc] initWithBytes:&(*png_representation)[0] |
| 258 length:png_representation->size()]); |
| 259 contentSnapShot_.reset([[NSImage alloc] initWithData:image_data]); |
| 260 NSURL* pageUrl = [NSURL URLWithString:pageUrlForCurrentTab_]; |
| 261 base::scoped_nsobject<NSData> pageData([[NSData alloc] |
| 262 initWithContentsOfURL:pageUrl]); |
| 263 NSLog(@"page url %@", pageUrlForCurrentTab_); |
| 264 page_.reset([[NSString alloc] initWithData:pageData |
| 265 encoding:NSUTF8StringEncoding]); |
| 266 pageHtml_.reset([[NSMutableAttributedString alloc] |
| 267 initWithData:pageData.get() documentAttributes:nil]); |
| 268 //NSLog(@"page html size %ld", [pageHtml_ length]); |
| 269 } |
| 270 } |
| 271 |
| 272 - (void)setPageUrlFor:(content::WebContents*)contents { |
| 273 std::string pageUrl = contents->GetVisibleURL().spec(); |
| 274 pageUrlForCurrentTab_ = base::SysUTF8ToNSString(pageUrl); |
| 275 } |
| 276 |
| 277 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { |
| 278 return ([menuItem action] == @selector(systemShareService:)); |
| 279 } |
| 280 |
| 281 - (void)systemShareService:(id)sender { |
| 282 NSMenuItem* currentMenuItem = (NSMenuItem*)sender; |
| 283 [self setPageUrlFor:pageContents_]; |
| 284 [self setPageScreenShotFor:pageContents_]; |
| 285 pageInfo_.reset([[NSDictionary alloc] |
| 286 initWithObjectsAndKeys:pageUrlForCurrentTab_, kPageUrl, |
| 287 contentSnapShot_.get(), kPageScreenShot, |
| 288 pageHtml_.get(), kPageHtml,nil]); |
| 289 |
| 290 [ShareMenuManager dispatchSharingServiceEventsFor: |
| 291 currentMenuItem.representedObject AndPageInfo:pageInfo_]; |
| 292 } |
| 293 |
| 294 // Sharing Service delegate methods. |
| 295 - (NSRect)sharingService:(NSSharingService*)sharingService |
| 296 sourceFrameOnScreenForShareItem:(id<NSPasteboardWriting>)item { |
| 297 if (![item isKindOfClass:[NSImage class]]) |
| 298 return NSZeroRect; |
| 299 |
| 300 NSView* webView = pageContents_->GetNativeView(); |
| 301 NSRect frame = [webView frame]; |
| 302 return frame; |
| 303 } |
| 304 |
| 305 - (NSImage *)sharingService:(NSSharingService*)sharingService |
| 306 transitionImageForShareItem:(id<NSPasteboardWriting>)item |
| 307 contentRect:(NSRect *)contentRect { |
| 308 if (![item isKindOfClass:[NSImage class]]) |
| 309 return nil; |
| 310 |
| 311 return contentSnapShot_.get(); |
| 312 } |
| 313 |
| 314 @end |
OLD | NEW |