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