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 { 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