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