Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(521)

Side by Side Diff: chrome/browser/tab_contents/tab_contents_view_mac.mm

Issue 160083: Enable dragging of images to desktop (Finder), Preview, etc. (on Mac).... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/tab_contents/tab_contents_view_mac.h ('k') | chrome/chrome.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/tab_contents/tab_contents_view_mac.h" 5 #include "chrome/browser/tab_contents/tab_contents_view_mac.h"
6 6
7 #include "base/sys_string_conversions.h" 7 #include <string>
8
8 #include "chrome/browser/browser.h" // TODO(beng): this dependency is awful. 9 #include "chrome/browser/browser.h" // TODO(beng): this dependency is awful.
9 #include "chrome/browser/cocoa/nsimage_cache.h"
10 #include "chrome/browser/cocoa/sad_tab_view.h" 10 #include "chrome/browser/cocoa/sad_tab_view.h"
11 #import "chrome/browser/cocoa/web_drag_source.h"
11 #import "chrome/browser/cocoa/web_drop_target.h" 12 #import "chrome/browser/cocoa/web_drop_target.h"
12 #include "chrome/browser/renderer_host/render_widget_host.h" 13 #include "chrome/browser/renderer_host/render_widget_host.h"
13 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" 14 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
14 #include "chrome/browser/tab_contents/render_view_context_menu_mac.h" 15 #include "chrome/browser/tab_contents/render_view_context_menu_mac.h"
15 #include "chrome/browser/tab_contents/tab_contents.h" 16 #include "chrome/browser/tab_contents/tab_contents.h"
16 #include "chrome/common/notification_type.h" 17 #include "chrome/common/notification_type.h"
17 #include "chrome/common/notification_service.h" 18 #include "chrome/common/notification_service.h"
18 #include "chrome/common/render_messages.h" 19 #include "chrome/common/render_messages.h"
19 #include "net/base/net_util.h"
20 #import "third_party/mozilla/include/NSPasteboard+Utils.h" 20 #import "third_party/mozilla/include/NSPasteboard+Utils.h"
21 21
22 #include "chrome/common/temp_scaffolding_stubs.h" 22 #include "chrome/common/temp_scaffolding_stubs.h"
23 23
24 @interface TabContentsViewCocoa (Private) 24 @interface TabContentsViewCocoa (Private)
25 - (id)initWithTabContentsViewMac:(TabContentsViewMac*)w; 25 - (id)initWithTabContentsViewMac:(TabContentsViewMac*)w;
26 - (void)processKeyboardEvent:(NSEvent*)event; 26 - (void)processKeyboardEvent:(NSEvent*)event;
27 - (TabContents*)tabContents;
28 - (void)registerDragTypes; 27 - (void)registerDragTypes;
29 - (void)setIsDropTarget:(BOOL)isTarget; 28 - (void)setIsDropTarget:(BOOL)isTarget;
29 - (void)startDragWithDropData:(const WebDropData&)dropData;
30 @end 30 @end
31 31
32 // static 32 // static
33 TabContentsView* TabContentsView::Create(TabContents* tab_contents) { 33 TabContentsView* TabContentsView::Create(TabContents* tab_contents) {
34 return new TabContentsViewMac(tab_contents); 34 return new TabContentsViewMac(tab_contents);
35 } 35 }
36 36
37 TabContentsViewMac::TabContentsViewMac(TabContents* tab_contents) 37 TabContentsViewMac::TabContentsViewMac(TabContents* tab_contents)
38 : TabContentsView(tab_contents) { 38 : TabContentsView(tab_contents) {
39 registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED, 39 registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED,
40 Source<TabContents>(tab_contents)); 40 Source<TabContents>(tab_contents));
41 } 41 }
42 42
43 TabContentsViewMac::~TabContentsViewMac() {
44 }
45
46 void TabContentsViewMac::CreateView() { 43 void TabContentsViewMac::CreateView() {
47 TabContentsViewCocoa* view = 44 TabContentsViewCocoa* view =
48 [[TabContentsViewCocoa alloc] initWithTabContentsViewMac:this]; 45 [[TabContentsViewCocoa alloc] initWithTabContentsViewMac:this];
49 cocoa_view_.reset(view); 46 cocoa_view_.reset(view);
50 } 47 }
51 48
52 RenderWidgetHostView* TabContentsViewMac::CreateViewForWidget( 49 RenderWidgetHostView* TabContentsViewMac::CreateViewForWidget(
53 RenderWidgetHost* render_widget_host) { 50 RenderWidgetHost* render_widget_host) {
54 DCHECK(!render_widget_host->view()); 51 DCHECK(!render_widget_host->view());
55 RenderWidgetHostViewMac* view = 52 RenderWidgetHostViewMac* view =
(...skipping 23 matching lines...) Expand all
79 } 76 }
80 77
81 gfx::NativeWindow TabContentsViewMac::GetTopLevelNativeWindow() const { 78 gfx::NativeWindow TabContentsViewMac::GetTopLevelNativeWindow() const {
82 return [cocoa_view_.get() window]; 79 return [cocoa_view_.get() window];
83 } 80 }
84 81
85 void TabContentsViewMac::GetContainerBounds(gfx::Rect* out) const { 82 void TabContentsViewMac::GetContainerBounds(gfx::Rect* out) const {
86 *out = [cocoa_view_.get() NSRectToRect:[cocoa_view_.get() bounds]]; 83 *out = [cocoa_view_.get() NSRectToRect:[cocoa_view_.get() bounds]];
87 } 84 }
88 85
89 // Returns a drag pasteboard filled with the appropriate data. The types are
90 // populated in decending order of richness.
91 NSPasteboard* TabContentsViewMac::FillDragData(
92 const WebDropData& drop_data) {
93 NSPasteboard* pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
94 [pasteboard declareTypes:[NSArray array] owner:nil];
95
96 // HTML.
97 if (!drop_data.text_html.empty()) {
98 [pasteboard addTypes:[NSArray arrayWithObject:NSHTMLPboardType]
99 owner:nil];
100 [pasteboard setString:base::SysUTF16ToNSString(drop_data.text_html)
101 forType:NSHTMLPboardType];
102 }
103
104 // URL.
105 if (drop_data.url.is_valid()) {
106 // TODO(pinkerton/jrg): special javascript: handling for bookmark bar. Win
107 // doesn't allow you to drop js: bookmarks on the desktop (since they're
108 // meaningless) but does allow you to drop them on the bookmark bar (where
109 // they're intended to go generally). We need to figure out a private
110 // flavor for Bookmark dragging and then flag this down in the drag source.
111 [pasteboard addTypes:[NSArray arrayWithObject:NSURLPboardType]
112 owner:nil];
113 NSString* url = base::SysUTF8ToNSString(drop_data.url.spec());
114 NSString* title = base::SysUTF16ToNSString(drop_data.url_title);
115 [pasteboard setURLs:[NSArray arrayWithObject:url]
116 withTitles:[NSArray arrayWithObject:title]];
117 }
118
119 // Files.
120 // TODO(pinkerton): Hook up image drags, data is in drop_data.file_contents.
121 if (!drop_data.file_contents.empty()) {
122 #if 0
123 // Images without ALT text will only have a file extension so we need to
124 // synthesize one from the provided extension and URL.
125 std::string filename_utf8 =
126 [base::SysUTF16ToNSString(drop_data.file_description_filename)
127 fileSystemRepresentation];
128 FilePath file_name(filename_utf8);
129 file_name = file_name.BaseName().RemoveExtension();
130 if (file_name.value().empty()) {
131 // Retrieve the name from the URL.
132 file_name = FilePath::FromWStringHack(
133 net::GetSuggestedFilename(drop_data.url, "", "", L""));
134 }
135 std::string file_extension_utf8 =
136 [base::SysUTF16ToNSString(drop_data.file_extension)
137 fileSystemRepresentation];
138 file_name = file_name.ReplaceExtension(file_extension_utf8);
139 NSArray* types = [NSArray arrayWithObjects:NSFileContentsPboardType,
140 NSFilenamesPboardType,
141 nil];
142 [pasteboard addTypes:types owner:nil];
143 NSArray* file_name_array =
144 [NSArray arrayWithObject:base::SysUTF8ToNSString(file_name.value())];
145 [pasteboard setPropertyList:file_name_array forType:NSFilenamesPboardType];
146 NSData* data = [NSData dataWithBytes:drop_data.file_contents.data()
147 length:drop_data.file_contents.length()];
148 [pasteboard setData:data forType:NSFileContentsPboardType];
149 #endif
150 }
151
152 // Plain text.
153 if (!drop_data.plain_text.empty()) {
154 [pasteboard addTypes:[NSArray arrayWithObject:NSStringPboardType]
155 owner:nil];
156 [pasteboard setString:base::SysUTF16ToNSString(drop_data.plain_text)
157 forType:NSStringPboardType];
158 }
159 return pasteboard;
160 }
161
162 void TabContentsViewMac::StartDragging(const WebDropData& drop_data) { 86 void TabContentsViewMac::StartDragging(const WebDropData& drop_data) {
163 // We are only allowed to call dragImage:... from inside mouseDragged:, which 87 // We are only allowed to call dragImage:... from inside mouseDragged:, which
164 // we will never be (we're called back async), but it seems that the mouse 88 // we will never be (we're called back async), but it seems that the mouse
165 // event is still always the proper left mouse drag, so everything works out 89 // event is still always the proper left mouse drag, so everything works out
166 // in the end. However, we occasionally get spurrious "start drag" messages 90 // in the end. However, we occasionally get spurious "start drag" messages
167 // from the back-end when we shouldn't. If we go through with the drag, Cocoa 91 // from the back-end when we shouldn't. If we go through with the drag, Cocoa
168 // asserts in a bad way. Just bail for now until we can figure out the root of 92 // asserts in a bad way. Just bail for now until we can figure out the root of
169 // why we're getting the messages. 93 // why we're getting the messages.
170 // TODO(pinkerton): http://crbug.com/16811 94 // TODO(pinkerton): http://crbug.com/16811
171 NSEvent* currentEvent = [NSApp currentEvent]; 95 NSEvent* currentEvent = [NSApp currentEvent];
172 if ([currentEvent type] != NSLeftMouseDragged) { 96 if ([currentEvent type] != NSLeftMouseDragged) {
173 LOG(INFO) << "Spurious StartDragging() message"; 97 LOG(INFO) << "Spurious StartDragging() message";
174 RenderViewHost* rvh = tab_contents()->render_view_host(); 98 RenderViewHost* rvh = tab_contents()->render_view_host();
175 if (rvh) 99 if (rvh)
176 rvh->DragSourceSystemDragEnded(); 100 rvh->DragSourceSystemDragEnded();
177 return; 101 return;
178 } 102 }
179 103
180 // Create an image to use for the drag. 104 // The drag invokes a nested event loop, but we need to continue processing
181 // TODO(pinkerton): Generate the proper image. This one will do in a pinch. 105 // events.
182 NSImage* dragImage = nsimage_cache::ImageNamed(@"nav.pdf");
183
184 NSPasteboard* pasteboard = FillDragData(drop_data);
185
186 // Tell the view to start a drag using |cocoa_view_| as the drag source. The
187 // source will get notified when the drag completes (success or failure) so
188 // it can tell the render view host the drag is done. The drag invokes a
189 // nested event loop, but we need to continue processing events.
190 NSPoint mousePoint = [currentEvent locationInWindow];
191 mousePoint = [cocoa_view_ convertPoint:mousePoint fromView:nil];
192 MessageLoop::current()->SetNestableTasksAllowed(true); 106 MessageLoop::current()->SetNestableTasksAllowed(true);
193 [cocoa_view_ dragImage:dragImage 107 [cocoa_view_ startDragWithDropData:drop_data];
194 at:mousePoint
195 offset:NSZeroSize
196 event:currentEvent
197 pasteboard:pasteboard
198 source:cocoa_view_
199 slideBack:YES];
200 MessageLoop::current()->SetNestableTasksAllowed(false); 108 MessageLoop::current()->SetNestableTasksAllowed(false);
201 } 109 }
202 110
203 void TabContentsViewMac::OnContentsDestroy() { 111 void TabContentsViewMac::OnContentsDestroy() {
204 } 112 }
205 113
206 void TabContentsViewMac::RenderViewCreated(RenderViewHost* host) { 114 void TabContentsViewMac::RenderViewCreated(RenderViewHost* host) {
207 // We want updates whenever the intrinsic width of the webpage 115 // We want updates whenever the intrinsic width of the webpage
208 // changes. Put the RenderView into that mode. 116 // changes. Put the RenderView into that mode.
209 int routing_id = host->routing_id(); 117 int routing_id = host->routing_id();
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 } 326 }
419 327
420 - (void)copy:(id)sender { 328 - (void)copy:(id)sender {
421 [self tabContents]->Copy(); 329 [self tabContents]->Copy();
422 } 330 }
423 331
424 - (void)paste:(id)sender { 332 - (void)paste:(id)sender {
425 [self tabContents]->Paste(); 333 [self tabContents]->Paste();
426 } 334 }
427 335
336 - (void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type {
337 [dragSource_ lazyWriteToPasteboard:sender
338 forType:type];
339 }
340
341 - (void)startDragWithDropData:(const WebDropData&)dropData {
342 dragSource_.reset([[WebDragSource alloc]
343 initWithContentsView:self
344 dropData:&dropData
345 pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard]]);
346 [dragSource_ startDrag];
347 }
348
428 // NSDraggingSource methods 349 // NSDraggingSource methods
429 350
430 // Returns what kind of drag operations are available. This is a required 351 // Returns what kind of drag operations are available. This is a required
431 // method for NSDraggingSource. 352 // method for NSDraggingSource.
432 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { 353 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
433 // TODO(pinkerton): I think this is right... 354 // TODO(pinkerton): I think this is right...
434 return NSDragOperationCopy; 355 return NSDragOperationCopy;
435 } 356 }
436 357
437 // Called when a drag initiated in our view ends. We need to make sure that 358 // Called when a drag initiated in our view ends.
438 // we tell WebCore so that it can go about processing things as normal.
439 - (void)draggedImage:(NSImage*)anImage 359 - (void)draggedImage:(NSImage*)anImage
440 endedAt:(NSPoint)screenPoint 360 endedAt:(NSPoint)screenPoint
441 operation:(NSDragOperation)operation { 361 operation:(NSDragOperation)operation {
442 RenderViewHost* rvh = [self tabContents]->render_view_host(); 362 [dragSource_ endDragAt:screenPoint
443 if (rvh) { 363 isCancelled:(operation == NSDragOperationNone)];
444 rvh->DragSourceSystemDragEnded();
445 364
446 // Convert |screenPoint| to view coordinates and flip it. 365 // Might as well throw out this object now.
447 NSPoint localPoint = [self convertPointFromBase:screenPoint]; 366 dragSource_.reset();
448 NSRect viewFrame = [self frame];
449 localPoint.y = viewFrame.size.height - localPoint.y;
450 // Flip |screenPoint|.
451 NSRect screenFrame = [[[self window] screen] frame];
452 screenPoint.y = screenFrame.size.height - screenPoint.y;
453
454 if (operation != NSDragOperationNone)
455 rvh->DragSourceEndedAt(localPoint.x, localPoint.y,
456 screenPoint.x, screenPoint.y);
457 else
458 rvh->DragSourceCancelledAt(localPoint.x, localPoint.y,
459 screenPoint.x, screenPoint.y);
460 }
461 } 367 }
462 368
463 // Called when a drag initiated in our view moves. We need to tell WebCore 369 // Called when a drag initiated in our view moves.
464 // so it can update anything watching for drag events.
465 - (void)draggedImage:(NSImage*)draggedImage movedTo:(NSPoint)screenPoint { 370 - (void)draggedImage:(NSImage*)draggedImage movedTo:(NSPoint)screenPoint {
466 RenderViewHost* rvh = [self tabContents]->render_view_host(); 371 [dragSource_ moveDragTo:screenPoint];
467 if (rvh) { 372 }
468 // Convert |screenPoint| to view coordinates and flip it.
469 NSPoint localPoint = [self convertPointFromBase:screenPoint];
470 NSRect viewFrame = [self frame];
471 localPoint.y = viewFrame.size.height - localPoint.y;
472 // Flip |screenPoint|.
473 NSRect screenFrame = [[[self window] screen] frame];
474 screenPoint.y = screenFrame.size.height - screenPoint.y;
475 373
476 rvh->DragSourceMovedTo(localPoint.x, localPoint.y, 374 // Called when we're informed where a file should be dropped.
477 screenPoint.x, screenPoint.y); 375 - (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDest {
478 } 376 if (![dropDest isFileURL])
377 return nil;
378
379 NSString* file_name = [dragSource_ dragPromisedFileTo:[dropDest path]];
380 if (!file_name)
381 return nil;
382
383 return [NSArray arrayWithObject:file_name];
479 } 384 }
480 385
481 // NSDraggingDestination methods 386 // NSDraggingDestination methods
482 387
483 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender { 388 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
484 return [dropTarget_ draggingEntered:sender view:self]; 389 return [dropTarget_ draggingEntered:sender view:self];
485 } 390 }
486 391
487 - (void)draggingExited:(id<NSDraggingInfo>)sender { 392 - (void)draggingExited:(id<NSDraggingInfo>)sender {
488 [dropTarget_ draggingExited:sender]; 393 [dropTarget_ draggingExited:sender];
489 } 394 }
490 395
491 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { 396 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
492 return [dropTarget_ draggingUpdated:sender view:self]; 397 return [dropTarget_ draggingUpdated:sender view:self];
493 } 398 }
494 399
495 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { 400 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
496 return [dropTarget_ performDragOperation:sender view:self]; 401 return [dropTarget_ performDragOperation:sender view:self];
497 } 402 }
498 403
499 // Tons of stuff goes here, where we grab events going on in Cocoaland and send 404 // Tons of stuff goes here, where we grab events going on in Cocoaland and send
500 // them into the C++ system. TODO(avi): all that jazz 405 // them into the C++ system. TODO(avi): all that jazz
501 406
502 @end 407 @end
OLDNEW
« no previous file with comments | « chrome/browser/tab_contents/tab_contents_view_mac.h ('k') | chrome/chrome.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698