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