
/*
 * Osmo - a handy personal organizer
 *
 * Copyright (C) 2007 Tomasz Maka <pasp@users.sourceforge.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "about.h"
#include "backup.h"
#include "contacts.h"
#include "i18n.h"
#include "contacts_items.h"
#include "utils.h"
#include "utils_date.h"
#include "utils_gui.h"
#include "options_prefs.h"
#include "preferences_gui.h"
#include "stock_icons.h"
#include "contacts_birthdays.h"
#include "contacts_import.h"
#include "contacts_export.h"
#include "calendar_utils.h"

#ifdef CONTACTS_ENABLED

/*============================================================================*/

static void
show_preferences_window_cb (GtkToolButton *toolbutton, gpointer data)
{
    GUI *appGUI = (GUI *) data;
    appGUI->opt->window = opt_create_preferences_window (appGUI);
    gtk_widget_show (appGUI->opt->window);

    gint page = gtk_notebook_page_num (GTK_NOTEBOOK (appGUI->opt->notebook), appGUI->opt->contacts);
    gtk_notebook_set_current_page (GTK_NOTEBOOK (appGUI->opt->notebook), page);
}

/*------------------------------------------------------------------------------*/


void
set_export_active (GUI *appGUI) {

GtkTreeIter iter;
gboolean state;

    state = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(appGUI->cnt->contacts_filter), &iter);
    gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->export_toolbar_button), state);
}

/*------------------------------------------------------------------------------*/

gboolean
find_combo_box_focus_cb (GtkWidget *widget, GtkDirectionType *arg1, gpointer user_data) {
    return TRUE;
}

/*------------------------------------------------------------------------------*/

void
contacts_panel_close_desc_cb (GtkWidget *widget, gpointer data) {
    GtkPaned *paned;
    gint max_position;
    GUI *appGUI = (GUI *)data;

    paned = GTK_PANED (appGUI->cnt->contacts_paned);
    g_object_get(paned, "max-position", &max_position, NULL);
    gtk_paned_set_position(paned, max_position);
}

/*------------------------------------------------------------------------------*/

gboolean
contacts_list_filter_cb (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) {

const gchar *text;
gchar *value = NULL;
gint i;
guint32 date;
gboolean result;

    GUI *appGUI = (GUI *)data;

    text = gtk_entry_get_text(GTK_ENTRY(appGUI->cnt->contacts_find_entry));

    if (text == NULL) {
        return TRUE;
    }
    if (!g_utf8_strlen(text, -1)) {
        return TRUE;
    }

    if (config.find_mode == CONTACTS_FF_ALL_FIELDS) {
        result = FALSE;
        for (i = 0; i < CONTACTS_NUM_COLUMNS && !result; i++) {

            if (i != COLUMN_PHOTO && i != COLUMN_ID) {
                if (i == COLUMN_BIRTH_DAY_DATE || i == COLUMN_NAME_DAY_DATE) {
                    gtk_tree_model_get(model, iter, i, &date, -1);
                    if (date == 0) {
                        value = NULL;
                    } else {
                        if (i == COLUMN_BIRTH_DAY_DATE) {
                            value = g_strdup((const gchar *) julian_to_str(date, DATE_FULL, config.override_locale_settings));
                        } else {
                            value = g_strdup((const gchar *) julian_to_str(date, DATE_NAME_DAY, config.override_locale_settings));
                        }
                    }
                } else {
                    gtk_tree_model_get(model, iter, i, &value, -1);
                }

                if (value != NULL) {
                    result = utl_text_strcasestr(value, text);
                    g_free(value);
                }
            }
        }
    } else {
        if (config.find_mode == CONTACTS_FF_FIRST_NAME) {
            gtk_tree_model_get(model, iter, COLUMN_FIRST_NAME, &value, -1);
        } else if (config.find_mode == CONTACTS_FF_LAST_NAME) {
            gtk_tree_model_get(model, iter, COLUMN_LAST_NAME, &value, -1);
        } else if (config.find_mode == CONTACTS_FF_TAGS) {
            gtk_tree_model_get(model, iter, COLUMN_TAGS, &value, -1);
        }

        if (value == NULL) {
            result = FALSE;
        } else {
            result = utl_text_strcasestr(value, text);
        }
        g_free(value);
    }

    return result;
}

/*------------------------------------------------------------------------------*/

void
contacts_select_first_position_in_list (GUI *appGUI) {

GtkTreeIter     iter;
GtkTreePath     *path;

    /* set cursor at first position */
    if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(appGUI->cnt->contacts_list_store), &iter) == TRUE) {
        path = gtk_tree_model_get_path (GTK_TREE_MODEL(appGUI->cnt->contacts_list_store), &iter);
        if (path != NULL) {
            gtk_tree_view_set_cursor (GTK_TREE_VIEW (appGUI->cnt->contacts_list), path, NULL, FALSE);
            gtk_tree_path_free (path);
        }
    }
}

/*------------------------------------------------------------------------------*/

void
contacts_item_selected_cb (GtkTreeSelection *selection, GUI *appGUI)
{
    GtkTreeModel *model;
    GtkTreeIter iter;
    gint selection_size;
    gboolean address_available = FALSE, additional_info = FALSE;
    guint32 date;
    gchar *fname, *sname, *lname, *html, *photo;
    gchar tmpbuf[BUFFER_SIZE], htmpbuf[BUFFER_SIZE];
    gint i;

    selection_size = gtk_tree_selection_count_selected_rows(selection);
    if (selection_size > 1) {
        gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->edit_toolbar_button), FALSE);
        gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->delete_toolbar_button), TRUE);
        gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->map_location_toolbar_button), FALSE);

#ifdef HAVE_LIBWEBKIT
        webkit_web_view_load_html(appGUI->cnt->html_webkitview, "", "file://");
#endif  /* LIBWEBKIT */
    } else if (selection_size == 1) {
        gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->edit_toolbar_button), TRUE);
        gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->delete_toolbar_button), TRUE);

        address_available = check_address(HOME_ADDRESS, appGUI);
        if (address_available == FALSE) {
            address_available = check_address(WORK_ADDRESS, appGUI);
        }

        gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->map_location_toolbar_button), address_available);

        /****************************************************************/

        html = g_strdup_printf(
                "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"
                "<style type=\"text/css\">\n"
                "body { font-size: %dpx; }\n"
                "h1 { font-size: %dpx; font-weight: bold; font-style: italic; }\n"
                "pre { white-space: pre; margin-top: 0; margin-left: 2px; margin-bottom: 2px; }\n"
                "a { color: %s; }\n"
                "table { width: 100%%; }\n"
                "td.tag { width: 30%%; }\n"
                "td.value { width: 70%%; }\n"
                ".tag { font-weight: bold; color: %s; }\n"
#ifdef HAVE_LIBWEBKIT
                ".photo { position: absolute; top: 4; right: 4; width: %dpx; border: 1px solid #000; float: right; }\n"
#endif  /* HAVE_LIBWEBKIT */
                "</style>\n</head>\n\n<body>\n",
                config.contact_item_font_size, config.contact_name_font_size,
                config.contact_link_color, config.contact_tag_color, config.photo_width);

        /****************************************************************/

        iter = utl_gui_get_first_selection_iter(selection, &model);
        gtk_tree_model_get(model, &iter,
                COLUMN_FIRST_NAME, &fname,
                COLUMN_SECOND_NAME, &sname,
                COLUMN_LAST_NAME, &lname,
                COLUMN_PHOTO, &photo,
                -1);

        if (!fname) fname = g_strdup("");
        if (!sname) sname = g_strdup("");
        if (!lname) lname = g_strdup("");

        g_snprintf(htmpbuf, BUFFER_SIZE, "<h1>%s %s %s</h1>\n", fname, sname, lname);
        html = utl_strconcat(html, htmpbuf, NULL);
        g_free(fname);
        g_free(sname);
        g_free(lname);

        /* insert photo */
        if (photo != NULL) {
#ifdef HAVE_LIBWEBKIT
            g_snprintf(htmpbuf, BUFFER_SIZE, "<img src=\"file://%s\" alt=\"\" class=\"photo\">", photo);
#endif  /* HAVE_LIBWEBKIT */
            html = utl_strconcat(html, htmpbuf, NULL);
            g_free(photo);
        }

        g_snprintf(htmpbuf, BUFFER_SIZE, "<table>\n");
        html = utl_strconcat(html, htmpbuf, NULL);

        for (i = 0; i < CONTACTS_NUM_COLUMNS; i++) {
            gchar *text;
            if ((i == COLUMN_ID) ||
                    (i == COLUMN_PHOTO) ||
                    (i == COLUMN_FIRST_NAME) ||
                    (i == COLUMN_SECOND_NAME) ||
                    (i == COLUMN_LAST_NAME) ||
                    (i == COLUMN_GROUP))
                continue;

            if (i == COLUMN_BIRTH_DAY_DATE || i == COLUMN_NAME_DAY_DATE) {
                gtk_tree_model_get(model, &iter, i, &date, -1);
                if (date == 0) {
                    text = NULL;
                } else {
                    if (i == COLUMN_BIRTH_DAY_DATE) {
                        text = g_strdup((const gchar *) julian_to_str(date, DATE_FULL, config.override_locale_settings));
                    } else {
                        text = g_strdup((const gchar *) julian_to_str(date, DATE_NAME_DAY, config.override_locale_settings));
                    }
                }
            } else {
                gtk_tree_model_get(model, &iter, i, &text, -1);
            }

            if (text == NULL || !strlen(text)) {
                g_free(text);
                continue;
            }

            g_snprintf(htmpbuf, BUFFER_SIZE, "<tr>");
            html = utl_strconcat(html, htmpbuf, NULL);

            if ((i >= COLUMN_HOME_PHONE_2 && i <= COLUMN_HOME_PHONE_4) ||
                    (i >= COLUMN_WORK_PHONE_2 && i <= COLUMN_WORK_PHONE_4) ||
                    (i >= COLUMN_CELL_PHONE_2 && i <= COLUMN_CELL_PHONE_4) ||
                    (i >= COLUMN_EMAIL_2 && i <= COLUMN_EMAIL_4) ||
                    (i >= COLUMN_WWW_2 && i <= COLUMN_WWW_4)) {
                tmpbuf[0] = '\0';
            } else {
                g_snprintf(tmpbuf, BUFFER_SIZE, "%s:", gettext(appGUI->cnt->contact_fields_tags_name[2 * i]));
            }

            if (i == COLUMN_INFO) {

                gchar *tmp = utl_text_to_html(text, FALSE, TRUE);

                if (tmp != NULL) {
                    additional_info = TRUE;

                    gchar *tmp2 = utl_text_replace(tmp, REGEX_URL, "<a href=\"\\0\">\\0</a>");
                    g_free(tmp);
                    gchar *tmp3 = utl_text_replace(tmp2, REGEX_EMAIL, "<a href=\"mailto:\\0\">\\0</a>");
                    g_free(tmp2);

                    g_snprintf(htmpbuf, BUFFER_SIZE,
                            "<td colspan=\"2\" class=\"tag\">%s</td></tr></table>\n<pre>%s</pre>\n", tmpbuf, tmp3);

                    html = utl_strconcat(html, htmpbuf, NULL);
                    g_free(tmp3);
                }

            } else {

                g_snprintf(htmpbuf, BUFFER_SIZE, "<td class=\"tag\">%s</td>", tmpbuf);
                html = utl_strconcat(html, htmpbuf, NULL);

            }

            if (i == COLUMN_BLOG || (i >= COLUMN_EMAIL_1 && i <= COLUMN_EMAIL_4) || (i >= COLUMN_WWW_1 && i <= COLUMN_WWW_4)) {

                gchar *protocol;
                if (i >= COLUMN_EMAIL_1 && i <= COLUMN_EMAIL_4) {
                    protocol = "mailto:";
                } else if (!utl_text_match(text, REGEX_URI_PROTO)) {
                    protocol = "http://";
                } else {
                    protocol = "";
                }
                g_snprintf(htmpbuf, BUFFER_SIZE, "<td class=\"value\"><a href=\"%s%s\">%s</a></td></tr>\n", protocol, text, text);
                html = utl_strconcat(html, htmpbuf, NULL);

            } else if (i != COLUMN_INFO) {

                g_snprintf(htmpbuf, BUFFER_SIZE, "<td class=\"value\">%s</td></tr>\n", text);
                html = utl_strconcat(html, htmpbuf, NULL);

            }
            g_free(text);
        }

        if (additional_info == TRUE) {
            g_snprintf(htmpbuf, BUFFER_SIZE, "</body>\n</html>\n");
        } else {
            g_snprintf(htmpbuf, BUFFER_SIZE, "</table>\n</body>\n</html>\n");
        }
        html = utl_strconcat(html, htmpbuf, NULL);

#ifdef HAVE_LIBWEBKIT
        webkit_web_view_load_html(appGUI->cnt->html_webkitview, html, "file://");
#endif  /* LIBWEBKIT */

        g_free(html);
    } else {

        gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->edit_toolbar_button), FALSE);
        gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->delete_toolbar_button), FALSE);
        gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->map_location_toolbar_button), FALSE);

#ifdef HAVE_LIBWEBKIT
        webkit_web_view_load_html(appGUI->cnt->html_webkitview, "", "file://");
#endif  /* LIBWEBKIT */
    }
    set_export_active(appGUI);
}

/*------------------------------------------------------------------------------*/

gboolean
contacts_search_entry_changed_cb (GtkEditable *editable, gpointer user_data) {
    GUI *appGUI = (GUI *)user_data;

    gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(appGUI->cnt->contacts_filter));
    set_export_active (appGUI);

    return FALSE;
}

/*------------------------------------------------------------------------------*/

void
contacts_find_type_selected_cb (GtkComboBox *widget, gpointer user_data) {

GtkTreeIter iter;
gboolean has_next;

    GUI *appGUI = (GUI *)user_data;

    config.find_mode = gtk_combo_box_get_active (widget);

    if(strlen(gtk_entry_get_text (GTK_ENTRY(appGUI->cnt->contacts_find_entry)))) {
        gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(appGUI->cnt->contacts_filter));

        has_next = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (appGUI->cnt->contacts_filter), &iter);
        gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->export_toolbar_button), has_next);
        if (has_next) {
            GtkTreePath *path = gtk_tree_path_new_first();
            if (path != NULL) {
                gtk_tree_view_set_cursor(GTK_TREE_VIEW(appGUI->cnt->contacts_list), path, NULL, FALSE);
            }
            gtk_tree_path_free(path);
        }
    }
}

/*------------------------------------------------------------------------------*/

gint
contacts_column_sort_function (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gint sort_column, GUI *appGUI)
{
    gchar *last_name_a, *last_name_b;
    gchar *group_a, *group_b;
    gchar *first_name_a, *first_name_b;
    gint diff;

    if (iter_a == NULL || iter_b == NULL) {
        return 0;
    }
    
    
    switch(sort_column) {
        case COLUMN_GROUP:
            gtk_tree_model_get(model, iter_a, COLUMN_GROUP, &group_a, -1);
            gtk_tree_model_get(model, iter_b, COLUMN_GROUP, &group_b, -1);
            diff = utl_text_strcmp(group_a, group_b);
            g_free(group_a);
            g_free(group_b);
            break;
        case COLUMN_FIRST_NAME:
            gtk_tree_model_get(model, iter_a, COLUMN_FIRST_NAME, &first_name_a, -1);
            gtk_tree_model_get(model, iter_b, COLUMN_FIRST_NAME, &first_name_b, -1);
            diff = utl_text_strcmp(first_name_a, first_name_b);
            g_free(first_name_a);
            g_free(first_name_b);
            break;
        case COLUMN_LAST_NAME:
            gtk_tree_model_get(model, iter_a, COLUMN_LAST_NAME, &last_name_a, -1);
            gtk_tree_model_get(model, iter_b, COLUMN_LAST_NAME, &last_name_b, -1);
            diff = utl_text_strcmp(last_name_a, last_name_b);
            g_free(last_name_a);
            g_free(last_name_b);
            break;
        default:
            diff = 0;
    }
    return diff;
}

/*------------------------------------------------------------------------------*/

gint
contacts_column_sort_by_group_function (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer user_data)
{
    return contacts_column_sort_function(model, iter_a, iter_b, COLUMN_GROUP, (GUI *)user_data);
}

/*------------------------------------------------------------------------------*/

gint
contacts_column_sort_by_first_name_function (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer user_data)
{
    return contacts_column_sort_function(model, iter_a, iter_b, COLUMN_FIRST_NAME, (GUI *)user_data);
}

/*------------------------------------------------------------------------------*/

gint
contacts_column_sort_by_last_name_function (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer user_data)
{
    return contacts_column_sort_function(model, iter_a, iter_b, COLUMN_LAST_NAME, (GUI *)user_data);
}


/*------------------------------------------------------------------------------*/

void contacts_sort_column_changed_cb (GtkTreeSortable *sortable, gpointer user_data)
{
    GtkSortType sort_order;

    gtk_tree_sortable_get_sort_column_id(sortable, &config.contacts_sorting_column, &sort_order);
    config.contacts_sorting_order = sort_order;
}
/*------------------------------------------------------------------------------*/

static void
contacts_add_item_cb (GtkToolButton *toolbutton, gpointer data) {

    GUI *appGUI = (GUI *)data;
    contacts_add_edit_dialog_show (FALSE, appGUI);
}

/*------------------------------------------------------------------------------*/

static void
contacts_edit_item_cb (GtkToolButton *toolbutton, gpointer data) {

    GUI *appGUI = (GUI *)data;

    if (gtk_tree_selection_count_selected_rows (appGUI->cnt->contacts_list_selection) == 1) {
        contacts_add_edit_dialog_show (TRUE, appGUI);
    }
}

/*------------------------------------------------------------------------------*/

static void
contacts_remove_item_cb (GtkToolButton *toolbutton, gpointer data) {

    GUI *appGUI = (GUI *)data;
    contacts_remove_dialog_show(appGUI);
}

/*------------------------------------------------------------------------------*/

static void
contacts_birthdays_item_cb (GtkToolButton *toolbutton, gpointer data) {

    GUI *appGUI = (GUI *)data;
    contacts_create_birthdays_window (appGUI);
}

/*------------------------------------------------------------------------------*/

static void
contacts_map_location_cb (GtkToolButton *toolbutton, gpointer data) {

gint response = -1;
GtkWidget *info_dialog = NULL;
GtkWidget *hbox;
GtkWidget *home_addr_radiobutton;
GtkWidget *work_addr_radiobutton;
GSList *hw_radiobutton_group = NULL;


    GUI *appGUI = (GUI *)data;

    if (gtk_tree_selection_count_selected_rows (appGUI->cnt->contacts_list_selection) == 1) {
    
        if (check_address (HOME_ADDRESS, appGUI) && check_address (WORK_ADDRESS, appGUI)) {
            GtkWidget *message_area;

            info_dialog = gtk_message_dialog_new (GTK_WINDOW(appGUI->main_window),
                                                  GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
                                                  GTK_MESSAGE_INFO, GTK_BUTTONS_OK_CANCEL, 
                                                  "\n%s:", _("Please select address"));

            gtk_window_set_title(GTK_WINDOW(info_dialog), _("Information"));
            gtk_widget_show (info_dialog);

            hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
            message_area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(info_dialog));
            gtk_box_pack_start (GTK_BOX(message_area), hbox, FALSE, TRUE, 2);
            gtk_widget_show (hbox);

            work_addr_radiobutton = gtk_radio_button_new_with_mnemonic (NULL, _("Work"));
            gtk_widget_show (work_addr_radiobutton);
            gtk_box_pack_end (GTK_BOX(hbox), work_addr_radiobutton, FALSE, TRUE, 2);
            gtk_radio_button_set_group (GTK_RADIO_BUTTON (work_addr_radiobutton), hw_radiobutton_group);
            hw_radiobutton_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (work_addr_radiobutton));

            home_addr_radiobutton = gtk_radio_button_new_with_mnemonic (NULL, _("Home"));
            gtk_widget_show (home_addr_radiobutton);
            gtk_box_pack_end (GTK_BOX(hbox), home_addr_radiobutton, FALSE, TRUE, 2);
            gtk_radio_button_set_group (GTK_RADIO_BUTTON (home_addr_radiobutton), hw_radiobutton_group);
            hw_radiobutton_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (home_addr_radiobutton));

            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (home_addr_radiobutton), TRUE);

            response = gtk_dialog_run(GTK_DIALOG(info_dialog));

            if (response == GTK_RESPONSE_OK) {
                if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (home_addr_radiobutton)) == TRUE) {
                    show_contact_location_on_map (HOME_ADDRESS, appGUI);
                } else {
                    show_contact_location_on_map (WORK_ADDRESS, appGUI);
                }
            }

            gtk_widget_destroy(info_dialog);

        } else {
            if (check_address (HOME_ADDRESS, appGUI)) {
                show_contact_location_on_map (HOME_ADDRESS, appGUI);
            } else {
                show_contact_location_on_map (WORK_ADDRESS, appGUI);
            }
        }
    }
}

/*------------------------------------------------------------------------------*/

static void
contacts_export_items_cb (GtkToolButton *toolbutton, gpointer data) {

    GUI *appGUI = (GUI *)data;
    contacts_create_export_window(appGUI);
}

/*------------------------------------------------------------------------------*/

static void
contacts_import_items_cb (GtkToolButton *toolbutton, gpointer data) {

    GUI *appGUI = (GUI *)data;
    import_contacts_from_csv_file (appGUI);
}

/*------------------------------------------------------------------------------*/

gint
contacts_list_dbclick_cb(GtkWidget * widget, GdkEventButton * event, gpointer func_data) {

    GUI *appGUI = (GUI *)func_data;

    if ((event->type==GDK_2BUTTON_PRESS) && (event->button == 1)) {
        contacts_edit_item_cb (NULL, appGUI);
        return TRUE;
    }

    return FALSE;
}

/*------------------------------------------------------------------------------*/

void
contacts_selection_activate (gboolean active, GUI *appGUI) {
    if (active == TRUE) {
        g_signal_connect(G_OBJECT(appGUI->cnt->contacts_list_selection), "changed",
                         G_CALLBACK(contacts_item_selected_cb), appGUI);
    } else {
        g_signal_handlers_disconnect_by_func (G_OBJECT (appGUI->cnt->contacts_list_selection),
                                              G_CALLBACK (contacts_item_selected_cb), appGUI);
    }
}

/*------------------------------------------------------------------------------*/

void
store_contact_columns_info (GUI *appGUI) {

    gint n;

    config.contacts_column_idx_0 = utl_gui_get_column_position (appGUI->cnt->contacts_columns[COLUMN_GROUP],
                                                                GTK_TREE_VIEW(appGUI->cnt->contacts_list), MAX_VISIBLE_CONTACT_COLUMNS, appGUI);
    config.contacts_column_idx_1 = utl_gui_get_column_position (appGUI->cnt->contacts_columns[COLUMN_FIRST_NAME], 
                                                                GTK_TREE_VIEW(appGUI->cnt->contacts_list), MAX_VISIBLE_CONTACT_COLUMNS, appGUI);
    config.contacts_column_idx_2 = utl_gui_get_column_position (appGUI->cnt->contacts_columns[COLUMN_LAST_NAME], 
                                                                GTK_TREE_VIEW(appGUI->cnt->contacts_list), MAX_VISIBLE_CONTACT_COLUMNS, appGUI);

    n = gtk_tree_view_column_get_width(gtk_tree_view_get_column (GTK_TREE_VIEW(appGUI->cnt->contacts_list), 0));
    if (n > 1) {
        config.contacts_column_idx_0_width = n;
    }
    n = gtk_tree_view_column_get_width(gtk_tree_view_get_column (GTK_TREE_VIEW(appGUI->cnt->contacts_list), 1));
    if (n > 1) {
        config.contacts_column_idx_1_width = n;
    }
    n = gtk_tree_view_column_get_width(gtk_tree_view_get_column (GTK_TREE_VIEW(appGUI->cnt->contacts_list), 2));
    if (n > 1) {
        config.contacts_column_idx_2_width = n;
    }
}

/*------------------------------------------------------------------------------*/

void
set_contacts_columns_width (GUI *appGUI) {

    GtkTreeViewColumn   *col;
    gint w;

    w = 2 * utl_gui_get_sw_vscrollbar_width (appGUI->cnt->scrolled_win);

    col = gtk_tree_view_get_column (GTK_TREE_VIEW(appGUI->cnt->contacts_list), COLUMN_GROUP);
    if (gtk_tree_view_column_get_visible(col) == TRUE && config.contacts_column_idx_0_width > 0) {
        gtk_tree_view_column_set_fixed_width (col, config.contacts_column_idx_0_width);
    }
    col = gtk_tree_view_get_column (GTK_TREE_VIEW(appGUI->cnt->contacts_list), COLUMN_FIRST_NAME);
    if (gtk_tree_view_column_get_visible(col) == TRUE && config.contacts_column_idx_1_width > 0) {
        gtk_tree_view_column_set_fixed_width (col, config.contacts_column_idx_1_width);
    }
    col = gtk_tree_view_get_column (GTK_TREE_VIEW(appGUI->cnt->contacts_list), COLUMN_LAST_NAME);
    if (gtk_tree_view_column_get_visible(col) == TRUE && config.contacts_column_idx_2_width > w) {
        gtk_tree_view_column_set_fixed_width (col, config.contacts_column_idx_2_width - w);
    }
}

/*------------------------------------------------------------------------------*/

void
cnt_clear_find_cb (GtkWidget *widget, gpointer user_data)
{
    GUI *appGUI = (GUI *) user_data;
    if (strlen(gtk_entry_get_text(GTK_ENTRY(appGUI->cnt->contacts_find_entry)))) {
        gtk_entry_set_text(GTK_ENTRY(appGUI->cnt->contacts_find_entry), "");
    }
    gtk_widget_grab_focus (appGUI->cnt->contacts_find_entry);
}

/*------------------------------------------------------------------------------*/

static void
create_contact_fields(GUI *appGUI)
{
static gchar *contact_fields_tags_name[] = {
    N_("Group"), "group", 
    N_("First name"), "first_name", N_("Last name"), "last_name", 
    N_("Second name"), "second_name", 
    N_("Nickname"), "nickname", N_("Tags"), "tags", 
    N_("Birthday date"), "birthday_date", N_("Name day date"), "name_day_date",

    /*--------------------------------------------------*/
    N_("Home address"), "home_address", N_("Home postcode"), "home_postcode", N_("Home city"), 
    "home_city", N_("Home state"), "home_state", N_("Home country"), "home_country",
    /*--------------------------------------------------*/

    N_("Organization"), "organization", N_("Department"), "department",

    /*--------------------------------------------------*/
    N_("Work address"), "work_address", N_("Work postcode"), "work_postcode", N_("Work city"), 
    "work_city", N_("Work state"), "work_state", N_("Work country"), "work_country",
    /*--------------------------------------------------*/

    N_("Fax"), "work_fax",

    /*--------------------------------------------------*/
    N_("Home phone"), "home_phone_1", N_("Home phone 2"), "home_phone_2",
    N_("Home phone 3"), "home_phone_3", N_("Home phone 4"), "home_phone_4",
    N_("Work phone"), "work_phone_1", N_("Work phone 2"), "work_phone_2",
    N_("Work phone 3"), "work_phone_3", N_("Work phone 4"), "work_phone_4",
    N_("Cell phone"), "cell_phone_1", N_("Cell phone 2"), "cell_phone_2",
    N_("Cell phone 3"), "cell_phone_3", N_("Cell phone 4"), "cell_phone_4",
    N_("E-Mail"), "email_1", N_("E-Mail 2"), "email_2", N_("E-Mail 3"), "email_3", 
    N_("E-Mail 4"), "email_4", N_("WWW"), "www_1", N_("WWW 2"), "www_2", N_("WWW 3"), "www_3", 
    N_("WWW 4"), "www_4",
    /*--------------------------------------------------*/

    N_("IM Gadu-Gadu"), "im_gg", N_("IM Yahoo"), "im_yahoo", N_("IM MSN"), "im_msn",
    N_("IM ICQ"), "im_icq", N_("IM AOL"), "im_aol",
    N_("IM Jabber"), "im_jabber", N_("IM Skype"), "im_skype", N_("IM Tlen"), "im_tlen",
    N_("Blog"), "blog", N_("Photo"), "photo_path", N_("Additional info"), "additional_info", "ID", "id"
};

    appGUI->cnt->contact_fields_tags_name = contact_fields_tags_name;
}

/*------------------------------------------------------------------------------*/

void
create_contacts_list_store(GUI* appGUI)
{
    GType contact_columns_types[CONTACTS_NUM_COLUMNS];
    gint i;

    for(i=0; i< CONTACTS_NUM_COLUMNS; i++) {
        if (i == COLUMN_BIRTH_DAY_DATE || i == COLUMN_NAME_DAY_DATE || i == COLUMN_ID) {
            contact_columns_types[i] = G_TYPE_UINT;
        } else {
            contact_columns_types[i] = G_TYPE_STRING;
        }
    }
    appGUI->cnt->contacts_list_store = gtk_list_store_newv(CONTACTS_NUM_COLUMNS, &contact_columns_types[0]);
}
/*------------------------------------------------------------------------------*/

#if defined(BACKUP_SUPPORT) && defined(HAVE_LIBGRINGOTTS)

static void
button_create_backup_cb(GtkToolButton *toolbutton, gpointer data) {
    GUI *appGUI = (GUI *) data;
    backup_create(appGUI);
}

static void
button_restore_backup_cb(GtkToolButton *toolbutton, gpointer data) {
    GUI *appGUI = (GUI *) data;
    backup_restore(appGUI);
}

#endif  /* BACKUP_SUPPORT && HAVE_LIBGRINGOTTS */

/*------------------------------------------------------------------------------*/

void
contacts_paned_position_change_cb (GObject *gobject, GParamSpec *pspec, GUI *appGUI)
{
    config.contacts_pane_pos = gtk_paned_get_position (GTK_PANED (appGUI->cnt->contacts_paned));
}

/*------------------------------------------------------------------------------*/

void
gui_create_contacts(GUI *appGUI) {

GtkWidget           *vbox1;
GtkWidget           *vbox2;
GtkWidget           *vbox3;
GtkWidget           *hbox2;
GtkWidget           *frame;
GtkWidget           *hseparator;
GtkWidget           *label;
GtkWidget           *top_viewport;
GtkWidget           *bottom_viewport;
GtkWidget           *close_button;
GtkCellRenderer     *renderer[CONTACTS_NUM_COLUMNS];
gint                i, n;
gchar tmpbuf[BUFFER_SIZE];

gint columns_order[MAX_VISIBLE_CONTACT_COLUMNS];

gint co_columns[MAX_VISIBLE_CONTACT_COLUMNS] = { 
        COLUMN_GROUP, COLUMN_FIRST_NAME, COLUMN_LAST_NAME
};

    create_contact_fields(appGUI); 

    vbox1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
    gtk_widget_show (vbox1);
    gtk_container_set_border_width (GTK_CONTAINER (vbox1), 0);
    g_snprintf(tmpbuf, BUFFER_SIZE, "<b>%s</b>", _("Contacts"));
    gui_add_to_notebook (vbox1, tmpbuf, appGUI);

    appGUI->cnt->vbox = GTK_BOX(vbox1);

    if (config.hide_contacts == TRUE) {
        gtk_widget_hide(GTK_WIDGET(appGUI->cnt->vbox));
    }

    /*-------------------------------------------------------------------------------------*/
    appGUI->cnt->contacts_toolbar = GTK_TOOLBAR(gtk_toolbar_new());
    gtk_box_pack_start(GTK_BOX(vbox1), GTK_WIDGET(appGUI->cnt->contacts_toolbar), FALSE, FALSE, 0);
    
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gui_create_toolbar_button(appGUI, OSMO_STOCK_CONTACTS_ADD, _("New contact"), contacts_add_item_cb), -1);
    appGUI->cnt->edit_toolbar_button = gui_create_toolbar_button(appGUI, OSMO_STOCK_CONTACTS_EDIT, _("Edit contact"), contacts_edit_item_cb);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, appGUI->cnt->edit_toolbar_button, -1);
    appGUI->cnt->delete_toolbar_button = gui_create_toolbar_button(appGUI, OSMO_STOCK_CONTACTS_REMOVE, _("Remove contact"), contacts_remove_item_cb);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, appGUI->cnt->delete_toolbar_button, -1);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gtk_separator_tool_item_new(), -1);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gui_create_toolbar_button(appGUI, OSMO_STOCK_CONTACTS_BIRTHDAYS, _("Show birthdays"), contacts_birthdays_item_cb), -1);
    appGUI->cnt->map_location_toolbar_button = gui_create_toolbar_button(appGUI, OSMO_STOCK_OPEN_URL, _("Show contact location on the map"), contacts_map_location_cb);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, appGUI->cnt->map_location_toolbar_button, -1);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gtk_separator_tool_item_new(), -1);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gui_create_toolbar_button(appGUI, OSMO_STOCK_CONTACTS_IMPORT, _("Import contacts"), contacts_import_items_cb), -1);
    appGUI->cnt->export_toolbar_button = gui_create_toolbar_button(appGUI, OSMO_STOCK_CONTACTS_EXPORT, _("Export contacts"), contacts_export_items_cb);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, appGUI->cnt->export_toolbar_button, -1);
    gui_append_toolbar_spring(appGUI->cnt->contacts_toolbar);
#if defined(BACKUP_SUPPORT) && defined(HAVE_LIBGRINGOTTS)
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gtk_separator_tool_item_new(), -1);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gui_create_toolbar_button(appGUI, OSMO_STOCK_BACKUP, _("Backup data"), button_create_backup_cb), -1);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gui_create_toolbar_button(appGUI, OSMO_STOCK_RESTORE, _("Restore data"), button_restore_backup_cb), -1);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gtk_separator_tool_item_new(), -1);
#endif  /* BACKUP_SUPPORT && HAVE_LIBGRINGOTTS */
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gui_create_toolbar_button(appGUI, OSMO_STOCK_PREFERENCES, _("Preferences"), show_preferences_window_cb), -1);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, gui_create_toolbar_button(appGUI, OSMO_STOCK_ABOUT, _("About"), gui_show_about_window_cb), -1);
    appGUI->cnt->quit_toolbar_button = gui_create_toolbar_button(appGUI, "application-exit", _("Quit"), gui_quit_osmo_cb);
    gtk_toolbar_insert(appGUI->cnt->contacts_toolbar, appGUI->cnt->quit_toolbar_button, -1);
    
    gtk_toolbar_set_style (appGUI->cnt->contacts_toolbar, GTK_TOOLBAR_ICONS);
    gtk_toolbar_set_icon_size(appGUI->cnt->contacts_toolbar, GTK_ICON_SIZE_LARGE_TOOLBAR);
    gtk_widget_show_all(GTK_WIDGET(appGUI->cnt->contacts_toolbar));

    /*-------------------------------------------------------------------------------------*/

    gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->edit_toolbar_button), FALSE);
    gtk_widget_set_sensitive(GTK_WIDGET(appGUI->cnt->delete_toolbar_button), FALSE);

/******************************************************************************************/

    if (!config.gui_layout) {
        appGUI->cnt->contacts_paned = gtk_paned_new(GTK_ORIENTATION_VERTICAL );
    } else {
        appGUI->cnt->contacts_paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
    }

    gtk_widget_show (appGUI->cnt->contacts_paned);
    gtk_box_pack_start(GTK_BOX(vbox1), appGUI->cnt->contacts_paned, TRUE, TRUE, 0);

    top_viewport = gtk_viewport_new (NULL, NULL);
    gtk_widget_show (top_viewport);
    gtk_viewport_set_shadow_type (GTK_VIEWPORT (top_viewport), GTK_SHADOW_NONE);
    gtk_paned_pack1 (GTK_PANED (appGUI->cnt->contacts_paned), top_viewport, FALSE, TRUE);

    vbox3 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1);
    gtk_widget_show (vbox3);
    gtk_container_add (GTK_CONTAINER (top_viewport), vbox3);
	gtk_widget_set_margin_left (vbox3, 8);
	gtk_widget_set_margin_right (vbox3, 8);
	gtk_widget_set_margin_bottom (vbox3, 8);

    hseparator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
    gtk_widget_show (hseparator);
    gtk_box_pack_start (GTK_BOX (vbox3), hseparator, FALSE, FALSE, 6);

    g_snprintf(tmpbuf, BUFFER_SIZE, "<b>%s:</b>", _("Search"));
    label = gtk_label_new (tmpbuf);
    gtk_widget_show (label);
    gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
    gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, FALSE, 0);
    gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
    gtk_widget_set_halign(label, GTK_ALIGN_START);

    hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
    gtk_widget_show (hbox2);
    gtk_box_pack_start (GTK_BOX (vbox3), hbox2, FALSE, TRUE, 0);

    appGUI->cnt->contacts_find_entry = gtk_entry_new();
    gtk_entry_set_max_length(GTK_ENTRY(appGUI->cnt->contacts_find_entry), 128);
    gtk_widget_show (appGUI->cnt->contacts_find_entry);
    g_signal_connect (G_OBJECT(appGUI->cnt->contacts_find_entry), "changed",
                        G_CALLBACK(contacts_search_entry_changed_cb), appGUI);
    gtk_box_pack_start (GTK_BOX (hbox2), appGUI->cnt->contacts_find_entry, TRUE, TRUE, 0);

    appGUI->cnt->contacts_find_clear_button = gtk_button_new_from_icon_name ("edit-clear", GTK_ICON_SIZE_BUTTON);
    gtk_widget_show (appGUI->cnt->contacts_find_clear_button);
    gtk_widget_set_can_focus (appGUI->cnt->contacts_find_clear_button, FALSE);
    gtk_button_set_relief (GTK_BUTTON(appGUI->cnt->contacts_find_clear_button), GTK_RELIEF_NONE);
    if (config.enable_tooltips) {
        gtk_widget_set_tooltip_text (appGUI->cnt->contacts_find_clear_button, _("Clear"));
    }
    g_signal_connect (G_OBJECT (appGUI->cnt->contacts_find_clear_button), "clicked",
                        G_CALLBACK (cnt_clear_find_cb), appGUI);
    gtk_box_pack_start (GTK_BOX (hbox2), appGUI->cnt->contacts_find_clear_button, FALSE, FALSE, 0);

    appGUI->cnt->contacts_find_combobox = gtk_combo_box_text_new ();
    gtk_widget_show (appGUI->cnt->contacts_find_combobox);
    gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (appGUI->cnt->contacts_find_combobox), FALSE);
    gtk_box_pack_start (GTK_BOX (hbox2), appGUI->cnt->contacts_find_combobox, FALSE, FALSE, 0);
    g_signal_connect (G_OBJECT (appGUI->cnt->contacts_find_combobox), "changed",
                      G_CALLBACK (contacts_find_type_selected_cb), appGUI);
    g_signal_connect(G_OBJECT(appGUI->cnt->contacts_find_combobox), "focus",
                     G_CALLBACK(find_combo_box_focus_cb), appGUI);
    gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (appGUI->cnt->contacts_find_combobox), NULL, _("First Name"));
    gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (appGUI->cnt->contacts_find_combobox), NULL, _("Last Name"));
    gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (appGUI->cnt->contacts_find_combobox), NULL, _("Tags"));
    gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (appGUI->cnt->contacts_find_combobox), NULL, _("All fields"));

    hseparator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
    gtk_widget_show (hseparator);
    gtk_box_pack_start (GTK_BOX (vbox3), hseparator, FALSE, FALSE, 6);

    appGUI->cnt->scrolled_win = gtk_scrolled_window_new (NULL, NULL);
    gtk_widget_show (appGUI->cnt->scrolled_win);
    gtk_box_pack_start (GTK_BOX (vbox3), appGUI->cnt->scrolled_win, TRUE, TRUE, 0);

    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (appGUI->cnt->scrolled_win), GTK_SHADOW_IN);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (appGUI->cnt->scrolled_win), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

    create_contacts_list_store(appGUI);

    appGUI->cnt->contacts_filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(appGUI->cnt->contacts_list_store), NULL);
    gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER(appGUI->cnt->contacts_filter),
                                            (GtkTreeModelFilterVisibleFunc)contacts_list_filter_cb,
                                            appGUI, NULL);

    appGUI->cnt->contacts_sort = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(appGUI->cnt->contacts_filter));

    appGUI->cnt->contacts_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(appGUI->cnt->contacts_sort));
    gtk_widget_show (appGUI->cnt->contacts_list);
    gtk_widget_set_can_default (appGUI->cnt->contacts_list, TRUE);
    gtk_tree_view_set_enable_search (GTK_TREE_VIEW(appGUI->cnt->contacts_list), FALSE);

    g_signal_connect(G_OBJECT(appGUI->cnt->contacts_list), "button_press_event",
                     G_CALLBACK(contacts_list_dbclick_cb), appGUI);

    appGUI->cnt->contacts_list_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (appGUI->cnt->contacts_list));
    gtk_tree_selection_set_mode (appGUI->cnt->contacts_list_selection, GTK_SELECTION_MULTIPLE);
    contacts_selection_activate (TRUE, appGUI);

    /* columns setup */

    for (i = COLUMN_GROUP; i < CONTACTS_NUM_COLUMNS; i++) {
        renderer[i] = gtk_cell_renderer_text_new();
        appGUI->cnt->contacts_columns[i] = gtk_tree_view_column_new_with_attributes(gettext(appGUI->cnt->contact_fields_tags_name[i*2]),
                                                              renderer[i], "text", i, NULL);
        gtk_tree_view_append_column (GTK_TREE_VIEW(appGUI->cnt->contacts_list), appGUI->cnt->contacts_columns[i]);

        if(i != COLUMN_FIRST_NAME && i != COLUMN_LAST_NAME && i != COLUMN_GROUP) {
            gtk_tree_view_column_set_visible (appGUI->cnt->contacts_columns[i], FALSE);
        } else {

            if (config.hide_group_column == TRUE && i == COLUMN_GROUP) {
                gtk_tree_view_column_set_visible (appGUI->cnt->contacts_columns[i], FALSE);
            }

            gtk_tree_view_column_set_reorderable (appGUI->cnt->contacts_columns[i], TRUE);
            gtk_tree_view_column_set_resizable (appGUI->cnt->contacts_columns[i], TRUE);
            gtk_tree_view_column_set_sizing (appGUI->cnt->contacts_columns[i], GTK_TREE_VIEW_COLUMN_FIXED);

        }
    }


    /* restore columns order */

    columns_order[0] = config.contacts_column_idx_0;
    columns_order[1] = config.contacts_column_idx_1;
    columns_order[2] = config.contacts_column_idx_2;

    n = MAX_VISIBLE_CONTACT_COLUMNS-1;

    while (n >= 0) {
        for (i = 0; i < MAX_VISIBLE_CONTACT_COLUMNS; i++) {
            if (n == columns_order[i]) {
                gtk_tree_view_move_column_after(GTK_TREE_VIEW(appGUI->cnt->contacts_list),
                                                appGUI->cnt->contacts_columns[co_columns[i]], NULL);
                n--;
            }
        }
    }

    set_contacts_columns_width (appGUI);

    gtk_container_add (GTK_CONTAINER (appGUI->cnt->scrolled_win), appGUI->cnt->contacts_list);

    /* configure sorting */
    for (i = 0; i < MAX_VISIBLE_CONTACT_COLUMNS; i++) {
        gtk_tree_view_column_set_sort_column_id (appGUI->cnt->contacts_columns[co_columns[i]], co_columns[i]);
    }
    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (appGUI->cnt->contacts_sort), COLUMN_GROUP,
            contacts_column_sort_by_group_function, appGUI, NULL);
    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (appGUI->cnt->contacts_sort), COLUMN_FIRST_NAME,
            contacts_column_sort_by_first_name_function, appGUI, NULL);
    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (appGUI->cnt->contacts_sort), COLUMN_LAST_NAME,
            contacts_column_sort_by_last_name_function, appGUI, NULL);


    /* restore sorting */
    gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE (appGUI->cnt->contacts_sort),
            config.contacts_sorting_column, config.contacts_sorting_order);

    g_signal_connect (appGUI->cnt->contacts_sort, "sort-column-changed", G_CALLBACK (contacts_sort_column_changed_cb), appGUI);

    bottom_viewport = gtk_viewport_new (NULL, NULL);
    gtk_widget_show (bottom_viewport);
    gtk_viewport_set_shadow_type (GTK_VIEWPORT (bottom_viewport), GTK_SHADOW_NONE);
    gtk_paned_pack2 (GTK_PANED (appGUI->cnt->contacts_paned), bottom_viewport, TRUE, TRUE);

    vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
    gtk_widget_show (vbox2);
    gtk_container_set_border_width (GTK_CONTAINER (vbox2), 0);
    gtk_container_add (GTK_CONTAINER (bottom_viewport), vbox2);

    appGUI->cnt->panel_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
    gtk_box_pack_start (GTK_BOX (vbox2), appGUI->cnt->panel_hbox, FALSE, FALSE, 0);
    gtk_widget_show(appGUI->cnt->panel_hbox);

	frame = gtk_frame_new (NULL);
	gtk_widget_show (frame);
	gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, 0);
	gtk_widget_set_margin_left(GTK_WIDGET(frame), 8);
	gtk_widget_set_margin_right(GTK_WIDGET(frame), 8);
	gtk_widget_set_margin_bottom(GTK_WIDGET(frame), 8);
	gtk_frame_set_label_align (GTK_FRAME (frame), 0.98, 0.5);
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);

    g_snprintf(tmpbuf, BUFFER_SIZE, "<b>%s</b>", _("Contact details"));
    label = gtk_label_new (tmpbuf);
    gtk_widget_show (label);
    gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
    gtk_frame_set_label_widget (GTK_FRAME (frame), label);

    if (!config.gui_layout) {
        close_button = gtk_button_new_from_icon_name ("window-close", GTK_ICON_SIZE_BUTTON);
        gtk_widget_set_can_focus(close_button, FALSE);
        gtk_button_set_relief (GTK_BUTTON(close_button), GTK_RELIEF_NONE);
        if (config.enable_tooltips) {
            gtk_widget_set_tooltip_text (close_button, _("Close contact panel"));
        }
        gtk_widget_show (close_button);
        gtk_box_pack_end (GTK_BOX (appGUI->cnt->panel_hbox), close_button, FALSE, FALSE, 0);
        g_signal_connect (G_OBJECT (close_button), "clicked", G_CALLBACK (contacts_panel_close_desc_cb), appGUI);
    }

    appGUI->cnt->contacts_panel_scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
    gtk_widget_show (appGUI->cnt->contacts_panel_scrolledwindow);
    gtk_container_add (GTK_CONTAINER (frame), appGUI->cnt->contacts_panel_scrolledwindow);
    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (appGUI->cnt->contacts_panel_scrolledwindow), GTK_SHADOW_NONE);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (appGUI->cnt->contacts_panel_scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

#ifdef HAVE_LIBWEBKIT
    appGUI->cnt->html_webkitview = utl_create_webkit_web_view(appGUI);
    webkit_settings_set_default_font_size (webkit_web_view_get_settings(appGUI->cnt->html_webkitview), config.contact_item_font_size);

    g_signal_connect (appGUI->cnt->html_webkitview, "context-menu",
                      G_CALLBACK (utl_webkit_on_menu), appGUI);
    g_signal_connect (appGUI->cnt->html_webkitview, "decide-policy",
                      G_CALLBACK (utl_webkit_link_clicked), appGUI);

    gtk_widget_show (GTK_WIDGET(appGUI->cnt->html_webkitview));
    gtk_container_add (GTK_CONTAINER (appGUI->cnt->contacts_panel_scrolledwindow), 
                       GTK_WIDGET(appGUI->cnt->html_webkitview));
#endif  /* LIBWEBKIT */

    gtk_combo_box_set_active (GTK_COMBO_BOX (appGUI->cnt->contacts_find_combobox), config.find_mode);

    gtk_tree_sortable_sort_column_changed((GtkTreeSortable *)appGUI->cnt->contacts_sort);
    gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(appGUI->cnt->contacts_filter));

    g_signal_connect(G_OBJECT(appGUI->cnt->contacts_paned), "notify::position", G_CALLBACK(contacts_paned_position_change_cb), appGUI);
    gtk_paned_set_position(GTK_PANED(appGUI->cnt->contacts_paned), config.contacts_pane_pos);

    gtk_widget_grab_focus (appGUI->cnt->contacts_find_entry);
}

/*------------------------------------------------------------------------------*/

gboolean
check_address (gint address_type, GUI *appGUI) {

GtkTreeIter iter;
GtkTreeModel *model;
gchar *text = NULL;
gint n = 0;
gint c1, c2, c3;
    
    if (gtk_tree_selection_count_selected_rows(appGUI->cnt->contacts_list_selection) == 1) {

        if (address_type == HOME_ADDRESS) {
            c1 = COLUMN_HOME_ADDRESS;
            c2 = COLUMN_HOME_CITY;
            c3 = COLUMN_HOME_COUNTRY;
        } else {
            c1 = COLUMN_WORK_ADDRESS;
            c2 = COLUMN_WORK_CITY;
            c3 = COLUMN_WORK_COUNTRY;
        }

        iter = utl_gui_get_first_selection_iter(appGUI->cnt->contacts_list_selection, &model);

        gtk_tree_model_get (model, &iter, c1, &text, -1);
        if (text == NULL) return FALSE;
        if (strlen(text)) n++;
        g_free (text);
        gtk_tree_model_get (model, &iter, c2, &text, -1);
        if (text == NULL) return FALSE;
        if (strlen(text)) n++;
        g_free (text);
        gtk_tree_model_get (model, &iter, c3, &text, -1);
        if (text == NULL) return FALSE;
        if (strlen(text)) n++;
        g_free (text);
    }

    return (n == 3);
}

/*------------------------------------------------------------------------------*/

void
show_contact_location_on_map (gint address_type, GUI *appGUI) {

GtkTreeIter     iter;
GtkTreeModel    *model;
gboolean pn_flag = FALSE;
gint i;
gchar *text = NULL, *mapsURL = NULL;
gchar maps_url[BUFFER_SIZE];
gint cbegin, cend, cskip1, cskip2;

    if (gtk_tree_selection_count_selected_rows(appGUI->cnt->contacts_list_selection) == 1) {

        if (address_type == HOME_ADDRESS) {
            cbegin = COLUMN_HOME_ADDRESS;
            cend = COLUMN_HOME_COUNTRY;
            cskip1 = COLUMN_HOME_POST_CODE;
            cskip2 = COLUMN_HOME_STATE;
        } else {
            cbegin = COLUMN_WORK_ADDRESS;
            cend = COLUMN_WORK_COUNTRY;
            cskip1 = COLUMN_WORK_POST_CODE;
            cskip2 = COLUMN_WORK_STATE;
        }

        iter = utl_gui_get_first_selection_iter(appGUI->cnt->contacts_list_selection, &model);

        i = config.maps_provider % 3;
        if (i == 0) {
            g_snprintf(maps_url, BUFFER_SIZE, "%s", GOOGLE_MAPS_QUERY);
        } else if (i == 1) {
            g_snprintf(maps_url, BUFFER_SIZE, "%s", BING_MAPS_QUERY);
        } else {
            g_snprintf(maps_url, BUFFER_SIZE, "%s", OSM_MAPS_QUERY);
        }
            
        for (i = cbegin; i <= cend; i++) {

            if (i == cskip1 || i == cskip2) continue;

                gtk_tree_model_get (model, &iter, i, &text, -1);
                if (text != NULL) {
                    if (pn_flag) {
                        g_strlcat (maps_url, ",", BUFFER_SIZE);
                    }
                    g_strlcat (maps_url, text, BUFFER_SIZE);
                    pn_flag = TRUE;
                    g_free (text);
                }
        }

        mapsURL = utl_text_to_html(maps_url, TRUE, FALSE);
        utl_run_helper(mapsURL, WWW);
        free(mapsURL);
    }
}

/*------------------------------------------------------------------------------*/

gboolean
queryFilter(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
    gboolean matches;
    gchar*   value;
    gchar*   matchWith = data;


    /* we don't want to match the empty string to match everything */
    if (!g_utf8_strlen(matchWith, -1)) return FALSE;

    /* try first name */
    value = NULL;
    gtk_tree_model_get(model, iter, COLUMN_FIRST_NAME, &value, -1);
    if(value != NULL)
    {
        matches = utl_text_strcasestr(value, matchWith);
        g_free (value);
        if (matches) return TRUE;
    }
    /* and last name */
    value = NULL;
    gtk_tree_model_get(model, iter, COLUMN_LAST_NAME, &value, -1);
    if(value != NULL)
    {
        matches = utl_text_strcasestr(value, matchWith);
        g_free (value);
        if (matches) return TRUE;
    }

    return FALSE;
}

gint
query(GUI* appGUI, gchar *matchWith)
{
    GtkTreeIter sort_iter;
    gboolean valid;
    gchar *text;
    gint n = 0, col;

    create_contact_fields(appGUI);
    create_contacts_list_store(appGUI);
    read_contacts_entries(appGUI);

    appGUI->cnt->contacts_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL(appGUI->cnt->contacts_list_store), 
                                                              NULL);

    gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER(appGUI->cnt->contacts_filter), 
                                            queryFilter, /* < this is where the actual filtering takes place */
                                            matchWith, NULL);

    /* FIXME: for some reason mutt ignores the first line */
    printf("\n");

    /* here we loop over all matching contacts and print the e-mail adresses */

    appGUI->cnt->contacts_sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL(appGUI->cnt->contacts_filter));
    valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(appGUI->cnt->contacts_sort), &sort_iter);

    while (valid) {
        GtkTreeIter filter_iter, iter;
        gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(appGUI->cnt->contacts_sort), &filter_iter, &sort_iter);
        gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(appGUI->cnt->contacts_filter), &iter, &filter_iter);

        for (col = COLUMN_EMAIL_1; col <= COLUMN_EMAIL_4; col++) {

            gtk_tree_model_get(GTK_TREE_MODEL(appGUI->cnt->contacts_list_store),
                    &iter, col, &text, -1);
            if (text) {
                printf("%s\n", text);
                n++;
            }
        }
        valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(appGUI->cnt->contacts_sort), &sort_iter);
    }

    return n;   /* returns number of found emails */
}

/*------------------------------------------------------------------------------*/
#endif  /* CONTACTS_ENABLED */

