1 // Copyright (c) 2012 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.
5 #ifndef CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_VIEW_WIN_H_
6 #define CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_VIEW_WIN_H_
13 #include <tom.h> // For ITextDocument, a COM interface to CRichEditCtrl.
15 #include "base/memory/scoped_ptr.h"
16 #include "base/win/scoped_comptr.h"
17 #include "chrome/browser/ui/omnibox/omnibox_view.h"
18 #include "chrome/browser/ui/toolbar/toolbar_model.h"
19 #include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
20 #include "ui/base/ime/win/tsf_event_router.h"
21 #include "ui/base/models/simple_menu_model.h"
22 #include "ui/base/win/extra_sdk_defines.h"
23 #include "ui/base/window_open_disposition.h"
24 #include "ui/gfx/font_list.h"
26 class LocationBarView;
27 class OmniboxPopupView;
35 // Provides the implementation of an edit control with a drop-down
36 // autocomplete box. The box itself is implemented in autocomplete_popup.cc
37 // This file implements the edit box and management for the popup.
39 : public CWindowImpl<OmniboxViewWin,
41 CWinTraits<WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL |
43 public CRichEditCommands<OmniboxViewWin>,
44 public ui::SimpleMenuModel::Delegate,
45 public ui::TSFEventRouterObserver,
49 State(const CHARRANGE& selection,
50 const CHARRANGE& saved_selection_for_focus_change)
51 : selection(selection),
52 saved_selection_for_focus_change(saved_selection_for_focus_change) {
55 const CHARRANGE selection;
56 const CHARRANGE saved_selection_for_focus_change;
59 DECLARE_WND_SUPERCLASS(L"Chrome_OmniboxView", MSFTEDIT_CLASS);
61 OmniboxViewWin(OmniboxEditController* controller,
62 LocationBarView* parent_view,
63 CommandUpdater* command_updater,
64 bool popup_window_mode,
65 const gfx::FontList& font_list,
69 // Gets the relative window for the specified native view.
70 static gfx::NativeView GetRelativeWindowForNativeView(
71 gfx::NativeView edit_native_view);
73 views::View* parent_view() const;
76 virtual void SaveStateToTab(content::WebContents* tab) OVERRIDE;
77 virtual void OnTabChanged(const content::WebContents* web_contents) OVERRIDE;
78 virtual void Update() OVERRIDE;
79 virtual void OpenMatch(const AutocompleteMatch& match,
80 WindowOpenDisposition disposition,
81 const GURL& alternate_nav_url,
82 size_t index) OVERRIDE;
83 virtual string16 GetText() const OVERRIDE;
84 virtual void SetUserText(const string16& text,
85 const string16& display_text,
86 bool update_popup) OVERRIDE;
87 virtual void SetWindowTextAndCaretPos(const string16& text,
90 bool notify_text_changed) OVERRIDE;
91 virtual void SetForcedQuery() OVERRIDE;
92 virtual bool IsSelectAll() const OVERRIDE;
93 virtual bool DeleteAtEndPressed() OVERRIDE;
94 virtual void GetSelectionBounds(string16::size_type* start,
95 string16::size_type* end) const OVERRIDE;
96 virtual void SelectAll(bool reversed) OVERRIDE;
97 virtual void RevertAll() OVERRIDE;
98 virtual void UpdatePopup() OVERRIDE;
99 virtual void SetFocus() OVERRIDE;
100 virtual void ApplyCaretVisibility() OVERRIDE;
101 virtual void OnTemporaryTextMaybeChanged(
102 const string16& display_text,
103 bool save_original_selection,
104 bool notify_text_changed) OVERRIDE;
105 virtual bool OnInlineAutocompleteTextMaybeChanged(
106 const string16& display_text, size_t user_text_length) OVERRIDE;
107 virtual void OnRevertTemporaryText() OVERRIDE;
108 virtual void OnBeforePossibleChange() OVERRIDE;
109 virtual bool OnAfterPossibleChange() OVERRIDE;
110 virtual gfx::NativeView GetNativeView() const OVERRIDE;
111 virtual gfx::NativeView GetRelativeWindowForPopup() const OVERRIDE;
112 virtual void SetGrayTextAutocompletion(const string16& suggestion) OVERRIDE;
113 virtual int TextWidth() const OVERRIDE;
114 virtual string16 GetGrayTextAutocompletion() const OVERRIDE;
115 virtual bool IsImeComposing() const OVERRIDE;
116 virtual int GetMaxEditWidth(int entry_width) const OVERRIDE;
117 virtual views::View* AddToView(views::View* parent) OVERRIDE;
118 virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
120 int GetPopupMaxYCoordinate();
122 void SetDropHighlightPosition(int position);
123 int drop_highlight_position() const { return drop_highlight_position_; }
125 // Returns true if a drag a drop session was initiated by this edit.
126 bool in_drag() const { return in_drag_; }
128 // Moves the selected text to the specified position.
129 void MoveSelectedText(int new_position);
131 // Inserts the text at the specified position.
132 void InsertText(int position, const string16& text);
134 void set_force_hidden(bool force_hidden) { force_hidden_ = force_hidden; }
136 // Called before an accelerator is processed to give us a chance to override
138 bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event);
140 // Handler for external events passed in to us. The View that owns us may
141 // send us events that we should treat as if they were events on us.
142 void HandleExternalMsg(UINT msg, UINT flags, const CPoint& screen_point);
145 BEGIN_MSG_MAP(OmniboxViewWin)
147 MSG_WM_CONTEXTMENU(OnContextMenu)
149 MSG_WM_CREATE(OnCreate)
151 MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
152 MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition)
153 MESSAGE_HANDLER_EX(WM_IME_ENDCOMPOSITION, OnImeEndComposition)
154 MESSAGE_HANDLER_EX(WM_IME_NOTIFY, OnImeNotify)
155 MESSAGE_HANDLER_EX(WM_TOUCH, OnTouchEvent)
156 MSG_WM_KEYDOWN(OnKeyDown)
157 MSG_WM_KEYUP(OnKeyUp)
158 MSG_WM_KILLFOCUS(OnKillFocus)
159 MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
160 MSG_WM_LBUTTONDOWN(OnLButtonDown)
161 MSG_WM_LBUTTONUP(OnLButtonUp)
162 MSG_WM_MBUTTONDBLCLK(OnMButtonDblClk)
163 MSG_WM_MBUTTONDOWN(OnMButtonDown)
164 MSG_WM_MBUTTONUP(OnMButtonUp)
165 MSG_WM_MOUSEACTIVATE(OnMouseActivate)
166 MSG_WM_MOUSEMOVE(OnMouseMove)
167 MSG_WM_MOUSEWHEEL(OnMouseWheel)
168 MSG_WM_PAINT(OnPaint)
169 MSG_WM_PASTE(OnPaste)
170 MSG_WM_RBUTTONDBLCLK(OnRButtonDblClk)
171 MSG_WM_RBUTTONDOWN(OnRButtonDown)
172 MSG_WM_RBUTTONUP(OnRButtonUp)
173 MSG_WM_SETFOCUS(OnSetFocus)
174 MSG_WM_SETTEXT(OnSetText)
175 MSG_WM_SYSCHAR(OnSysChar) // WM_SYSxxx == WM_xxx with ALT down
176 MSG_WM_SYSKEYDOWN(OnKeyDown)
177 MSG_WM_SYSKEYUP(OnKeyUp)
178 MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging)
179 DEFAULT_REFLECTION_HANDLER() // avoids black margin area
182 // ui::SimpleMenuModel::Delegate
183 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
184 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
185 virtual bool GetAcceleratorForCommandId(
187 ui::Accelerator* accelerator) OVERRIDE;
188 virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE;
189 virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE;
190 virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
198 // This object freezes repainting of the edit until the object is destroyed.
199 // Some methods of the CRichEditCtrl draw synchronously to the screen. If we
200 // don't freeze, the user will see a rapid series of calls to these as
203 // Freezing the control while it is already frozen is permitted; the control
204 // will unfreeze once both freezes are released (the freezes stack).
207 ScopedFreeze(OmniboxViewWin* edit, ITextDocument* text_object_model);
211 OmniboxViewWin* const edit_;
212 ITextDocument* const text_object_model_;
214 DISALLOW_COPY_AND_ASSIGN(ScopedFreeze);
217 class EditDropTarget;
218 friend class EditDropTarget;
220 // This object suspends placing any operations on the edit's undo stack until
221 // the object is destroyed. If we don't do this, some of the operations we
222 // perform behind the user's back will be undoable by the user, which feels
223 // bizarre and confusing.
224 class ScopedSuspendUndo {
226 explicit ScopedSuspendUndo(ITextDocument* text_object_model);
227 ~ScopedSuspendUndo();
230 ITextDocument* const text_object_model_;
232 DISALLOW_COPY_AND_ASSIGN(ScopedSuspendUndo);
235 // Replacement word-breaking proc for the rich edit control.
236 static int CALLBACK WordBreakProc(LPTSTR edit_text,
241 // Returns true if |edit_text| starting at |current_pos| is "://".
242 static bool SchemeEnd(LPTSTR edit_text, int current_pos, int length);
245 void OnChar(TCHAR ch, UINT repeat_count, UINT flags);
246 void OnContextMenu(HWND window, const CPoint& point);
248 LRESULT OnCreate(const CREATESTRUCTW* create_struct);
250 LRESULT OnGetObject(UINT message, WPARAM wparam, LPARAM lparam);
251 LRESULT OnImeComposition(UINT message, WPARAM wparam, LPARAM lparam);
252 LRESULT OnImeEndComposition(UINT message, WPARAM wparam, LPARAM lparam);
253 LRESULT OnImeNotify(UINT message, WPARAM wparam, LPARAM lparam);
254 LRESULT OnTouchEvent(UINT message, WPARAM wparam, LPARAM lparam);
255 void OnKeyDown(TCHAR key, UINT repeat_count, UINT flags);
256 void OnKeyUp(TCHAR key, UINT repeat_count, UINT flags);
257 void OnKillFocus(HWND focus_wnd);
258 void OnLButtonDblClk(UINT keys, const CPoint& point);
259 void OnLButtonDown(UINT keys, const CPoint& point);
260 void OnLButtonUp(UINT keys, const CPoint& point);
261 void OnMButtonDblClk(UINT keys, const CPoint& point);
262 void OnMButtonDown(UINT keys, const CPoint& point);
263 void OnMButtonUp(UINT keys, const CPoint& point);
264 LRESULT OnMouseActivate(HWND window, UINT hit_test, UINT mouse_message);
265 void OnMouseMove(UINT keys, const CPoint& point);
266 BOOL OnMouseWheel(UINT flags, short delta, CPoint point);
267 void OnPaint(HDC bogus_hdc);
269 void OnRButtonDblClk(UINT keys, const CPoint& point);
270 void OnRButtonDown(UINT keys, const CPoint& point);
271 void OnRButtonUp(UINT keys, const CPoint& point);
272 void OnSetFocus(HWND focus_wnd);
273 LRESULT OnSetText(const wchar_t* text);
274 void OnSysChar(TCHAR ch, UINT repeat_count, UINT flags);
275 void OnWindowPosChanging(WINDOWPOS* window_pos);
277 // Helper function for OnChar() and OnKeyDown() that handles keystrokes that
278 // could change the text in the edit.
279 void HandleKeystroke(UINT message, TCHAR key, UINT repeat_count, UINT flags);
281 // Helper functions for OnKeyDown() that handle accelerators applicable when
282 // we're not read-only and all the time, respectively. These return true if
283 // they handled the key.
284 bool OnKeyDownOnlyWritable(TCHAR key, UINT repeat_count, UINT flags);
285 bool OnKeyDownAllModes(TCHAR key, UINT repeat_count, UINT flags);
287 // Like GetSel(), but returns a range where |cpMin| will be larger than
288 // |cpMax| if the cursor is at the start rather than the end of the selection
289 // (in other words, tracks selection direction as well as offsets).
290 // Note the non-Google-style "non-const-ref" argument, which matches GetSel().
291 void GetSelection(CHARRANGE& sel) const;
293 // Returns the currently selected text of the edit control.
294 string16 GetSelectedText() const;
296 // Like SetSel(), but respects the selection direction implied by |start| and
297 // |end|: if |end| < |start|, the effective cursor will be placed at the
298 // beginning of the selection.
299 void SetSelection(LONG start, LONG end);
301 // Like SetSelection(), but takes a CHARRANGE.
302 void SetSelectionRange(const CHARRANGE& sel) {
303 SetSelection(sel.cpMin, sel.cpMax);
306 // Places the caret at the given position. This clears any selection.
307 void PlaceCaretAt(size_t pos);
309 // Returns true if |sel| represents a forward or backward selection of all the
311 bool IsSelectAllForRange(const CHARRANGE& sel) const;
313 // Given an X coordinate in client coordinates, returns that coordinate
314 // clipped to be within the horizontal bounds of the visible text.
316 // This is used in our mouse handlers to work around quirky behaviors of the
317 // underlying CRichEditCtrl like not supporting triple-click when the user
318 // doesn't click on the text itself.
320 // |is_triple_click| should be true iff this is the third click of a triple
321 // click. Sadly, we need to clip slightly differently in this case.
322 LONG ClipXCoordToVisibleText(LONG x, bool is_triple_click) const;
324 virtual int GetOmniboxTextLength() const OVERRIDE;
326 // Parses the contents of the control for the scheme and the host name.
327 // Highlights the scheme in green or red depending on it security level.
328 // If a host name is found, it makes it visually stronger.
329 virtual void EmphasizeURLComponents() OVERRIDE;
331 // TSFEventRouter::Observer:
332 virtual void OnCandidateWindowCountChanged(size_t window_count) OVERRIDE;
333 virtual void OnTextUpdated(const gfx::Range& composition_range) OVERRIDE;
335 // Erases the portion of the selection in the font's y-adjustment area. For
336 // some reason the edit draws the selection rect here even though it's not
338 void EraseTopOfSelection(CDC* dc,
339 const CRect& client_rect,
340 const CRect& paint_clip_rect);
342 // Draws a slash across the scheme if desired.
343 void DrawSlashForInsecureScheme(HDC hdc,
344 const CRect& client_rect,
345 const CRect& paint_clip_rect);
347 // Renders the drop highlight.
348 void DrawDropHighlight(HDC hdc,
349 const CRect& client_rect,
350 const CRect& paint_clip_rect);
352 // Internally invoked whenever the text changes in some way.
353 void TextChanged() OVERRIDE;
355 // Getter for the text_object_model_. Note that the pointer returned here is
356 // only valid as long as the AutocompleteEdit is still alive. Also, if the
357 // underlying call fails, this may return NULL.
358 ITextDocument* GetTextObjectModel() const;
360 // Invoked during a mouse move. As necessary starts a drag and drop session.
361 void StartDragIfNecessary(const CPoint& point);
363 // Invoked during a mouse down. If the mouse location is over the selection
364 // this sets possible_drag_ to true to indicate a drag should start if the
365 // user moves the mouse far enough to start a drag.
366 void OnPossibleDrag(const CPoint& point);
368 // Redraws the necessary region for a drop highlight at the specified
369 // position. This does nothing if position is beyond the bounds of the
371 void RepaintDropHighlight(int position);
373 // Generates the context menu for the edit field.
374 void BuildContextMenu();
376 void SelectAllIfNecessary(MouseButton button, const CPoint& point);
377 void TrackMousePosition(MouseButton button, const CPoint& point);
379 // Returns the sum of the left and right margins.
380 int GetHorizontalMargin() const;
382 // Returns the width in pixels needed to display |text|.
383 int WidthNeededToDisplay(const string16& text) const;
385 // Real implementation of OnAfterPossibleChange() method.
386 // If |force_text_changed| is true, then the text_changed code will always be
387 // triggerred no matter if the text is actually changed or not.
388 bool OnAfterPossibleChangeInternal(bool force_text_changed);
390 // Common implementation for performing a drop on the edit view.
391 int OnPerformDropImpl(const ui::DropTargetEvent& event, bool in_drag);
393 // The handle to the RichEdit DLL. In the rare case where the user's system
394 // is missing this DLL (due to some kind of system corruption), the similar
395 // OmniboxViewViews is used instead; see Textfield::IsViewsTextfieldEnabled().
396 static HMODULE loaded_library_module_;
398 scoped_ptr<OmniboxPopupView> popup_view_;
400 // The parent view for the edit, used to align the popup and for
402 LocationBarView* location_bar_;
404 // When true, the location bar view is read only and also is has a slightly
405 // different presentation (font size / color). This is used for popups.
406 bool popup_window_mode_;
408 // True if we should prevent attempts to make the window visible when we
409 // handle WM_WINDOWPOSCHANGING. While toggling fullscreen mode, the main
410 // window is hidden, and if the edit is shown it will draw over the main
411 // window when that window reappears.
414 // Non-null when the edit is gaining focus from a left click. This is only
415 // needed between when WM_MOUSEACTIVATE and WM_LBUTTONDOWN get processed. It
416 // serves two purposes: first, by communicating to OnLButtonDown() that we're
417 // gaining focus from a left click, it allows us to work even with the
418 // inconsistent order in which various Windows messages get sent (see comments
419 // in OnMouseActivate()). Second, by holding the edit frozen, it ensures that
420 // when we process WM_SETFOCUS the edit won't first redraw itself with the
421 // caret at the beginning, and then have it blink to where the mouse cursor
422 // really is shortly afterward.
423 scoped_ptr<ScopedFreeze> gaining_focus_;
425 // When the user clicks to give us focus, we watch to see if they're clicking
426 // or dragging. When they're clicking, we select nothing until mouseup, then
427 // select all the text in the edit. During this process, tracking_click_[X]
428 // is true and click_point_[X] holds the original click location.
429 // At other times, tracking_click_[X] is false, and the contents of
430 // click_point_[X] should be ignored. The arrays hold the state for the
431 // left and right mouse buttons, and are indexed using the MouseButton enum.
432 bool tracking_click_[2];
433 CPoint click_point_[2];
435 // We need to know if the user triple-clicks, so track double click points
436 // and times so we can see if subsequent clicks are actually triple clicks.
437 bool tracking_double_click_;
438 CPoint double_click_point_;
439 DWORD double_click_time_;
441 // Used to discard unnecessary WM_MOUSEMOVE events after the first such
442 // unnecessary event. See detailed comments in OnMouseMove().
443 bool can_discard_mousemove_;
445 // Used to prevent IME message handling in the midst of updating the edit
446 // text. See comments where this is used.
447 bool ignore_ime_messages_;
449 // Variables for tracking state before and after a possible change.
450 string16 text_before_change_;
451 CHARRANGE sel_before_change_;
453 // Set at the same time the model's original_* members are set, and valid in
455 CHARRANGE original_selection_;
457 // Holds the user's selection across focus changes. cpMin holds -1 when
458 // there is no saved selection.
459 CHARRANGE saved_selection_for_focus_change_;
461 // Was the delete key pressed with an empty selection at the end of the edit?
462 bool delete_at_end_pressed_;
464 // The context menu for the edit.
465 scoped_ptr<ui::SimpleMenuModel> context_menu_contents_;
466 scoped_ptr<views::MenuRunner> context_menu_runner_;
468 // The font list to draw text in Omnibox.
469 gfx::FontList font_list_;
471 // Metrics about the font, which we keep so we don't need to recalculate them
472 // every time we paint. |font_y_adjustment_| is the number of pixels we need
473 // to shift the font vertically in order to make its baseline be at our
474 // desired baseline in the edit.
476 int font_y_adjustment_;
478 // If true, indicates the mouse is down and if the mouse is moved enough we
479 // should start a drag.
482 // If true, we're in a call to DoDragDrop.
485 // If true indicates we've run a drag and drop session. This is used to
486 // avoid starting two drag and drop sessions if the drag is canceled while
487 // the mouse is still down.
488 bool initiated_drag_;
490 // Position of the drop highlight. If this is -1, there is no drop highlight.
491 int drop_highlight_position_;
493 // True if the IME candidate window is open. When this is true, we want to
494 // avoid showing the popup.
495 bool ime_candidate_window_open_;
497 // Security UI-related data.
498 COLORREF background_color_;
499 ToolbarModel::SecurityLevel security_level_;
501 // This interface is useful for accessing the CRichEditCtrl at a low level.
502 mutable ITextDocument* text_object_model_;
504 // This contains the scheme char start and stop indexes that should be
505 // stricken-out when displaying an insecure scheme.
506 url_parse::Component insecure_scheme_component_;
508 // Instance of accessibility information and handling.
509 mutable base::win::ScopedComPtr<IAccessible> autocomplete_accessibility_;
511 // The native view host.
512 views::NativeViewHost* native_view_host_;
514 // TSF related event router.
515 scoped_ptr<ui::TSFEventRouter> tsf_event_router_;
517 DISALLOW_COPY_AND_ASSIGN(OmniboxViewWin);
520 #endif // CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_VIEW_WIN_H_