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