+/* Application UI data struct */
+typedef struct _BirthdayData BirthdayData;
+struct _BirthdayData {
+ GtkWidget *window;
+ GtkWidget *label;
+ GtkWidget *view;
+ GtkWidget *search;
+
+ GtkWidget *tree_view;
+ GtkTreeModel *sorted;
+ GtkTreeModel *filter;
+
+ gchar *searched_name;
+ gboolean found;
+
+ guint n_contacts;
+};
+
+static gboolean
+birthday_filered_view_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ BirthdayData *priv;
+ gchar *fullname = NULL, *ascii_searched_name = NULL, *ascii_fullname = NULL;
+ gboolean found = FALSE;
+
+ g_return_val_if_fail (data, FALSE);
+ priv = (BirthdayData *) data;
+
+ if (priv->searched_name == NULL) {
+ priv->found = TRUE;
+ return TRUE;
+ }
+
+ ascii_searched_name = g_ascii_strdown (priv->searched_name, strlen (priv->searched_name));
+
+ gtk_tree_model_get (model, iter, COLUMN_FULLNAME, &fullname, -1);
+ if (fullname) {
+ ascii_fullname = g_ascii_strdown (fullname, strlen (fullname));
+ g_free (fullname);
+ }
+
+ if (g_strstr_len (ascii_fullname, strlen (ascii_fullname), ascii_searched_name) != NULL)
+ found = TRUE;
+
+ if (ascii_searched_name)
+ g_free (ascii_searched_name);
+
+ if (ascii_fullname)
+ g_free (ascii_fullname);
+
+ if (found)
+ priv->found = TRUE;
+
+ return found;
+}
+
+static void
+sort_by_name_clicked (GtkButton *button,
+ gpointer data)
+{
+ BirthdayData *priv;
+
+ g_return_if_fail (data);
+ priv = (BirthdayData *) data;
+
+ if (priv->sorted) {
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->sorted),
+ COLUMN_FULLNAME, GTK_SORT_ASCENDING);
+ }
+}
+
+static void
+sort_by_date_clicked (GtkButton *button,
+ gpointer data)
+{
+ BirthdayData *priv;
+
+ g_return_if_fail (data);
+ priv = (BirthdayData *) data;
+
+ if (priv->sorted) {
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->sorted),
+ COLUMN_NEXT_BIRTHDAY, GTK_SORT_ASCENDING);
+ }
+}
+
+static void
+search_menu_clicked (GtkButton *button,
+ gpointer data)
+{
+ BirthdayData *priv;
+ GtkWidget *entry;
+
+ g_return_if_fail (data);
+ priv = (BirthdayData *) data;
+
+ /* show search bar */
+ gtk_widget_show (priv->search);
+
+ /* focus on search entry */
+ entry = g_object_get_data (G_OBJECT (priv->search), "entry");
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ gtk_widget_grab_focus (GTK_WIDGET (entry));
+
+ /* refilter tree view */
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter));
+}
+
+static void
+on_search_entry_changed (GtkEditable *editable,
+ gpointer data)
+{
+ BirthdayData *priv;
+
+ g_return_if_fail (data);
+ priv = (BirthdayData *) data;
+
+ priv->found = FALSE;
+
+ if (priv->searched_name)
+ g_free (priv->searched_name);
+ priv->searched_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (editable)));
+
+ /* refilter tree view */
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter));
+
+ if (priv->found) {
+ /* hide label */
+ gtk_widget_hide (priv->label);
+
+ /* show tree view */
+ gtk_widget_show (priv->view);
+ } else {
+ /* hide label */
+ gtk_widget_show (priv->label);
+ gtk_label_set_text (GTK_LABEL (priv->label), _("No search results"));
+
+ /* show tree view */
+ gtk_widget_hide (priv->view);
+ }
+
+ /* ugly, but working way how to scroll to the first row */
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->tree_view),
+ gtk_tree_path_new_from_string ("0"), NULL, FALSE, 0, 0);
+}
+
+static void
+on_search_close_clicked (GtkButton *button,
+ gpointer data)
+{
+ BirthdayData *priv;
+
+ g_return_if_fail (data);
+ priv = (BirthdayData *) data;
+
+ /* hide search bar */
+ gtk_widget_hide (priv->search);
+
+ /* hide label */
+ gtk_widget_hide (priv->label);
+
+ /* show tree view */
+ gtk_widget_show (priv->view);
+
+ /* clear searched name */
+ if (priv->searched_name)
+ g_free (priv->searched_name);
+ priv->searched_name = NULL;
+
+ /* refilter tree view */
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter));
+
+ /* ugly, but working way how to scroll to the first row */
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->tree_view),
+ gtk_tree_path_new_from_string ("0"), NULL, FALSE, 0, 0);
+}
+
+
+static gboolean
+on_key_press_event (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer data)
+{
+ BirthdayData *priv;
+
+ g_return_val_if_fail (data, TRUE);
+ priv = (BirthdayData *) data;
+
+ if (priv->n_contacts == 0)
+ return FALSE;
+
+ if ((event->keyval > GDK_space) && (event->keyval <= GDK_stricteq) && !GTK_WIDGET_VISIBLE (priv->search)) {
+ GtkWidget *entry;
+
+ /* show search bar */
+ gtk_widget_show (priv->search);
+
+ /* focus on search entry */
+ entry = g_object_get_data (G_OBJECT (priv->search), "entry");
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ gtk_widget_grab_focus (GTK_WIDGET (entry));
+
+ /* refilter tree view */
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter));
+ }
+
+ return FALSE;
+}
+