1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3 * Copyright © 2019 Purism SPC
4 *
5 * This file is part of Epiphany.
6 *
7 * Epiphany is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Epiphany is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Epiphany. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22 #include "ephy-data-view.h"
23
24 #include <ctype.h>
25
26 typedef struct {
27 GtkWidget *box;
28 GtkWidget *child;
29 GtkWidget *header_bar;
30 GtkWidget *back_button;
31 GtkWidget *clear_button;
32 GtkWidget *search_bar;
33 GtkWidget *search_entry;
34 GtkWidget *search_button;
35 GtkWidget *stack;
36 GtkWidget *empty_page;
37 GtkWidget *spinner;
38
39 gboolean is_loading : 1;
40 gboolean has_data : 1;
41 gboolean has_search_results : 1;
42 gboolean can_clear : 1;
43 char *search_text;
44 } EphyDataViewPrivate;
45
46 G_DEFINE_TYPE_WITH_PRIVATE (EphyDataView, ephy_data_view, GTK_TYPE_BIN)
47
48 enum {
49 PROP_0,
50 PROP_TITLE,
51 PROP_CLEAR_ACTION_NAME,
52 PROP_CLEAR_ACTION_TARGET,
53 PROP_CLEAR_BUTTON_LABEL,
54 PROP_CLEAR_BUTTON_TOOLTIP,
55 PROP_SEARCH_DESCRIPTION,
56 PROP_EMPTY_TITLE,
57 PROP_EMPTY_DESCRIPTION,
58 PROP_SEARCH_TEXT,
59 PROP_IS_LOADING,
60 PROP_HAS_DATA,
61 PROP_HAS_SEARCH_RESULTS,
62 PROP_CAN_CLEAR,
63 LAST_PROP,
64 };
65
66 static GParamSpec *obj_properties[LAST_PROP];
67
68 enum {
69 BACK_BUTTON_CLICKED,
70 CLEAR_BUTTON_CLICKED,
71 LAST_SIGNAL,
72 };
73
74 static gint signals[LAST_SIGNAL] = { 0 };
75
76 static void
update(EphyDataView * self)77 update (EphyDataView *self)
78 {
79 EphyDataViewPrivate *priv = ephy_data_view_get_instance_private (self);
80 gboolean has_data = priv->has_data && priv->child && gtk_widget_get_visible (priv->child);
81
82 if (priv->is_loading) {
83 gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "loading");
84 gtk_spinner_start (GTK_SPINNER (priv->spinner));
85 } else {
86 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->search_button))) {
87 if (has_data && priv->has_search_results)
88 gtk_stack_set_visible_child (GTK_STACK (priv->stack), priv->child);
89 else
90 gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "no-results");
91 } else {
92 if (has_data)
93 gtk_stack_set_visible_child (GTK_STACK (priv->stack), priv->child);
94 else
95 gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "empty");
96 }
97 gtk_spinner_stop (GTK_SPINNER (priv->spinner));
98 }
99
100 gtk_widget_set_sensitive (priv->clear_button, has_data && priv->can_clear);
101 gtk_widget_set_sensitive (priv->search_button, has_data);
102 }
103
104 static void
on_back_button_clicked(GtkWidget * button,EphyDataView * self)105 on_back_button_clicked (GtkWidget *button,
106 EphyDataView *self)
107 {
108 g_signal_emit (self, signals[BACK_BUTTON_CLICKED], 0);
109 }
110
111 static void
on_clear_button_clicked(EphyDataView * self)112 on_clear_button_clicked (EphyDataView *self)
113 {
114 g_signal_emit (self, signals[CLEAR_BUTTON_CLICKED], 0);
115 }
116
117 static void
on_search_entry_changed(GtkSearchEntry * entry,EphyDataView * self)118 on_search_entry_changed (GtkSearchEntry *entry,
119 EphyDataView *self)
120 {
121 EphyDataViewPrivate *priv = ephy_data_view_get_instance_private (self);
122 const char *text;
123
124 text = gtk_entry_get_text (GTK_ENTRY (entry));
125 g_free (priv->search_text);
126 priv->search_text = g_strdup (text);
127
128 g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_SEARCH_TEXT]);
129 }
130
131 gboolean
ephy_data_view_handle_event(EphyDataView * self,GdkEvent * event)132 ephy_data_view_handle_event (EphyDataView *self,
133 GdkEvent *event)
134 {
135 EphyDataViewPrivate *priv = ephy_data_view_get_instance_private (self);
136 GdkEventKey *key = (GdkEventKey *)event;
137 gint result;
138
139 /* Firstly, we check if the HdySearchBar can handle the event */
140 result = hdy_search_bar_handle_event (HDY_SEARCH_BAR (priv->search_bar), event);
141
142 if (result == GDK_EVENT_STOP)
143 return result;
144
145 /* Secondly, we check for the shortcuts implemented by the data views */
146 /* Ctrl + F */
147 if ((key->state & GDK_CONTROL_MASK) && key->keyval == GDK_KEY_f) {
148 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->search_button), TRUE);
149 return GDK_EVENT_STOP;
150 }
151
152 /* Shift + Delete */
153 if ((key->state & GDK_SHIFT_MASK) && key->keyval == GDK_KEY_Delete) {
154 gtk_button_clicked (GTK_BUTTON (priv->clear_button));
155 return GDK_EVENT_STOP;
156 }
157
158 /* Finally, we check for the Escape key */
159 if (key->keyval == GDK_KEY_Escape) {
160 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->search_button)))
161 /* If the user presses the Escape key and the search bar is hidden,
162 * we want the event to have the same effect as clicking the back button*/
163 gtk_button_clicked (GTK_BUTTON (priv->back_button));
164 else
165 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->search_button), FALSE);
166
167 return GDK_EVENT_STOP;
168 }
169
170 return GDK_EVENT_PROPAGATE;
171 }
172
173 static void
ephy_data_view_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)174 ephy_data_view_set_property (GObject *object,
175 guint prop_id,
176 const GValue *value,
177 GParamSpec *pspec)
178 {
179 EphyDataView *self = EPHY_DATA_VIEW (object);
180 EphyDataViewPrivate *priv = ephy_data_view_get_instance_private (self);
181
182 switch (prop_id) {
183 case PROP_TITLE:
184 gtk_header_bar_set_title (GTK_HEADER_BAR (priv->header_bar), g_value_get_string (value));
185 break;
186 case PROP_CLEAR_ACTION_NAME:
187 gtk_actionable_set_action_name (GTK_ACTIONABLE (priv->clear_button), g_value_get_string (value));
188 break;
189 case PROP_CLEAR_ACTION_TARGET:
190 gtk_actionable_set_action_target_value (GTK_ACTIONABLE (priv->clear_button), g_value_get_variant (value));
191 break;
192 case PROP_CLEAR_BUTTON_LABEL:
193 ephy_data_view_set_clear_button_label (self, g_value_get_string (value));
194 break;
195 case PROP_CLEAR_BUTTON_TOOLTIP:
196 ephy_data_view_set_clear_button_tooltip (self, g_value_get_string (value));
197 break;
198 case PROP_SEARCH_DESCRIPTION:
199 gtk_entry_set_placeholder_text (GTK_ENTRY (priv->search_entry), g_value_get_string (value));
200 atk_object_set_description (gtk_widget_get_accessible (GTK_WIDGET (self)), g_value_get_string (value));
201 break;
202 case PROP_EMPTY_TITLE:
203 hdy_status_page_set_title (HDY_STATUS_PAGE (priv->empty_page), g_value_get_string (value));
204 break;
205 case PROP_EMPTY_DESCRIPTION:
206 hdy_status_page_set_description (HDY_STATUS_PAGE (priv->empty_page), g_value_get_string (value));
207 break;
208 case PROP_IS_LOADING:
209 ephy_data_view_set_is_loading (self, g_value_get_boolean (value));
210 break;
211 case PROP_HAS_DATA:
212 ephy_data_view_set_has_data (self, g_value_get_boolean (value));
213 break;
214 case PROP_HAS_SEARCH_RESULTS:
215 ephy_data_view_set_has_search_results (self, g_value_get_boolean (value));
216 break;
217 case PROP_CAN_CLEAR:
218 ephy_data_view_set_can_clear (self, g_value_get_boolean (value));
219 break;
220 default:
221 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
222 break;
223 }
224 }
225
226 static void
ephy_data_view_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)227 ephy_data_view_get_property (GObject *object,
228 guint prop_id,
229 GValue *value,
230 GParamSpec *pspec)
231 {
232 EphyDataView *self = EPHY_DATA_VIEW (object);
233 EphyDataViewPrivate *priv = ephy_data_view_get_instance_private (self);
234
235 switch (prop_id) {
236 case PROP_TITLE:
237 g_value_set_string (value, gtk_header_bar_get_title (GTK_HEADER_BAR (priv->header_bar)));
238 break;
239 case PROP_CLEAR_ACTION_NAME:
240 g_value_set_string (value, gtk_actionable_get_action_name (GTK_ACTIONABLE (priv->clear_button)));
241 break;
242 case PROP_CLEAR_ACTION_TARGET:
243 g_value_set_variant (value, gtk_actionable_get_action_target_value (GTK_ACTIONABLE (priv->clear_button)));
244 break;
245 case PROP_CLEAR_BUTTON_LABEL:
246 g_value_set_string (value, ephy_data_view_get_clear_button_label (self));
247 break;
248 case PROP_CLEAR_BUTTON_TOOLTIP:
249 g_value_set_string (value, ephy_data_view_get_clear_button_tooltip (self));
250 break;
251 case PROP_SEARCH_DESCRIPTION:
252 g_value_set_string (value, gtk_entry_get_placeholder_text (GTK_ENTRY (priv->search_entry)));
253 break;
254 case PROP_EMPTY_TITLE:
255 g_value_set_string (value, hdy_status_page_get_title (HDY_STATUS_PAGE (priv->empty_page)));
256 break;
257 case PROP_EMPTY_DESCRIPTION:
258 g_value_set_string (value, hdy_status_page_get_description (HDY_STATUS_PAGE (priv->empty_page)));
259 break;
260 case PROP_SEARCH_TEXT:
261 g_value_set_string (value, ephy_data_view_get_search_text (self));
262 break;
263 case PROP_IS_LOADING:
264 g_value_set_boolean (value, ephy_data_view_get_is_loading (self));
265 break;
266 case PROP_HAS_DATA:
267 g_value_set_boolean (value, ephy_data_view_get_has_data (self));
268 break;
269 case PROP_HAS_SEARCH_RESULTS:
270 g_value_set_boolean (value, ephy_data_view_get_has_search_results (self));
271 break;
272 case PROP_CAN_CLEAR:
273 g_value_set_boolean (value, ephy_data_view_get_can_clear (self));
274 break;
275 default:
276 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
277 break;
278 }
279 }
280
281 static void
ephy_data_view_finalize(GObject * object)282 ephy_data_view_finalize (GObject *object)
283 {
284 EphyDataView *self = EPHY_DATA_VIEW (object);
285 EphyDataViewPrivate *priv = ephy_data_view_get_instance_private (self);
286
287 g_free (priv->search_text);
288
289 G_OBJECT_CLASS (ephy_data_view_parent_class)->finalize (object);
290 }
291
292 static void
ephy_data_view_add(GtkContainer * container,GtkWidget * child)293 ephy_data_view_add (GtkContainer *container,
294 GtkWidget *child)
295 {
296 EphyDataView *self = EPHY_DATA_VIEW (container);
297 EphyDataViewPrivate *priv = ephy_data_view_get_instance_private (self);
298
299 if (!priv->box) {
300 GTK_CONTAINER_CLASS (ephy_data_view_parent_class)->add (container, child);
301 return;
302 }
303
304 g_assert (!priv->child);
305
306 priv->child = child;
307 gtk_container_add (GTK_CONTAINER (priv->stack), child);
308
309 update (self);
310 }
311
312 static void
ephy_data_view_class_init(EphyDataViewClass * klass)313 ephy_data_view_class_init (EphyDataViewClass *klass)
314 {
315 GObjectClass *object_class = G_OBJECT_CLASS (klass);
316 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
317 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
318
319 object_class->set_property = ephy_data_view_set_property;
320 object_class->get_property = ephy_data_view_get_property;
321 object_class->finalize = ephy_data_view_finalize;
322
323 container_class->add = ephy_data_view_add;
324
325 obj_properties[PROP_TITLE] =
326 g_param_spec_string ("title",
327 "Title",
328 "The title used for the top HdyHeaderBar",
329 NULL,
330 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
331
332 obj_properties[PROP_CLEAR_ACTION_NAME] =
333 g_param_spec_string ("clear-action-name",
334 "'Clear' action name",
335 "The name of the action associated to the 'Clear' button",
336 NULL,
337 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
338
339 obj_properties[PROP_CLEAR_ACTION_TARGET] =
340 g_param_spec_variant ("clear-action-target",
341 "'Clear' action target value",
342 "The parameter for 'Clear' action invocations",
343 G_VARIANT_TYPE_ANY, NULL,
344 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
345
346 obj_properties[PROP_CLEAR_BUTTON_LABEL] =
347 g_param_spec_string ("clear-button-label",
348 "'Clear' button label",
349 "The label of the 'Clear' button",
350 NULL,
351 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
352
353 obj_properties[PROP_CLEAR_BUTTON_TOOLTIP] =
354 g_param_spec_string ("clear-button-tooltip",
355 "'Clear' button tooltip",
356 "The description of the 'Clear' action",
357 NULL,
358 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
359
360 obj_properties[PROP_SEARCH_DESCRIPTION] =
361 g_param_spec_string ("search-description",
362 "'Search' description",
363 "The description of the 'Search' action",
364 NULL,
365 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
366
367 obj_properties[PROP_EMPTY_TITLE] =
368 g_param_spec_string ("empty-title",
369 "'Empty' title",
370 "The title of the 'Empty' state page",
371 NULL,
372 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
373
374 obj_properties[PROP_EMPTY_DESCRIPTION] =
375 g_param_spec_string ("empty-description",
376 "'Empty' description",
377 "The description of the 'Empty' state page",
378 NULL,
379 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
380
381 obj_properties[PROP_SEARCH_TEXT] =
382 g_param_spec_string ("search-text",
383 "Search text",
384 "The text of the search entry",
385 NULL,
386 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
387
388 obj_properties[PROP_IS_LOADING] =
389 g_param_spec_boolean ("is-loading",
390 "Is loading",
391 "Whether the dialog is loading its data",
392 FALSE,
393 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
394
395 obj_properties[PROP_HAS_DATA] =
396 g_param_spec_boolean ("has-data",
397 "Has data",
398 "Whether the dialog has data",
399 FALSE,
400 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
401
402 obj_properties[PROP_HAS_SEARCH_RESULTS] =
403 g_param_spec_boolean ("has-search-results",
404 "Has search results",
405 "Whether the dialog has search results",
406 FALSE,
407 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
408
409 obj_properties[PROP_CAN_CLEAR] =
410 g_param_spec_boolean ("can-clear",
411 "Can clear",
412 "Whether the data can be cleared",
413 FALSE,
414 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
415
416 g_object_class_install_properties (object_class, LAST_PROP, obj_properties);
417
418 signals[BACK_BUTTON_CLICKED] =
419 g_signal_new ("back-button-clicked",
420 EPHY_TYPE_DATA_VIEW,
421 G_SIGNAL_RUN_LAST,
422 0, NULL, NULL, NULL,
423 G_TYPE_NONE, 0);
424
425 /**
426 * EphyLocationEntry::user-changed:
427 * @entry: the object on which the signal is emitted
428 *
429 * Emitted when the user changes the contents of the internal #GtkEntry
430 *
431 */
432 signals[CLEAR_BUTTON_CLICKED] =
433 g_signal_new ("clear-button-clicked",
434 G_OBJECT_CLASS_TYPE (klass),
435 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
436 0, NULL, NULL, NULL,
437 G_TYPE_NONE,
438 0,
439 G_TYPE_NONE);
440
441 gtk_widget_class_set_template_from_resource (widget_class,
442 "/org/gnome/epiphany/gtk/data-view.ui");
443
444 gtk_widget_class_bind_template_child_private (widget_class, EphyDataView, box);
445 gtk_widget_class_bind_template_child_private (widget_class, EphyDataView, header_bar);
446 gtk_widget_class_bind_template_child_private (widget_class, EphyDataView, back_button);
447 gtk_widget_class_bind_template_child_private (widget_class, EphyDataView, clear_button);
448 gtk_widget_class_bind_template_child_private (widget_class, EphyDataView, empty_page);
449 gtk_widget_class_bind_template_child_private (widget_class, EphyDataView, search_bar);
450 gtk_widget_class_bind_template_child_private (widget_class, EphyDataView, search_button);
451 gtk_widget_class_bind_template_child_private (widget_class, EphyDataView, search_entry);
452 gtk_widget_class_bind_template_child_private (widget_class, EphyDataView, spinner);
453 gtk_widget_class_bind_template_child_private (widget_class, EphyDataView, stack);
454
455 gtk_widget_class_bind_template_callback (widget_class, on_back_button_clicked);
456 gtk_widget_class_bind_template_callback (widget_class, on_clear_button_clicked);
457 gtk_widget_class_bind_template_callback (widget_class, on_search_entry_changed);
458 }
459
460 static void
ephy_data_view_init(EphyDataView * self)461 ephy_data_view_init (EphyDataView *self)
462 {
463 EphyDataViewPrivate *priv = ephy_data_view_get_instance_private (self);
464
465 gtk_widget_init_template (GTK_WIDGET (self));
466
467 hdy_search_bar_connect_entry (HDY_SEARCH_BAR (priv->search_bar), GTK_ENTRY (priv->search_entry));
468
469 hdy_status_page_set_icon_name (HDY_STATUS_PAGE (priv->empty_page),
470 APPLICATION_ID "-symbolic");
471
472 update (self);
473 }
474
475 const gchar *
ephy_data_view_get_clear_button_label(EphyDataView * self)476 ephy_data_view_get_clear_button_label (EphyDataView *self)
477 {
478 EphyDataViewPrivate *priv;
479
480 g_assert (EPHY_IS_DATA_VIEW (self));
481
482 priv = ephy_data_view_get_instance_private (self);
483
484 return gtk_button_get_label (GTK_BUTTON (priv->clear_button));
485 }
486
487 void
ephy_data_view_set_clear_button_label(EphyDataView * self,const gchar * label)488 ephy_data_view_set_clear_button_label (EphyDataView *self,
489 const gchar *label)
490 {
491 EphyDataViewPrivate *priv;
492
493 g_assert (EPHY_IS_DATA_VIEW (self));
494
495 priv = ephy_data_view_get_instance_private (self);
496
497 if (g_strcmp0 (gtk_button_get_label (GTK_BUTTON (priv->clear_button)), label) == 0)
498 return;
499
500 gtk_button_set_label (GTK_BUTTON (priv->clear_button), label);
501
502 g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_CLEAR_BUTTON_LABEL]);
503 }
504
505 const gchar *
ephy_data_view_get_clear_button_tooltip(EphyDataView * self)506 ephy_data_view_get_clear_button_tooltip (EphyDataView *self)
507 {
508 EphyDataViewPrivate *priv;
509
510 g_assert (EPHY_IS_DATA_VIEW (self));
511
512 priv = ephy_data_view_get_instance_private (self);
513
514 return gtk_widget_get_tooltip_text (GTK_WIDGET (priv->clear_button));
515 }
516
517 void
ephy_data_view_set_clear_button_tooltip(EphyDataView * self,const gchar * tooltip)518 ephy_data_view_set_clear_button_tooltip (EphyDataView *self,
519 const gchar *tooltip)
520 {
521 EphyDataViewPrivate *priv;
522
523 g_assert (EPHY_IS_DATA_VIEW (self));
524
525 priv = ephy_data_view_get_instance_private (self);
526
527 if (g_strcmp0 (gtk_widget_get_tooltip_text (GTK_WIDGET (priv->clear_button)), tooltip) == 0)
528 return;
529
530 gtk_widget_set_tooltip_text (GTK_WIDGET (priv->clear_button), tooltip);
531
532 g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_CLEAR_BUTTON_TOOLTIP]);
533 }
534
535 gboolean
ephy_data_view_get_is_loading(EphyDataView * self)536 ephy_data_view_get_is_loading (EphyDataView *self)
537 {
538 EphyDataViewPrivate *priv;
539
540 g_assert (EPHY_IS_DATA_VIEW (self));
541
542 priv = ephy_data_view_get_instance_private (self);
543
544 return priv->is_loading;
545 }
546
547 void
ephy_data_view_set_is_loading(EphyDataView * self,gboolean is_loading)548 ephy_data_view_set_is_loading (EphyDataView *self,
549 gboolean is_loading)
550 {
551 EphyDataViewPrivate *priv;
552
553 g_assert (EPHY_IS_DATA_VIEW (self));
554
555 priv = ephy_data_view_get_instance_private (self);
556 is_loading = !!is_loading;
557
558 if (priv->is_loading == is_loading)
559 return;
560
561 priv->is_loading = is_loading;
562
563 update (self);
564
565 g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_IS_LOADING]);
566 }
567
568 gboolean
ephy_data_view_get_has_data(EphyDataView * self)569 ephy_data_view_get_has_data (EphyDataView *self)
570 {
571 EphyDataViewPrivate *priv;
572
573 g_assert (EPHY_IS_DATA_VIEW (self));
574
575 priv = ephy_data_view_get_instance_private (self);
576
577 return priv->has_data;
578 }
579
580 void
ephy_data_view_set_has_data(EphyDataView * self,gboolean has_data)581 ephy_data_view_set_has_data (EphyDataView *self,
582 gboolean has_data)
583 {
584 EphyDataViewPrivate *priv;
585
586 g_assert (EPHY_IS_DATA_VIEW (self));
587
588 priv = ephy_data_view_get_instance_private (self);
589 has_data = !!has_data;
590
591 if (priv->has_data == has_data)
592 return;
593
594 priv->has_data = has_data;
595
596 update (self);
597
598 g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_HAS_DATA]);
599 }
600
601 gboolean
ephy_data_view_get_has_search_results(EphyDataView * self)602 ephy_data_view_get_has_search_results (EphyDataView *self)
603 {
604 EphyDataViewPrivate *priv;
605
606 g_assert (EPHY_IS_DATA_VIEW (self));
607
608 priv = ephy_data_view_get_instance_private (self);
609
610 return priv->has_search_results;
611 }
612
613 void
ephy_data_view_set_has_search_results(EphyDataView * self,gboolean has_search_results)614 ephy_data_view_set_has_search_results (EphyDataView *self,
615 gboolean has_search_results)
616 {
617 EphyDataViewPrivate *priv;
618
619 g_assert (EPHY_IS_DATA_VIEW (self));
620
621 priv = ephy_data_view_get_instance_private (self);
622 has_search_results = !!has_search_results;
623
624 if (priv->has_search_results == has_search_results)
625 return;
626
627 priv->has_search_results = has_search_results;
628
629 update (self);
630
631 g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_HAS_SEARCH_RESULTS]);
632 }
633
634 gboolean
ephy_data_view_get_can_clear(EphyDataView * self)635 ephy_data_view_get_can_clear (EphyDataView *self)
636 {
637 EphyDataViewPrivate *priv;
638
639 g_assert (EPHY_IS_DATA_VIEW (self));
640
641 priv = ephy_data_view_get_instance_private (self);
642
643 return priv->can_clear;
644 }
645
646 void
ephy_data_view_set_can_clear(EphyDataView * self,gboolean can_clear)647 ephy_data_view_set_can_clear (EphyDataView *self,
648 gboolean can_clear)
649 {
650 EphyDataViewPrivate *priv;
651
652 g_assert (EPHY_IS_DATA_VIEW (self));
653
654 priv = ephy_data_view_get_instance_private (self);
655 can_clear = !!can_clear;
656
657 if (priv->can_clear == can_clear)
658 return;
659
660 priv->can_clear = can_clear;
661
662 update (self);
663
664 g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_CAN_CLEAR]);
665 }
666
667 const gchar *
ephy_data_view_get_search_text(EphyDataView * self)668 ephy_data_view_get_search_text (EphyDataView *self)
669 {
670 EphyDataViewPrivate *priv;
671
672 g_assert (EPHY_IS_DATA_VIEW (self));
673
674 priv = ephy_data_view_get_instance_private (self);
675
676 return priv->search_text;
677 }
678