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 15NSString* 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