1 // Copyright (c) 2010 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/bookmarks/bookmark_folder_target.h" 6 7 #include "base/logging.h" 8 #include "base/sys_string_conversions.h" 9 #include "chrome/browser/bookmarks/bookmark_model.h" 10 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h" 11 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" 12 #import "chrome/browser/ui/cocoa/event_utils.h" 13 #import "third_party/mozilla/NSPasteboard+Utils.h" 14 15 NSString* kBookmarkButtonDragType = @"ChromiumBookmarkButtonDragType"; 16 17 @implementation BookmarkFolderTarget 18 19 - (id)initWithController:(id<BookmarkButtonControllerProtocol>)controller { 20 if ((self = [super init])) { 21 controller_ = controller; 22 } 23 return self; 24 } 25 26 // This IBAction is called when the user clicks (mouseUp, really) on a 27 // "folder" bookmark button. (In this context, "Click" does not 28 // include right-click to open a context menu which follows a 29 // different path). Scenarios when folder X is clicked: 30 // *Predicate* *Action* 31 // (nothing) Open Folder X 32 // Folder X open Close folder X 33 // Folder Y open Close Y, open X 34 // Cmd-click Open All with proper disposition 35 // 36 // Note complication in which a click-drag engages drag and drop, not 37 // a click-to-open. Thus the path to get here is a little twisted. 38 - (IBAction)openBookmarkFolderFromButton:(id)sender { 39 DCHECK(sender); 40 // Watch out for a modifier click. For example, command-click 41 // should open all. 42 // 43 // NOTE: we cannot use [[sender cell] mouseDownFlags] because we 44 // thwart the normal mouse click mechanism to make buttons 45 // draggable. Thus we must use [NSApp currentEvent]. 46 // 47 // Holding command while using the scroll wheel (or moving around 48 // over a bookmark folder) can confuse us. Unless we check the 49 // event type, we are not sure if this is an "open folder" due to a 50 // hover-open or "open folder" due to a click. It doesn't matter 51 // (both do the same thing) unless a modifier is held, since 52 // command-click should "open all" but command-move should not. 53 // WindowOpenDispositionFromNSEvent does not consider the event 54 // type; only the modifiers. Thus the need for an extra 55 // event-type-check here. 56 DCHECK([sender bookmarkNode]->is_folder()); 57 NSEvent* event = [NSApp currentEvent]; 58 WindowOpenDisposition disposition = 59 event_utils::WindowOpenDispositionFromNSEvent(event); 60 if (([event type] != NSMouseEntered) && 61 ([event type] != NSMouseMoved) && 62 ([event type] != NSScrollWheel) && 63 (disposition == NEW_BACKGROUND_TAB)) { 64 [controller_ closeAllBookmarkFolders]; 65 [controller_ openAll:[sender bookmarkNode] disposition:disposition]; 66 return; 67 } 68 69 // If click on same folder, close it and be done. 70 // Else we clicked on a different folder so more work to do. 71 if ([[controller_ folderController] parentButton] == sender) { 72 [controller_ closeBookmarkFolder:controller_]; 73 return; 74 } 75 76 [controller_ addNewFolderControllerWithParentButton:sender]; 77 } 78 79 - (void)copyBookmarkNode:(const BookmarkNode*)node 80 toPasteboard:(NSPasteboard*)pboard { 81 if (!node) { 82 NOTREACHED(); 83 return; 84 } 85 86 if (node->is_folder()) { 87 // TODO(viettrungluu): I'm not sure what we should do, so just declare the 88 // "additional" types we're given for now. Maybe we want to add a list of 89 // URLs? Would we then have to recurse if there were subfolders? 90 // In the meanwhile, we *must* set it to a known state. (If this survives to 91 // a 10.6-only release, it can be replaced with |-clearContents|.) 92 [pboard declareTypes:[NSArray array] owner:nil]; 93 } else { 94 const std::string spec = node->GetURL().spec(); 95 NSString* url = base::SysUTF8ToNSString(spec); 96 NSString* title = base::SysUTF16ToNSString(node->GetTitle()); 97 [pboard declareURLPasteboardWithAdditionalTypes:[NSArray array] 98 owner:nil]; 99 [pboard setDataForURL:url title:title]; 100 } 101 } 102 103 - (void)fillPasteboard:(NSPasteboard*)pboard 104 forDragOfButton:(BookmarkButton*)button { 105 if (const BookmarkNode* node = [button bookmarkNode]) { 106 // Put the bookmark information into the pasteboard, and then write our own 107 // data for |kBookmarkButtonDragType|. 108 [self copyBookmarkNode:node toPasteboard:pboard]; 109 [pboard addTypes:[NSArray arrayWithObject:kBookmarkButtonDragType] 110 owner:nil]; 111 [pboard setData:[NSData dataWithBytes:&button length:sizeof(button)] 112 forType:kBookmarkButtonDragType]; 113 } else { 114 NOTREACHED(); 115 } 116 } 117 118 @end 119