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