• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
28 class Profile;
29 class TabContents;
30 namespace views {
31 class View;
32 }
33 
34 class AutocompleteEditController;
35 class AutocompleteEditModel;
36 class AutocompleteEditView;
37 class AutocompletePopupView;
38 class 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.
43 class 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 {
StateState53     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.
model()87   virtual AutocompleteEditModel* model() { return model_.get(); }
model()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);
drop_highlight_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.
in_drag()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 
set_force_hidden(bool force_hidden)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.
SetSelectionRange(const CHARRANGE & sel)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