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