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

Side by Side Diff: chrome/browser/autocomplete/autocomplete_edit_view_win.cc

Issue 6462009: Allow dragging and dropping of URLs to any portion of the toolbar view.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 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
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/autocomplete/autocomplete_edit_view_win.h" 5 #include "chrome/browser/autocomplete/autocomplete_edit_view_win.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <locale> 8 #include <locale>
9 #include <string> 9 #include <string>
10 10
(...skipping 22 matching lines...) Expand all
33 #include "chrome/browser/search_engines/template_url_model.h" 33 #include "chrome/browser/search_engines/template_url_model.h"
34 #include "chrome/browser/tab_contents/tab_contents.h" 34 #include "chrome/browser/tab_contents/tab_contents.h"
35 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" 35 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
36 #include "chrome/common/notification_service.h" 36 #include "chrome/common/notification_service.h"
37 #include "googleurl/src/url_util.h" 37 #include "googleurl/src/url_util.h"
38 #include "grit/generated_resources.h" 38 #include "grit/generated_resources.h"
39 #include "net/base/escape.h" 39 #include "net/base/escape.h"
40 #include "skia/ext/skia_utils_win.h" 40 #include "skia/ext/skia_utils_win.h"
41 #include "ui/base/clipboard/clipboard.h" 41 #include "ui/base/clipboard/clipboard.h"
42 #include "ui/base/clipboard/scoped_clipboard_writer.h" 42 #include "ui/base/clipboard/scoped_clipboard_writer.h"
43 #include "ui/base/dragdrop/drag_drop_types.h"
43 #include "ui/base/dragdrop/drag_source.h" 44 #include "ui/base/dragdrop/drag_source.h"
44 #include "ui/base/dragdrop/drop_target.h" 45 #include "ui/base/dragdrop/drop_target.h"
45 #include "ui/base/dragdrop/os_exchange_data.h" 46 #include "ui/base/dragdrop/os_exchange_data.h"
46 #include "ui/base/dragdrop/os_exchange_data_provider_win.h" 47 #include "ui/base/dragdrop/os_exchange_data_provider_win.h"
47 #include "ui/base/keycodes/keyboard_codes.h" 48 #include "ui/base/keycodes/keyboard_codes.h"
48 #include "ui/base/l10n/l10n_util.h" 49 #include "ui/base/l10n/l10n_util.h"
49 #include "ui/base/l10n/l10n_util_win.h" 50 #include "ui/base/l10n/l10n_util_win.h"
50 #include "ui/gfx/canvas.h" 51 #include "ui/gfx/canvas.h"
51 #include "ui/gfx/canvas_skia.h" 52 #include "ui/gfx/canvas_skia.h"
52 #include "views/controls/textfield/native_textfield_win.h" 53 #include "views/controls/textfield/native_textfield_win.h"
53 #include "views/drag_utils.h" 54 #include "views/drag_utils.h"
54 #include "views/events/event_utils_win.h" 55 #include "views/events/event_utils_win.h"
55 #include "views/focus/focus_util_win.h" 56 #include "views/focus/focus_util_win.h"
56 #include "views/widget/widget.h" 57 #include "views/widget/widget.h"
57 58
58 #pragma comment(lib, "oleacc.lib") // Needed for accessibility support. 59 #pragma comment(lib, "oleacc.lib") // Needed for accessibility support.
59 #pragma comment(lib, "riched20.lib") // Needed for the richedit control. 60 #pragma comment(lib, "riched20.lib") // Needed for the richedit control.
60 61
61 /////////////////////////////////////////////////////////////////////////////// 62 ///////////////////////////////////////////////////////////////////////////////
62 // AutocompleteEditModel 63 // AutocompleteEditModel
63 64
64 namespace { 65 namespace {
65 66
67 // A helper method for determining a valid DROPEFFECT given the allowed
68 // DROPEFFECTS. We prefer copy over link.
69 DWORD CopyOrLinkDropEffect(DWORD effect) {
70 if (effect & DROPEFFECT_COPY)
71 return DROPEFFECT_COPY;
72 if (effect & DROPEFFECT_LINK)
73 return DROPEFFECT_LINK;
74 return DROPEFFECT_NONE;
75 }
76
77 // A helper method for determining a valid drag operation given the allowed
78 // operation. We prefer copy over link.
79 int CopyOrLinkDragOperation(int drag_operation) {
80 if (drag_operation & ui::DragDropTypes::DRAG_COPY)
81 return ui::DragDropTypes::DRAG_COPY;
82 if (drag_operation & ui::DragDropTypes::DRAG_LINK)
83 return ui::DragDropTypes::DRAG_LINK;
84 return ui::DragDropTypes::DRAG_NONE;
85 }
86
87 // The AutocompleteEditState struct contains enough information about the
88 // AutocompleteEditModel and AutocompleteEditViewWin to save/restore a user's
89 // typing, caret position, etc. across tab changes. We explicitly don't
90 // preserve things like whether the popup was open as this might be weird.
91 struct AutocompleteEditState {
92 AutocompleteEditState(const AutocompleteEditModel::State model_state,
93 const AutocompleteEditViewWin::State view_state)
94 : model_state(model_state),
95 view_state(view_state) {
96 }
97
98 const AutocompleteEditModel::State model_state;
99 const AutocompleteEditViewWin::State view_state;
100 };
101
102 // Returns true if the current point is far enough from the origin that it
103 // would be considered a drag.
104 bool IsDrag(const POINT& origin, const POINT& current) {
105 return views::View::ExceededDragThreshold(current.x - origin.x,
106 current.y - origin.y);
107 }
108
109 } // namespace
110
66 // EditDropTarget is the IDropTarget implementation installed on 111 // EditDropTarget is the IDropTarget implementation installed on
67 // AutocompleteEditViewWin. EditDropTarget prefers URL over plain text. A drop 112 // AutocompleteEditViewWin. EditDropTarget prefers URL over plain text. A drop
68 // of a URL replaces all the text of the edit and navigates immediately to the 113 // of a URL replaces all the text of the edit and navigates immediately to the
69 // URL. A drop of plain text from the same edit either copies or moves the 114 // URL. A drop of plain text from the same edit either copies or moves the
70 // selected text, and a drop of plain text from a source other than the edit 115 // selected text, and a drop of plain text from a source other than the edit
71 // does a paste and go. 116 // does a paste and go.
72 class EditDropTarget : public ui::DropTarget { 117 class AutocompleteEditViewWin::EditDropTarget : public ui::DropTarget {
73 public: 118 public:
74 explicit EditDropTarget(AutocompleteEditViewWin* edit); 119 explicit EditDropTarget(AutocompleteEditViewWin* edit);
75 120
76 protected: 121 protected:
77 virtual DWORD OnDragEnter(IDataObject* data_object, 122 virtual DWORD OnDragEnter(IDataObject* data_object,
78 DWORD key_state, 123 DWORD key_state,
79 POINT cursor_position, 124 POINT cursor_position,
80 DWORD effect); 125 DWORD effect);
81 virtual DWORD OnDragOver(IDataObject* data_object, 126 virtual DWORD OnDragOver(IDataObject* data_object,
82 DWORD key_state, 127 DWORD key_state,
(...skipping 19 matching lines...) Expand all
102 // If true, the drag session contains a URL. 147 // If true, the drag session contains a URL.
103 bool drag_has_url_; 148 bool drag_has_url_;
104 149
105 // If true, the drag session contains a string. If drag_has_url_ is true, 150 // If true, the drag session contains a string. If drag_has_url_ is true,
106 // this is false regardless of whether the clipboard has a string. 151 // this is false regardless of whether the clipboard has a string.
107 bool drag_has_string_; 152 bool drag_has_string_;
108 153
109 DISALLOW_COPY_AND_ASSIGN(EditDropTarget); 154 DISALLOW_COPY_AND_ASSIGN(EditDropTarget);
110 }; 155 };
111 156
112 // A helper method for determining a valid DROPEFFECT given the allowed 157 AutocompleteEditViewWin::EditDropTarget::EditDropTarget(
113 // DROPEFFECTS. We prefer copy over link. 158 AutocompleteEditViewWin* edit)
114 DWORD CopyOrLinkDropEffect(DWORD effect) {
115 if (effect & DROPEFFECT_COPY)
116 return DROPEFFECT_COPY;
117 if (effect & DROPEFFECT_LINK)
118 return DROPEFFECT_LINK;
119 return DROPEFFECT_NONE;
120 }
121
122 EditDropTarget::EditDropTarget(AutocompleteEditViewWin* edit)
123 : ui::DropTarget(edit->m_hWnd), 159 : ui::DropTarget(edit->m_hWnd),
124 edit_(edit), 160 edit_(edit),
125 drag_has_url_(false), 161 drag_has_url_(false),
126 drag_has_string_(false) { 162 drag_has_string_(false) {
127 } 163 }
128 164
129 DWORD EditDropTarget::OnDragEnter(IDataObject* data_object, 165 DWORD AutocompleteEditViewWin::EditDropTarget::OnDragEnter(
130 DWORD key_state, 166 IDataObject* data_object,
131 POINT cursor_position, 167 DWORD key_state,
132 DWORD effect) { 168 POINT cursor_position,
169 DWORD effect) {
133 ui::OSExchangeData os_data(new ui::OSExchangeDataProviderWin(data_object)); 170 ui::OSExchangeData os_data(new ui::OSExchangeDataProviderWin(data_object));
134 drag_has_url_ = os_data.HasURL(); 171 drag_has_url_ = os_data.HasURL();
135 drag_has_string_ = !drag_has_url_ && os_data.HasString(); 172 drag_has_string_ = !drag_has_url_ && os_data.HasString();
136 if (drag_has_url_) { 173 if (drag_has_url_) {
137 if (edit_->in_drag()) { 174 if (edit_->in_drag()) {
138 // The edit we're associated with originated the drag. No point in 175 // The edit we're associated with originated the drag. No point in
139 // allowing the user to drop back on us. 176 // allowing the user to drop back on us.
140 drag_has_url_ = false; 177 drag_has_url_ = false;
141 } 178 }
142 // NOTE: it would be nice to visually show all the text is going to 179 // NOTE: it would be nice to visually show all the text is going to
143 // be replaced by selecting all, but this caused painting problems. In 180 // be replaced by selecting all, but this caused painting problems. In
144 // particular the flashing caret would appear outside the edit! For now 181 // particular the flashing caret would appear outside the edit! For now
145 // we stick with no visual indicator other than that shown own the mouse 182 // we stick with no visual indicator other than that shown own the mouse
146 // cursor. 183 // cursor.
147 } 184 }
148 return OnDragOver(data_object, key_state, cursor_position, effect); 185 return OnDragOver(data_object, key_state, cursor_position, effect);
149 } 186 }
150 187
151 DWORD EditDropTarget::OnDragOver(IDataObject* data_object, 188 DWORD AutocompleteEditViewWin::EditDropTarget::OnDragOver(
152 DWORD key_state, 189 IDataObject* data_object,
153 POINT cursor_position, 190 DWORD key_state,
154 DWORD effect) { 191 POINT cursor_position,
192 DWORD effect) {
155 if (drag_has_url_) 193 if (drag_has_url_)
156 return CopyOrLinkDropEffect(effect); 194 return CopyOrLinkDropEffect(effect);
157 195
158 if (drag_has_string_) { 196 if (drag_has_string_) {
159 UpdateDropHighlightPosition(cursor_position); 197 UpdateDropHighlightPosition(cursor_position);
160 if (edit_->drop_highlight_position() == -1 && edit_->in_drag()) 198 if (edit_->drop_highlight_position() == -1 && edit_->in_drag())
161 return DROPEFFECT_NONE; 199 return DROPEFFECT_NONE;
162 if (edit_->in_drag()) { 200 if (edit_->in_drag()) {
163 // The edit we're associated with originated the drag. Do the normal drag 201 // The edit we're associated with originated the drag. Do the normal drag
164 // behavior. 202 // behavior.
165 DCHECK((effect & DROPEFFECT_COPY) && (effect & DROPEFFECT_MOVE)); 203 DCHECK((effect & DROPEFFECT_COPY) && (effect & DROPEFFECT_MOVE));
166 return (key_state & MK_CONTROL) ? DROPEFFECT_COPY : DROPEFFECT_MOVE; 204 return (key_state & MK_CONTROL) ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
167 } 205 }
168 // Our edit didn't originate the drag, only allow link or copy. 206 // Our edit didn't originate the drag, only allow link or copy.
169 return CopyOrLinkDropEffect(effect); 207 return CopyOrLinkDropEffect(effect);
170 } 208 }
171 209
172 return DROPEFFECT_NONE; 210 return DROPEFFECT_NONE;
173 } 211 }
174 212
175 void EditDropTarget::OnDragLeave(IDataObject* data_object) { 213 void AutocompleteEditViewWin::EditDropTarget::OnDragLeave(
214 IDataObject* data_object) {
176 ResetDropHighlights(); 215 ResetDropHighlights();
177 } 216 }
178 217
179 DWORD EditDropTarget::OnDrop(IDataObject* data_object, 218 DWORD AutocompleteEditViewWin::EditDropTarget::OnDrop(
180 DWORD key_state, 219 IDataObject* data_object,
181 POINT cursor_position, 220 DWORD key_state,
182 DWORD effect) { 221 POINT cursor_position,
222 DWORD effect) {
223 effect = OnDragOver(data_object, key_state, cursor_position, effect);
224
183 ui::OSExchangeData os_data(new ui::OSExchangeDataProviderWin(data_object)); 225 ui::OSExchangeData os_data(new ui::OSExchangeDataProviderWin(data_object));
226 views::DropTargetEvent event(os_data, cursor_position.x, cursor_position.y,
227 ui::DragDropTypes::DropEffectToDragOperation(effect));
184 228
185 if (drag_has_url_) { 229 int drag_operation = edit_->OnPerformDropImpl(event, edit_->in_drag());
186 GURL url;
187 string16 title;
188 if (os_data.GetURLAndTitle(&url, &title)) {
189 edit_->SetUserText(UTF8ToWide(url.spec()));
190 edit_->model()->AcceptInput(CURRENT_TAB, true);
191 return CopyOrLinkDropEffect(effect);
192 }
193 } else if (drag_has_string_) {
194 int string_drop_position = edit_->drop_highlight_position();
195 string16 text;
196 if ((string_drop_position != -1 || !edit_->in_drag()) &&
197 os_data.GetString(&text)) {
198 DCHECK(string_drop_position == -1 ||
199 ((string_drop_position >= 0) &&
200 (string_drop_position <= edit_->GetTextLength())));
201 const DWORD drop_operation =
202 OnDragOver(data_object, key_state, cursor_position, effect);
203 if (edit_->in_drag()) {
204 if (drop_operation == DROPEFFECT_MOVE)
205 edit_->MoveSelectedText(string_drop_position);
206 else
207 edit_->InsertText(string_drop_position, text);
208 } else {
209 edit_->PasteAndGo(CollapseWhitespace(text, true));
210 }
211 ResetDropHighlights();
212 return drop_operation;
213 }
214 }
215 230
216 ResetDropHighlights(); 231 if (!drag_has_url_)
232 ResetDropHighlights();
217 233
218 return DROPEFFECT_NONE; 234 return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
219 } 235 }
220 236
221 void EditDropTarget::UpdateDropHighlightPosition( 237 void AutocompleteEditViewWin::EditDropTarget::UpdateDropHighlightPosition(
222 const POINT& cursor_screen_position) { 238 const POINT& cursor_screen_position) {
223 if (drag_has_string_) { 239 if (drag_has_string_) {
224 POINT client_position = cursor_screen_position; 240 POINT client_position = cursor_screen_position;
225 ScreenToClient(edit_->m_hWnd, &client_position); 241 ::ScreenToClient(edit_->m_hWnd, &client_position);
226 int drop_position = edit_->CharFromPos(client_position); 242 int drop_position = edit_->CharFromPos(client_position);
227 if (edit_->in_drag()) { 243 if (edit_->in_drag()) {
228 // Our edit originated the drag, don't allow a drop if over the selected 244 // Our edit originated the drag, don't allow a drop if over the selected
229 // region. 245 // region.
230 LONG sel_start, sel_end; 246 LONG sel_start, sel_end;
231 edit_->GetSel(sel_start, sel_end); 247 edit_->GetSel(sel_start, sel_end);
232 if ((sel_start != sel_end) && (drop_position >= sel_start) && 248 if ((sel_start != sel_end) && (drop_position >= sel_start) &&
233 (drop_position <= sel_end)) 249 (drop_position <= sel_end))
234 drop_position = -1; 250 drop_position = -1;
235 } else { 251 } else {
236 // A drop from a source other than the edit replaces all the text, so 252 // A drop from a source other than the edit replaces all the text, so
237 // we don't show the drop location. See comment in OnDragEnter as to why 253 // we don't show the drop location. See comment in OnDragEnter as to why
238 // we don't try and select all here. 254 // we don't try and select all here.
239 drop_position = -1; 255 drop_position = -1;
240 } 256 }
241 edit_->SetDropHighlightPosition(drop_position); 257 edit_->SetDropHighlightPosition(drop_position);
242 } 258 }
243 } 259 }
244 260
245 void EditDropTarget::ResetDropHighlights() { 261 void AutocompleteEditViewWin::EditDropTarget::ResetDropHighlights() {
246 if (drag_has_string_) 262 if (drag_has_string_)
247 edit_->SetDropHighlightPosition(-1); 263 edit_->SetDropHighlightPosition(-1);
248 } 264 }
249 265
250 // The AutocompleteEditState struct contains enough information about the
251 // AutocompleteEditModel and AutocompleteEditViewWin to save/restore a user's
252 // typing, caret position, etc. across tab changes. We explicitly don't
253 // preserve things like whether the popup was open as this might be weird.
254 struct AutocompleteEditState {
255 AutocompleteEditState(const AutocompleteEditModel::State model_state,
256 const AutocompleteEditViewWin::State view_state)
257 : model_state(model_state),
258 view_state(view_state) {
259 }
260
261 const AutocompleteEditModel::State model_state;
262 const AutocompleteEditViewWin::State view_state;
263 };
264
265 // Returns true if the current point is far enough from the origin that it
266 // would be considered a drag.
267 bool IsDrag(const POINT& origin, const POINT& current) {
268 // The CXDRAG and CYDRAG system metrics describe the width and height of a
269 // rectangle around the origin position, inside of which motion is not
270 // considered a drag.
271 return (abs(current.x - origin.x) > (GetSystemMetrics(SM_CXDRAG) / 2)) ||
272 (abs(current.y - origin.y) > (GetSystemMetrics(SM_CYDRAG) / 2));
273 }
274
275 } // namespace
276 266
277 /////////////////////////////////////////////////////////////////////////////// 267 ///////////////////////////////////////////////////////////////////////////////
278 // Helper classes 268 // Helper classes
279 269
280 AutocompleteEditViewWin::ScopedFreeze::ScopedFreeze( 270 AutocompleteEditViewWin::ScopedFreeze::ScopedFreeze(
281 AutocompleteEditViewWin* edit, 271 AutocompleteEditViewWin* edit,
282 ITextDocument* text_object_model) 272 ITextDocument* text_object_model)
283 : edit_(edit), 273 : edit_(edit),
284 text_object_model_(text_object_model) { 274 text_object_model_(text_object_model) {
285 // Freeze the screen. 275 // Freeze the screen.
(...skipping 670 matching lines...) Expand 10 before | Expand all | Expand 10 after
956 } 946 }
957 947
958 views::View* AutocompleteEditViewWin::AddToView(views::View* parent) { 948 views::View* AutocompleteEditViewWin::AddToView(views::View* parent) {
959 views::NativeViewHost* host = new views::NativeViewHost; 949 views::NativeViewHost* host = new views::NativeViewHost;
960 parent->AddChildView(host); 950 parent->AddChildView(host);
961 host->set_focus_view(parent); 951 host->set_focus_view(parent);
962 host->Attach(GetNativeView()); 952 host->Attach(GetNativeView());
963 return host; 953 return host;
964 } 954 }
965 955
956 int AutocompleteEditViewWin::OnPerformDrop(
957 const views::DropTargetEvent& event) {
958 return OnPerformDropImpl(event, false);
959 }
960
961 int AutocompleteEditViewWin::OnPerformDropImpl(
962 const views::DropTargetEvent& event,
963 bool in_drag) {
964 const ui::OSExchangeData& data = event.data();
965
966 if (data.HasURL()) {
967 GURL url;
968 string16 title;
969 if (data.GetURLAndTitle(&url, &title)) {
970 SetUserText(UTF8ToWide(url.spec()));
971 model()->AcceptInput(CURRENT_TAB, true);
972 return CopyOrLinkDragOperation(event.source_operations());
973 }
974 } else if (data.HasString()) {
975 int string_drop_position = drop_highlight_position();
976 string16 text;
977 if ((string_drop_position != -1 || !in_drag) && data.GetString(&text)) {
978 DCHECK(string_drop_position == -1 ||
979 ((string_drop_position >= 0) &&
980 (string_drop_position <= GetTextLength())));
981 if (in_drag) {
982 if (event.source_operations()== ui::DragDropTypes::DRAG_MOVE)
983 MoveSelectedText(string_drop_position);
984 else
985 InsertText(string_drop_position, text);
986 } else {
987 PasteAndGo(CollapseWhitespace(text, true));
988 }
989 return CopyOrLinkDragOperation(event.source_operations());
990 }
991 }
992
993 return ui::DragDropTypes::DRAG_NONE;
994 }
995
966 void AutocompleteEditViewWin::PasteAndGo(const string16& text) { 996 void AutocompleteEditViewWin::PasteAndGo(const string16& text) {
967 if (CanPasteAndGo(text)) 997 if (CanPasteAndGo(text))
968 model_->PasteAndGo(); 998 model_->PasteAndGo();
969 } 999 }
970 1000
971 bool AutocompleteEditViewWin::SkipDefaultKeyEventProcessing( 1001 bool AutocompleteEditViewWin::SkipDefaultKeyEventProcessing(
972 const views::KeyEvent& e) { 1002 const views::KeyEvent& e) {
973 ui::KeyboardCode key = e.key_code(); 1003 ui::KeyboardCode key = e.key_code();
974 // We don't process ALT + numpad digit as accelerators, they are used for 1004 // We don't process ALT + numpad digit as accelerators, they are used for
975 // entering special characters. We do translate alt-home. 1005 // entering special characters. We do translate alt-home.
(...skipping 1607 matching lines...) Expand 10 before | Expand all | Expand 10 after
2583 // PosFromChar(i) might return 0 when i is greater than 1. 2613 // PosFromChar(i) might return 0 when i is greater than 1.
2584 return font_.GetStringWidth(text) + GetHorizontalMargin(); 2614 return font_.GetStringWidth(text) + GetHorizontalMargin();
2585 } 2615 }
2586 2616
2587 bool AutocompleteEditViewWin::IsCaretAtEnd() const { 2617 bool AutocompleteEditViewWin::IsCaretAtEnd() const {
2588 long length = GetTextLength(); 2618 long length = GetTextLength();
2589 CHARRANGE sel; 2619 CHARRANGE sel;
2590 GetSelection(sel); 2620 GetSelection(sel);
2591 return sel.cpMin == sel.cpMax && sel.cpMin == length; 2621 return sel.cpMin == sel.cpMax && sel.cpMin == length;
2592 } 2622 }
OLDNEW
« no previous file with comments | « chrome/browser/autocomplete/autocomplete_edit_view_win.h ('k') | chrome/browser/ui/views/toolbar_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698