• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
29 class AutocompleteEditController;
30 class AutocompleteEditModel;
31 class AutocompletePopupView;
32 class Profile;
33 class TabContents;
34 
35 namespace gfx {
36 class Font;
37 }
38 
39 namespace ui {
40 class MultiAnimation;
41 }
42 
43 namespace views {
44 class View;
45 }
46 
47 #if !defined(TOOLKIT_VIEWS)
48 class GtkThemeService;
49 #endif
50 
51 class 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 {
CharRangeCharRange59     CharRange() : cp_min(0), cp_max(0) { }
CharRangeCharRange60     CharRange(int n, int x) : cp_min(n), cp_max(x) { }
61 
62     // Returns the start/end of the selection.
selection_minCharRange63     int selection_min() const { return std::min(cp_min, cp_max); }
selection_maxCharRange64     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.
text_view()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