autocomplete_edit_view_win.h revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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 CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_WIN_H_
6#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_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 <tom.h>  // For ITextDocument, a COM interface to CRichEditCtrl.
14
15#include "app/menus/simple_menu_model.h"
16#include "base/scoped_comptr_win.h"
17#include "base/scoped_ptr.h"
18#include "chrome/browser/autocomplete/autocomplete.h"
19#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
20#include "chrome/browser/toolbar_model.h"
21#include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h"
22#include "chrome/common/page_transition_types.h"
23#include "gfx/font.h"
24#include "webkit/glue/window_open_disposition.h"
25#include "views/controls/menu/menu_2.h"
26
27class AutocompletePopupModel;
28class Profile;
29class TabContents;
30namespace views {
31class View;
32}
33
34class AutocompleteEditController;
35class AutocompleteEditModel;
36class AutocompleteEditView;
37class AutocompletePopupView;
38
39// Provides the implementation of an edit control with a drop-down
40// autocomplete box. The box itself is implemented in autocomplete_popup.cc
41// This file implements the edit box and management for the popup.
42class AutocompleteEditViewWin
43    : public CWindowImpl<AutocompleteEditViewWin,
44                         CRichEditCtrl,
45                         CWinTraits<WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL |
46                                    ES_NOHIDESEL> >,
47      public CRichEditCommands<AutocompleteEditViewWin>,
48      public menus::SimpleMenuModel::Delegate,
49      public AutocompleteEditView {
50 public:
51  struct State {
52    State(const CHARRANGE& selection,
53          const CHARRANGE& saved_selection_for_focus_change)
54        : selection(selection),
55          saved_selection_for_focus_change(saved_selection_for_focus_change) {
56    }
57
58    const CHARRANGE selection;
59    const CHARRANGE saved_selection_for_focus_change;
60  };
61
62  DECLARE_WND_CLASS(L"Chrome_AutocompleteEditView");
63
64  AutocompleteEditViewWin(const gfx::Font& font,
65                          AutocompleteEditController* controller,
66                          ToolbarModel* toolbar_model,
67                          views::View* parent_view,
68                          HWND hwnd,
69                          Profile* profile,
70                          CommandUpdater* command_updater,
71                          bool popup_window_mode,
72                          const views::View* location_bar);
73  ~AutocompleteEditViewWin();
74
75  views::View* parent_view() const { return parent_view_; }
76
77  // Implement the AutocompleteEditView interface.
78  virtual AutocompleteEditModel* model() { return model_.get(); }
79  virtual const AutocompleteEditModel* model() const { return model_.get(); }
80
81  virtual void SaveStateToTab(TabContents* tab);
82
83  virtual void Update(const TabContents* tab_for_state_restoring);
84
85  virtual void OpenURL(const GURL& url,
86                       WindowOpenDisposition disposition,
87                       PageTransition::Type transition,
88                       const GURL& alternate_nav_url,
89                       size_t selected_line,
90                       const std::wstring& keyword);
91
92  virtual std::wstring GetText() const;
93
94  virtual bool IsEditingOrEmpty() const;
95  virtual int GetIcon() const;
96
97  virtual void SetUserText(const std::wstring& text) {
98    SetUserText(text, text, true);
99  }
100  virtual void SetUserText(const std::wstring& text,
101                           const std::wstring& display_text,
102                           bool update_popup);
103
104  virtual void SetWindowTextAndCaretPos(const std::wstring& text,
105                                        size_t caret_pos);
106
107  virtual void SetForcedQuery();
108
109  virtual bool IsSelectAll();
110  virtual void SelectAll(bool reversed);
111  virtual void RevertAll();
112
113  virtual void UpdatePopup();
114  virtual void ClosePopup();
115
116  virtual void SetFocus();
117
118  virtual void OnTemporaryTextMaybeChanged(const std::wstring& display_text,
119                                           bool save_original_selection);
120  virtual bool OnInlineAutocompleteTextMaybeChanged(
121      const std::wstring& display_text, size_t user_text_length);
122  virtual void OnRevertTemporaryText();
123  virtual void OnBeforePossibleChange();
124  virtual bool OnAfterPossibleChange();
125  virtual gfx::NativeView GetNativeView() const;
126  virtual CommandUpdater* GetCommandUpdater();
127
128  // Exposes custom IAccessible implementation to the overall MSAA hierarchy.
129  IAccessible* GetIAccessible();
130
131  void SetDropHighlightPosition(int position);
132  int drop_highlight_position() const { return drop_highlight_position_; }
133
134  // Returns true if a drag a drop session was initiated by this edit.
135  bool in_drag() const { return in_drag_; }
136
137  // Moves the selected text to the specified position.
138  void MoveSelectedText(int new_position);
139
140  // Inserts the text at the specified position.
141  void InsertText(int position, const std::wstring& text);
142
143  // Invokes CanPasteAndGo with the specified text, and if successful navigates
144  // to the appropriate URL. The behavior of this is the same as if the user
145  // typed in the specified text and pressed enter.
146  void PasteAndGo(const std::wstring& text);
147
148  void set_force_hidden(bool force_hidden) { force_hidden_ = force_hidden; }
149
150  // Called before an accelerator is processed to give us a chance to override
151  // it.
152  bool SkipDefaultKeyEventProcessing(const views::KeyEvent& e);
153
154  // Handler for external events passed in to us.  The View that owns us may
155  // send us events that we should treat as if they were events on us.
156  void HandleExternalMsg(UINT msg, UINT flags, const CPoint& screen_point);
157
158  // CWindowImpl
159  BEGIN_MSG_MAP(AutocompleteEdit)
160    MSG_WM_CHAR(OnChar)
161    MSG_WM_CONTEXTMENU(OnContextMenu)
162    MSG_WM_COPY(OnCopy)
163    MSG_WM_CUT(OnCut)
164    MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
165    MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition)
166    MESSAGE_HANDLER_EX(WM_IME_NOTIFY, OnImeNotify)
167    MSG_WM_KEYDOWN(OnKeyDown)
168    MSG_WM_KEYUP(OnKeyUp)
169    MSG_WM_KILLFOCUS(OnKillFocus)
170    MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
171    MSG_WM_LBUTTONDOWN(OnLButtonDown)
172    MSG_WM_LBUTTONUP(OnLButtonUp)
173    MSG_WM_MBUTTONDBLCLK(OnMButtonDblClk)
174    MSG_WM_MBUTTONDOWN(OnMButtonDown)
175    MSG_WM_MBUTTONUP(OnMButtonUp)
176    MSG_WM_MOUSEACTIVATE(OnMouseActivate)
177    MSG_WM_MOUSEMOVE(OnMouseMove)
178    MSG_WM_MOUSEWHEEL(OnMouseWheel)
179    MSG_WM_PAINT(OnPaint)
180    MSG_WM_PASTE(OnPaste)
181    MSG_WM_RBUTTONDBLCLK(OnRButtonDblClk)
182    MSG_WM_RBUTTONDOWN(OnRButtonDown)
183    MSG_WM_RBUTTONUP(OnRButtonUp)
184    MSG_WM_SETFOCUS(OnSetFocus)
185    MSG_WM_SETTEXT(OnSetText)
186    MSG_WM_SYSCHAR(OnSysChar)  // WM_SYSxxx == WM_xxx with ALT down
187    MSG_WM_SYSKEYDOWN(OnKeyDown)
188    MSG_WM_SYSKEYUP(OnKeyUp)
189    MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging)
190    DEFAULT_REFLECTION_HANDLER()  // avoids black margin area
191  END_MSG_MAP()
192
193  // menus::SimpleMenuModel::Delegate
194  virtual bool IsCommandIdChecked(int command_id) const;
195  virtual bool IsCommandIdEnabled(int command_id) const;
196  virtual bool GetAcceleratorForCommandId(int command_id,
197                                          menus::Accelerator* accelerator);
198  virtual bool IsLabelForCommandIdDynamic(int command_id) const;
199  virtual std::wstring GetLabelForCommandId(int command_id) const;
200  virtual void ExecuteCommand(int command_id);
201
202 private:
203  enum MouseButton {
204    kLeft  = 0,
205    kRight = 1,
206  };
207
208  // This object freezes repainting of the edit until the object is destroyed.
209  // Some methods of the CRichEditCtrl draw synchronously to the screen.  If we
210  // don't freeze, the user will see a rapid series of calls to these as
211  // flickers.
212  //
213  // Freezing the control while it is already frozen is permitted; the control
214  // will unfreeze once both freezes are released (the freezes stack).
215  class ScopedFreeze {
216   public:
217    ScopedFreeze(AutocompleteEditViewWin* edit,
218                 ITextDocument* text_object_model);
219    ~ScopedFreeze();
220
221   private:
222    AutocompleteEditViewWin* const edit_;
223    ITextDocument* const text_object_model_;
224
225    DISALLOW_COPY_AND_ASSIGN(ScopedFreeze);
226  };
227
228  // This object suspends placing any operations on the edit's undo stack until
229  // the object is destroyed.  If we don't do this, some of the operations we
230  // perform behind the user's back will be undoable by the user, which feels
231  // bizarre and confusing.
232  class ScopedSuspendUndo {
233   public:
234    explicit ScopedSuspendUndo(ITextDocument* text_object_model);
235    ~ScopedSuspendUndo();
236
237   private:
238    ITextDocument* const text_object_model_;
239
240    DISALLOW_COPY_AND_ASSIGN(ScopedSuspendUndo);
241  };
242
243  // Replacement word-breaking proc for the rich edit control.
244  static int CALLBACK WordBreakProc(LPTSTR edit_text,
245                                    int current_pos,
246                                    int num_bytes,
247                                    int action);
248
249  // Returns true if |edit_text| starting at |current_pos| is "://".
250  static bool SchemeEnd(LPTSTR edit_text, int current_pos, int length);
251
252  // Message handlers
253  void OnChar(TCHAR ch, UINT repeat_count, UINT flags);
254  void OnContextMenu(HWND window, const CPoint& point);
255  void OnCopy();
256  void OnCut();
257  LRESULT OnGetObject(UINT uMsg, WPARAM wparam, LPARAM lparam);
258  LRESULT OnImeComposition(UINT message, WPARAM wparam, LPARAM lparam);
259  LRESULT OnImeNotify(UINT message, WPARAM wparam, LPARAM lparam);
260  void OnKeyDown(TCHAR key, UINT repeat_count, UINT flags);
261  void OnKeyUp(TCHAR key, UINT repeat_count, UINT flags);
262  void OnKillFocus(HWND focus_wnd);
263  void OnLButtonDblClk(UINT keys, const CPoint& point);
264  void OnLButtonDown(UINT keys, const CPoint& point);
265  void OnLButtonUp(UINT keys, const CPoint& point);
266  void OnMButtonDblClk(UINT keys, const CPoint& point);
267  void OnMButtonDown(UINT keys, const CPoint& point);
268  void OnMButtonUp(UINT keys, const CPoint& point);
269  LRESULT OnMouseActivate(HWND window, UINT hit_test, UINT mouse_message);
270  void OnMouseMove(UINT keys, const CPoint& point);
271  BOOL OnMouseWheel(UINT flags, short delta, CPoint point);
272  void OnPaint(HDC bogus_hdc);
273  void OnPaste();
274  void OnRButtonDblClk(UINT keys, const CPoint& point);
275  void OnRButtonDown(UINT keys, const CPoint& point);
276  void OnRButtonUp(UINT keys, const CPoint& point);
277  void OnSetFocus(HWND focus_wnd);
278  LRESULT OnSetText(const wchar_t* text);
279  void OnSysChar(TCHAR ch, UINT repeat_count, UINT flags);
280  void OnWindowPosChanging(WINDOWPOS* window_pos);
281
282  // Helper function for OnChar() and OnKeyDown() that handles keystrokes that
283  // could change the text in the edit.
284  void HandleKeystroke(UINT message, TCHAR key, UINT repeat_count, UINT flags);
285
286  // Helper functions for OnKeyDown() that handle accelerators applicable when
287  // we're not read-only and all the time, respectively.  These return true if
288  // they handled the key.
289  bool OnKeyDownOnlyWritable(TCHAR key, UINT repeat_count, UINT flags);
290  bool OnKeyDownAllModes(TCHAR key, UINT repeat_count, UINT flags);
291
292  // Like GetSel(), but returns a range where |cpMin| will be larger than
293  // |cpMax| if the cursor is at the start rather than the end of the selection
294  // (in other words, tracks selection direction as well as offsets).
295  // Note the non-Google-style "non-const-ref" argument, which matches GetSel().
296  void GetSelection(CHARRANGE& sel) const;
297
298  // Returns the currently selected text of the edit control.
299  std::wstring GetSelectedText() const;
300
301  // Like SetSel(), but respects the selection direction implied by |start| and
302  // |end|: if |end| < |start|, the effective cursor will be placed at the
303  // beginning of the selection.
304  void SetSelection(LONG start, LONG end);
305
306  // Like SetSelection(), but takes a CHARRANGE.
307  void SetSelectionRange(const CHARRANGE& sel) {
308    SetSelection(sel.cpMin, sel.cpMax);
309  }
310
311  // Places the caret at the given position.  This clears any selection.
312  void PlaceCaretAt(size_t pos);
313
314  // Returns true if |sel| represents a forward or backward selection of all the
315  // text.
316  bool IsSelectAllForRange(const CHARRANGE& sel) const;
317
318  // Given an X coordinate in client coordinates, returns that coordinate
319  // clipped to be within the horizontal bounds of the visible text.
320  //
321  // This is used in our mouse handlers to work around quirky behaviors of the
322  // underlying CRichEditCtrl like not supporting triple-click when the user
323  // doesn't click on the text itself.
324  //
325  // |is_triple_click| should be true iff this is the third click of a triple
326  // click.  Sadly, we need to clip slightly differently in this case.
327  LONG ClipXCoordToVisibleText(LONG x, bool is_triple_click) const;
328
329  // Parses the contents of the control for the scheme and the host name.
330  // Highlights the scheme in green or red depending on it security level.
331  // If a host name is found, it makes it visually stronger.
332  void EmphasizeURLComponents();
333
334  // Erases the portion of the selection in the font's y-adjustment area.  For
335  // some reason the edit draws the selection rect here even though it's not
336  // part of the font.
337  void EraseTopOfSelection(CDC* dc,
338                           const CRect& client_rect,
339                           const CRect& paint_clip_rect);
340
341  // Draws a slash across the scheme if desired.
342  void DrawSlashForInsecureScheme(HDC hdc,
343                                  const CRect& client_rect,
344                                  const CRect& paint_clip_rect);
345
346  // Renders the drop highlight.
347  void DrawDropHighlight(HDC hdc,
348                         const CRect& client_rect,
349                         const CRect& paint_clip_rect);
350
351  // Internally invoked whenever the text changes in some way.
352  void TextChanged();
353
354  // Returns the current clipboard contents as a string that can be pasted in.
355  // In addition to just getting CF_UNICODETEXT out, this can also extract URLs
356  // from bookmarks on the clipboard.
357  std::wstring GetClipboardText() const;
358
359  // Determines whether the user can "paste and go", given the specified text.
360  bool CanPasteAndGo(const std::wstring& text) const;
361
362  // Getter for the text_object_model_.  Note that the pointer returned here is
363  // only valid as long as the AutocompleteEdit is still alive.  Also, if the
364  // underlying call fails, this may return NULL.
365  ITextDocument* GetTextObjectModel() const;
366
367  // Invoked during a mouse move. As necessary starts a drag and drop session.
368  void StartDragIfNecessary(const CPoint& point);
369
370  // Invoked during a mouse down. If the mouse location is over the selection
371  // this sets possible_drag_ to true to indicate a drag should start if the
372  // user moves the mouse far enough to start a drag.
373  void OnPossibleDrag(const CPoint& point);
374
375  // Redraws the necessary region for a drop highlight at the specified
376  // position. This does nothing if position is beyond the bounds of the
377  // text.
378  void RepaintDropHighlight(int position);
379
380  // Generates the context menu for the edit field.
381  void BuildContextMenu();
382
383  void SelectAllIfNecessary(MouseButton button, const CPoint& point);
384  void TrackMousePosition(MouseButton button, const CPoint& point);
385
386  scoped_ptr<AutocompleteEditModel> model_;
387
388  scoped_ptr<AutocompletePopupView> popup_view_;
389
390  AutocompleteEditController* controller_;
391
392  // The parent view for the edit, used to align the popup and for
393  // accessibility.
394  views::View* parent_view_;
395
396  ToolbarModel* toolbar_model_;
397
398  // The object that handles additional command functionality exposed on the
399  // edit, such as invoking the keyword editor.
400  CommandUpdater* command_updater_;
401
402  // When true, the location bar view is read only and also is has a slightly
403  // different presentation (font size / color). This is used for popups.
404  bool popup_window_mode_;
405
406  // True if we should prevent attempts to make the window visible when we
407  // handle WM_WINDOWPOSCHANGING.  While toggling fullscreen mode, the main
408  // window is hidden, and if the edit is shown it will draw over the main
409  // window when that window reappears.
410  bool force_hidden_;
411
412  // Non-null when the edit is gaining focus from a left click.  This is only
413  // needed between when WM_MOUSEACTIVATE and WM_LBUTTONDOWN get processed.  It
414  // serves two purposes: first, by communicating to OnLButtonDown() that we're
415  // gaining focus from a left click, it allows us to work even with the
416  // inconsistent order in which various Windows messages get sent (see comments
417  // in OnMouseActivate()).  Second, by holding the edit frozen, it ensures that
418  // when we process WM_SETFOCUS the edit won't first redraw itself with the
419  // caret at the beginning, and then have it blink to where the mouse cursor
420  // really is shortly afterward.
421  scoped_ptr<ScopedFreeze> gaining_focus_;
422
423  // When the user clicks to give us focus, we watch to see if they're clicking
424  // or dragging.  When they're clicking, we select nothing until mouseup, then
425  // select all the text in the edit.  During this process, tracking_click_[X]
426  // is true and click_point_[X] holds the original click location.
427  // At other times, tracking_click_[X] is false, and the contents of
428  // click_point_[X] should be ignored. The arrays hold the state for the
429  // left and right mouse buttons, and are indexed using the MouseButton enum.
430  bool tracking_click_[2];
431  CPoint click_point_[2];
432
433  // We need to know if the user triple-clicks, so track double click points
434  // and times so we can see if subsequent clicks are actually triple clicks.
435  bool tracking_double_click_;
436  CPoint double_click_point_;
437  DWORD double_click_time_;
438
439  // Used to discard unnecessary WM_MOUSEMOVE events after the first such
440  // unnecessary event.  See detailed comments in OnMouseMove().
441  bool can_discard_mousemove_;
442
443  // Used to prevent IME message handling in the midst of updating the edit
444  // text.  See comments where this is used.
445  bool ignore_ime_messages_;
446
447  // Variables for tracking state before and after a possible change.
448  std::wstring text_before_change_;
449  CHARRANGE sel_before_change_;
450
451  // Set at the same time the model's original_* members are set, and valid in
452  // the same cases.
453  CHARRANGE original_selection_;
454
455  // Holds the user's selection across focus changes.  cpMin holds -1 when
456  // there is no saved selection.
457  CHARRANGE saved_selection_for_focus_change_;
458
459  // The context menu for the edit.
460  scoped_ptr<menus::SimpleMenuModel> context_menu_contents_;
461  scoped_ptr<views::Menu2> context_menu_;
462
463  // Font we're using.  We keep a reference to make sure the font supplied to
464  // the constructor doesn't go away before we do.
465  gfx::Font font_;
466
467  // Metrics about the font, which we keep so we don't need to recalculate them
468  // every time we paint.  |font_y_adjustment_| is the number of pixels we need
469  // to shift the font vertically in order to make its baseline be at our
470  // desired baseline in the edit.
471  int font_x_height_;
472  int font_y_adjustment_;
473
474  // If true, indicates the mouse is down and if the mouse is moved enough we
475  // should start a drag.
476  bool possible_drag_;
477
478  // If true, we're in a call to DoDragDrop.
479  bool in_drag_;
480
481  // If true indicates we've run a drag and drop session. This is used to
482  // avoid starting two drag and drop sessions if the drag is canceled while
483  // the mouse is still down.
484  bool initiated_drag_;
485
486  // Position of the drop highlight.  If this is -1, there is no drop highlight.
487  int drop_highlight_position_;
488
489  // Security UI-related data.
490  COLORREF background_color_;
491  ToolbarModel::SecurityLevel security_level_;
492
493  // This interface is useful for accessing the CRichEditCtrl at a low level.
494  mutable ITextDocument* text_object_model_;
495
496  // This contains the scheme char start and stop indexes that should be
497  // striken-out when displaying an insecure scheme.
498  url_parse::Component insecure_scheme_component_;
499
500  // Instance of accessibility information and handling.
501  mutable ScopedComPtr<IAccessible> autocomplete_accessibility_;
502
503  DISALLOW_COPY_AND_ASSIGN(AutocompleteEditViewWin);
504};
505
506#endif  // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_WIN_H_
507