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