1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * Copyright (C) 2009 Shaun McCance <shaunm@gnome.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Shaun McCance <shaunm@gnome.org>
27 #include <gdk/gdkkeysyms.h>
29 #include <glib/gi18n.h>
31 #include "yelp-location-entry.h"
32 #include "yelp-marshal.h"
33 #include "yelp-settings.h"
36 * SECTION:yelp-location-entry
37 * @short_description: A location entry with history and search
40 * #YelpLocationEntry is a #GtkComboBox designed to show the current location,
41 * provide a drop-down menu of previous locations, and allow the user to perform
44 * The #GtkTreeModel used by a #YelpLocationEntry is expected to have at least
45 * four columns: #GtkComboBox::entry-text-column contains the displayed name
46 * of the location, #YelpLocationEntry::desc-column contains a description
47 * for each entry, #YelpLocationEntry::icon-column contains an icon name for
48 * the location, and #YelpLocationEntry::flags-column contains a bit field
49 * of #YelpLocationEntryFlags. These columns are specified when creating a
50 * #YelpLocationEntry widget with yelp_location_entry_new_with_model().
52 * Usually, a single row in the #GtkTreeModel corresponds to a location. When
53 * a user selects a row from the drop-down menu, the icon and text for that
54 * row will be placed in the embedded text entry, and the
55 * #YelpLocationEntry:location-selected signal will be emitted.
57 * If a row has the %YELP_LOCATION_ENTRY_IS_SEARCH flag set, selecting that
58 * row will not emit the #YelpLocationEntry::location-selected signal. Instead,
59 * the #YelpLocationEntry widget will be placed into search mode, as if by a
60 * call to yelp_location_entry_start_search().
62 * When a row has the %YELP_LOCATION_ENTRY_CAN_BOOKMARK flag set, an icon
63 * will be displayed in the secondary icon position of the embedded text
64 * entry allowing the user to bookmark the location. Clicking this icon
65 * will cause the FIXME signal to be emitted.
68 static void location_entry_constructed (GObject
*object
);
69 static void location_entry_dispose (GObject
*object
);
70 static void location_entry_finalize (GObject
*object
);
71 static void location_entry_get_property (GObject
*object
,
75 static void location_entry_set_property (GObject
*object
,
81 static void location_entry_location_selected (YelpLocationEntry
*entry
);
82 static void location_entry_search_activated (YelpLocationEntry
*entry
);
83 static void location_entry_bookmark_clicked (YelpLocationEntry
*entry
);
86 static void location_entry_start_search (YelpLocationEntry
*entry
,
88 static void location_entry_cancel_search (YelpLocationEntry
*entry
);
89 static void location_entry_set_entry (YelpLocationEntry
*entry
,
91 static gboolean
location_entry_pulse (gpointer data
);
92 static void location_entry_set_completion (YelpLocationEntry
*entry
,
96 /* GtkTreeModel callbacks */
97 static void history_row_changed (GtkTreeModel
*model
,
101 /* GtkComboBox callbacks */
102 static void combo_box_changed_cb (GtkComboBox
*widget
,
104 static gboolean
combo_box_row_separator_func (GtkTreeModel
*model
,
107 /* GtkEntry callbacks */
108 static gboolean
entry_focus_in_cb (GtkWidget
*widget
,
109 GdkEventFocus
*event
,
111 static gboolean
entry_focus_out_cb (GtkWidget
*widget
,
112 GdkEventFocus
*event
,
114 static void entry_activate_cb (GtkEntry
*text_entry
,
116 static void entry_icon_press_cb (GtkEntry
*gtkentry
,
117 GtkEntryIconPosition icon_pos
,
119 YelpLocationEntry
*entry
);
120 static gboolean
entry_key_press_cb (GtkWidget
*widget
,
122 YelpLocationEntry
*entry
);
123 /* GtkCellLayout callbacks */
124 static void cell_set_text_cell (GtkCellLayout
*layout
,
125 GtkCellRenderer
*cell
,
128 YelpLocationEntry
*entry
);
129 static void cell_set_bookmark_icon (GtkCellLayout
*layout
,
130 GtkCellRenderer
*cell
,
133 YelpLocationEntry
*entry
);
134 /* GtkEntryCompletion callbacks */
135 static void cell_set_completion_bookmark_icon (GtkCellLayout
*layout
,
136 GtkCellRenderer
*cell
,
139 YelpLocationEntry
*entry
);
140 static void cell_set_completion_text_cell (GtkCellLayout
*layout
,
141 GtkCellRenderer
*cell
,
144 YelpLocationEntry
*entry
);
145 static gboolean
entry_match_func (GtkEntryCompletion
*completion
,
148 YelpLocationEntry
*entry
);
149 static gint
entry_completion_sort (GtkTreeModel
*model
,
153 static gboolean
entry_match_selected (GtkEntryCompletion
*completion
,
156 YelpLocationEntry
*entry
);
157 /* YelpView callbacks */
158 static void view_loaded (YelpView
*view
,
159 YelpLocationEntry
*entry
);
160 static void view_uri_selected (YelpView
*view
,
162 YelpLocationEntry
*entry
);
163 static void view_page_title (YelpView
*view
,
165 YelpLocationEntry
*entry
);
166 static void view_page_desc (YelpView
*view
,
168 YelpLocationEntry
*entry
);
169 static void view_page_icon (YelpView
*view
,
171 YelpLocationEntry
*entry
);
172 /* YelpBookmarks callbacks */
173 static void bookmarks_changed (YelpBookmarks
*bookmarks
,
174 const gchar
*doc_uri
,
175 YelpLocationEntry
*entry
);
179 typedef struct _YelpLocationEntryPrivate YelpLocationEntryPrivate
;
180 struct _YelpLocationEntryPrivate
183 YelpBookmarks
*bookmarks
;
184 GtkTreeRowReference
*row
;
185 gchar
*completion_uri
;
187 /* do not free below */
188 GtkWidget
*text_entry
;
189 GtkCellRenderer
*icon_cell
;
190 GtkListStore
*history
;
191 GtkEntryCompletion
*completion
;
193 gboolean enable_search
;
194 gboolean view_uri_selected
;
195 gboolean search_mode
;
197 gulong bookmarks_changed
;
199 gboolean icon_is_clear
;
203 LOCATION_ENTRY_IS_LOADING
= 1 << 0,
204 LOCATION_ENTRY_IS_SEPARATOR
= 1 << 1,
205 LOCATION_ENTRY_IS_SEARCH
= 1 << 2
220 COMPLETION_COL_TITLE
,
241 static GHashTable
*completions
;
243 static guint location_entry_signals
[LAST_SIGNAL
] = {0,};
245 #define MAX_HISTORY 8
247 G_DEFINE_TYPE (YelpLocationEntry
, yelp_location_entry
, GTK_TYPE_COMBO_BOX
)
248 #define GET_PRIV(object) (G_TYPE_INSTANCE_GET_PRIVATE((object), YELP_TYPE_LOCATION_ENTRY, YelpLocationEntryPrivate))
251 yelp_location_entry_class_init (YelpLocationEntryClass
*klass
)
253 GObjectClass
*object_class
;
255 klass
->location_selected
= location_entry_location_selected
;
256 klass
->search_activated
= location_entry_search_activated
;
257 klass
->bookmark_clicked
= location_entry_bookmark_clicked
;
259 object_class
= G_OBJECT_CLASS (klass
);
261 object_class
->constructed
= location_entry_constructed
;
262 object_class
->dispose
= location_entry_dispose
;
263 object_class
->finalize
= location_entry_finalize
;
264 object_class
->get_property
= location_entry_get_property
;
265 object_class
->set_property
= location_entry_set_property
;
268 * YelpLocationEntry::location-selected
269 * @widget: The #YelpLocationEntry for which the signal was emitted.
270 * @user_data: User data set when the handler was connected.
272 * This signal will be emitted whenever a user selects a normal row from the
273 * drop-down menu. Note that if a row has the flag %YELP_LOCATION_ENTRY_IS_SEARCH,
274 * clicking the row will cause @widget to enter search mode, and this signal
275 * will not be emitted.
277 location_entry_signals
[LOCATION_SELECTED
] =
278 g_signal_new ("location-selected",
279 G_OBJECT_CLASS_TYPE (klass
),
281 G_STRUCT_OFFSET (YelpLocationEntryClass
, location_selected
),
283 g_cclosure_marshal_VOID__VOID
,
287 * YelpLocationEntry::search-activated
288 * @widget: The #YelpLocationEntry for which the signal was emitted.
289 * @text: The search text.
290 * @user_data: User data set when the handler was connected.
292 * This signal will be emitted whenever the user activates a search, generally
293 * by pressing <keycap>Enter</keycap> in the embedded text entry while @widget
296 location_entry_signals
[SEARCH_ACTIVATED
] =
297 g_signal_new ("search-activated",
298 G_OBJECT_CLASS_TYPE (klass
),
300 G_STRUCT_OFFSET (YelpLocationEntryClass
, search_activated
),
302 g_cclosure_marshal_VOID__STRING
,
307 * YelpLocationEntry::bookmark-clicked
308 * @widget: The #YelpLocationEntry for which the signal was emitted.
309 * @user_data: User data set when the handler was connected.
311 * This signal will be emitted whenever a user clicks the bookmark icon
312 * embedded in the location entry.
314 location_entry_signals
[BOOKMARK_CLICKED
] =
315 g_signal_new ("bookmark-clicked",
316 G_OBJECT_CLASS_TYPE (klass
),
318 G_STRUCT_OFFSET (YelpLocationEntryClass
, bookmark_clicked
),
320 g_cclosure_marshal_VOID__VOID
,
324 * YelpLocationEntry:view
326 * The YelpView instance that this location entry controls.
328 g_object_class_install_property (object_class
,
330 g_param_spec_object ("view",
332 _("A YelpView instance to control"),
334 G_PARAM_CONSTRUCT_ONLY
|
336 G_PARAM_STATIC_STRINGS
));
339 * YelpLocationEntry:bookmarks
341 * An instance of an implementation of YelpBookmarks to provide
342 * bookmark information for this location entry.
344 g_object_class_install_property (object_class
,
346 g_param_spec_object ("bookmarks",
348 _("A YelpBookmarks implementation instance"),
350 G_PARAM_CONSTRUCT_ONLY
|
352 G_PARAM_STATIC_STRINGS
));
355 * YelpLocationEntry:enable-search
357 * Whether the location entry can act as a search entry. If search is not
358 * enabled, the user will not be able to initiate a search by clicking in
359 * the embedded text entry or selecting a search row in the drop-down menu.
361 g_object_class_install_property (object_class
,
363 g_param_spec_boolean ("enable-search",
365 N_("Whether the location entry can be used as a search field"),
369 G_PARAM_STATIC_STRINGS
));
371 g_type_class_add_private ((GObjectClass
*) klass
,
372 sizeof (YelpLocationEntryPrivate
));
374 completions
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
378 yelp_location_entry_init (YelpLocationEntry
*entry
)
380 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
382 priv
->search_mode
= FALSE
;
383 g_object_set (entry
, "entry-text-column", HISTORY_COL_TITLE
, NULL
);
387 location_entry_constructed (GObject
*object
)
389 GtkCellRenderer
*bookmark_cell
;
392 YelpLocationEntryPrivate
*priv
= GET_PRIV (object
);
394 /* Set up the text entry child */
395 priv
->text_entry
= gtk_bin_get_child (GTK_BIN (object
));
396 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
397 GTK_ENTRY_ICON_PRIMARY
,
399 gtk_entry_set_icon_activatable (GTK_ENTRY (priv
->text_entry
),
400 GTK_ENTRY_ICON_PRIMARY
,
402 gtk_entry_set_icon_activatable (GTK_ENTRY (priv
->text_entry
),
403 GTK_ENTRY_ICON_SECONDARY
,
405 gtk_editable_set_editable (GTK_EDITABLE (priv
->text_entry
),
406 priv
->enable_search
);
407 if (!priv
->enable_search
) {
408 priv
->search_mode
= FALSE
;
409 location_entry_set_entry ((YelpLocationEntry
*) object
, FALSE
);
412 /* Set up the history model */
413 priv
->history
= gtk_list_store_new (8,
414 G_TYPE_STRING
, /* title */
415 G_TYPE_STRING
, /* desc */
416 G_TYPE_STRING
, /* icon */
417 G_TYPE_STRING
, /* uri */
418 G_TYPE_STRING
, /* doc */
419 G_TYPE_STRING
, /* page */
420 G_TYPE_INT
, /* flags */
421 G_TYPE_STRING
/* search terms */
423 g_signal_connect (priv
->history
, "row-changed",
424 G_CALLBACK (history_row_changed
),
426 g_object_set (object
, "model", priv
->history
, NULL
);
427 if (priv
->enable_search
) {
428 gtk_list_store_append (priv
->history
, &iter
);
429 gtk_list_store_set (priv
->history
, &iter
,
430 HISTORY_COL_FLAGS
, LOCATION_ENTRY_IS_SEPARATOR
,
432 gtk_list_store_append (priv
->history
, &iter
);
433 gtk_list_store_set (priv
->history
, &iter
,
434 HISTORY_COL_ICON
, "edit-find-symbolic",
435 HISTORY_COL_TITLE
, _("Search..."),
436 HISTORY_COL_FLAGS
, LOCATION_ENTRY_IS_SEARCH
,
440 /* Set up the history drop-down */
441 /* Trying to get the text to line up with the text in the GtkEntry.
442 * The text cell is the zeroeth cell right now, since we haven't
443 * yet called reorder. I realize using a guesstimate pixel value
444 * won't be perfect all the time, but 4 looks niceish.
446 cells
= gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (object
));
447 g_object_set (cells
->data
, "xpad", 4, NULL
);
448 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (object
),
449 GTK_CELL_RENDERER (cells
->data
),
450 (GtkCellLayoutDataFunc
) cell_set_text_cell
,
452 g_object_set (cells
->data
, "ellipsize", PANGO_ELLIPSIZE_END
, NULL
);
455 priv
->icon_cell
= gtk_cell_renderer_pixbuf_new ();
456 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (object
), priv
->icon_cell
, FALSE
);
457 g_object_set (priv
->icon_cell
, "yalign", 0.2, NULL
);
458 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (object
),
463 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (object
), priv
->icon_cell
, 0);
465 if (priv
->bookmarks
) {
466 bookmark_cell
= gtk_cell_renderer_pixbuf_new ();
467 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (object
), bookmark_cell
, FALSE
);
468 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (object
),
470 (GtkCellLayoutDataFunc
) cell_set_bookmark_icon
,
473 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (object
),
474 (GtkTreeViewRowSeparatorFunc
)
475 combo_box_row_separator_func
,
477 /* Without this, you get a warning about the popup widget
478 * being NULL the firt time you click the arrow.
480 gtk_widget_show_all (GTK_WIDGET (object
));
482 /* Connect signals */
483 g_signal_connect (object
, "changed",
484 G_CALLBACK (combo_box_changed_cb
), NULL
);
486 g_signal_connect (priv
->text_entry
, "focus-in-event",
487 G_CALLBACK (entry_focus_in_cb
), object
);
488 g_signal_connect (priv
->text_entry
, "focus-out-event",
489 G_CALLBACK (entry_focus_out_cb
), object
);
490 g_signal_connect (priv
->text_entry
, "icon-press",
491 G_CALLBACK (entry_icon_press_cb
), object
);
492 g_signal_connect (priv
->text_entry
, "key-press-event",
493 G_CALLBACK (entry_key_press_cb
), object
);
494 g_signal_connect (priv
->text_entry
, "activate",
495 G_CALLBACK (entry_activate_cb
), object
);
498 priv
->bookmarks_changed
= g_signal_connect (priv
->bookmarks
,
500 G_CALLBACK (bookmarks_changed
),
503 g_signal_connect (priv
->view
, "loaded", G_CALLBACK (view_loaded
), object
);
504 g_signal_connect (priv
->view
, "notify::yelp-uri", G_CALLBACK (view_uri_selected
), object
);
505 g_signal_connect (priv
->view
, "notify::page-title", G_CALLBACK (view_page_title
), object
);
506 g_signal_connect (priv
->view
, "notify::page-desc", G_CALLBACK (view_page_desc
), object
);
507 g_signal_connect (priv
->view
, "notify::page-icon", G_CALLBACK (view_page_icon
), object
);
511 location_entry_dispose (GObject
*object
)
513 YelpLocationEntryPrivate
*priv
= GET_PRIV (object
);
516 g_object_unref (priv
->view
);
520 if (priv
->bookmarks
) {
521 g_object_unref (priv
->bookmarks
);
522 priv
->bookmarks
= NULL
;
525 if (priv
->bookmarks_changed
) {
526 g_source_remove (priv
->bookmarks_changed
);
527 priv
->bookmarks_changed
= 0;
531 gtk_tree_row_reference_free (priv
->row
);
535 if (priv
->pulse
> 0) {
536 g_source_remove (priv
->pulse
);
540 G_OBJECT_CLASS (yelp_location_entry_parent_class
)->dispose (object
);
544 location_entry_finalize (GObject
*object
)
546 YelpLocationEntryPrivate
*priv
= GET_PRIV (object
);
548 g_free (priv
->completion_uri
);
550 G_OBJECT_CLASS (yelp_location_entry_parent_class
)->finalize (object
);
554 location_entry_get_property (GObject
*object
,
559 YelpLocationEntryPrivate
*priv
= GET_PRIV (object
);
563 g_value_set_object (value
, priv
->view
);
566 g_value_set_object (value
, priv
->bookmarks
);
568 case PROP_ENABLE_SEARCH
:
569 g_value_set_boolean (value
, priv
->enable_search
);
572 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
578 location_entry_set_property (GObject
*object
,
583 YelpLocationEntryPrivate
*priv
= GET_PRIV (object
);
587 priv
->view
= g_value_dup_object (value
);
590 priv
->bookmarks
= g_value_dup_object (value
);
592 case PROP_ENABLE_SEARCH
:
593 priv
->enable_search
= g_value_get_boolean (value
);
596 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
602 location_entry_location_selected (YelpLocationEntry
*entry
)
605 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
607 if (priv
->view_uri_selected
)
610 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (entry
), &iter
)) {
612 gtk_tree_model_get (GTK_TREE_MODEL (priv
->history
), &iter
,
613 HISTORY_COL_URI
, &uri
,
615 yelp_view_load (priv
->view
, uri
);
621 location_entry_search_activated (YelpLocationEntry
*entry
)
624 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
626 g_object_get (priv
->view
, "yelp-uri", &base
, NULL
);
629 uri
= yelp_uri_new_search (base
,
630 gtk_entry_get_text (GTK_ENTRY (priv
->text_entry
)));
631 g_object_unref (base
);
632 yelp_view_load_uri (priv
->view
, uri
);
633 gtk_widget_grab_focus (GTK_WIDGET (priv
->view
));
637 location_entry_bookmark_clicked (YelpLocationEntry
*entry
)
640 gchar
*doc_uri
, *page_id
;
641 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
643 g_object_get (priv
->view
,
647 doc_uri
= yelp_uri_get_document_uri (uri
);
648 if (priv
->bookmarks
&& doc_uri
&& page_id
) {
649 if (!yelp_bookmarks_is_bookmarked (priv
->bookmarks
, doc_uri
, page_id
)) {
651 g_object_get (priv
->view
,
653 "page-title", &title
,
655 yelp_bookmarks_add_bookmark (priv
->bookmarks
, doc_uri
, page_id
, icon
, title
);
660 yelp_bookmarks_remove_bookmark (priv
->bookmarks
, doc_uri
, page_id
);
665 g_object_unref (uri
);
669 location_entry_start_search (YelpLocationEntry
*entry
,
672 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
674 if (!priv
->enable_search
)
676 if (clear
&& !priv
->search_mode
) {
677 const gchar
*icon
= gtk_entry_get_icon_name (GTK_ENTRY (priv
->text_entry
),
678 GTK_ENTRY_ICON_PRIMARY
);
679 if (!g_str_equal (icon
, "folder-saved-search"))
680 gtk_entry_set_text (GTK_ENTRY (priv
->text_entry
), "");
682 priv
->search_mode
= TRUE
;
683 location_entry_set_entry (entry
, FALSE
);
684 gtk_widget_grab_focus (priv
->text_entry
);
688 location_entry_cancel_search (YelpLocationEntry
*entry
)
691 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
692 GdkEventFocus
*event
= g_new0 (GdkEventFocus
, 1);
693 priv
->search_mode
= FALSE
;
694 location_entry_set_entry (entry
, FALSE
);
695 event
->type
= GDK_FOCUS_CHANGE
;
696 event
->window
= gtk_widget_get_window (GTK_WIDGET (entry
));
697 event
->send_event
= FALSE
;
699 g_signal_emit_by_name (entry
, "focus-out-event", event
, &ret
);
701 /* Hack: This makes the popup disappear when you hit Esc. */
702 if (priv
->completion
) {
703 g_object_ref (priv
->completion
);
704 gtk_entry_set_completion (GTK_ENTRY (priv
->text_entry
), NULL
);
705 gtk_entry_set_completion (GTK_ENTRY (priv
->text_entry
),
707 g_object_unref (priv
->completion
);
709 gtk_editable_select_region (GTK_EDITABLE (priv
->text_entry
), 0, 0);
713 location_entry_set_completion (YelpLocationEntry
*entry
,
716 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
718 GtkCellRenderer
*icon_cell
, *bookmark_cell
;
720 priv
->completion
= gtk_entry_completion_new ();
721 gtk_entry_completion_set_minimum_key_length (priv
->completion
, 3);
722 gtk_entry_completion_set_model (priv
->completion
, model
);
723 gtk_entry_completion_set_text_column (priv
->completion
, COMPLETION_COL_TITLE
);
724 gtk_entry_completion_set_match_func (priv
->completion
,
725 (GtkEntryCompletionMatchFunc
) entry_match_func
,
727 g_signal_connect (priv
->completion
, "match-selected",
728 G_CALLBACK (entry_match_selected
), entry
);
730 cells
= gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv
->completion
));
731 g_object_set (cells
->data
, "xpad", 4, NULL
);
732 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv
->completion
),
733 GTK_CELL_RENDERER (cells
->data
),
734 (GtkCellLayoutDataFunc
) cell_set_completion_text_cell
,
736 g_object_set (cells
->data
, "ellipsize", PANGO_ELLIPSIZE_END
, NULL
);
739 icon_cell
= gtk_cell_renderer_pixbuf_new ();
740 g_object_set (priv
->icon_cell
, "yalign", 0.2, NULL
);
741 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv
->completion
), icon_cell
, FALSE
);
742 gtk_cell_layout_reorder (GTK_CELL_LAYOUT (priv
->completion
), icon_cell
, 0);
743 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (priv
->completion
),
748 if (priv
->bookmarks
) {
749 bookmark_cell
= gtk_cell_renderer_pixbuf_new ();
750 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (priv
->completion
), bookmark_cell
, FALSE
);
751 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv
->completion
),
753 (GtkCellLayoutDataFunc
) cell_set_completion_bookmark_icon
,
756 gtk_entry_set_completion (GTK_ENTRY (priv
->text_entry
),
761 location_entry_set_entry (YelpLocationEntry
*entry
, gboolean emit
)
763 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
764 GtkTreeModel
*model
= gtk_combo_box_get_model (GTK_COMBO_BOX (entry
));
765 GtkTreePath
*path
= NULL
;
769 if (priv
->search_mode
) {
770 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
771 GTK_ENTRY_ICON_PRIMARY
,
772 "edit-find-symbolic");
773 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
774 GTK_ENTRY_ICON_SECONDARY
,
775 "edit-clear-symbolic");
776 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (priv
->text_entry
),
777 GTK_ENTRY_ICON_SECONDARY
,
778 _("Clear the search text"));
779 priv
->icon_is_clear
= TRUE
;
783 priv
->icon_is_clear
= FALSE
;
788 path
= gtk_tree_row_reference_get_path (priv
->row
);
791 gchar
*text
, *doc_uri
, *page_id
;
793 gtk_tree_model_get_iter (model
, &iter
, path
);
794 gtk_tree_model_get (model
, &iter
,
795 HISTORY_COL_TITLE
, &text
,
796 HISTORY_COL_ICON
, &icon_name
,
797 HISTORY_COL_FLAGS
, &flags
,
798 HISTORY_COL_DOC
, &doc_uri
,
799 HISTORY_COL_PAGE
, &page_id
,
801 if (flags
& LOCATION_ENTRY_IS_LOADING
) {
802 /* Would be nice to have a "loading" icon. I was using image-loading,
803 * but it look out of place with symbolic page icons. Plus, using
804 * image-loading-symbolic shows a broken image, because GtkEntry
805 * doesn't correctly use symbolic icons as of GNOME 3.0.
807 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
808 GTK_ENTRY_ICON_PRIMARY
,
809 "yelp-page-symbolic");
811 g_source_remove (priv
->pulse
);
812 priv
->pulse
= g_timeout_add (80, location_entry_pulse
, entry
);
815 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
816 GTK_ENTRY_ICON_PRIMARY
,
819 if (priv
->bookmarks
&& doc_uri
&& page_id
) {
821 if (!yelp_bookmarks_is_bookmarked (priv
->bookmarks
, doc_uri
, page_id
)) {
822 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
823 GTK_ENTRY_ICON_SECONDARY
,
824 "yelp-bookmark-add-symbolic");
825 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (priv
->text_entry
),
826 GTK_ENTRY_ICON_SECONDARY
,
827 _("Bookmark this page"));
830 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
831 GTK_ENTRY_ICON_SECONDARY
,
832 "yelp-bookmark-remove-symbolic");
833 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (priv
->text_entry
),
834 GTK_ENTRY_ICON_SECONDARY
,
835 _("Remove bookmark"));
839 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
840 GTK_ENTRY_ICON_SECONDARY
,
845 gtk_entry_set_text (GTK_ENTRY (priv
->text_entry
), text
);
847 g_signal_emit (entry
, location_entry_signals
[LOCATION_SELECTED
], 0);
849 gtk_tree_path_free (path
);
852 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
853 GTK_ENTRY_ICON_PRIMARY
,
855 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
856 GTK_ENTRY_ICON_SECONDARY
,
862 location_entry_pulse (gpointer data
)
864 YelpLocationEntryPrivate
*priv
= GET_PRIV (data
);
870 model
= gtk_tree_row_reference_get_model (priv
->row
);
871 path
= gtk_tree_row_reference_get_path (priv
->row
);
873 gtk_tree_model_get_iter (model
, &iter
, path
);
874 gtk_tree_model_get (model
, &iter
,
875 HISTORY_COL_FLAGS
, &flags
,
877 gtk_tree_path_free (path
);
880 if (flags
& LOCATION_ENTRY_IS_LOADING
&& !priv
->search_mode
) {
881 gtk_entry_progress_pulse (GTK_ENTRY (priv
->text_entry
));
884 gtk_entry_set_progress_fraction (GTK_ENTRY (priv
->text_entry
), 0.0);
887 return flags
& LOCATION_ENTRY_IS_LOADING
;
891 combo_box_changed_cb (GtkComboBox
*widget
,
894 YelpLocationEntryPrivate
*priv
= GET_PRIV (widget
);
898 model
= gtk_combo_box_get_model (GTK_COMBO_BOX (widget
));
900 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget
), &iter
)) {
902 gtk_tree_model_get (model
, &iter
,
903 HISTORY_COL_FLAGS
, &flags
,
905 if (flags
& LOCATION_ENTRY_IS_SEARCH
) {
906 location_entry_start_search ((YelpLocationEntry
*) widget
, TRUE
);
909 GtkTreePath
*cur
, *path
;
910 path
= gtk_tree_model_get_path (model
, &iter
);
912 cur
= gtk_tree_row_reference_get_path (priv
->row
);
913 if (gtk_tree_path_compare (cur
, path
) == 0) {
914 gtk_tree_path_free (cur
);
915 gtk_tree_path_free (path
);
918 gtk_tree_path_free (cur
);
919 gtk_tree_row_reference_free (priv
->row
);
921 priv
->row
= gtk_tree_row_reference_new (model
, path
);
922 gtk_tree_path_free (path
);
923 priv
->search_mode
= FALSE
;
924 location_entry_set_entry ((YelpLocationEntry
*) widget
, TRUE
);
930 combo_box_row_separator_func (GtkTreeModel
*model
,
934 YelpLocationEntryPrivate
*priv
= GET_PRIV (user_data
);
936 gtk_tree_model_get (model
, iter
,
937 HISTORY_COL_FLAGS
, &flags
,
939 return (flags
& LOCATION_ENTRY_IS_SEPARATOR
);
943 history_row_changed (GtkTreeModel
*model
,
948 /* FIXME: Should we bother checking path/iter against priv->row?
949 It doesn't really make a difference, since set_entry is pretty much
950 safe to call whenever. Does it make a performance impact?
952 location_entry_set_entry (YELP_LOCATION_ENTRY (user_data
), FALSE
);
956 entry_focus_in_cb (GtkWidget
*widget
,
957 GdkEventFocus
*event
,
960 GtkEntry
*text_entry
= GTK_ENTRY (widget
);
961 YelpLocationEntryPrivate
*priv
= GET_PRIV (user_data
);
963 if (priv
->enable_search
&& !priv
->search_mode
)
964 location_entry_start_search ((YelpLocationEntry
*) user_data
, TRUE
);
970 entry_focus_out_cb (GtkWidget
*widget
,
971 GdkEventFocus
*event
,
974 YelpLocationEntryPrivate
*priv
= GET_PRIV (user_data
);
976 if (gtk_entry_get_text_length (GTK_ENTRY (widget
)) == 0) {
977 priv
->search_mode
= FALSE
;
978 location_entry_set_entry ((YelpLocationEntry
*) user_data
, FALSE
);
985 entry_activate_cb (GtkEntry
*text_entry
,
988 YelpLocationEntryPrivate
*priv
= GET_PRIV (user_data
);
989 gchar
*text
= g_strdup (gtk_entry_get_text (text_entry
));
991 if (!priv
->enable_search
)
994 if (!priv
->search_mode
|| text
== NULL
|| strlen(text
) == 0)
997 g_signal_emit (user_data
, location_entry_signals
[SEARCH_ACTIVATED
], 0, text
);
1003 entry_icon_press_cb (GtkEntry
*gtkentry
,
1004 GtkEntryIconPosition icon_pos
,
1006 YelpLocationEntry
*entry
)
1008 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1010 if (icon_pos
== GTK_ENTRY_ICON_SECONDARY
) {
1011 if (priv
->icon_is_clear
)
1012 location_entry_cancel_search (entry
);
1014 g_signal_emit (entry
, location_entry_signals
[BOOKMARK_CLICKED
], 0);
1019 entry_key_press_cb (GtkWidget
*widget
,
1021 YelpLocationEntry
*entry
)
1023 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1024 if (event
->keyval
== GDK_KEY_Escape
) {
1025 location_entry_cancel_search (entry
);
1028 else if (!priv
->search_mode
) {
1029 location_entry_start_search (entry
, FALSE
);
1036 cell_set_text_cell (GtkCellLayout
*layout
,
1037 GtkCellRenderer
*cell
,
1038 GtkTreeModel
*model
,
1040 YelpLocationEntry
*entry
)
1042 gchar
*title
, *desc
, *color
, *text
;
1043 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1045 gtk_tree_model_get (model
, iter
,
1046 HISTORY_COL_TITLE
, &title
,
1047 HISTORY_COL_DESC
, &desc
,
1050 color
= yelp_settings_get_color (yelp_settings_get_default (),
1051 YELP_SETTINGS_COLOR_TEXT_LIGHT
);
1052 text
= g_markup_printf_escaped ("<span size='larger'>%s</span>\n<span color='%s'>%s</span>",
1053 title
, color
, desc
);
1058 text
= g_markup_printf_escaped ("<span size='larger'>%s</span>", title
);
1061 g_object_set (cell
, "markup", text
, NULL
);
1067 cell_set_bookmark_icon (GtkCellLayout
*layout
,
1068 GtkCellRenderer
*cell
,
1069 GtkTreeModel
*model
,
1071 YelpLocationEntry
*entry
)
1074 gchar
*doc_uri
, *page_id
;
1075 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1077 if (priv
->bookmarks
== NULL
) {
1078 g_object_set (cell
, "icon-name", NULL
, NULL
);
1082 gtk_tree_model_get (model
, iter
, HISTORY_COL_FLAGS
, &flags
, -1);
1083 if (flags
& (LOCATION_ENTRY_IS_SEPARATOR
| LOCATION_ENTRY_IS_SEARCH
)) {
1084 g_object_set (cell
, "icon-name", NULL
, NULL
);
1088 gtk_tree_model_get (model
, iter
,
1089 HISTORY_COL_DOC
, &doc_uri
,
1090 HISTORY_COL_PAGE
, &page_id
,
1092 if (doc_uri
&& page_id
&&
1093 yelp_bookmarks_is_bookmarked (priv
->bookmarks
, doc_uri
, page_id
))
1094 g_object_set (cell
, "icon-name", "yelp-bookmark-remove-symbolic", NULL
);
1096 g_object_set (cell
, "icon-name", NULL
, NULL
);
1103 cell_set_completion_bookmark_icon (GtkCellLayout
*layout
,
1104 GtkCellRenderer
*cell
,
1105 GtkTreeModel
*model
,
1107 YelpLocationEntry
*entry
)
1109 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1111 if (priv
->completion_uri
) {
1112 gchar
*page_id
= NULL
;
1113 gtk_tree_model_get (model
, iter
,
1114 COMPLETION_COL_PAGE
, &page_id
,
1117 if (page_id
&& yelp_bookmarks_is_bookmarked (priv
->bookmarks
,
1118 priv
->completion_uri
, page_id
))
1119 g_object_set (cell
, "icon-name", "yelp-bookmark-remove-symbolic", NULL
);
1121 g_object_set (cell
, "icon-name", NULL
, NULL
);
1128 cell_set_completion_text_cell (GtkCellLayout
*layout
,
1129 GtkCellRenderer
*cell
,
1130 GtkTreeModel
*model
,
1132 YelpLocationEntry
*entry
)
1134 gchar
*title
, *desc
, *color
, *text
;
1135 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1137 gtk_tree_model_get (model
, iter
,
1138 COMPLETION_COL_TITLE
, &title
,
1139 COMPLETION_COL_DESC
, &desc
,
1142 color
= yelp_settings_get_color (yelp_settings_get_default (),
1143 YELP_SETTINGS_COLOR_TEXT_LIGHT
);
1144 text
= g_markup_printf_escaped ("<span size='larger'>%s</span>\n<span color='%s'>%s</span>",
1145 title
, color
, desc
);
1150 text
= g_markup_printf_escaped ("<span size='larger'>%s</span>", title
);
1153 g_object_set (cell
, "markup", text
, NULL
);
1159 entry_match_func (GtkEntryCompletion
*completion
,
1162 YelpLocationEntry
*entry
)
1165 gchar
*title
, *desc
, *titlecase
= NULL
, *desccase
= NULL
;
1166 gboolean ret
= FALSE
;
1168 GtkTreeModel
*model
= gtk_entry_completion_get_model (completion
);
1169 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1170 static GRegex
*nonword
= NULL
;
1172 if (nonword
== NULL
)
1173 nonword
= g_regex_new ("\\W", 0, 0, NULL
);
1174 if (nonword
== NULL
)
1177 gtk_tree_model_get (model
, iter
,
1178 HISTORY_COL_TITLE
, &title
,
1179 HISTORY_COL_DESC
, &desc
,
1182 titlecase
= g_utf8_casefold (title
, -1);
1186 desccase
= g_utf8_casefold (desc
, -1);
1190 strs
= g_regex_split (nonword
, key
, 0);
1192 for (stri
= 0; strs
[stri
]; stri
++) {
1193 if (!titlecase
|| !strstr (titlecase
, strs
[stri
])) {
1194 if (!desccase
|| !strstr (desccase
, strs
[stri
])) {
1209 entry_completion_sort (GtkTreeModel
*model
,
1217 gtk_tree_model_get (model
, iter1
, COMPLETION_COL_ICON
, &key1
, -1);
1218 gtk_tree_model_get (model
, iter2
, COMPLETION_COL_ICON
, &key2
, -1);
1219 ret
= yelp_settings_cmp_icons (key1
, key2
);
1226 gtk_tree_model_get (model
, iter1
, COMPLETION_COL_TITLE
, &key1
, -1);
1227 gtk_tree_model_get (model
, iter2
, COMPLETION_COL_TITLE
, &key2
, -1);
1229 ret
= g_utf8_collate (key1
, key2
);
1230 else if (key2
== NULL
)
1232 else if (key1
== NULL
)
1241 entry_match_selected (GtkEntryCompletion
*completion
,
1242 GtkTreeModel
*model
,
1244 YelpLocationEntry
*entry
)
1246 YelpUri
*base
, *uri
;
1248 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1250 g_object_get (priv
->view
, "yelp-uri", &base
, NULL
);
1251 gtk_tree_model_get (model
, iter
, COMPLETION_COL_PAGE
, &page
, -1);
1253 xref
= g_strconcat ("xref:", page
, NULL
);
1254 uri
= yelp_uri_new_relative (base
, xref
);
1256 yelp_view_load_uri (priv
->view
, uri
);
1260 g_object_unref (uri
);
1261 g_object_unref (base
);
1263 gtk_widget_grab_focus (GTK_WIDGET (priv
->view
));
1268 view_loaded (YelpView
*view
,
1269 YelpLocationEntry
*entry
)
1276 gchar
*doc_uri
, *page_id
;
1277 GtkTreeModel
*completion
;
1278 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1279 YelpDocument
*document
= yelp_view_get_document (view
);
1281 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv
->history
), &iter
);
1282 gtk_tree_model_get (GTK_TREE_MODEL (priv
->history
), &iter
,
1283 HISTORY_COL_FLAGS
, &flags
,
1285 if (flags
& LOCATION_ENTRY_IS_LOADING
) {
1286 flags
= flags
& ~LOCATION_ENTRY_IS_LOADING
;
1287 gtk_list_store_set (priv
->history
, &iter
, HISTORY_COL_FLAGS
, flags
, -1);
1292 "page-id", &page_id
,
1294 doc_uri
= yelp_uri_get_document_uri (uri
);
1295 gtk_list_store_set (priv
->history
, &iter
,
1296 HISTORY_COL_DOC
, doc_uri
,
1297 HISTORY_COL_PAGE
, page_id
,
1301 if ((priv
->completion_uri
== NULL
) ||
1302 !g_str_equal (doc_uri
, priv
->completion_uri
)) {
1303 completion
= (GtkTreeModel
*) g_hash_table_lookup (completions
, doc_uri
);
1304 if (completion
== NULL
) {
1305 GtkListStore
*base
= gtk_list_store_new (5,
1306 G_TYPE_STRING
, /* title */
1307 G_TYPE_STRING
, /* desc */
1308 G_TYPE_STRING
, /* icon */
1309 G_TYPE_STRING
, /* uri */
1310 G_TYPE_INT
/* flags */
1312 completion
= gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (base
));
1313 gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (completion
),
1314 entry_completion_sort
,
1316 g_hash_table_insert (completions
, g_strdup (doc_uri
), completion
);
1317 if (document
!= NULL
) {
1318 ids
= yelp_document_list_page_ids (document
);
1319 for (i
= 0; ids
[i
]; i
++) {
1321 gchar
*title
, *desc
, *icon
;
1322 gtk_list_store_insert (GTK_LIST_STORE (base
), &iter
, 0);
1323 title
= yelp_document_get_page_title (document
, ids
[i
]);
1324 desc
= yelp_document_get_page_desc (document
, ids
[i
]);
1325 icon
= yelp_document_get_page_icon (document
, ids
[i
]);
1326 gtk_list_store_set (base
, &iter
,
1327 COMPLETION_COL_TITLE
, title
,
1328 COMPLETION_COL_DESC
, desc
,
1329 COMPLETION_COL_ICON
, icon
,
1330 COMPLETION_COL_PAGE
, ids
[i
],
1338 g_object_unref (base
);
1340 g_free (priv
->completion_uri
);
1341 priv
->completion_uri
= doc_uri
;
1342 location_entry_set_completion (entry
, completion
);
1345 g_object_unref (uri
);
1349 view_uri_selected (YelpView
*view
,
1351 YelpLocationEntry
*entry
)
1357 gchar
*struri
, *doc_uri
;
1358 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1360 g_object_get (G_OBJECT (view
), "yelp-uri", &uri
, NULL
);
1364 struri
= yelp_uri_get_canonical_uri (uri
);
1366 cont
= gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv
->history
), &iter
);
1368 gtk_tree_model_get (GTK_TREE_MODEL (priv
->history
), &iter
,
1369 HISTORY_COL_URI
, &iter_uri
,
1371 if (iter_uri
&& g_str_equal (struri
, iter_uri
)) {
1377 cont
= gtk_tree_model_iter_next (GTK_TREE_MODEL (priv
->history
), &iter
);
1382 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv
->history
), &first
);
1383 gtk_list_store_move_before (priv
->history
, &iter
, &first
);
1388 gtk_list_store_prepend (priv
->history
, &iter
);
1389 gtk_list_store_set (priv
->history
, &iter
,
1390 HISTORY_COL_TITLE
, _("Loading"),
1391 HISTORY_COL_ICON
, "help-contents",
1392 HISTORY_COL_URI
, struri
,
1393 HISTORY_COL_FLAGS
, LOCATION_ENTRY_IS_LOADING
,
1395 /* Limit to MAX_HISTORY entries. There are two extra for the search entry
1396 * and the separator above it.
1398 num
= gtk_tree_model_iter_n_children (GTK_TREE_MODEL (priv
->history
), NULL
);
1399 if (num
> MAX_HISTORY
+ 2) {
1400 if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv
->history
),
1403 gtk_list_store_remove (priv
->history
, &last
);
1407 priv
->view_uri_selected
= TRUE
;
1408 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (entry
), &iter
);
1409 priv
->view_uri_selected
= FALSE
;
1412 g_object_unref (uri
);
1416 view_page_title (YelpView
*view
,
1418 YelpLocationEntry
*entry
)
1421 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1423 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv
->history
), &first
)) {
1424 gchar
*title
, *frag
= NULL
;
1425 YelpViewState state
;
1429 "page-title", &title
,
1435 if (state
!= YELP_VIEW_STATE_ERROR
) {
1437 g_object_get (view
, "yelp-uri", &uri
, NULL
);
1438 frag
= yelp_uri_get_frag_id (uri
);
1439 g_object_unref (uri
);
1443 gchar
*tmp
= g_strdup_printf ("%s (#%s)", title
, frag
);
1444 gtk_list_store_set (priv
->history
, &first
,
1445 HISTORY_COL_TITLE
, tmp
,
1451 gtk_list_store_set (priv
->history
, &first
,
1452 HISTORY_COL_TITLE
, title
,
1460 view_page_desc (YelpView
*view
,
1462 YelpLocationEntry
*entry
)
1466 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1468 g_object_get (view
, "page-desc", &desc
, NULL
);
1472 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv
->history
), &first
))
1473 gtk_list_store_set (priv
->history
, &first
,
1474 HISTORY_COL_DESC
, desc
,
1480 view_page_icon (YelpView
*view
,
1482 YelpLocationEntry
*entry
)
1486 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1488 g_object_get (view
, "page-icon", &icon
, NULL
);
1492 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv
->history
), &first
))
1493 gtk_list_store_set (priv
->history
, &first
,
1494 HISTORY_COL_ICON
, icon
,
1500 bookmarks_changed (YelpBookmarks
*bookmarks
,
1501 const gchar
*doc_uri
,
1502 YelpLocationEntry
*entry
)
1505 YelpLocationEntryPrivate
*priv
= GET_PRIV (entry
);
1508 path
= gtk_tree_row_reference_get_path (priv
->row
);
1512 gchar
*this_uri
, *page_id
;
1513 gtk_tree_model_get_iter (GTK_TREE_MODEL (priv
->history
), &iter
, path
);
1514 gtk_tree_model_get (GTK_TREE_MODEL (priv
->history
), &iter
,
1515 HISTORY_COL_DOC
, &this_uri
,
1516 HISTORY_COL_PAGE
, &page_id
,
1518 if (this_uri
&& g_str_equal (this_uri
, doc_uri
) && page_id
) {
1519 if (!yelp_bookmarks_is_bookmarked (priv
->bookmarks
, doc_uri
, page_id
)) {
1520 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
1521 GTK_ENTRY_ICON_SECONDARY
,
1522 "yelp-bookmark-add-symbolic");
1523 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (priv
->text_entry
),
1524 GTK_ENTRY_ICON_SECONDARY
,
1525 _("Bookmark this page"));
1528 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
1529 GTK_ENTRY_ICON_SECONDARY
,
1530 "yelp-bookmark-remove-symbolic");
1531 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (priv
->text_entry
),
1532 GTK_ENTRY_ICON_SECONDARY
,
1533 _("Remove bookmark"));
1537 gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv
->text_entry
),
1538 GTK_ENTRY_ICON_SECONDARY
,
1547 * yelp_location_entry_new:
1548 * @view: A #YelpView.
1550 * Creates a new #YelpLocationEntry widget to control @view.
1552 * Returns: A new #YelpLocationEntry.
1555 yelp_location_entry_new (YelpView
*view
,
1556 YelpBookmarks
*bookmarks
)
1559 g_return_val_if_fail (YELP_IS_VIEW (view
), NULL
);
1561 ret
= GTK_WIDGET (g_object_new (YELP_TYPE_LOCATION_ENTRY
,
1564 "bookmarks", bookmarks
,
1571 * yelp_location_entry_start_search:
1572 * @entry: A #YelpLocationEntry.
1574 * Puts @entry into search mode. This focuses the entry and clears its text
1575 * contents. When the user activates the search, the
1576 * #YelpLocationEntry::search-activated signal will be emitted.
1579 yelp_location_entry_start_search (YelpLocationEntry
*entry
)
1581 location_entry_start_search (entry
, TRUE
);