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