Home | History | Annotate | Download | only in textfield
      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.
      4 
      5 #ifndef UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WIN_H_
      6 #define UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WIN_H_
      7 
      8 #include <atlbase.h>
      9 #include <atlapp.h>
     10 #include <atlcrack.h>
     11 #include <atlctrls.h>
     12 #include <atlmisc.h>
     13 #include <oleacc.h>
     14 #include <tom.h>  // For ITextDocument, a COM interface to CRichEditCtrl
     15 #include <vsstyle.h>
     16 
     17 #include "base/memory/scoped_ptr.h"
     18 #include "base/strings/string16.h"
     19 #include "base/win/scoped_comptr.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/gfx/insets.h"
     24 #include "ui/views/controls/textfield/native_textfield_wrapper.h"
     25 
     26 namespace views {
     27 
     28 class MenuRunner;
     29 class NativeViewHost;
     30 class Textfield;
     31 
     32 static const int kDefaultEditStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
     33     WS_CLIPSIBLINGS;
     34 
     35 // TODO(beng): make a subclass of NativeControlWin instead.
     36 class NativeTextfieldWin
     37     : public CWindowImpl<NativeTextfieldWin, CRichEditCtrl,
     38                          CWinTraits<kDefaultEditStyle> >,
     39       public CRichEditCommands<NativeTextfieldWin>,
     40       public NativeTextfieldWrapper,
     41       public ui::SimpleMenuModel::Delegate,
     42       public ui::TSFEventRouterObserver {
     43  public:
     44   DECLARE_WND_SUPERCLASS(L"ViewsTextfieldEdit", MSFTEDIT_CLASS);
     45 
     46   explicit NativeTextfieldWin(Textfield* parent);
     47   ~NativeTextfieldWin();
     48 
     49   // Returns true if the current point is close enough to the origin point in
     50   // space and time that it would be considered a double click.
     51   VIEWS_EXPORT static bool IsDoubleClick(const POINT& origin,
     52                                          const POINT& current,
     53                                          DWORD elapsed_time);
     54 
     55   // See the code in textfield.cc that calls this for why this is here.
     56   void AttachHack();
     57 
     58   // NativeTextfieldWrapper:
     59   virtual string16 GetText() const OVERRIDE;
     60   virtual void UpdateText() OVERRIDE;
     61   virtual void AppendText(const string16& text) OVERRIDE;
     62   virtual void InsertOrReplaceText(const string16& text) OVERRIDE;
     63   virtual base::i18n::TextDirection GetTextDirection() const OVERRIDE;
     64   virtual string16 GetSelectedText() const OVERRIDE;
     65   virtual void SelectAll(bool reversed) OVERRIDE;
     66   virtual void ClearSelection() OVERRIDE;
     67   virtual void UpdateBorder() OVERRIDE;
     68   virtual void UpdateTextColor() OVERRIDE;
     69   virtual void UpdateBackgroundColor() OVERRIDE;
     70   virtual void UpdateReadOnly() OVERRIDE;
     71   virtual void UpdateFont() OVERRIDE;
     72   virtual void UpdateIsObscured() OVERRIDE;
     73   virtual void UpdateEnabled() OVERRIDE;
     74   virtual gfx::Insets CalculateInsets() OVERRIDE;
     75   virtual void UpdateHorizontalMargins() OVERRIDE;
     76   virtual void UpdateVerticalMargins() OVERRIDE;
     77   virtual void UpdateVerticalAlignment() OVERRIDE;
     78   virtual bool SetFocus() OVERRIDE;
     79   virtual View* GetView() OVERRIDE;
     80   virtual gfx::NativeView GetTestingHandle() const OVERRIDE;
     81   virtual bool IsIMEComposing() const OVERRIDE;
     82   virtual ui::Range GetSelectedRange() const OVERRIDE;
     83   virtual void SelectRange(const ui::Range& range) OVERRIDE;
     84   virtual gfx::SelectionModel GetSelectionModel() const OVERRIDE;
     85   virtual void SelectSelectionModel(const gfx::SelectionModel& sel) OVERRIDE;
     86   virtual size_t GetCursorPosition() const OVERRIDE;
     87   virtual bool GetCursorEnabled() const OVERRIDE;
     88   virtual void SetCursorEnabled(bool enabled) OVERRIDE;
     89   virtual bool HandleKeyPressed(const ui::KeyEvent& event) OVERRIDE;
     90   virtual bool HandleKeyReleased(const ui::KeyEvent& event) OVERRIDE;
     91   virtual void HandleFocus() OVERRIDE;
     92   virtual void HandleBlur() OVERRIDE;
     93   virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
     94   virtual void SetColor(SkColor value) OVERRIDE;
     95   virtual void ApplyColor(SkColor value, const ui::Range& range) OVERRIDE;
     96   virtual void SetStyle(gfx::TextStyle style, bool value) OVERRIDE;
     97   virtual void ApplyStyle(gfx::TextStyle style,
     98                           bool value,
     99                           const ui::Range& range) OVERRIDE;
    100   virtual void ClearEditHistory() OVERRIDE;
    101   virtual int GetFontHeight() OVERRIDE;
    102   virtual int GetTextfieldBaseline() const OVERRIDE;
    103   virtual int GetWidthNeededForText() const OVERRIDE;
    104   virtual void ExecuteTextCommand(int command_id) OVERRIDE;
    105   virtual bool HasTextBeingDragged() OVERRIDE;
    106 
    107   // ui::SimpleMenuModel::Delegate:
    108   virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
    109   virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
    110   virtual bool GetAcceleratorForCommandId(
    111       int command_id,
    112       ui::Accelerator* accelerator) OVERRIDE;
    113   virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
    114 
    115   // ui::TSFEventRouterObserver:
    116   virtual void OnTextUpdated(const ui::Range& composition_range) OVERRIDE;
    117   virtual void OnTSFStartComposition() OVERRIDE;
    118   virtual void OnTSFEndComposition() OVERRIDE;
    119 
    120   // Update accessibility information.
    121   void InitializeAccessibilityInfo();
    122   void UpdateAccessibleState(uint32 state_flag, bool set_value);
    123   void UpdateAccessibleValue(const string16& value);
    124 
    125   // CWindowImpl
    126   BEGIN_MSG_MAP(Edit)
    127     MSG_WM_CHAR(OnChar)
    128     MSG_WM_CONTEXTMENU(OnContextMenu)
    129     MSG_WM_COPY(OnCopy)
    130     MSG_WM_CREATE(OnCreate)
    131     MSG_WM_CUT(OnCut)
    132     MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
    133     MESSAGE_HANDLER_EX(WM_IME_CHAR, OnImeChar)
    134     MESSAGE_HANDLER_EX(WM_IME_STARTCOMPOSITION, OnImeStartComposition)
    135     MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition)
    136     MESSAGE_HANDLER_EX(WM_IME_ENDCOMPOSITION, OnImeEndComposition)
    137     MESSAGE_HANDLER_EX(WM_POINTERDOWN, OnPointerDown)
    138     MSG_WM_KEYDOWN(OnKeyDown)
    139     MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
    140     MSG_WM_LBUTTONDOWN(OnLButtonDown)
    141     MSG_WM_LBUTTONUP(OnLButtonUp)
    142     MSG_WM_MBUTTONDOWN(OnNonLButtonDown)
    143     MSG_WM_MOUSEMOVE(OnMouseMove)
    144     MSG_WM_MOUSELEAVE(OnMouseLeave)
    145     MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, OnMouseWheel)
    146     MSG_WM_NCCALCSIZE(OnNCCalcSize)
    147     MSG_WM_NCPAINT(OnNCPaint)
    148     MSG_WM_RBUTTONDOWN(OnNonLButtonDown)
    149     MSG_WM_PASTE(OnPaste)
    150     MSG_WM_SETFOCUS(OnSetFocus)
    151     MSG_WM_KILLFOCUS(OnKillFocus)
    152     MSG_WM_SYSCHAR(OnSysChar)  // WM_SYSxxx == WM_xxx with ALT down
    153     MSG_WM_SYSKEYDOWN(OnKeyDown)
    154   END_MSG_MAP()
    155 
    156  private:
    157   // This object freezes repainting of the edit until the object is destroyed.
    158   // Some methods of the CRichEditCtrl draw synchronously to the screen.  If we
    159   // don't freeze, the user will see a rapid series of calls to these as
    160   // flickers.
    161   //
    162   // Freezing the control while it is already frozen is permitted; the control
    163   // will unfreeze once both freezes are released (the freezes stack).
    164   class ScopedFreeze {
    165    public:
    166     ScopedFreeze(NativeTextfieldWin* edit, ITextDocument* text_object_model);
    167     ~ScopedFreeze();
    168 
    169    private:
    170     NativeTextfieldWin* const edit_;
    171     ITextDocument* const text_object_model_;
    172 
    173     DISALLOW_COPY_AND_ASSIGN(ScopedFreeze);
    174   };
    175 
    176   // This object suspends placing any operations on the edit's undo stack until
    177   // the object is destroyed.  If we don't do this, some of the operations we
    178   // perform behind the user's back will be undoable by the user, which feels
    179   // bizarre and confusing.
    180   class ScopedSuspendUndo {
    181    public:
    182     explicit ScopedSuspendUndo(ITextDocument* text_object_model);
    183     ~ScopedSuspendUndo();
    184 
    185    private:
    186     ITextDocument* const text_object_model_;
    187 
    188     DISALLOW_COPY_AND_ASSIGN(ScopedSuspendUndo);
    189   };
    190 
    191   // Message handlers.
    192   void OnChar(TCHAR key, UINT repeat_count, UINT flags);
    193   void OnContextMenu(HWND window, const POINT& point);
    194   void OnCopy();
    195   LRESULT OnCreate(const CREATESTRUCTW* create_struct);
    196   void OnCut();
    197   LRESULT OnGetObject(UINT message, WPARAM wparam, LPARAM lparam);
    198   LRESULT OnImeChar(UINT message, WPARAM wparam, LPARAM lparam);
    199   LRESULT OnImeStartComposition(UINT message, WPARAM wparam, LPARAM lparam);
    200   LRESULT OnImeComposition(UINT message, WPARAM wparam, LPARAM lparam);
    201   LRESULT OnImeEndComposition(UINT message, WPARAM wparam, LPARAM lparam);
    202   LRESULT OnPointerDown(UINT message, WPARAM wparam, LPARAM lparam);
    203   void OnKeyDown(TCHAR key, UINT repeat_count, UINT flags);
    204   void OnLButtonDblClk(UINT keys, const CPoint& point);
    205   void OnLButtonDown(UINT keys, const CPoint& point);
    206   void OnLButtonUp(UINT keys, const CPoint& point);
    207   void OnMouseLeave();
    208   LRESULT OnMouseWheel(UINT message, WPARAM w_param, LPARAM l_param);
    209   void OnMouseMove(UINT keys, const CPoint& point);
    210   int OnNCCalcSize(BOOL w_param, LPARAM l_param);
    211   void OnNCPaint(HRGN region);
    212   void OnNonLButtonDown(UINT keys, const CPoint& point);
    213   void OnPaste();
    214   void OnSetFocus(HWND hwnd);
    215   void OnKillFocus(HWND hwnd);
    216   void OnSysChar(TCHAR ch, UINT repeat_count, UINT flags);
    217 
    218   // CWindowImpl overrides:
    219   virtual void OnFinalMessage(HWND hwnd) OVERRIDE;
    220 
    221   // Helper function for OnChar() and OnKeyDown() that handles keystrokes that
    222   // could change the text in the edit.
    223   // Note: This function assumes GetCurrentMessage() returns a MSG with
    224   // msg > WM_KEYFIRST and < WM_KEYLAST.
    225   void HandleKeystroke();
    226 
    227   // Every piece of code that can change the edit should call these functions
    228   // before and after the change.  These functions determine if anything
    229   // meaningful changed, and do any necessary updating and notification.
    230   void OnBeforePossibleChange();
    231 
    232   // When a user types a BIDI mirroring character (e.g. left parenthesis
    233   // U+0028, which should be rendered as '(' in LTR context unless  surrounded
    234   // by RTL characters in both sides, and it should be rendered as ')' in RTL
    235   // context unless surrounded by LTR characters in both sides.), the textfield
    236   // does not properly mirror the character when necessary. However, if we
    237   // explicitly set the text in the edit to the entire current string, then
    238   // the BIDI mirroring characters will be mirrored properly. When
    239   // |should_redraw_text| is true, we explicitly set the text in the edit to
    240   // the entire current string any time the text changes.
    241   void OnAfterPossibleChange(bool should_redraw_text);
    242 
    243   // Given an X coordinate in client coordinates, returns that coordinate
    244   // clipped to be within the horizontal bounds of the visible text.
    245   //
    246   // This is used in our mouse handlers to work around quirky behaviors of the
    247   // underlying CRichEditCtrl like not supporting triple-click when the user
    248   // doesn't click on the text itself.
    249   //
    250   // |is_triple_click| should be true iff this is the third click of a triple
    251   // click.  Sadly, we need to clip slightly differently in this case.
    252   LONG ClipXCoordToVisibleText(LONG x, bool is_triple_click) const;
    253 
    254   // Sets whether the mouse is in the edit. As necessary this redraws the
    255   // edit.
    256   void SetContainsMouse(bool contains_mouse);
    257 
    258   // Handles composition related works on both IMM32 and TSF implementation.
    259   void OnImeStartCompositionInternal();
    260   void OnImeEndCompositionInternal();
    261 
    262   // Getter for the text_object_model_, used by the ScopedFreeze class.  Note
    263   // that the pointer returned here is only valid as long as the Edit is still
    264   // alive.
    265   ITextDocument* GetTextObjectModel() const;
    266 
    267   // Generates the contents of the context menu.
    268   void BuildContextMenu();
    269 
    270   // Returns true if normal processing of the current mouse press event should
    271   // occur.
    272   bool ShouldProcessMouseEvent();
    273 
    274   static HMODULE loaded_libarary_module_;
    275 
    276   // The Textfield this object is bound to.
    277   Textfield* textfield_;
    278 
    279   // We need to know if the user triple-clicks, so track double click points
    280   // and times so we can see if subsequent clicks are actually triple clicks.
    281   bool tracking_double_click_;
    282   CPoint double_click_point_;
    283   DWORD double_click_time_;
    284 
    285   // Used to discard unnecessary WM_MOUSEMOVE events after the first such
    286   // unnecessary event.  See detailed comments in OnMouseMove().
    287   bool can_discard_mousemove_;
    288 
    289   // The text of this control before a possible change.
    290   string16 text_before_change_;
    291 
    292   // If true, the mouse is over the edit.
    293   bool contains_mouse_;
    294 
    295   // The contents of the context menu for the edit.
    296   scoped_ptr<ui::SimpleMenuModel> context_menu_contents_;
    297   scoped_ptr<MenuRunner> context_menu_runner_;
    298 
    299   // Border insets.
    300   gfx::Insets content_insets_;
    301 
    302   // This interface is useful for accessing the CRichEditCtrl at a low level.
    303   mutable base::win::ScopedComPtr<ITextDocument> text_object_model_;
    304 
    305   // The position and the length of the ongoing composition string.
    306   // These values are used for removing a composition string from a search
    307   // text to emulate Firefox.
    308   bool ime_discard_composition_;
    309   int ime_composition_start_;
    310   int ime_composition_length_;
    311 
    312   // TODO(beng): remove this when we are a subclass of NativeControlWin.
    313   NativeViewHost* container_view_;
    314 
    315   COLORREF bg_color_;
    316 
    317   //  The accessibility state of this object.
    318   int accessibility_state_;
    319 
    320   scoped_ptr<ui::TSFEventRouter> tsf_event_router_;
    321 
    322   DISALLOW_COPY_AND_ASSIGN(NativeTextfieldWin);
    323 };
    324 
    325 }  // namespace views
    326 
    327 #endif  // UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WIN_H_
    328