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