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