| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_VIEW_WIN_H_ |
| #define CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_VIEW_WIN_H_ |
| |
| #include <atlbase.h> |
| #include <atlapp.h> |
| #include <atlcrack.h> |
| #include <atlctrls.h> |
| #include <atlmisc.h> |
| #include <tom.h> // For ITextDocument, a COM interface to CRichEditCtrl. |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "base/win/scoped_comptr.h" |
| #include "chrome/browser/ui/omnibox/omnibox_view.h" |
| #include "chrome/browser/ui/toolbar/toolbar_model.h" |
| #include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h" |
| #include "ui/base/ime/win/tsf_event_router.h" |
| #include "ui/base/models/simple_menu_model.h" |
| #include "ui/base/win/extra_sdk_defines.h" |
| #include "ui/base/window_open_disposition.h" |
| #include "ui/gfx/font_list.h" |
| |
| class LocationBarView; |
| class OmniboxPopupView; |
| |
| namespace views { |
| class MenuRunner; |
| class NativeViewHost; |
| class View; |
| } |
| |
| // Provides the implementation of an edit control with a drop-down |
| // autocomplete box. The box itself is implemented in autocomplete_popup.cc |
| // This file implements the edit box and management for the popup. |
| class OmniboxViewWin |
| : public CWindowImpl<OmniboxViewWin, |
| CRichEditCtrl, |
| CWinTraits<WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | |
| ES_NOHIDESEL> >, |
| public CRichEditCommands<OmniboxViewWin>, |
| public ui::SimpleMenuModel::Delegate, |
| public ui::TSFEventRouterObserver, |
| public OmniboxView { |
| public: |
| struct State { |
| State(const CHARRANGE& selection, |
| const CHARRANGE& saved_selection_for_focus_change) |
| : selection(selection), |
| saved_selection_for_focus_change(saved_selection_for_focus_change) { |
| } |
| |
| const CHARRANGE selection; |
| const CHARRANGE saved_selection_for_focus_change; |
| }; |
| |
| DECLARE_WND_SUPERCLASS(L"Chrome_OmniboxView", MSFTEDIT_CLASS); |
| |
| OmniboxViewWin(OmniboxEditController* controller, |
| LocationBarView* parent_view, |
| CommandUpdater* command_updater, |
| bool popup_window_mode, |
| const gfx::FontList& font_list, |
| int font_y_offset); |
| ~OmniboxViewWin(); |
| |
| // Gets the relative window for the specified native view. |
| static gfx::NativeView GetRelativeWindowForNativeView( |
| gfx::NativeView edit_native_view); |
| |
| views::View* parent_view() const; |
| |
| // OmniboxView: |
| virtual void SaveStateToTab(content::WebContents* tab) OVERRIDE; |
| virtual void OnTabChanged(const content::WebContents* web_contents) OVERRIDE; |
| virtual void Update() OVERRIDE; |
| virtual void OpenMatch(const AutocompleteMatch& match, |
| WindowOpenDisposition disposition, |
| const GURL& alternate_nav_url, |
| size_t index) OVERRIDE; |
| virtual string16 GetText() const OVERRIDE; |
| virtual void SetUserText(const string16& text, |
| const string16& display_text, |
| bool update_popup) OVERRIDE; |
| virtual void SetWindowTextAndCaretPos(const string16& text, |
| size_t caret_pos, |
| bool update_popup, |
| bool notify_text_changed) OVERRIDE; |
| virtual void SetForcedQuery() OVERRIDE; |
| virtual bool IsSelectAll() const OVERRIDE; |
| virtual bool DeleteAtEndPressed() OVERRIDE; |
| virtual void GetSelectionBounds(string16::size_type* start, |
| string16::size_type* end) const OVERRIDE; |
| virtual void SelectAll(bool reversed) OVERRIDE; |
| virtual void RevertAll() OVERRIDE; |
| virtual void UpdatePopup() OVERRIDE; |
| virtual void SetFocus() OVERRIDE; |
| virtual void ApplyCaretVisibility() OVERRIDE; |
| virtual void OnTemporaryTextMaybeChanged( |
| const string16& display_text, |
| bool save_original_selection, |
| bool notify_text_changed) OVERRIDE; |
| virtual bool OnInlineAutocompleteTextMaybeChanged( |
| const string16& display_text, size_t user_text_length) OVERRIDE; |
| virtual void OnRevertTemporaryText() OVERRIDE; |
| virtual void OnBeforePossibleChange() OVERRIDE; |
| virtual bool OnAfterPossibleChange() OVERRIDE; |
| virtual gfx::NativeView GetNativeView() const OVERRIDE; |
| virtual gfx::NativeView GetRelativeWindowForPopup() const OVERRIDE; |
| virtual void SetGrayTextAutocompletion(const string16& suggestion) OVERRIDE; |
| virtual int TextWidth() const OVERRIDE; |
| virtual string16 GetGrayTextAutocompletion() const OVERRIDE; |
| virtual bool IsImeComposing() const OVERRIDE; |
| virtual int GetMaxEditWidth(int entry_width) const OVERRIDE; |
| virtual views::View* AddToView(views::View* parent) OVERRIDE; |
| virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE; |
| |
| int GetPopupMaxYCoordinate(); |
| |
| void SetDropHighlightPosition(int position); |
| int drop_highlight_position() const { return drop_highlight_position_; } |
| |
| // Returns true if a drag a drop session was initiated by this edit. |
| bool in_drag() const { return in_drag_; } |
| |
| // Moves the selected text to the specified position. |
| void MoveSelectedText(int new_position); |
| |
| // Inserts the text at the specified position. |
| void InsertText(int position, const string16& text); |
| |
| void set_force_hidden(bool force_hidden) { force_hidden_ = force_hidden; } |
| |
| // Called before an accelerator is processed to give us a chance to override |
| // it. |
| bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event); |
| |
| // Handler for external events passed in to us. The View that owns us may |
| // send us events that we should treat as if they were events on us. |
| void HandleExternalMsg(UINT msg, UINT flags, const CPoint& screen_point); |
| |
| // CWindowImpl |
| BEGIN_MSG_MAP(OmniboxViewWin) |
| MSG_WM_CHAR(OnChar) |
| MSG_WM_CONTEXTMENU(OnContextMenu) |
| MSG_WM_COPY(OnCopy) |
| MSG_WM_CREATE(OnCreate) |
| MSG_WM_CUT(OnCut) |
| MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject) |
| MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition) |
| MESSAGE_HANDLER_EX(WM_IME_ENDCOMPOSITION, OnImeEndComposition) |
| MESSAGE_HANDLER_EX(WM_IME_NOTIFY, OnImeNotify) |
| MESSAGE_HANDLER_EX(WM_TOUCH, OnTouchEvent) |
| MSG_WM_KEYDOWN(OnKeyDown) |
| MSG_WM_KEYUP(OnKeyUp) |
| MSG_WM_KILLFOCUS(OnKillFocus) |
| MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk) |
| MSG_WM_LBUTTONDOWN(OnLButtonDown) |
| MSG_WM_LBUTTONUP(OnLButtonUp) |
| MSG_WM_MBUTTONDBLCLK(OnMButtonDblClk) |
| MSG_WM_MBUTTONDOWN(OnMButtonDown) |
| MSG_WM_MBUTTONUP(OnMButtonUp) |
| MSG_WM_MOUSEACTIVATE(OnMouseActivate) |
| MSG_WM_MOUSEMOVE(OnMouseMove) |
| MSG_WM_MOUSEWHEEL(OnMouseWheel) |
| MSG_WM_PAINT(OnPaint) |
| MSG_WM_PASTE(OnPaste) |
| MSG_WM_RBUTTONDBLCLK(OnRButtonDblClk) |
| MSG_WM_RBUTTONDOWN(OnRButtonDown) |
| MSG_WM_RBUTTONUP(OnRButtonUp) |
| MSG_WM_SETFOCUS(OnSetFocus) |
| MSG_WM_SETTEXT(OnSetText) |
| MSG_WM_SYSCHAR(OnSysChar) // WM_SYSxxx == WM_xxx with ALT down |
| MSG_WM_SYSKEYDOWN(OnKeyDown) |
| MSG_WM_SYSKEYUP(OnKeyUp) |
| MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging) |
| DEFAULT_REFLECTION_HANDLER() // avoids black margin area |
| END_MSG_MAP() |
| |
| // ui::SimpleMenuModel::Delegate |
| virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; |
| virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; |
| virtual bool GetAcceleratorForCommandId( |
| int command_id, |
| ui::Accelerator* accelerator) OVERRIDE; |
| virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; |
| virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE; |
| virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; |
| |
| private: |
| enum MouseButton { |
| kLeft = 0, |
| kRight = 1, |
| }; |
| |
| // This object freezes repainting of the edit until the object is destroyed. |
| // Some methods of the CRichEditCtrl draw synchronously to the screen. If we |
| // don't freeze, the user will see a rapid series of calls to these as |
| // flickers. |
| // |
| // Freezing the control while it is already frozen is permitted; the control |
| // will unfreeze once both freezes are released (the freezes stack). |
| class ScopedFreeze { |
| public: |
| ScopedFreeze(OmniboxViewWin* edit, ITextDocument* text_object_model); |
| ~ScopedFreeze(); |
| |
| private: |
| OmniboxViewWin* const edit_; |
| ITextDocument* const text_object_model_; |
| |
| 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 |
| // bizarre and confusing. |
| class ScopedSuspendUndo { |
| public: |
| explicit ScopedSuspendUndo(ITextDocument* text_object_model); |
| ~ScopedSuspendUndo(); |
| |
| private: |
| ITextDocument* const text_object_model_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedSuspendUndo); |
| }; |
| |
| // Replacement word-breaking proc for the rich edit control. |
| static int CALLBACK WordBreakProc(LPTSTR edit_text, |
| int current_pos, |
| int length, |
| int action); |
| |
| // Returns true if |edit_text| starting at |current_pos| is "://". |
| static bool SchemeEnd(LPTSTR edit_text, int current_pos, int length); |
| |
| // Message handlers |
| void OnChar(TCHAR ch, UINT repeat_count, UINT flags); |
| void OnContextMenu(HWND window, const CPoint& point); |
| void OnCopy(); |
| LRESULT OnCreate(const CREATESTRUCTW* create_struct); |
| void OnCut(); |
| LRESULT OnGetObject(UINT message, WPARAM wparam, LPARAM lparam); |
| LRESULT OnImeComposition(UINT message, WPARAM wparam, LPARAM lparam); |
| LRESULT OnImeEndComposition(UINT message, WPARAM wparam, LPARAM lparam); |
| LRESULT OnImeNotify(UINT message, WPARAM wparam, LPARAM lparam); |
| LRESULT OnTouchEvent(UINT message, WPARAM wparam, LPARAM lparam); |
| void OnKeyDown(TCHAR key, UINT repeat_count, UINT flags); |
| void OnKeyUp(TCHAR key, UINT repeat_count, UINT flags); |
| void OnKillFocus(HWND focus_wnd); |
| void OnLButtonDblClk(UINT keys, const CPoint& point); |
| void OnLButtonDown(UINT keys, const CPoint& point); |
| void OnLButtonUp(UINT keys, const CPoint& point); |
| void OnMButtonDblClk(UINT keys, const CPoint& point); |
| void OnMButtonDown(UINT keys, const CPoint& point); |
| void OnMButtonUp(UINT keys, const CPoint& point); |
| LRESULT OnMouseActivate(HWND window, UINT hit_test, UINT mouse_message); |
| void OnMouseMove(UINT keys, const CPoint& point); |
| BOOL OnMouseWheel(UINT flags, short delta, CPoint point); |
| void OnPaint(HDC bogus_hdc); |
| void OnPaste(); |
| void OnRButtonDblClk(UINT keys, const CPoint& point); |
| void OnRButtonDown(UINT keys, const CPoint& point); |
| void OnRButtonUp(UINT keys, const CPoint& point); |
| void OnSetFocus(HWND focus_wnd); |
| LRESULT OnSetText(const wchar_t* text); |
| void OnSysChar(TCHAR ch, UINT repeat_count, UINT flags); |
| void OnWindowPosChanging(WINDOWPOS* window_pos); |
| |
| // Helper function for OnChar() and OnKeyDown() that handles keystrokes that |
| // could change the text in the edit. |
| void HandleKeystroke(UINT message, TCHAR key, UINT repeat_count, UINT flags); |
| |
| // Helper functions for OnKeyDown() that handle accelerators applicable when |
| // we're not read-only and all the time, respectively. These return true if |
| // they handled the key. |
| bool OnKeyDownOnlyWritable(TCHAR key, UINT repeat_count, UINT flags); |
| bool OnKeyDownAllModes(TCHAR key, UINT repeat_count, UINT flags); |
| |
| // Like GetSel(), but returns a range where |cpMin| will be larger than |
| // |cpMax| if the cursor is at the start rather than the end of the selection |
| // (in other words, tracks selection direction as well as offsets). |
| // Note the non-Google-style "non-const-ref" argument, which matches GetSel(). |
| void GetSelection(CHARRANGE& sel) const; |
| |
| // Returns the currently selected text of the edit control. |
| string16 GetSelectedText() const; |
| |
| // Like SetSel(), but respects the selection direction implied by |start| and |
| // |end|: if |end| < |start|, the effective cursor will be placed at the |
| // beginning of the selection. |
| void SetSelection(LONG start, LONG end); |
| |
| // Like SetSelection(), but takes a CHARRANGE. |
| void SetSelectionRange(const CHARRANGE& sel) { |
| SetSelection(sel.cpMin, sel.cpMax); |
| } |
| |
| // Places the caret at the given position. This clears any selection. |
| void PlaceCaretAt(size_t pos); |
| |
| // Returns true if |sel| represents a forward or backward selection of all the |
| // text. |
| bool IsSelectAllForRange(const CHARRANGE& sel) const; |
| |
| // Given an X coordinate in client coordinates, returns that coordinate |
| // clipped to be within the horizontal bounds of the visible text. |
| // |
| // This is used in our mouse handlers to work around quirky behaviors of the |
| // underlying CRichEditCtrl like not supporting triple-click when the user |
| // doesn't click on the text itself. |
| // |
| // |is_triple_click| should be true iff this is the third click of a triple |
| // click. Sadly, we need to clip slightly differently in this case. |
| LONG ClipXCoordToVisibleText(LONG x, bool is_triple_click) const; |
| |
| virtual int GetOmniboxTextLength() const OVERRIDE; |
| |
| // Parses the contents of the control for the scheme and the host name. |
| // Highlights the scheme in green or red depending on it security level. |
| // If a host name is found, it makes it visually stronger. |
| virtual void EmphasizeURLComponents() OVERRIDE; |
| |
| // TSFEventRouter::Observer: |
| virtual void OnCandidateWindowCountChanged(size_t window_count) OVERRIDE; |
| virtual void OnTextUpdated(const gfx::Range& composition_range) OVERRIDE; |
| |
| // Erases the portion of the selection in the font's y-adjustment area. For |
| // some reason the edit draws the selection rect here even though it's not |
| // part of the font. |
| void EraseTopOfSelection(CDC* dc, |
| const CRect& client_rect, |
| const CRect& paint_clip_rect); |
| |
| // Draws a slash across the scheme if desired. |
| void DrawSlashForInsecureScheme(HDC hdc, |
| const CRect& client_rect, |
| const CRect& paint_clip_rect); |
| |
| // Renders the drop highlight. |
| void DrawDropHighlight(HDC hdc, |
| const CRect& client_rect, |
| const CRect& paint_clip_rect); |
| |
| // Internally invoked whenever the text changes in some way. |
| void TextChanged() OVERRIDE; |
| |
| // Getter for the text_object_model_. Note that the pointer returned here is |
| // only valid as long as the AutocompleteEdit is still alive. Also, if the |
| // underlying call fails, this may return NULL. |
| ITextDocument* GetTextObjectModel() const; |
| |
| // Invoked during a mouse move. As necessary starts a drag and drop session. |
| void StartDragIfNecessary(const CPoint& point); |
| |
| // Invoked during a mouse down. If the mouse location is over the selection |
| // this sets possible_drag_ to true to indicate a drag should start if the |
| // user moves the mouse far enough to start a drag. |
| void OnPossibleDrag(const CPoint& point); |
| |
| // Redraws the necessary region for a drop highlight at the specified |
| // position. This does nothing if position is beyond the bounds of the |
| // text. |
| void RepaintDropHighlight(int position); |
| |
| // Generates the context menu for the edit field. |
| void BuildContextMenu(); |
| |
| void SelectAllIfNecessary(MouseButton button, const CPoint& point); |
| void TrackMousePosition(MouseButton button, const CPoint& point); |
| |
| // Returns the sum of the left and right margins. |
| int GetHorizontalMargin() const; |
| |
| // Returns the width in pixels needed to display |text|. |
| int WidthNeededToDisplay(const string16& text) const; |
| |
| // Real implementation of OnAfterPossibleChange() method. |
| // If |force_text_changed| is true, then the text_changed code will always be |
| // 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 ui::DropTargetEvent& event, bool in_drag); |
| |
| // The handle to the RichEdit DLL. In the rare case where the user's system |
| // is missing this DLL (due to some kind of system corruption), the similar |
| // OmniboxViewViews is used instead; see Textfield::IsViewsTextfieldEnabled(). |
| static HMODULE loaded_library_module_; |
| |
| scoped_ptr<OmniboxPopupView> popup_view_; |
| |
| // The parent view for the edit, used to align the popup and for |
| // accessibility. |
| LocationBarView* location_bar_; |
| |
| // When true, the location bar view is read only and also is has a slightly |
| // different presentation (font size / color). This is used for popups. |
| bool popup_window_mode_; |
| |
| // True if we should prevent attempts to make the window visible when we |
| // handle WM_WINDOWPOSCHANGING. While toggling fullscreen mode, the main |
| // window is hidden, and if the edit is shown it will draw over the main |
| // window when that window reappears. |
| bool force_hidden_; |
| |
| // Non-null when the edit is gaining focus from a left click. This is only |
| // needed between when WM_MOUSEACTIVATE and WM_LBUTTONDOWN get processed. It |
| // serves two purposes: first, by communicating to OnLButtonDown() that we're |
| // gaining focus from a left click, it allows us to work even with the |
| // inconsistent order in which various Windows messages get sent (see comments |
| // in OnMouseActivate()). Second, by holding the edit frozen, it ensures that |
| // when we process WM_SETFOCUS the edit won't first redraw itself with the |
| // caret at the beginning, and then have it blink to where the mouse cursor |
| // really is shortly afterward. |
| scoped_ptr<ScopedFreeze> gaining_focus_; |
| |
| // When the user clicks to give us focus, we watch to see if they're clicking |
| // or dragging. When they're clicking, we select nothing until mouseup, then |
| // select all the text in the edit. During this process, tracking_click_[X] |
| // is true and click_point_[X] holds the original click location. |
| // At other times, tracking_click_[X] is false, and the contents of |
| // click_point_[X] should be ignored. The arrays hold the state for the |
| // left and right mouse buttons, and are indexed using the MouseButton enum. |
| bool tracking_click_[2]; |
| CPoint click_point_[2]; |
| |
| // We need to know if the user triple-clicks, so track double click points |
| // and times so we can see if subsequent clicks are actually triple clicks. |
| bool tracking_double_click_; |
| CPoint double_click_point_; |
| DWORD double_click_time_; |
| |
| // Used to discard unnecessary WM_MOUSEMOVE events after the first such |
| // unnecessary event. See detailed comments in OnMouseMove(). |
| bool can_discard_mousemove_; |
| |
| // Used to prevent IME message handling in the midst of updating the edit |
| // text. See comments where this is used. |
| bool ignore_ime_messages_; |
| |
| // Variables for tracking state before and after a possible change. |
| string16 text_before_change_; |
| CHARRANGE sel_before_change_; |
| |
| // Set at the same time the model's original_* members are set, and valid in |
| // the same cases. |
| CHARRANGE original_selection_; |
| |
| // Holds the user's selection across focus changes. cpMin holds -1 when |
| // there is no saved selection. |
| CHARRANGE saved_selection_for_focus_change_; |
| |
| // Was the delete key pressed with an empty selection at the end of the edit? |
| bool delete_at_end_pressed_; |
| |
| // The context menu for the edit. |
| scoped_ptr<ui::SimpleMenuModel> context_menu_contents_; |
| scoped_ptr<views::MenuRunner> context_menu_runner_; |
| |
| // The font list to draw text in Omnibox. |
| gfx::FontList font_list_; |
| |
| // Metrics about the font, which we keep so we don't need to recalculate them |
| // every time we paint. |font_y_adjustment_| is the number of pixels we need |
| // to shift the font vertically in order to make its baseline be at our |
| // desired baseline in the edit. |
| int font_x_height_; |
| int font_y_adjustment_; |
| |
| // If true, indicates the mouse is down and if the mouse is moved enough we |
| // should start a drag. |
| bool possible_drag_; |
| |
| // If true, we're in a call to DoDragDrop. |
| bool in_drag_; |
| |
| // If true indicates we've run a drag and drop session. This is used to |
| // avoid starting two drag and drop sessions if the drag is canceled while |
| // the mouse is still down. |
| bool initiated_drag_; |
| |
| // Position of the drop highlight. If this is -1, there is no drop highlight. |
| int drop_highlight_position_; |
| |
| // True if the IME candidate window is open. When this is true, we want to |
| // avoid showing the popup. |
| bool ime_candidate_window_open_; |
| |
| // Security UI-related data. |
| COLORREF background_color_; |
| ToolbarModel::SecurityLevel security_level_; |
| |
| // This interface is useful for accessing the CRichEditCtrl at a low level. |
| mutable ITextDocument* text_object_model_; |
| |
| // This contains the scheme char start and stop indexes that should be |
| // stricken-out when displaying an insecure scheme. |
| url_parse::Component insecure_scheme_component_; |
| |
| // Instance of accessibility information and handling. |
| mutable base::win::ScopedComPtr<IAccessible> autocomplete_accessibility_; |
| |
| // The native view host. |
| views::NativeViewHost* native_view_host_; |
| |
| // TSF related event router. |
| scoped_ptr<ui::TSFEventRouter> tsf_event_router_; |
| |
| DISALLOW_COPY_AND_ASSIGN(OmniboxViewWin); |
| }; |
| |
| #endif // CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_VIEW_WIN_H_ |