diff options
author | rogerta@chromium.org <rogerta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-17 18:44:01 +0000 |
---|---|---|
committer | rogerta@chromium.org <rogerta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-17 18:44:01 +0000 |
commit | 557205cef10e483f2953299d241e21e0a96c007e (patch) | |
tree | be8df5f77cc8267405c9d799bd8631ec9b1e612c /chrome | |
parent | 531b5d55c4ce29b7c84e3b6be201b5bfb5ac3df5 (diff) | |
download | chromium_src-557205cef10e483f2953299d241e21e0a96c007e.zip chromium_src-557205cef10e483f2953299d241e21e0a96c007e.tar.gz chromium_src-557205cef10e483f2953299d241e21e0a96c007e.tar.bz2 |
Allow dragging and dropping of URLs to any portion of the toolbar view.
BUG=9181
TEST=Drag a URL or ay text to the toolbar area, including back/forward/reload
buttons, and the browser action/menu area. This should not interfere with
dragging and dropping of browser actions. Test that browser actions behave
as they should (i.e. should be able to change their order in the toolbar).
Review URL: http://codereview.chromium.org/6462009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75288 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
10 files changed, 219 insertions, 89 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc index 5697cb4..8c2fcdd 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc @@ -63,6 +63,7 @@ class TestingAutocompleteEditView : public AutocompleteEditView { #if defined(TOOLKIT_VIEWS) virtual views::View* AddToView(views::View* parent) { return NULL; } + virtual int OnPerformDrop(const views::DropTargetEvent& event) { return 0; } #endif private: diff --git a/chrome/browser/autocomplete/autocomplete_edit_view.h b/chrome/browser/autocomplete/autocomplete_edit_view.h index a7af148..1925983 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view.h @@ -26,6 +26,7 @@ class TabContents; #if defined(TOOLKIT_VIEWS) namespace views { +class DropTargetEvent; class View; } // namespace views #endif @@ -175,6 +176,9 @@ class AutocompleteEditView { // Adds the autocomplete edit view to view hierarchy and // returns the views::View of the edit view. virtual views::View* AddToView(views::View* parent) = 0; + + // Performs the drop of a drag and drop operation on the view. + virtual int OnPerformDrop(const views::DropTargetEvent& event) = 0; #endif virtual ~AutocompleteEditView() {} diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc index fd04090..192a40e 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc @@ -31,6 +31,7 @@ #include "net/base/escape.h" #include "third_party/undoview/undo_view.h" #include "ui/base/animation/multi_animation.h" +#include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/color_utils.h" @@ -44,6 +45,7 @@ #include "chrome/browser/ui/views/autocomplete/autocomplete_popup_contents_view.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" #include "views/controls/textfield/native_textfield_views.h" +#include "views/events/event.h" #else #include "chrome/browser/autocomplete/autocomplete_popup_view_gtk.h" #include "chrome/browser/ui/gtk/gtk_theme_provider.h" @@ -65,6 +67,16 @@ size_t GetUTF8Offset(const string16& text, size_t text_offset) { return UTF16ToUTF8(text.substr(0, text_offset)).size(); } +// A helper method for determining a valid drag operation given the allowed +// operation. We prefer copy over link. +int CopyOrLinkDragOperation(int drag_operation) { + if (drag_operation & ui::DragDropTypes::DRAG_COPY) + return ui::DragDropTypes::DRAG_COPY; + if (drag_operation & ui::DragDropTypes::DRAG_LINK) + return ui::DragDropTypes::DRAG_LINK; + return ui::DragDropTypes::DRAG_NONE; +} + // Stores GTK+-specific state so it can be restored after switching tabs. struct ViewState { explicit ViewState(const AutocompleteEditViewGtk::CharRange& selection_range) @@ -843,6 +855,27 @@ views::View* AutocompleteEditViewGtk::AddToView(views::View* parent) { return host; } +int AutocompleteEditViewGtk::OnPerformDrop( + const views::DropTargetEvent& event) { + std::wstring text; + const ui::OSExchangeData& data = event.data(); + if (data.HasURL()) { + GURL url; + std::wstring title; + if (data.GetURLAndTitle(&url, &title)) + text = UTF8ToWide(url.spec()); + } else { + std::wstring data_string; + if (data.GetString(&data_string)) + text = CollapseWhitespace(data_string, true); + } + + if (!text.empty() && OnPerformDropImpl(WideToUTF16(text))) + return CopyOrLinkDragOperation(event.source_operations()); + + return ui::DragDropTypes::DRAG_NONE; +} + void AutocompleteEditViewGtk::EnableAccessibility() { accessible_widget_helper_.reset( new AccessibleWidgetHelper(text_view(), model_->profile())); @@ -1545,8 +1578,7 @@ void AutocompleteEditViewGtk::HandleDragDataReceived( string16 possible_url = UTF8ToUTF16(reinterpret_cast<char*>(text)); g_free(text); - if (model_->CanPasteAndGo(CollapseWhitespace(possible_url, true))) { - model_->PasteAndGo(); + if (OnPerformDropImpl(possible_url)) { gtk_drag_finish(context, TRUE, TRUE, time); static guint signal_id = @@ -1737,6 +1769,15 @@ void AutocompleteEditViewGtk::HandleCopyOrCutClipboard(bool copy) { OwnPrimarySelection(UTF16ToUTF8(text)); } +bool AutocompleteEditViewGtk::OnPerformDropImpl(const string16& text) { + if (model_->CanPasteAndGo(CollapseWhitespace(text, true))) { + model_->PasteAndGo(); + return true; + } + + return false; +} + gfx::Font AutocompleteEditViewGtk::GetFont() { #if defined(TOOLKIT_VIEWS) bool use_gtk = false; diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h index 615b137..7ed1456 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h @@ -147,6 +147,7 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, #if defined(TOOLKIT_VIEWS) virtual views::View* AddToView(views::View* parent); + virtual int OnPerformDrop(const views::DropTargetEvent& event); // Enables accessibility on AutocompleteEditView. void EnableAccessibility(); @@ -276,6 +277,9 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, void HandleCopyOrCutClipboard(bool copy); + // Common implementation for performing a drop on the edit view. + bool OnPerformDropImpl(const string16& text); + // Returns the font used in |text_view_|. gfx::Font GetFont(); diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_views.cc b/chrome/browser/autocomplete/autocomplete_edit_view_views.cc index 68e84ec2..0afef21 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_views.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_views.cc @@ -19,6 +19,7 @@ #include "googleurl/src/gurl.h" #include "grit/generated_resources.h" #include "net/base/escape.h" +#include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/font.h" #include "views/border.h" @@ -559,6 +560,12 @@ views::View* AutocompleteEditViewViews::AddToView(views::View* parent) { return this; } +int AutocompleteEditViewViews::OnPerformDrop( + const views::DropTargetEvent& event) { + NOTIMPLEMENTED(); + return ui::DragDropTypes::DRAG_NONE; +} + //////////////////////////////////////////////////////////////////////////////// // AutocompleteEditViewViews, NotificationObserver implementation: diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_views.h b/chrome/browser/autocomplete/autocomplete_edit_view_views.h index e347aa2..92279cc 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_views.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_views.h @@ -27,10 +27,11 @@ class TabContents; // Views-implementation of AutocompleteEditView. This is based on // gtk implementation. The following features are not yet supported. // -// IME supoprt. +// IME support. // LTR support. // Selection behavior. // Cut,copy and paste behavior. +// Drag and drop behavior. // URL styles (strikestrough insecure scheme, emphasize host). // Custom context menu for omnibox. // Instant. @@ -116,6 +117,7 @@ class AutocompleteEditViewViews : public views::View, virtual int TextWidth() const; virtual bool IsImeComposing() const; virtual views::View* AddToView(views::View* parent); + virtual int OnPerformDrop(const views::DropTargetEvent& event); // Overridden from NotificationObserver: virtual void Observe(NotificationType type, diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc index 6c8b923..ba736c0 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc @@ -40,6 +40,7 @@ #include "skia/ext/skia_utils_win.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/scoped_clipboard_writer.h" +#include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/drag_source.h" #include "ui/base/dragdrop/drop_target.h" #include "ui/base/dragdrop/os_exchange_data.h" @@ -63,13 +64,57 @@ namespace { +// A helper method for determining a valid DROPEFFECT given the allowed +// DROPEFFECTS. We prefer copy over link. +DWORD CopyOrLinkDropEffect(DWORD effect) { + if (effect & DROPEFFECT_COPY) + return DROPEFFECT_COPY; + if (effect & DROPEFFECT_LINK) + return DROPEFFECT_LINK; + return DROPEFFECT_NONE; +} + +// A helper method for determining a valid drag operation given the allowed +// operation. We prefer copy over link. +int CopyOrLinkDragOperation(int drag_operation) { + if (drag_operation & ui::DragDropTypes::DRAG_COPY) + return ui::DragDropTypes::DRAG_COPY; + if (drag_operation & ui::DragDropTypes::DRAG_LINK) + return ui::DragDropTypes::DRAG_LINK; + return ui::DragDropTypes::DRAG_NONE; +} + +// The AutocompleteEditState struct contains enough information about the +// AutocompleteEditModel and AutocompleteEditViewWin to save/restore a user's +// typing, caret position, etc. across tab changes. We explicitly don't +// preserve things like whether the popup was open as this might be weird. +struct AutocompleteEditState { + AutocompleteEditState(const AutocompleteEditModel::State model_state, + const AutocompleteEditViewWin::State view_state) + : model_state(model_state), + view_state(view_state) { + } + + const AutocompleteEditModel::State model_state; + const AutocompleteEditViewWin::State view_state; +}; + +// Returns true if the current point is far enough from the origin that it +// would be considered a drag. +bool IsDrag(const POINT& origin, const POINT& current) { + return views::View::ExceededDragThreshold(current.x - origin.x, + current.y - origin.y); +} + +} // namespace + // EditDropTarget is the IDropTarget implementation installed on // AutocompleteEditViewWin. EditDropTarget prefers URL over plain text. A drop // of a URL replaces all the text of the edit and navigates immediately to the // URL. A drop of plain text from the same edit either copies or moves the // selected text, and a drop of plain text from a source other than the edit // does a paste and go. -class EditDropTarget : public ui::DropTarget { +class AutocompleteEditViewWin::EditDropTarget : public ui::DropTarget { public: explicit EditDropTarget(AutocompleteEditViewWin* edit); @@ -109,27 +154,19 @@ class EditDropTarget : public ui::DropTarget { DISALLOW_COPY_AND_ASSIGN(EditDropTarget); }; -// A helper method for determining a valid DROPEFFECT given the allowed -// DROPEFFECTS. We prefer copy over link. -DWORD CopyOrLinkDropEffect(DWORD effect) { - if (effect & DROPEFFECT_COPY) - return DROPEFFECT_COPY; - if (effect & DROPEFFECT_LINK) - return DROPEFFECT_LINK; - return DROPEFFECT_NONE; -} - -EditDropTarget::EditDropTarget(AutocompleteEditViewWin* edit) +AutocompleteEditViewWin::EditDropTarget::EditDropTarget( + AutocompleteEditViewWin* edit) : ui::DropTarget(edit->m_hWnd), edit_(edit), drag_has_url_(false), drag_has_string_(false) { } -DWORD EditDropTarget::OnDragEnter(IDataObject* data_object, - DWORD key_state, - POINT cursor_position, - DWORD effect) { +DWORD AutocompleteEditViewWin::EditDropTarget::OnDragEnter( + IDataObject* data_object, + DWORD key_state, + POINT cursor_position, + DWORD effect) { ui::OSExchangeData os_data(new ui::OSExchangeDataProviderWin(data_object)); drag_has_url_ = os_data.HasURL(); drag_has_string_ = !drag_has_url_ && os_data.HasString(); @@ -148,10 +185,11 @@ DWORD EditDropTarget::OnDragEnter(IDataObject* data_object, return OnDragOver(data_object, key_state, cursor_position, effect); } -DWORD EditDropTarget::OnDragOver(IDataObject* data_object, - DWORD key_state, - POINT cursor_position, - DWORD effect) { +DWORD AutocompleteEditViewWin::EditDropTarget::OnDragOver( + IDataObject* data_object, + DWORD key_state, + POINT cursor_position, + DWORD effect) { if (drag_has_url_) return CopyOrLinkDropEffect(effect); @@ -172,57 +210,35 @@ DWORD EditDropTarget::OnDragOver(IDataObject* data_object, return DROPEFFECT_NONE; } -void EditDropTarget::OnDragLeave(IDataObject* data_object) { +void AutocompleteEditViewWin::EditDropTarget::OnDragLeave( + IDataObject* data_object) { ResetDropHighlights(); } -DWORD EditDropTarget::OnDrop(IDataObject* data_object, - DWORD key_state, - POINT cursor_position, - DWORD effect) { +DWORD AutocompleteEditViewWin::EditDropTarget::OnDrop( + IDataObject* data_object, + DWORD key_state, + POINT cursor_position, + DWORD effect) { + effect = OnDragOver(data_object, key_state, cursor_position, effect); + ui::OSExchangeData os_data(new ui::OSExchangeDataProviderWin(data_object)); + views::DropTargetEvent event(os_data, cursor_position.x, cursor_position.y, + ui::DragDropTypes::DropEffectToDragOperation(effect)); - if (drag_has_url_) { - GURL url; - string16 title; - if (os_data.GetURLAndTitle(&url, &title)) { - edit_->SetUserText(UTF8ToWide(url.spec())); - edit_->model()->AcceptInput(CURRENT_TAB, true); - return CopyOrLinkDropEffect(effect); - } - } else if (drag_has_string_) { - int string_drop_position = edit_->drop_highlight_position(); - string16 text; - if ((string_drop_position != -1 || !edit_->in_drag()) && - os_data.GetString(&text)) { - DCHECK(string_drop_position == -1 || - ((string_drop_position >= 0) && - (string_drop_position <= edit_->GetTextLength()))); - const DWORD drop_operation = - OnDragOver(data_object, key_state, cursor_position, effect); - if (edit_->in_drag()) { - if (drop_operation == DROPEFFECT_MOVE) - edit_->MoveSelectedText(string_drop_position); - else - edit_->InsertText(string_drop_position, text); - } else { - edit_->PasteAndGo(CollapseWhitespace(text, true)); - } - ResetDropHighlights(); - return drop_operation; - } - } + int drag_operation = edit_->OnPerformDropImpl(event, edit_->in_drag()); - ResetDropHighlights(); + if (!drag_has_url_) + ResetDropHighlights(); - return DROPEFFECT_NONE; + return ui::DragDropTypes::DragOperationToDropEffect(drag_operation); } -void EditDropTarget::UpdateDropHighlightPosition( +void AutocompleteEditViewWin::EditDropTarget::UpdateDropHighlightPosition( const POINT& cursor_screen_position) { if (drag_has_string_) { POINT client_position = cursor_screen_position; - ScreenToClient(edit_->m_hWnd, &client_position); + ::ScreenToClient(edit_->m_hWnd, &client_position); int drop_position = edit_->CharFromPos(client_position); if (edit_->in_drag()) { // Our edit originated the drag, don't allow a drop if over the selected @@ -242,37 +258,11 @@ void EditDropTarget::UpdateDropHighlightPosition( } } -void EditDropTarget::ResetDropHighlights() { +void AutocompleteEditViewWin::EditDropTarget::ResetDropHighlights() { if (drag_has_string_) edit_->SetDropHighlightPosition(-1); } -// The AutocompleteEditState struct contains enough information about the -// AutocompleteEditModel and AutocompleteEditViewWin to save/restore a user's -// typing, caret position, etc. across tab changes. We explicitly don't -// preserve things like whether the popup was open as this might be weird. -struct AutocompleteEditState { - AutocompleteEditState(const AutocompleteEditModel::State model_state, - const AutocompleteEditViewWin::State view_state) - : model_state(model_state), - view_state(view_state) { - } - - const AutocompleteEditModel::State model_state; - const AutocompleteEditViewWin::State view_state; -}; - -// Returns true if the current point is far enough from the origin that it -// would be considered a drag. -bool IsDrag(const POINT& origin, const POINT& current) { - // The CXDRAG and CYDRAG system metrics describe the width and height of a - // rectangle around the origin position, inside of which motion is not - // considered a drag. - return (abs(current.x - origin.x) > (GetSystemMetrics(SM_CXDRAG) / 2)) || - (abs(current.y - origin.y) > (GetSystemMetrics(SM_CYDRAG) / 2)); -} - -} // namespace /////////////////////////////////////////////////////////////////////////////// // Helper classes @@ -961,6 +951,46 @@ views::View* AutocompleteEditViewWin::AddToView(views::View* parent) { return host; } +int AutocompleteEditViewWin::OnPerformDrop( + const views::DropTargetEvent& event) { + return OnPerformDropImpl(event, false); +} + +int AutocompleteEditViewWin::OnPerformDropImpl( + const views::DropTargetEvent& event, + bool in_drag) { + const ui::OSExchangeData& data = event.data(); + + if (data.HasURL()) { + GURL url; + string16 title; + if (data.GetURLAndTitle(&url, &title)) { + SetUserText(UTF8ToWide(url.spec())); + model()->AcceptInput(CURRENT_TAB, true); + return CopyOrLinkDragOperation(event.source_operations()); + } + } else if (data.HasString()) { + int string_drop_position = drop_highlight_position(); + string16 text; + if ((string_drop_position != -1 || !in_drag) && data.GetString(&text)) { + DCHECK(string_drop_position == -1 || + ((string_drop_position >= 0) && + (string_drop_position <= GetTextLength()))); + if (in_drag) { + if (event.source_operations()== ui::DragDropTypes::DRAG_MOVE) + MoveSelectedText(string_drop_position); + else + InsertText(string_drop_position, text); + } else { + PasteAndGo(CollapseWhitespace(text, true)); + } + return CopyOrLinkDragOperation(event.source_operations()); + } + } + + return ui::DragDropTypes::DRAG_NONE; +} + void AutocompleteEditViewWin::PasteAndGo(const string16& text) { if (CanPasteAndGo(text)) model_->PasteAndGo(); diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.h b/chrome/browser/autocomplete/autocomplete_edit_view_win.h index aaa4b73..2d5284b 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.h @@ -139,6 +139,7 @@ class AutocompleteEditViewWin virtual bool IsImeComposing() const; virtual views::View* AddToView(views::View* parent); + virtual int OnPerformDrop(const views::DropTargetEvent& event); int GetPopupMaxYCoordinate(); @@ -244,6 +245,9 @@ class AutocompleteEditViewWin DISALLOW_COPY_AND_ASSIGN(ScopedFreeze); }; + class EditDropTarget; + friend class EditDropTarget; + // This object suspends placing any operations on the edit's undo stack until // the object is destroyed. If we don't do this, some of the operations we // perform behind the user's back will be undoable by the user, which feels @@ -412,6 +416,9 @@ class AutocompleteEditViewWin // triggerred no matter if the text is actually changed or not. bool OnAfterPossibleChangeInternal(bool force_text_changed); + // Common implementation for performing a drop on the edit view. + int OnPerformDropImpl(const views::DropTargetEvent& event, bool in_drag); + scoped_ptr<AutocompleteEditModel> model_; scoped_ptr<AutocompletePopupView> popup_view_; diff --git a/chrome/browser/ui/views/toolbar_view.cc b/chrome/browser/ui/views/toolbar_view.cc index 6e26bf2..6391ad8 100644 --- a/chrome/browser/ui/views/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar_view.cc @@ -612,6 +612,34 @@ void ToolbarView::OnPaint(gfx::Canvas* canvas) { canvas->FillRectInt(SK_ColorBLACK, 0, height() - 1, width(), 1); } +// Note this method is ignored on Windows, but needs to be implemented for +// linux, where it is called before CanDrop(). +bool ToolbarView::GetDropFormats( + int* formats, + std::set<OSExchangeData::CustomFormat>* custom_formats) { + *formats = ui::OSExchangeData::URL | ui::OSExchangeData::STRING; + return true; +} + +bool ToolbarView::CanDrop(const ui::OSExchangeData& data) { + // To support loading URLs by dropping into the toolbar, we need to support + // dropping URLs and/or text. + return data.HasURL() || data.HasString(); +} + +int ToolbarView::OnDragUpdated(const views::DropTargetEvent& event) { + if (event.source_operations() & ui::DragDropTypes::DRAG_COPY) { + return ui::DragDropTypes::DRAG_COPY; + } else if (event.source_operations() & ui::DragDropTypes::DRAG_LINK) { + return ui::DragDropTypes::DRAG_LINK; + } + return ui::DragDropTypes::DRAG_NONE; +} + +int ToolbarView::OnPerformDrop(const views::DropTargetEvent& event) { + return location_bar_->location_entry()->OnPerformDrop(event); +} + void ToolbarView::OnThemeChanged() { LoadImages(); } diff --git a/chrome/browser/ui/views/toolbar_view.h b/chrome/browser/ui/views/toolbar_view.h index 37176e6..06d5003 100644 --- a/chrome/browser/ui/views/toolbar_view.h +++ b/chrome/browser/ui/views/toolbar_view.h @@ -119,6 +119,12 @@ class ToolbarView : public AccessiblePaneView, virtual gfx::Size GetPreferredSize(); virtual void Layout(); virtual void OnPaint(gfx::Canvas* canvas); + virtual bool GetDropFormats( + int* formats, + std::set<OSExchangeData::CustomFormat>* custom_formats); + virtual bool CanDrop(const ui::OSExchangeData& data); + virtual int OnDragUpdated(const views::DropTargetEvent& event); + virtual int OnPerformDrop(const views::DropTargetEvent& event); virtual void OnThemeChanged(); // The apparent horizontal space between most items, and the vertical padding |