| // Copyright (c) 2010 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_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_WIN_H_ |
| #define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_WIN_H_ |
| #pragma once |
| |
| #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 "app/menus/simple_menu_model.h" |
| #include "base/scoped_comptr_win.h" |
| #include "base/scoped_ptr.h" |
| #include "chrome/browser/autocomplete/autocomplete.h" |
| #include "chrome/browser/autocomplete/autocomplete_edit_view.h" |
| #include "chrome/browser/toolbar_model.h" |
| #include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h" |
| #include "chrome/common/page_transition_types.h" |
| #include "gfx/font.h" |
| #include "views/controls/menu/menu_2.h" |
| #include "webkit/glue/window_open_disposition.h" |
| |
| class Profile; |
| class TabContents; |
| namespace views { |
| class View; |
| } |
| |
| class AutocompleteEditController; |
| class AutocompleteEditModel; |
| class AutocompleteEditView; |
| class AutocompletePopupView; |
| |
| // 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 AutocompleteEditViewWin |
| : public CWindowImpl<AutocompleteEditViewWin, |
| CRichEditCtrl, |
| CWinTraits<WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | |
| ES_NOHIDESEL> >, |
| public CRichEditCommands<AutocompleteEditViewWin>, |
| public menus::SimpleMenuModel::Delegate, |
| public AutocompleteEditView { |
| 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_CLASS(L"Chrome_AutocompleteEditView"); |
| |
| AutocompleteEditViewWin(const gfx::Font& font, |
| AutocompleteEditController* controller, |
| ToolbarModel* toolbar_model, |
| views::View* parent_view, |
| HWND hwnd, |
| Profile* profile, |
| CommandUpdater* command_updater, |
| bool popup_window_mode, |
| const views::View* location_bar); |
| ~AutocompleteEditViewWin(); |
| |
| views::View* parent_view() const { return parent_view_; } |
| |
| // Returns the width in pixels needed to display the current text. The |
| // returned value includes margins. |
| int TextWidth(); |
| |
| // Returns the width in pixels needed to display the text from one character |
| // before the caret to the end of the string. See comments in |
| // LocationBarView::Layout as to why this uses -1. |
| int WidthOfTextAfterCursor(); |
| |
| // Returns the font. |
| gfx::Font GetFont(); |
| |
| // Implement the AutocompleteEditView interface. |
| virtual AutocompleteEditModel* model() { return model_.get(); } |
| virtual const AutocompleteEditModel* model() const { return model_.get(); } |
| |
| virtual void SaveStateToTab(TabContents* tab); |
| |
| virtual void Update(const TabContents* tab_for_state_restoring); |
| |
| virtual void OpenURL(const GURL& url, |
| WindowOpenDisposition disposition, |
| PageTransition::Type transition, |
| const GURL& alternate_nav_url, |
| size_t selected_line, |
| const std::wstring& keyword); |
| |
| virtual std::wstring GetText() const; |
| |
| virtual bool IsEditingOrEmpty() const; |
| virtual int GetIcon() const; |
| |
| virtual void SetUserText(const std::wstring& text); |
| virtual void SetUserText(const std::wstring& text, |
| const std::wstring& display_text, |
| bool update_popup); |
| |
| virtual void SetWindowTextAndCaretPos(const std::wstring& text, |
| size_t caret_pos); |
| |
| virtual void SetForcedQuery(); |
| |
| virtual bool IsSelectAll(); |
| virtual bool DeleteAtEndPressed(); |
| virtual void GetSelectionBounds(std::wstring::size_type* start, |
| std::wstring::size_type* end); |
| virtual void SelectAll(bool reversed); |
| virtual void RevertAll(); |
| |
| virtual void UpdatePopup(); |
| virtual void ClosePopup(); |
| |
| virtual void SetFocus(); |
| |
| virtual void OnTemporaryTextMaybeChanged(const std::wstring& display_text, |
| bool save_original_selection); |
| virtual bool OnInlineAutocompleteTextMaybeChanged( |
| const std::wstring& display_text, size_t user_text_length); |
| virtual void OnRevertTemporaryText(); |
| virtual void OnBeforePossibleChange(); |
| virtual bool OnAfterPossibleChange(); |
| virtual gfx::NativeView GetNativeView() const; |
| virtual CommandUpdater* GetCommandUpdater(); |
| int GetPopupMaxYCoordinate(); |
| |
| // Exposes custom IAccessible implementation to the overall MSAA hierarchy. |
| IAccessible* GetIAccessible(); |
| |
| 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 std::wstring& text); |
| |
| // Invokes CanPasteAndGo with the specified text, and if successful navigates |
| // to the appropriate URL. The behavior of this is the same as if the user |
| // typed in the specified text and pressed enter. |
| void PasteAndGo(const std::wstring& 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 views::KeyEvent& e); |
| |
| // 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(AutocompleteEdit) |
| MSG_WM_CHAR(OnChar) |
| MSG_WM_CONTEXTMENU(OnContextMenu) |
| MSG_WM_COPY(OnCopy) |
| MSG_WM_CUT(OnCut) |
| MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject) |
| MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition) |
| MESSAGE_HANDLER_EX(WM_IME_NOTIFY, OnImeNotify) |
| 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() |
| |
| // menus::SimpleMenuModel::Delegate |
| virtual bool IsCommandIdChecked(int command_id) const; |
| virtual bool IsCommandIdEnabled(int command_id) const; |
| virtual bool GetAcceleratorForCommandId(int command_id, |
| menus::Accelerator* accelerator); |
| virtual bool IsLabelForCommandIdDynamic(int command_id) const; |
| virtual std::wstring GetLabelForCommandId(int command_id) const; |
| virtual void ExecuteCommand(int command_id); |
| |
| 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(AutocompleteEditViewWin* edit, |
| ITextDocument* text_object_model); |
| ~ScopedFreeze(); |
| |
| private: |
| AutocompleteEditViewWin* const edit_; |
| ITextDocument* const text_object_model_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedFreeze); |
| }; |
| |
| // 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 num_bytes, |
| 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(); |
| void OnCut(); |
| LRESULT OnGetObject(UINT uMsg, WPARAM wparam, LPARAM lparam); |
| LRESULT OnImeComposition(UINT message, WPARAM wparam, LPARAM lparam); |
| LRESULT OnImeNotify(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. |
| std::wstring 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; |
| |
| // 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. |
| void EmphasizeURLComponents(); |
| |
| // 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(); |
| |
| // Returns the current clipboard contents as a string that can be pasted in. |
| // In addition to just getting CF_UNICODETEXT out, this can also extract URLs |
| // from bookmarks on the clipboard. |
| std::wstring GetClipboardText() const; |
| |
| // Determines whether the user can "paste and go", given the specified text. |
| bool CanPasteAndGo(const std::wstring& text) const; |
| |
| // 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(); |
| |
| // Returns the width in pixels needed to display |text|. |
| int WidthNeededToDisplay(const std::wstring& text); |
| |
| scoped_ptr<AutocompleteEditModel> model_; |
| |
| scoped_ptr<AutocompletePopupView> popup_view_; |
| |
| AutocompleteEditController* controller_; |
| |
| // The parent view for the edit, used to align the popup and for |
| // accessibility. |
| views::View* parent_view_; |
| |
| ToolbarModel* toolbar_model_; |
| |
| // The object that handles additional command functionality exposed on the |
| // edit, such as invoking the keyword editor. |
| CommandUpdater* command_updater_; |
| |
| // 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. |
| std::wstring 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<menus::SimpleMenuModel> context_menu_contents_; |
| scoped_ptr<views::Menu2> context_menu_; |
| |
| // Font we're using. We keep a reference to make sure the font supplied to |
| // the constructor doesn't go away before we do. |
| gfx::Font font_; |
| |
| // 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_; |
| |
| // 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 |
| // striken-out when displaying an insecure scheme. |
| url_parse::Component insecure_scheme_component_; |
| |
| // Instance of accessibility information and handling. |
| mutable ScopedComPtr<IAccessible> autocomplete_accessibility_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AutocompleteEditViewWin); |
| }; |
| |
| #endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_WIN_H_ |