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