autocomplete_edit_view_gtk.h revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
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_GTK_H_ 6#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_GTK_H_ 7#pragma once 8 9#include <gtk/gtk.h> 10 11#include <algorithm> 12#include <string> 13 14#include "app/animation_delegate.h" 15#include "app/gtk_signal.h" 16#include "app/gtk_signal_registrar.h" 17#include "base/basictypes.h" 18#include "base/scoped_ptr.h" 19#include "base/string_util.h" 20#include "chrome/browser/autocomplete/autocomplete_edit_view.h" 21#include "chrome/browser/gtk/owned_widget_gtk.h" 22#include "chrome/browser/ui/toolbar/toolbar_model.h" 23#include "chrome/common/notification_observer.h" 24#include "chrome/common/notification_registrar.h" 25#include "chrome/common/page_transition_types.h" 26#include "gfx/rect.h" 27#include "webkit/glue/window_open_disposition.h" 28 29class AutocompleteEditController; 30class AutocompleteEditModel; 31class AutocompletePopupView; 32class MultiAnimation; 33class Profile; 34class TabContents; 35 36namespace gfx{ 37class Font; 38} 39 40namespace views { 41class View; 42} 43 44#if !defined(TOOLKIT_VIEWS) 45class GtkThemeProvider; 46#endif 47 48class AutocompleteEditViewGtk : public AutocompleteEditView, 49 public NotificationObserver, 50 public AnimationDelegate { 51 public: 52 // Modeled like the Windows CHARRANGE. Represent a pair of cursor position 53 // offsets. Since GtkTextIters are invalid after the buffer is changed, we 54 // work in character offsets (not bytes). 55 struct CharRange { 56 CharRange() : cp_min(0), cp_max(0) { } 57 CharRange(int n, int x) : cp_min(n), cp_max(x) { } 58 59 // Returns the start/end of the selection. 60 int selection_min() const { return std::min(cp_min, cp_max); } 61 int selection_max() const { return std::max(cp_min, cp_max); } 62 63 // Work in integers to match the gint GTK APIs. 64 int cp_min; // For a selection: Represents the start. 65 int cp_max; // For a selection: Represents the end (insert position). 66 }; 67 68 AutocompleteEditViewGtk(AutocompleteEditController* controller, 69 ToolbarModel* toolbar_model, 70 Profile* profile, 71 CommandUpdater* command_updater, 72 bool popup_window_mode, 73#if defined(TOOLKIT_VIEWS) 74 const views::View* location_bar); 75#else 76 GtkWidget* location_bar); 77#endif 78 ~AutocompleteEditViewGtk(); 79 80 // Initialize, create the underlying widgets, etc. 81 void Init(); 82 83 // Returns the width in pixels needed to display the current text. The 84 // returned value includes margins. 85 int TextWidth(); 86 87 // Returns the width in pixels needed to display the text from one character 88 // before the caret to the end of the string. See comments in 89 // LocationBarView::Layout as to why this uses -1. 90 int WidthOfTextAfterCursor(); 91 92 // Returns the font. 93 gfx::Font GetFont(); 94 95 // Implement the AutocompleteEditView interface. 96 virtual AutocompleteEditModel* model(); 97 virtual const AutocompleteEditModel* model() const; 98 99 virtual void SaveStateToTab(TabContents* tab); 100 101 virtual void Update(const TabContents* tab_for_state_restoring); 102 103 virtual void OpenURL(const GURL& url, 104 WindowOpenDisposition disposition, 105 PageTransition::Type transition, 106 const GURL& alternate_nav_url, 107 size_t selected_line, 108 const std::wstring& keyword); 109 110 virtual std::wstring GetText() const; 111 112 virtual bool IsEditingOrEmpty() const; 113 virtual int GetIcon() const; 114 115 virtual void SetUserText(const std::wstring& text); 116 virtual void SetUserText(const std::wstring& text, 117 const std::wstring& display_text, 118 bool update_popup); 119 120 virtual void SetWindowTextAndCaretPos(const std::wstring& text, 121 size_t caret_pos); 122 123 virtual void SetForcedQuery(); 124 125 virtual bool IsSelectAll(); 126 virtual bool DeleteAtEndPressed(); 127 virtual void GetSelectionBounds(std::wstring::size_type* start, 128 std::wstring::size_type* end); 129 virtual void SelectAll(bool reversed); 130 virtual void RevertAll(); 131 132 virtual void UpdatePopup(); 133 virtual void ClosePopup(); 134 135 virtual void SetFocus(); 136 137 virtual void OnTemporaryTextMaybeChanged(const std::wstring& display_text, 138 bool save_original_selection); 139 virtual bool OnInlineAutocompleteTextMaybeChanged( 140 const std::wstring& display_text, size_t user_text_length); 141 virtual void OnRevertTemporaryText(); 142 virtual void OnBeforePossibleChange(); 143 virtual bool OnAfterPossibleChange(); 144 virtual gfx::NativeView GetNativeView() const; 145 virtual CommandUpdater* GetCommandUpdater(); 146 147 // Overridden from NotificationObserver: 148 virtual void Observe(NotificationType type, 149 const NotificationSource& source, 150 const NotificationDetails& details); 151 152 // Overridden from AnimationDelegate. 153 virtual void AnimationEnded(const Animation* animation); 154 virtual void AnimationProgressed(const Animation* animation); 155 virtual void AnimationCanceled(const Animation* animation); 156 157 // Sets the colors of the text view according to the theme. 158 void SetBaseColor(); 159 // Sets the colors of the instant suggestion view according to the theme and 160 // the animation state. 161 void UpdateInstantViewColors(); 162 163 void SetInstantSuggestion(const std::string& suggestion); 164 bool CommitInstantSuggestion(); 165 166 // Used by LocationBarViewGtk to inform AutocompleteEditViewGtk if the tab to 167 // search should be enabled or not. See the comment of |enable_tab_to_search_| 168 // for details. 169 void set_enable_tab_to_search(bool enable) { 170 enable_tab_to_search_ = enable; 171 } 172 173 GtkWidget* text_view() { 174 return text_view_; 175 } 176 177 private: 178 CHROMEG_CALLBACK_0(AutocompleteEditViewGtk, void, HandleBeginUserAction, 179 GtkTextBuffer*); 180 CHROMEG_CALLBACK_0(AutocompleteEditViewGtk, void, HandleEndUserAction, 181 GtkTextBuffer*); 182 CHROMEG_CALLBACK_2(AutocompleteEditViewGtk, void, HandleMarkSet, 183 GtkTextBuffer*, GtkTextIter*, GtkTextMark*); 184 // As above, but called after the default handler. 185 CHROMEG_CALLBACK_2(AutocompleteEditViewGtk, void, HandleMarkSetAfter, 186 GtkTextBuffer*, GtkTextIter*, GtkTextMark*); 187 CHROMEG_CALLBACK_3(AutocompleteEditViewGtk, void, HandleInsertText, 188 GtkTextBuffer*, GtkTextIter*, const gchar*, gint); 189 CHROMEG_CALLBACK_0(AutocompleteEditViewGtk, void, 190 HandleKeymapDirectionChanged, GdkKeymap*); 191 CHROMEG_CALLBACK_2(AutocompleteEditViewGtk, void, HandleDeleteRange, 192 GtkTextBuffer*, GtkTextIter*, GtkTextIter*); 193 // Unlike above HandleMarkSet and HandleMarkSetAfter, this handler will always 194 // be connected to the signal. 195 CHROMEG_CALLBACK_2(AutocompleteEditViewGtk, void, HandleMarkSetAlways, 196 GtkTextBuffer*, GtkTextIter*, GtkTextMark*); 197 198 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, gboolean, HandleKeyPress, 199 GdkEventKey*); 200 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, gboolean, HandleKeyRelease, 201 GdkEventKey*); 202 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, gboolean, HandleViewButtonPress, 203 GdkEventButton*); 204 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, gboolean, 205 HandleViewButtonRelease, GdkEventButton*); 206 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, gboolean, HandleViewFocusIn, 207 GdkEventFocus*); 208 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, gboolean, HandleViewFocusOut, 209 GdkEventFocus*); 210 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, void, HandleViewMoveFocus, 211 GtkDirectionType); 212 CHROMEGTK_CALLBACK_3(AutocompleteEditViewGtk, void, HandleViewMoveCursor, 213 GtkMovementStep, gint, gboolean); 214 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, void, HandleViewSizeRequest, 215 GtkRequisition*); 216 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, void, HandlePopulatePopup, 217 GtkMenu*); 218 CHROMEGTK_CALLBACK_0(AutocompleteEditViewGtk, void, HandleEditSearchEngines); 219 CHROMEGTK_CALLBACK_0(AutocompleteEditViewGtk, void, HandlePasteAndGo); 220 CHROMEGTK_CALLBACK_6(AutocompleteEditViewGtk, void, HandleDragDataReceived, 221 GdkDragContext*, gint, gint, GtkSelectionData*, 222 guint, guint); 223 CHROMEGTK_CALLBACK_4(AutocompleteEditViewGtk, void, HandleDragDataGet, 224 GdkDragContext*, GtkSelectionData*, guint, guint); 225 CHROMEGTK_CALLBACK_0(AutocompleteEditViewGtk, void, HandleBackSpace); 226 CHROMEGTK_CALLBACK_0(AutocompleteEditViewGtk, void, HandleCopyClipboard); 227 CHROMEGTK_CALLBACK_0(AutocompleteEditViewGtk, void, HandleCutClipboard); 228 CHROMEGTK_CALLBACK_0(AutocompleteEditViewGtk, void, HandlePasteClipboard); 229 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, gboolean, HandleExposeEvent, 230 GdkEventExpose*); 231 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, void, 232 HandleWidgetDirectionChanged, GtkTextDirection); 233 CHROMEGTK_CALLBACK_2(AutocompleteEditViewGtk, void, 234 HandleDeleteFromCursor, GtkDeleteType, gint); 235 // We connect to this so we can determine our toplevel window, so we can 236 // listen to focus change events on it. 237 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, void, HandleHierarchyChanged, 238 GtkWidget*); 239#if GTK_CHECK_VERSION(2, 20, 0) 240 CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, void, HandlePreeditChanged, 241 const gchar*); 242#endif 243 // Undo/redo operations won't trigger "begin-user-action" and 244 // "end-user-action" signals, so we need to hook into "undo" and "redo" 245 // signals and call OnBeforePossibleChange()/OnAfterPossibleChange() by 246 // ourselves. 247 CHROMEGTK_CALLBACK_0(AutocompleteEditViewGtk, void, HandleUndoRedo); 248 CHROMEGTK_CALLBACK_0(AutocompleteEditViewGtk, void, HandleUndoRedoAfter); 249 250 CHROMEG_CALLBACK_1(AutocompleteEditViewGtk, void, HandleWindowSetFocus, 251 GtkWindow*, GtkWidget*); 252 253 // Callback for the PRIMARY selection clipboard. 254 static void ClipboardGetSelectionThunk(GtkClipboard* clipboard, 255 GtkSelectionData* selection_data, 256 guint info, 257 gpointer object); 258 void ClipboardGetSelection(GtkClipboard* clipboard, 259 GtkSelectionData* selection_data, 260 guint info); 261 262 void HandleCopyOrCutClipboard(bool copy); 263 264 // Take control of the PRIMARY selection clipboard with |text|. Use 265 // |text_buffer_| as the owner, so that this doesn't remove the selection on 266 // it. This makes use of the above callbacks. 267 void OwnPrimarySelection(const std::string& text); 268 269 // Gets the GTK_TEXT_WINDOW_WIDGET coordinates for |text_view_| that bound the 270 // given iters. 271 gfx::Rect WindowBoundsFromIters(GtkTextIter* iter1, GtkTextIter* iter2); 272 273 // Actual implementation of SelectAll(), but also provides control over 274 // whether the PRIMARY selection is set to the selected text (in SelectAll(), 275 // it isn't, but we want set the selection when the user clicks in the entry). 276 void SelectAllInternal(bool reversed, bool update_primary_selection); 277 278 // Get ready to update |text_buffer_|'s highlighting without making changes to 279 // the PRIMARY selection. Removes the clipboard from |text_buffer_| and 280 // blocks the "mark-set" signal handler. 281 void StartUpdatingHighlightedText(); 282 283 // Finish updating |text_buffer_|'s highlighting such that future changes will 284 // automatically update the PRIMARY selection. Undoes 285 // StartUpdatingHighlightedText()'s changes. 286 void FinishUpdatingHighlightedText(); 287 288 // Get the character indices of the current selection. This honors 289 // direction, cp_max is the insertion point, and cp_min is the bound. 290 CharRange GetSelection(); 291 292 // Translate from character positions to iterators for the current buffer. 293 void ItersFromCharRange(const CharRange& range, 294 GtkTextIter* iter_min, 295 GtkTextIter* iter_max); 296 297 // Return the number of characers in the current buffer. 298 int GetTextLength() const; 299 300 // Try to parse the current text as a URL and colorize the components. 301 void EmphasizeURLComponents(); 302 303 // Internally invoked whenever the text changes in some way. 304 void TextChanged(); 305 306 // Save |selected_text| as the PRIMARY X selection. Unlike 307 // OwnPrimarySelection(), this won't set an owner or use callbacks. 308 void SavePrimarySelection(const std::string& selected_text); 309 310 // Update the field with |text| and set the selection. 311 void SetTextAndSelectedRange(const std::wstring& text, 312 const CharRange& range); 313 314 // Set the selection to |range|. 315 void SetSelectedRange(const CharRange& range); 316 317 // Adjust the text justification according to the text direction of the widget 318 // and |text_buffer_|'s content, to make sure the real text justification is 319 // always in sync with the UI language direction. 320 void AdjustTextJustification(); 321 322 // Get the text direction of |text_buffer_|'s content, by searching the first 323 // character that has a strong direction. 324 PangoDirection GetContentDirection(); 325 326 // Returns the selected text. 327 std::string GetSelectedText() const; 328 329 // If the selected text parses as a URL OwnPrimarySelection is invoked. 330 void UpdatePrimarySelectionIfValidURL(); 331 332 // Retrieves the first and last iterators in the |text_buffer_|, but excludes 333 // the anchor holding the |instant_view_| widget. 334 void GetTextBufferBounds(GtkTextIter* start, GtkTextIter* end) const; 335 336 // Validates an iterator in the |text_buffer_|, to make sure it doesn't go 337 // beyond the anchor for holding the |instant_view_| widget. 338 void ValidateTextBufferIter(GtkTextIter* iter) const; 339 340 // Adjusts vertical alignment of the |instant_view_| in the |text_view_|, to 341 // make sure they have the same baseline. 342 void AdjustVerticalAlignmentOfInstantView(); 343 344 // Stop showing the instant suggest auto-commit animation. 345 void StopAnimation(); 346 347 // The widget we expose, used for vertically centering the real text edit, 348 // since the height will change based on the font / font size, etc. 349 OwnedWidgetGtk alignment_; 350 351 // The actual text entry which will be owned by the alignment_. 352 GtkWidget* text_view_; 353 354 GtkTextTagTable* tag_table_; 355 GtkTextBuffer* text_buffer_; 356 GtkTextTag* faded_text_tag_; 357 GtkTextTag* secure_scheme_tag_; 358 GtkTextTag* security_error_scheme_tag_; 359 GtkTextTag* normal_text_tag_; 360 361 // Objects for the instant suggestion text view. 362 GtkTextTag* instant_anchor_tag_; 363 364 // A widget for displaying instant suggestion text. It'll be attached to a 365 // child anchor in the |text_buffer_| object. 366 GtkWidget* instant_view_; 367 // Animation from instant suggest (faded text) to autocomplete (selected 368 // text). 369 scoped_ptr<MultiAnimation> instant_animation_; 370 371 // A mark to split the content and the instant anchor. Wherever the end 372 // iterator of the text buffer is required, the iterator to this mark should 373 // be used. 374 GtkTextMark* instant_mark_; 375 376 scoped_ptr<AutocompleteEditModel> model_; 377 scoped_ptr<AutocompletePopupView> popup_view_; 378 AutocompleteEditController* controller_; 379 ToolbarModel* toolbar_model_; 380 381 // The object that handles additional command functionality exposed on the 382 // edit, such as invoking the keyword editor. 383 CommandUpdater* command_updater_; 384 385 // When true, the location bar view is read only and also is has a slightly 386 // different presentation (smaller font size). This is used for popups. 387 bool popup_window_mode_; 388 389 ToolbarModel::SecurityLevel security_level_; 390 391 // Selection at the point where the user started using the 392 // arrows to move around in the popup. 393 CharRange saved_temporary_selection_; 394 395 // Tracking state before and after a possible change. 396 std::wstring text_before_change_; 397 CharRange sel_before_change_; 398 399 // The most-recently-selected text from the entry that was copied to the 400 // clipboard. This is updated on-the-fly as the user selects text. This may 401 // differ from the actual selected text, such as when 'http://' is prefixed to 402 // the text. It is used in cases where we need to make the PRIMARY selection 403 // persist even after the user has unhighlighted the text in the view 404 // (e.g. when they highlight some text and then click to unhighlight it, we 405 // pass this string to SavePrimarySelection()). 406 std::string selected_text_; 407 408 // When we own the X clipboard, this is the text for it. 409 std::string primary_selection_text_; 410 411 // IDs of the signal handlers for "mark-set" on |text_buffer_|. 412 gulong mark_set_handler_id_; 413 gulong mark_set_handler_id2_; 414 415#if defined(OS_CHROMEOS) 416 // The following variables are used to implement select-all-on-mouse-up, which 417 // is disabled in the standard Linux build due to poor interaction with the 418 // PRIMARY X selection. 419 420 // Is the first mouse button currently down? When selection marks get moved, 421 // we use this to determine if the user was highlighting text with the mouse 422 // -- if so, we avoid selecting all the text on mouse-up. 423 bool button_1_pressed_; 424 425 // Did the user change the selected text in the middle of the current click? 426 // If so, we don't select all of the text when the button is released -- we 427 // don't want to blow away their selection. 428 bool text_selected_during_click_; 429 430 // Was the text view already focused before the user clicked in it? We use 431 // this to figure out whether we should select all of the text when the button 432 // is released (we only do so if the view was initially unfocused). 433 bool text_view_focused_before_button_press_; 434#endif 435 436#if !defined(TOOLKIT_VIEWS) 437 // Supplies colors, et cetera. 438 GtkThemeProvider* theme_provider_; 439 440 NotificationRegistrar registrar_; 441#endif 442 443 // Indicates if Enter key was pressed. 444 // 445 // It's used in the key press handler to detect an Enter key press event 446 // during sync dispatch of "end-user-action" signal so that an unexpected 447 // change caused by the event can be ignored in OnAfterPossibleChange(). 448 bool enter_was_pressed_; 449 450 // Indicates if Tab key was pressed. 451 // 452 // It's only used in the key press handler to detect a Tab key press event 453 // during sync dispatch of "move-focus" signal. 454 bool tab_was_pressed_; 455 456 // Indicates that user requested to paste clipboard. 457 // The actual paste clipboard action might be performed later if the 458 // clipboard is not empty. 459 bool paste_clipboard_requested_; 460 461 // Indicates if an Enter key press is inserted as text. 462 // It's used in the key press handler to determine if an Enter key event is 463 // handled by IME or not. 464 bool enter_was_inserted_; 465 466 // Indicates whether the IME changed the text. It's possible for the IME to 467 // handle a key event but not change the text contents (e.g., when pressing 468 // shift+del with no selection). 469 bool text_changed_; 470 471 // Contains the character range that should have a strikethrough (used for 472 // insecure schemes). If the range is size one or less, no strikethrough 473 // is needed. 474 CharRange strikethrough_; 475 476 // Indicate if the tab to search should be enabled or not. It's true by 477 // default and will only be set to false if the location bar view is not able 478 // to show the tab to search hint. 479 bool enable_tab_to_search_; 480 481 // Indicates if the selected text is suggested text or not. If the selection 482 // is not suggested text, that means the user manually made the selection. 483 bool selection_suggested_; 484 485 // Was delete pressed? 486 bool delete_was_pressed_; 487 488 // Was the delete key pressed with an empty selection at the end of the edit? 489 bool delete_at_end_pressed_; 490 491 // Indicates if we are handling a key press event. 492 bool handling_key_press_; 493 494 // Indicates if omnibox's content maybe changed by a key press event, so that 495 // we need to call OnAfterPossibleChange() after handling the event. 496 // This flag should be set for changes directly caused by a key press event, 497 // including changes to content text, selection range and preedit string. 498 // Changes caused by function calls like SetUserText() should not affect this 499 // flag. 500 bool content_maybe_changed_by_key_press_; 501 502#if GTK_CHECK_VERSION(2, 20, 0) 503 // Stores the text being composed by the input method. 504 std::wstring preedit_; 505 506 // Tracking preedit state before and after a possible change. We don't need to 507 // track preedit_'s content, as it'll be treated as part of text content. 508 size_t preedit_size_before_change_; 509#endif 510 511 // The view that is going to be focused next. Only valid while handling 512 // "focus-out" events. 513 GtkWidget* going_to_focus_; 514 515 GtkSignalRegistrar signals_; 516 517 DISALLOW_COPY_AND_ASSIGN(AutocompleteEditViewGtk); 518}; 519 520#endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_GTK_H_ 521