/*
 *  media-select.c
 *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
 *
 *  This file is part of gLabels.
 *
 *  gLabels 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 3 of the License, or
 *  (at your option) any later version.
 *
 *  gLabels 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 gLabels.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#include "media-select.h"

#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <string.h>

#include <libglabels.h>
#include "mini-preview-pixbuf-cache.h"
#include "prefs.h"
#include "message-bar.h"
#include "template-history.h"
#include "template-designer.h"
#include "str-util.h"
#include "combo-util.h"
#include "builder-util.h"
#include "color.h"
#include "marshal.h"

#include "debug.h"


#define HISTORY_SIZE 5

/*===========================================*/
/* Private types                             */
/*===========================================*/

enum {
	NAME_COLUMN,
	PREVIEW_COLUMN,
	PREVIEW_COLUMN_STOCK,
	PREVIEW_COLUMN_STOCK_SIZE,
	DESCRIPTION_COLUMN,
	N_COLUMNS
};

struct _glMediaSelectPrivate {

        gulong        db_notify_id;

        GtkBuilder   *builder;

        GtkWidget    *notebook;
        guint         current_page_num;

        gint          recent_page_num;
        GtkWidget    *recent_tab_vbox;
        GtkWidget    *recent_info_vbox;
        GtkWidget    *recent_info_bar;
        GtkWidget    *recent_treeview;
        GtkListStore *recent_store;

        gint          search_all_page_num;
        GtkWidget    *search_all_tab_vbox;
        GtkWidget    *search_all_info_vbox;
        GtkWidget    *search_all_info_bar;
        GtkWidget    *brand_combo_hbox;
        GtkWidget    *brand_combo;
        GtkWidget    *page_size_combo_hbox;
        GtkWidget    *page_size_combo;
        GtkWidget    *category_combo_hbox;
        GtkWidget    *category_combo;
        GtkWidget    *search_all_treeview;
        GtkListStore *search_all_store;

        gint          custom_page_num;
        GtkWidget    *custom_tab_vbox;
        GtkWidget    *custom_info_vbox;
        GtkWidget    *custom_info_bar;
        GtkWidget    *custom_treeview;
        GtkListStore *custom_store;
        GtkWidget    *custom_add_button;
        GtkWidget    *custom_edit_button;
        GtkWidget    *custom_delete_button;

        /* Prevent recursion */
	gboolean    stop_signals;
};

enum {
        CHANGED,
        LAST_SIGNAL
};


/*===========================================*/
/* Private globals                           */
/*===========================================*/

static gint signals[LAST_SIGNAL] = { 0 };


/*===========================================*/
/* Local function prototypes                 */
/*===========================================*/

static void   gl_media_select_finalize   (GObject                *object);

static void   gl_media_select_construct  (glMediaSelect          *this);

static void   filter_changed_cb          (glMediaSelect          *this);

static void   selection_changed_cb       (GtkTreeSelection       *selection,
                                          gpointer                user_data);

static void   custom_add_clicked_cb      (GtkButton              *button,
                                          gpointer                user_data);

static void   custom_edit_clicked_cb     (GtkButton              *button,
                                          gpointer                user_data);

static void   custom_delete_clicked_cb   (GtkButton              *button,
                                          gpointer                user_data);

static void   page_changed_cb            (GtkNotebook            *notebook,
                                          GtkWidget              *page,
                                          guint                   page_num,
                                          gpointer                user_data);

static void   db_changed_cb              (glMediaSelect          *this);

static void   load_recent_list           (glMediaSelect          *this,
                                          GtkListStore           *store,
                                          GtkTreeSelection       *selection,
                                          GList                  *list);

static void   load_custom_list          (glMediaSelect          *this,
                                          GtkListStore           *store,
                                          GtkTreeSelection       *selection,
                                          GList                  *list);

static void   load_search_all_list       (glMediaSelect          *this,
                                          GtkListStore           *store,
                                          GtkTreeSelection       *selection,
                                          GList                  *list);


/****************************************************************************/
/* Boilerplate Object stuff.                                                */
/****************************************************************************/
G_DEFINE_TYPE (glMediaSelect, gl_media_select, GTK_TYPE_VBOX)


static void
gl_media_select_class_init (glMediaSelectClass *class)
{
        GObjectClass *object_class = G_OBJECT_CLASS (class);

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        gl_media_select_parent_class = g_type_class_peek_parent (class);

        object_class->finalize = gl_media_select_finalize;

        signals[CHANGED] =
            g_signal_new ("changed",
                          G_OBJECT_CLASS_TYPE(object_class),
                          G_SIGNAL_RUN_LAST,
                          G_STRUCT_OFFSET (glMediaSelectClass, changed),
                          NULL, NULL,
                          gl_marshal_VOID__VOID,
                          G_TYPE_NONE, 0);

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


static void
gl_media_select_init (glMediaSelect *this)
{
        gl_debug (DEBUG_MEDIA_SELECT, "START");

        this->priv = g_new0 (glMediaSelectPrivate, 1);

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


static void
gl_media_select_finalize (GObject *object)
{
        glMediaSelect *this = GL_MEDIA_SELECT (object);

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        g_return_if_fail (object != NULL);
        g_return_if_fail (GL_IS_MEDIA_SELECT (object));

        if (this->priv->db_notify_id)
        {
                lgl_db_notify_remove (this->priv->db_notify_id);
        }

        if (this->priv->builder)
        {
                g_object_unref (this->priv->builder);
        }
        g_object_unref (this->priv->recent_store);
        g_object_unref (this->priv->search_all_store);
        g_free (this->priv);

        G_OBJECT_CLASS (gl_media_select_parent_class)->finalize (object);

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


GtkWidget *
gl_media_select_new (void)
{
        glMediaSelect *this;

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        this = g_object_new (gl_media_select_get_type (), NULL);

        gl_media_select_construct (this);

        gl_debug (DEBUG_MEDIA_SELECT, "END");

        return GTK_WIDGET (this);
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  Construct composite widget.                                    */
/*--------------------------------------------------------------------------*/
static void
gl_media_select_construct (glMediaSelect *this)
{
        gchar             *builder_filename;
        GtkBuilder        *builder;
        static gchar      *object_ids[] = { "media_select_hbox",
                                            "custom_buttons_sizegroup",
                                            NULL };
        GError            *error = NULL;
        GtkWidget         *hbox;
        GList             *recent_list = NULL;
        GList             *brands = NULL;
        GList             *page_sizes = NULL;
        GList             *categories = NULL;
        GList             *search_all_names = NULL;
        const gchar       *page_size_id;
        gchar             *page_size_name;
        GList             *custom_list = NULL;
        GtkCellRenderer   *renderer;
        GtkTreeViewColumn *column;
        GtkTreeSelection  *recent_selection;
        GtkTreeSelection  *search_all_selection;
        GtkTreeSelection  *custom_selection;

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        g_return_if_fail (GL_IS_MEDIA_SELECT (this));
        g_return_if_fail (this->priv != NULL);

        builder = gtk_builder_new ();
        builder_filename = g_build_filename (GLABELS_DATA_DIR, "ui", "media-select.ui", NULL);
        gtk_builder_add_objects_from_file (builder, builder_filename, object_ids, &error);
        g_free (builder_filename);
	if (error) {
		g_critical ("%s\n\ngLabels may not be installed correctly!", error->message);
                g_error_free (error);
		return;
	}

        gl_builder_util_get_widgets (builder,
                                     "media_select_hbox",      &hbox,
                                     "notebook",               &this->priv->notebook,
                                     "recent_tab_vbox",        &this->priv->recent_tab_vbox,
                                     "recent_info_vbox",       &this->priv->recent_info_vbox,
                                     "recent_treeview",        &this->priv->recent_treeview,
                                     "search_all_tab_vbox",    &this->priv->search_all_tab_vbox,
                                     "brand_combo_hbox",       &this->priv->brand_combo_hbox,
                                     "page_size_combo_hbox",   &this->priv->page_size_combo_hbox,
                                     "category_combo_hbox",    &this->priv->category_combo_hbox,
                                     "search_all_info_vbox",   &this->priv->search_all_info_vbox,
                                     "search_all_treeview",    &this->priv->search_all_treeview,
                                     "custom_tab_vbox",        &this->priv->custom_tab_vbox,
                                     "custom_info_vbox",       &this->priv->custom_info_vbox,
                                     "custom_treeview",        &this->priv->custom_treeview,
                                     "custom_add_button",      &this->priv->custom_add_button,
                                     "custom_edit_button",     &this->priv->custom_edit_button,
                                     "custom_delete_button",   &this->priv->custom_delete_button,
                                     NULL);

        gtk_container_add (GTK_CONTAINER (this), hbox);
        this->priv->builder = builder;

        this->priv->recent_page_num =
                gtk_notebook_page_num (GTK_NOTEBOOK (this->priv->notebook),
                                       this->priv->recent_tab_vbox);
        this->priv->search_all_page_num =
                gtk_notebook_page_num (GTK_NOTEBOOK (this->priv->notebook),
                                       this->priv->search_all_tab_vbox);
        this->priv->custom_page_num =
                gtk_notebook_page_num (GTK_NOTEBOOK (this->priv->notebook),
                                       this->priv->custom_tab_vbox);

        this->priv->brand_combo = gtk_combo_box_text_new ();
        gtk_box_pack_start (GTK_BOX (this->priv->brand_combo_hbox), this->priv->brand_combo, FALSE, FALSE, 0);
        this->priv->page_size_combo = gtk_combo_box_text_new ();
        gtk_box_pack_start (GTK_BOX (this->priv->page_size_combo_hbox), this->priv->page_size_combo, FALSE, FALSE, 0);
        this->priv->category_combo = gtk_combo_box_text_new ();
        gtk_box_pack_start (GTK_BOX (this->priv->category_combo_hbox), this->priv->category_combo, FALSE, FALSE, 0);

        gtk_widget_show_all (GTK_WIDGET (this));

        /* Recent templates treeview */
        this->priv->recent_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING);
        gtk_tree_view_set_model (GTK_TREE_VIEW (this->priv->recent_treeview),
                                 GTK_TREE_MODEL (this->priv->recent_store));
        renderer = gtk_cell_renderer_pixbuf_new ();
        column = gtk_tree_view_column_new_with_attributes ("", renderer,
                                                           "pixbuf", PREVIEW_COLUMN,
                                                           "stock-id", PREVIEW_COLUMN_STOCK,
                                                           "stock-size", PREVIEW_COLUMN_STOCK_SIZE,
                                                           NULL);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_append_column (GTK_TREE_VIEW (this->priv->recent_treeview), column);
        renderer = gtk_cell_renderer_text_new ();
        column = gtk_tree_view_column_new_with_attributes ("", renderer,
                                                           "markup", DESCRIPTION_COLUMN,
                                                           NULL);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_append_column (GTK_TREE_VIEW (this->priv->recent_treeview), column);
        recent_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->recent_treeview));
        recent_list = gl_template_history_model_get_name_list (gl_template_history);
        load_recent_list (this, this->priv->recent_store, recent_selection, recent_list);

        page_size_id = gl_prefs_model_get_default_page_size (gl_prefs);
        page_size_name = lgl_db_lookup_paper_name_from_id (page_size_id);

        /* Brand selection control */
        brands = lgl_db_get_brand_list (NULL, NULL);
        brands = g_list_prepend (brands, g_strdup (C_("Brand", "Any")));
        gl_combo_util_set_strings (GTK_COMBO_BOX_TEXT (this->priv->brand_combo), brands);
        lgl_db_free_brand_list (brands);
        gl_combo_util_set_active_text (GTK_COMBO_BOX (this->priv->brand_combo), C_("Brand", "Any"));

        /* Page size selection control */
        page_sizes = lgl_db_get_paper_name_list ();
        page_sizes = g_list_prepend (page_sizes, g_strdup (C_("Page size", "Any")));
        gl_combo_util_set_strings (GTK_COMBO_BOX_TEXT (this->priv->page_size_combo), page_sizes);
        lgl_db_free_paper_name_list (page_sizes);
        gl_combo_util_set_active_text (GTK_COMBO_BOX (this->priv->page_size_combo), page_size_name);

        /* Category selection control */
        categories = lgl_db_get_category_name_list ();
        categories = g_list_prepend (categories, g_strdup (C_("Category", "Any")));
        gl_combo_util_set_strings (GTK_COMBO_BOX_TEXT (this->priv->category_combo), categories);
        lgl_db_free_category_name_list (categories);
        gl_combo_util_set_active_text (GTK_COMBO_BOX (this->priv->category_combo), C_("Category", "Any"));

        /* Search all treeview */
        this->priv->search_all_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING);
        gtk_tree_view_set_model (GTK_TREE_VIEW (this->priv->search_all_treeview),
                                 GTK_TREE_MODEL (this->priv->search_all_store));
        renderer = gtk_cell_renderer_pixbuf_new ();
        column = gtk_tree_view_column_new_with_attributes ("", renderer,
                                                           "pixbuf", PREVIEW_COLUMN,
                                                           "stock-id", PREVIEW_COLUMN_STOCK,
                                                           "stock-size", PREVIEW_COLUMN_STOCK_SIZE,
                                                           NULL);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_append_column (GTK_TREE_VIEW (this->priv->search_all_treeview), column);
        renderer = gtk_cell_renderer_text_new ();
        column = gtk_tree_view_column_new_with_attributes ("", renderer,
                                                           "markup", DESCRIPTION_COLUMN,
                                                           NULL);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_append_column (GTK_TREE_VIEW (this->priv->search_all_treeview), column);
        search_all_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->search_all_treeview));
        search_all_names = lgl_db_get_template_name_list_all (NULL, page_size_id, NULL);
        load_search_all_list (this, this->priv->search_all_store, search_all_selection, search_all_names);
        lgl_db_free_template_name_list (search_all_names);

        /* Custom templates treeview */
        this->priv->custom_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING);
        gtk_tree_view_set_model (GTK_TREE_VIEW (this->priv->custom_treeview),
                                 GTK_TREE_MODEL (this->priv->custom_store));
        renderer = gtk_cell_renderer_pixbuf_new ();
        column = gtk_tree_view_column_new_with_attributes ("", renderer,
                                                           "pixbuf", PREVIEW_COLUMN,
                                                           "stock-id", PREVIEW_COLUMN_STOCK,
                                                           "stock-size", PREVIEW_COLUMN_STOCK_SIZE,
                                                           NULL);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_append_column (GTK_TREE_VIEW (this->priv->custom_treeview), column);
        renderer = gtk_cell_renderer_text_new ();
        column = gtk_tree_view_column_new_with_attributes ("", renderer,
                                                           "markup", DESCRIPTION_COLUMN,
                                                           NULL);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_append_column (GTK_TREE_VIEW (this->priv->custom_treeview), column);
        custom_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->custom_treeview));
        custom_list = lgl_db_get_template_name_list_all (NULL, NULL, "user-defined");
        load_custom_list (this, this->priv->custom_store, custom_selection, custom_list);
        lgl_db_free_template_name_list (custom_list);

        page_size_id = gl_prefs_model_get_default_page_size (gl_prefs);
        page_size_name = lgl_db_lookup_paper_name_from_id (page_size_id);

        /* Connect signals to controls */
        g_signal_connect_swapped (G_OBJECT (this->priv->brand_combo), "changed",
                                  G_CALLBACK (filter_changed_cb),
                                  this);
        g_signal_connect_swapped (G_OBJECT (this->priv->page_size_combo), "changed",
                                  G_CALLBACK (filter_changed_cb),
                                  this);
        g_signal_connect_swapped (G_OBJECT (this->priv->category_combo), "changed",
                                  G_CALLBACK (filter_changed_cb),
                                  this);
        g_signal_connect (G_OBJECT (recent_selection), "changed",
                          G_CALLBACK (selection_changed_cb),
                          this);
        g_signal_connect (G_OBJECT (search_all_selection), "changed",
                          G_CALLBACK (selection_changed_cb),
                          this);
        g_signal_connect (G_OBJECT (custom_selection), "changed",
                          G_CALLBACK (selection_changed_cb),
                          this);
        g_signal_connect (G_OBJECT (this->priv->custom_add_button), "clicked",
                          G_CALLBACK (custom_add_clicked_cb),
                          this);
        g_signal_connect (G_OBJECT (this->priv->custom_edit_button), "clicked",
                          G_CALLBACK (custom_edit_clicked_cb),
                          this);
        g_signal_connect (G_OBJECT (this->priv->custom_delete_button), "clicked",
                          G_CALLBACK (custom_delete_clicked_cb),
                          this);
        g_signal_connect (G_OBJECT (this->priv->notebook), "switch-page",
                          G_CALLBACK (page_changed_cb),
                          this);

        g_free (page_size_name);

        if ( recent_list )
        {
                gtk_notebook_set_current_page (GTK_NOTEBOOK (this->priv->notebook),
                                               this->priv->recent_page_num);
        }
        else
        {
                gtk_notebook_set_current_page (GTK_NOTEBOOK (this->priv->notebook),
                                               this->priv->search_all_page_num);
        }
        gl_template_history_model_free_name_list (recent_list);

        this->priv->db_notify_id = lgl_db_notify_add ((lglDbNotifyFunc)db_changed_cb, this);

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  modify widget due to change in selection                       */
/*--------------------------------------------------------------------------*/
static void
filter_changed_cb (glMediaSelect *this)
{
        gchar             *brand;
        gchar             *page_size_name, *page_size_id;
        gchar             *category_name, *category_id;
        GList             *search_all_names;
        GtkTreeSelection  *selection;

        gl_debug (DEBUG_MEDIA_SELECT, "START");


	this->priv->stop_signals = TRUE;

        /* Update template selections for new filter settings */
        brand = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (this->priv->brand_combo));
        page_size_name = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (this->priv->page_size_combo));
        category_name = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (this->priv->category_combo));
        if ( brand && strlen(brand) &&
             page_size_name && strlen(page_size_name) &&
             category_name && strlen(category_name) )
        {
                gl_debug (DEBUG_MEDIA_SELECT, "brand = \"%s\"", brand);
                gl_debug (DEBUG_MEDIA_SELECT, "page_size_name = \"%s\"", page_size_name);
                gl_debug (DEBUG_MEDIA_SELECT, "category_name = \"%s\"", category_name);
                if (!g_utf8_collate (brand, C_("Brand", "Any")))
                {
                        g_free (brand);
                        brand = NULL;
                }
                page_size_id = lgl_db_lookup_paper_id_from_name (page_size_name);
                category_id = lgl_db_lookup_category_id_from_name (category_name);
                gl_debug (DEBUG_MEDIA_SELECT, "page_size_id = \"%s\"", page_size_id);
                gl_debug (DEBUG_MEDIA_SELECT, "category_id = \"%s\"", category_id);
                search_all_names = lgl_db_get_template_name_list_all (brand, page_size_id, category_id);
                selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->search_all_treeview));
                load_search_all_list (this, this->priv->search_all_store, selection, search_all_names);
                lgl_db_free_template_name_list (search_all_names);
                g_free (page_size_id);
                g_free (category_id);

                /* Emit our "changed" signal */
                g_signal_emit (G_OBJECT (this), signals[CHANGED], 0);
        }
        g_free (brand);
        g_free (page_size_name);
        g_free (category_name);


	this->priv->stop_signals = FALSE;

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  modify widget due to change in selection                       */
/*--------------------------------------------------------------------------*/
static void
selection_changed_cb (GtkTreeSelection       *selection,
                      gpointer                user_data)
{
        glMediaSelect     *this = GL_MEDIA_SELECT (user_data);
        GtkTreeSelection  *custom_selection;

	if (this->priv->stop_signals) return;

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        custom_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->custom_treeview));
        gtk_widget_set_sensitive (GTK_WIDGET (this->priv->custom_edit_button),
                                  gtk_tree_selection_get_mode (custom_selection) != GTK_SELECTION_NONE );
        gtk_widget_set_sensitive (GTK_WIDGET (this->priv->custom_delete_button),
                                  gtk_tree_selection_get_mode (custom_selection) != GTK_SELECTION_NONE );

        /* Emit our "changed" signal */
        g_signal_emit (G_OBJECT (user_data), signals[CHANGED], 0);

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  Custom add button clicked callback.                            */
/*--------------------------------------------------------------------------*/
static void
custom_add_clicked_cb (GtkButton  *button,
                       gpointer    user_data)
{
        glMediaSelect *this = GL_MEDIA_SELECT (user_data);
        GtkWidget     *window;
        GtkWidget     *dialog;

        window = gtk_widget_get_toplevel (GTK_WIDGET (this));
        
        dialog = gl_template_designer_new (GTK_WINDOW (window));

        gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
        gtk_widget_show (dialog);
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  Custom edit button clicked callback.                           */
/*--------------------------------------------------------------------------*/
static void
custom_edit_clicked_cb (GtkButton  *button,
                        gpointer    user_data)
{
        glMediaSelect     *this = GL_MEDIA_SELECT (user_data);
        GtkTreeSelection  *selection;
        GtkTreeIter        iter;
        GtkTreeModel      *model;
        gchar             *name;
        GtkWidget         *window;
        GtkWidget         *dialog;

        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->custom_treeview));

        if (!gtk_tree_selection_get_mode (selection) == GTK_SELECTION_NONE)
        {
                gtk_tree_selection_get_selected (selection, &model, &iter);
                gtk_tree_model_get (model, &iter, NAME_COLUMN, &name, -1);

                window = gtk_widget_get_toplevel (GTK_WIDGET (this));

                dialog = gl_template_designer_new (GTK_WINDOW (window));
                gl_template_designer_set_from_name (GL_TEMPLATE_DESIGNER (dialog), name);

                gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
                gtk_widget_show (dialog);

                g_free (name);
        }
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  Custom delete button clicked callback.                         */
/*--------------------------------------------------------------------------*/
static void
custom_delete_clicked_cb (GtkButton  *button,
                          gpointer    user_data)
{
        glMediaSelect     *this = GL_MEDIA_SELECT (user_data);
        GtkTreeSelection  *selection;
        GtkTreeIter        iter;
        GtkTreeModel      *model;        
        gchar             *name;
        GtkWidget         *window;
        GtkWidget         *dialog;
        gint               ret;

	this->priv->stop_signals = TRUE;

        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->custom_treeview));

        if (!gtk_tree_selection_get_mode (selection) == GTK_SELECTION_NONE)
        {
                gtk_tree_selection_get_selected (selection, &model, &iter);
                gtk_tree_model_get (model, &iter, NAME_COLUMN, &name, -1);

                window = gtk_widget_get_toplevel (GTK_WIDGET (this));
                dialog = gtk_message_dialog_new (GTK_WINDOW (window),
                                                 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                                 GTK_MESSAGE_QUESTION,
                                                 GTK_BUTTONS_YES_NO,
                                                 _("Delete template \"%s\"?"), name);
                gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
                                                          _("This action will permanently delete this template."));

                ret = gtk_dialog_run (GTK_DIALOG (dialog));
                gtk_widget_destroy (dialog);
                
                if ( ret == GTK_RESPONSE_YES )
                {
                        lgl_db_delete_template_by_name (name);
                        gl_mini_preview_pixbuf_cache_delete_by_name (name);
                }

                g_free (name);
        }

	this->priv->stop_signals = FALSE;
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  modify widget due to change in selection                       */
/*--------------------------------------------------------------------------*/
static void
page_changed_cb (GtkNotebook            *notebook,
                 GtkWidget              *page,
                 guint                   page_num,
                 gpointer                user_data)
{
        glMediaSelect *this = GL_MEDIA_SELECT (user_data);

	if (this->priv->stop_signals) return;

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        /*
         * Store new current page, because this signal is emitted before the actual page change.
         */
	this->priv->current_page_num = page_num;

        /* Emit our "changed" signal */
        g_signal_emit (G_OBJECT (user_data), signals[CHANGED], 0);

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  DB changed notification callback.                              */
/*--------------------------------------------------------------------------*/
static void
db_changed_cb (glMediaSelect *this)
{
        gchar             *brand;
        gchar             *page_size_name, *page_size_id;
        gchar             *category_name, *category_id;
        GtkTreeSelection  *selection;
        GList             *list;

	this->priv->stop_signals = TRUE;

        /* Update recent page. */
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->recent_treeview));
        list = gl_template_history_model_get_name_list (gl_template_history);
        load_recent_list (this, this->priv->recent_store, selection, list);
        lgl_db_free_template_name_list (list);

        /* Update search all page. */
        brand = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (this->priv->brand_combo));
        page_size_name = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (this->priv->page_size_combo));
        category_name = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (this->priv->category_combo));
        if ( brand && strlen(brand) &&
             page_size_name && strlen(page_size_name) &&
             category_name && strlen(category_name) )
        {
                if (!g_utf8_collate (brand, C_("Brand", "Any")))
                {
                        g_free (brand);
                        brand = NULL;
                }
                page_size_id = lgl_db_lookup_paper_id_from_name (page_size_name);
                category_id = lgl_db_lookup_category_id_from_name (category_name);
                list = lgl_db_get_template_name_list_all (brand, page_size_id, category_id);
                selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->search_all_treeview));
                load_search_all_list (this, this->priv->search_all_store, selection, list);
                lgl_db_free_template_name_list (list);
                g_free (page_size_id);
                g_free (category_id);
        }
        g_free (brand);
        g_free (page_size_name);
        g_free (category_name);

        /* Update custom page. */
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->custom_treeview));
        list = lgl_db_get_template_name_list_all (NULL, NULL, "user-defined");
        load_custom_list (this, this->priv->custom_store, selection, list);
        lgl_db_free_template_name_list (list);

	this->priv->stop_signals = FALSE;

        /* Emit our "changed" signal */
        g_signal_emit (G_OBJECT (this), signals[CHANGED], 0);

        filter_changed_cb (this);
}


/****************************************************************************/
/* query selected label template name.                                      */
/****************************************************************************/
gchar *
gl_media_select_get_name (glMediaSelect *this)
{
        gint               page_num;
        GtkTreeSelection  *selection;
        GtkTreeIter        iter;
        GtkTreeModel      *model;        
        gchar             *name;

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        page_num = this->priv->current_page_num;
        if (page_num == this->priv->recent_page_num)
        {
                selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->recent_treeview));
        }
        else if (page_num == this->priv->search_all_page_num)
        {
                selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->search_all_treeview));
        }
        else if (page_num == this->priv->custom_page_num)
        {
                selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->custom_treeview));
        }
        else
        {
                g_print ("notebook page = %d\n", page_num);
                g_assert_not_reached ();
        }

        if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_NONE)
        {
                name = NULL;
        }
        else
        {
                gtk_tree_selection_get_selected (selection, &model, &iter);
                gtk_tree_model_get (model, &iter, NAME_COLUMN, &name, -1);
        }

        gl_debug (DEBUG_MEDIA_SELECT, "END");
        return name;
}


/****************************************************************************/
/* set selected label template name.                                        */
/****************************************************************************/
void
gl_media_select_set_name (glMediaSelect *this,
                          gchar         *name)
{
        GtkTreeSelection  *selection;
        GtkTreeModel      *model;
        GtkTreeIter        iter;
        GtkTreePath       *path;
        gchar             *name_i;
        gboolean           flag;

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (this->priv->search_all_treeview));
        g_return_if_fail (GTK_IS_TREE_SELECTION (selection));

        model = GTK_TREE_MODEL (this->priv->search_all_store);

        for ( flag = gtk_tree_model_get_iter_first (model, &iter);
              flag;
              flag = gtk_tree_model_iter_next(model, &iter) )
        {
                gtk_tree_model_get (model, &iter, NAME_COLUMN, &name_i, -1); 
                if (lgl_str_utf8_casecmp(name, name_i) == 0)
                {
                        gtk_tree_selection_select_iter (selection, &iter);
                        path = gtk_tree_model_get_path (model, &iter);
                        gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (this->priv->search_all_treeview),
                                                      path,
                                                      NULL,
                                                      TRUE, 0.5, 0.0);
                        gtk_tree_path_free (path);
                        break;
                }
        }

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


/****************************************************************************/
/* query current filter parameters.                                         */
/****************************************************************************/
void
gl_media_select_get_filter_parameters (glMediaSelect  *this,
                                       gchar         **page_size_id,
                                       gchar         **category_id)
{
        gchar *page_size_name, *category_name;

        gl_debug (DEBUG_MEDIA_SELECT, "");

        g_free (*page_size_id);
        g_free (*category_id);

        page_size_name =
                gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (this->priv->page_size_combo));

        *page_size_id = lgl_db_lookup_paper_id_from_name (page_size_name);

        category_name =
                gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (this->priv->category_combo));

        *category_id = lgl_db_lookup_category_id_from_name (category_name);

        g_free (page_size_name);
        g_free (category_name);
}


/****************************************************************************/
/* set filter parameters.                                                   */
/****************************************************************************/
void
gl_media_select_set_filter_parameters (glMediaSelect  *this,
                                       const gchar    *page_size_id,
                                       const gchar    *category_id)
{
        gchar *page_size_name;
        gchar *category_name;

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        page_size_name = lgl_db_lookup_paper_name_from_id (page_size_id);
        if (page_size_name == NULL)
        {
                page_size_name = g_strdup (C_("Page size", "Any"));
        }

        gl_combo_util_set_active_text (GTK_COMBO_BOX (this->priv->page_size_combo),
                                       page_size_name);

        category_name = lgl_db_lookup_category_name_from_id (category_id);
        if (category_name == NULL)
        {
                category_name = g_strdup (C_("Category", "Any"));
        }

        gl_combo_util_set_active_text (GTK_COMBO_BOX (this->priv->category_combo),
                                       category_name);
        g_free (page_size_name);
        g_free (category_name);

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  Load list store from template name list.                       */
/*--------------------------------------------------------------------------*/
static void
load_recent_list (glMediaSelect      *this,
                  GtkListStore       *store,
                  GtkTreeSelection   *selection,
                  GList              *list)
{
        GList            *p;
        GtkTreeIter       iter;
        lglUnits          units;
        lglTemplate      *template;
        lglTemplateFrame *frame;
        GdkPixbuf        *pixbuf;
        gchar            *size;
        gchar            *layout;
        gchar            *description;

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        gtk_list_store_clear (store);


        if ( this->priv->recent_info_bar )
        {
                gtk_container_remove (GTK_CONTAINER (this->priv->recent_info_vbox),
                                      this->priv->recent_info_bar);
                this->priv->recent_info_bar = NULL;
        }

        if (list)
        {

                units = gl_prefs_model_get_units (gl_prefs);

                for ( p=list; p!=NULL; p=p->next )
                {

                        gl_debug (DEBUG_MEDIA_SELECT, "p->data = \"%s\"", p->data);

                        template = lgl_db_lookup_template_from_name (p->data);
                        frame    = (lglTemplateFrame *)template->frames->data;
                        pixbuf   = gl_mini_preview_pixbuf_cache_get_pixbuf (p->data);

                        size     = lgl_template_frame_get_size_description (frame, units);
                        layout   = lgl_template_frame_get_layout_description (frame);
                        description = g_strdup_printf ("<b>%s: %s</b>\n%s\n%s",
                                                       (gchar *)p->data,
                                                       template->description,
                                                       size,
                                                       layout);
                        g_free (size);
                        g_free (layout);

                        lgl_template_free (template);

                        gtk_list_store_append (store, &iter);
                        gtk_list_store_set (store, &iter,
                                            NAME_COLUMN, p->data,
                                            PREVIEW_COLUMN, pixbuf,
                                            DESCRIPTION_COLUMN, description,
                                            -1);

                        g_object_unref (G_OBJECT (pixbuf));
                        g_free (description);
                }

                gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
                gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
                gtk_tree_selection_select_iter (selection, &iter);

        }
        else
        {
                this->priv->recent_info_bar = gl_message_bar_new (GTK_MESSAGE_INFO, GTK_BUTTONS_NONE,
                                                                  "%s", _("No recent templates found."));
                gl_message_bar_format_secondary_text (GL_MESSAGE_BAR (this->priv->recent_info_bar),
                                                      "%s", _("Try selecting a template in the \"Search all\" tab."));

                gtk_box_pack_start (GTK_BOX (this->priv->recent_info_vbox),
                                    this->priv->recent_info_bar,
                                    FALSE, FALSE, 0);
                gtk_widget_show_all (this->priv->recent_info_bar);

                gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);

        }

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  Load list store from template name list.                       */
/*--------------------------------------------------------------------------*/
static void
load_search_all_list (glMediaSelect      *this,
                      GtkListStore       *store,
                      GtkTreeSelection   *selection,
                      GList              *list)
{
        GList            *p;
        GtkTreeIter       iter;
        lglUnits          units;
        lglTemplate      *template;
        lglTemplateFrame *frame;
        GdkPixbuf        *pixbuf;
        gchar            *size;
        gchar            *layout;
        gchar            *description;

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        gtk_list_store_clear (store);

        if ( this->priv->search_all_info_bar )
        {
                gtk_container_remove (GTK_CONTAINER (this->priv->search_all_info_vbox),
                                      this->priv->search_all_info_bar);
                this->priv->search_all_info_bar = NULL;
        }

        if (list)
        {

                units = gl_prefs_model_get_units (gl_prefs);

                for ( p=list; p!=NULL; p=p->next )
                {

                        gl_debug (DEBUG_MEDIA_SELECT, "p->data = \"%s\"", p->data);

                        template = lgl_db_lookup_template_from_name (p->data);
                        frame    = (lglTemplateFrame *)template->frames->data;
                        pixbuf   = gl_mini_preview_pixbuf_cache_get_pixbuf (p->data);

                        size     = lgl_template_frame_get_size_description (frame, units);
                        layout   = lgl_template_frame_get_layout_description (frame);
                        description = g_strdup_printf ("<b>%s: %s</b>\n%s\n%s",
                                                       (gchar *)p->data,
                                                       template->description,
                                                       size,
                                                       layout);
                        g_free (size);
                        g_free (layout);

                        lgl_template_free (template);

                        gtk_list_store_append (store, &iter);
                        gtk_list_store_set (store, &iter,
                                            NAME_COLUMN, p->data,
                                            PREVIEW_COLUMN, pixbuf,
                                            DESCRIPTION_COLUMN, description,
                                            -1);

                        g_object_unref (G_OBJECT (pixbuf));
                        g_free (description);
                }

                gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
                gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
                gtk_tree_selection_select_iter (selection, &iter);

        }
        else
        {
                /* Translators: "No match" means that for the given template search criteria, there
                 * were no matches found. */
                this->priv->search_all_info_bar = gl_message_bar_new (GTK_MESSAGE_INFO, GTK_BUTTONS_NONE, "%s", _("No match."));
                gl_message_bar_format_secondary_text (GL_MESSAGE_BAR (this->priv->search_all_info_bar),
                                                      "%s", _("Try selecting a different brand, page size or category."));

                gtk_box_pack_start (GTK_BOX (this->priv->search_all_info_vbox),
                                    this->priv->search_all_info_bar,
                                    FALSE, FALSE, 0);
                gtk_widget_show_all (this->priv->search_all_info_bar);

                gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);

        }

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  Load list store from template name list.                       */
/*--------------------------------------------------------------------------*/
static void
load_custom_list (glMediaSelect      *this,
                  GtkListStore       *store,
                  GtkTreeSelection   *selection,
                  GList              *list)
{
        GList            *p;
        GtkTreeIter       iter;
        lglUnits          units;
        lglTemplate      *template;
        lglTemplateFrame *frame;
        GdkPixbuf        *pixbuf;
        gchar            *size;
        gchar            *layout;
        gchar            *description;

        gl_debug (DEBUG_MEDIA_SELECT, "START");

        gtk_list_store_clear (store);


        if ( this->priv->custom_info_bar )
        {
                gtk_container_remove (GTK_CONTAINER (this->priv->custom_info_vbox),
                                      this->priv->custom_info_bar);
                this->priv->custom_info_bar = NULL;
        }

        if (list)
        {

                units = gl_prefs_model_get_units (gl_prefs);

                for ( p=list; p!=NULL; p=p->next )
                {

                        gl_debug (DEBUG_MEDIA_SELECT, "p->data = \"%s\"", p->data);

                        template = lgl_db_lookup_template_from_name (p->data);
                        frame    = (lglTemplateFrame *)template->frames->data;
                        pixbuf   = gl_mini_preview_pixbuf_cache_get_pixbuf (p->data);

                        size     = lgl_template_frame_get_size_description (frame, units);
                        layout   = lgl_template_frame_get_layout_description (frame);
                        description = g_strdup_printf ("<b>%s: %s</b>\n%s\n%s",
                                                       (gchar *)p->data,
                                                       template->description,
                                                       size,
                                                       layout);
                        g_free (size);
                        g_free (layout);

                        lgl_template_free (template);

                        gtk_list_store_append (store, &iter);
                        gtk_list_store_set (store, &iter,
                                            NAME_COLUMN, p->data,
                                            PREVIEW_COLUMN, pixbuf,
                                            DESCRIPTION_COLUMN, description,
                                            -1);

                        g_object_unref (G_OBJECT (pixbuf));
                        g_free (description);
                }

                gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
                gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
                gtk_tree_selection_select_iter (selection, &iter);

                gtk_widget_set_sensitive (GTK_WIDGET (this->priv->custom_edit_button), TRUE);
                gtk_widget_set_sensitive (GTK_WIDGET (this->priv->custom_delete_button), TRUE);
        }
        else
        {
                this->priv->custom_info_bar = gl_message_bar_new (GTK_MESSAGE_INFO,
                                                                          GTK_BUTTONS_NONE,
                                                                          "%s", _("No custom templates found."));
                gl_message_bar_format_secondary_text (GL_MESSAGE_BAR (this->priv->custom_info_bar),
                                                      "%s", _("You may create new templates or try searching for pre-defined templates in the \"Search all\" tab."));

                gtk_box_pack_start (GTK_BOX (this->priv->custom_info_vbox),
                                    this->priv->custom_info_bar,
                                    FALSE, FALSE, 0);
                gtk_widget_show_all (this->priv->custom_info_bar);

                gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);

                gtk_widget_set_sensitive (GTK_WIDGET (this->priv->custom_edit_button), FALSE);
                gtk_widget_set_sensitive (GTK_WIDGET (this->priv->custom_delete_button), FALSE);
        }

        gl_debug (DEBUG_MEDIA_SELECT, "END");
}



/*
 * Local Variables:       -- emacs
 * mode: C                -- emacs
 * c-basic-offset: 8      -- emacs
 * tab-width: 8           -- emacs
 * indent-tabs-mode: nil  -- emacs
 * End:                   -- emacs
 */
