From 07cc165a7d57312cffee8b56a318fe4a597cdb83 Mon Sep 17 00:00:00 2001 From: Jim Evins Date: Sun, 28 Mar 2010 23:03:39 -0400 Subject: [PATCH] Added "custom" tab to media select widget Added "custom" tab to media select widget. In this tab, the user can launch the template designer or delete an existing user-defined template. Added notification callbacks to libglabels db subsystem so that the media select widget will automatically update when user-defined templates are added or deleted. The "edit" button does not do anything yet. Also did some visual cleanup to the new label dialog. Also include ../libglabels in SUBDIRS in src/ so that libglabels can be rebuilt from src/ directory. --- data/builder/media-select.builder | 124 +++++++- data/builder/new-label-dialog.builder | 3 +- libglabels/db.c | 429 +++++++++++++++++++------- libglabels/db.h | 27 ++ src/Makefile.am | 2 +- src/media-select.c | 358 +++++++++++++++++++-- 6 files changed, 801 insertions(+), 142 deletions(-) diff --git a/data/builder/media-select.builder b/data/builder/media-select.builder index 9cb814fa..567648b0 100644 --- a/data/builder/media-select.builder +++ b/data/builder/media-select.builder @@ -55,7 +55,8 @@ True - Recent templates + 12 + Recent False @@ -211,19 +212,138 @@ True - Search all templates + 12 + Search all 1 False + + + 320 + True + 6 + vertical + + + True + vertical + + + + + + False + False + 0 + + + + + True + True + automatic + automatic + in + + + True + True + False + + + + + 1 + + + + + True + 9 + + + gtk-add + True + True + True + True + + + False + False + 0 + + + + + gtk-edit + True + True + True + True + + + False + 1 + + + + + gtk-delete + True + True + True + True + + + False + False + 2 + + + + + False + False + 6 + 2 + + + + + 2 + + + + + True + 12 + Custom + + + 2 + True + False + + + False + False 0 + + + + + + + diff --git a/data/builder/new-label-dialog.builder b/data/builder/new-label-dialog.builder index 9f3f5d07..2f4d70b7 100644 --- a/data/builder/new-label-dialog.builder +++ b/data/builder/new-label-dialog.builder @@ -22,8 +22,7 @@ True 0 - Choose label or card product from hundreds of predefined templates. You may also -define your own templates. + Choose label or card product from hundreds of predefined templates or define your own. False diff --git a/libglabels/db.c b/libglabels/db.c index af2adcae..37f9247e 100644 --- a/libglabels/db.c +++ b/libglabels/db.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -40,24 +41,63 @@ /* Private types */ /*===========================================*/ +#define TYPE_LGL_DB_MODEL (lgl_db_model_get_type ()) +#define LGL_DB_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_LGL_DB_MODEL, lglDbModel)) +#define LGL_DB_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_LGL_DB_MODEL, lglDbModelClass)) +#define IS_LGL_DB_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_LGL_DB_MODEL)) +#define IS_LGL_DB_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_LGL_DB_MODEL)) +#define LGL_DB_MODEL_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), TYPE_LGL_DB_MODEL, lglDbModelClass)) + + +typedef struct _lglDbModel lglDbModel; +typedef struct _lglDbModelClass lglDbModelClass; + + +struct _lglDbModel { + GObject parent; + + GList *papers; + GList *categories; + GList *vendors; + GList *templates; + + GHashTable *template_cache; +}; + + +struct _lglDbModelClass { + GObjectClass parent_class; + + /* + * Signals + */ + void (*changed) (lglDbModel *this, + gpointer user_data); + +}; + + +enum { + CHANGED, + LAST_SIGNAL +}; + /*===========================================*/ /* Private globals */ /*===========================================*/ -static GList *papers = NULL; -static GList *categories = NULL; -static GList *vendors = NULL; -static GList *templates = NULL; +static guint signals[LAST_SIGNAL] = {0}; -static GHashTable *template_cache = NULL; +static lglDbModel *model = NULL; /*===========================================*/ /* Local function prototypes */ /*===========================================*/ -static void init_template_cache (void); +static void lgl_db_model_finalize (GObject *object); + static void add_to_template_cache (lglTemplate *template); static GList *read_papers (void); @@ -78,6 +118,106 @@ static void read_template_files_from_dir (const gchar *dirname); static lglTemplate *template_full_page (const gchar *page_size); +/*****************************************************************************/ +/* Object infrastructure. */ +/*****************************************************************************/ +G_DEFINE_TYPE (lglDbModel, lgl_db_model, G_TYPE_OBJECT); + + +/*****************************************************************************/ +/* Class Init Function. */ +/*****************************************************************************/ +static void +lgl_db_model_class_init (lglDbModelClass *class) +{ + GObjectClass *gobject_class = (GObjectClass *) class; + + lgl_db_model_parent_class = g_type_class_peek_parent (class); + + gobject_class->finalize = lgl_db_model_finalize; + + signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (lglDbModelClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + + +/*****************************************************************************/ +/* Object Instance Init Function. */ +/*****************************************************************************/ +static void +lgl_db_model_init (lglDbModel *this) +{ + this->template_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)lgl_template_free); +} + + +/*****************************************************************************/ +/* Finalize Method. */ +/*****************************************************************************/ +static void +lgl_db_model_finalize (GObject *object) +{ + lglDbModel *this; + GList *p; + + g_return_if_fail (object && IS_LGL_DB_MODEL (object)); + this = LGL_DB_MODEL (object); + + g_hash_table_unref (this->template_cache); + + for (p = this->papers; p != NULL; p = p->next) + { + g_free (p->data); + p->data = NULL; + } + g_list_free (this->papers); + + for (p = this->categories; p != NULL; p = p->next) + { + g_free (p->data); + p->data = NULL; + } + g_list_free (this->categories); + + for (p = this->vendors; p != NULL; p = p->next) + { + g_free (p->data); + p->data = NULL; + } + g_list_free (this->vendors); + + for (p = this->templates; p != NULL; p = p->next) + { + lgl_template_free ((lglTemplate *)p->data); + p->data = NULL; + } + g_list_free (this->templates); + + G_OBJECT_CLASS (lgl_db_model_parent_class)->finalize (object); +} + + +/*****************************************************************************/ +/** New Object Generator. */ +/*****************************************************************************/ +lglDbModel * +lgl_db_model_new (void) +{ + lglDbModel *this; + + this = g_object_new (TYPE_LGL_DB_MODEL, NULL); + + return this; +} + + /*===========================================*/ /* Module initialization */ /*===========================================*/ @@ -103,63 +243,69 @@ lgl_db_init (void) GList *page_sizes; GList *p; + model = lgl_db_model_new (); + /* * Paper definitions */ - if (!papers) - { - - papers = read_papers (); + model->papers = read_papers (); - /* Create and append an "Other" entry. */ - paper_other = lgl_paper_new ("Other", _("Other"), 0.0, 0.0, NULL); - papers = g_list_append (papers, paper_other); - - } + /* Create and append an "Other" entry. */ + paper_other = lgl_paper_new ("Other", _("Other"), 0.0, 0.0, NULL); + model->papers = g_list_append (model->papers, paper_other); /* * Categories */ - if (!categories) - { - categories = read_categories (); + model->categories = read_categories (); - /* Create and append a "User defined" entry. */ - category_user_defined = lgl_category_new ("user-defined", _("User defined")); - categories = g_list_append (categories, category_user_defined); - } + /* Create and append a "User defined" entry. */ + category_user_defined = lgl_category_new ("user-defined", _("User defined")); + model->categories = g_list_append (model->categories, category_user_defined); /* * Vendors */ - if (!vendors) - { - vendors = read_vendors (); - } + model->vendors = read_vendors (); /* * Templates */ - if (!templates) + read_templates (); + + /* Create and append generic full page templates. */ + page_sizes = lgl_db_get_paper_id_list (); + for ( p=page_sizes; p != NULL; p=p->next ) { + if ( !lgl_db_is_paper_id_other (p->data) ) + { + template = template_full_page (p->data); + _lgl_db_register_template_internal (template); + lgl_template_free (template); + } + } + lgl_db_free_paper_id_list (page_sizes); - init_template_cache (); +} - read_templates (); - /* Create and append generic full page templates. */ - page_sizes = lgl_db_get_paper_id_list (); - for ( p=page_sizes; p != NULL; p=p->next ) - { - if ( !lgl_db_is_paper_id_other (p->data) ) - { - template = template_full_page (p->data); - _lgl_db_register_template_internal (template); - lgl_template_free (template); - } - } - lgl_db_free_paper_id_list (page_sizes); +gulong +lgl_db_notify_add (lglDbNotifyFunc func, + gpointer user_data) +{ + if (!model) + { + lgl_db_init (); } + + return g_signal_connect_swapped (G_OBJECT (model), "changed", G_CALLBACK (func), user_data); +} + + +void +lgl_db_notify_remove (gulong id) +{ + g_signal_handler_disconnect (G_OBJECT (model), id); } @@ -182,12 +328,12 @@ lgl_db_get_paper_id_list (void) GList *p; lglPaper *paper; - if (!papers) + if (!model) { lgl_db_init (); } - for ( p=papers; p != NULL; p=p->next ) + for ( p=model->papers; p != NULL; p=p->next ) { paper = (lglPaper *)p->data; ids = g_list_append (ids, g_strdup (paper->id)); @@ -235,12 +381,12 @@ lgl_db_get_paper_name_list (void) GList *p; lglPaper *paper; - if (!papers) + if (!model) { lgl_db_init (); } - for ( p=papers; p != NULL; p=p->next ) + for ( p=model->papers; p != NULL; p=p->next ) { paper = (lglPaper *)p->data; names = g_list_append (names, g_strdup (paper->name)); @@ -288,7 +434,7 @@ lgl_db_lookup_paper_from_name (const gchar *name) GList *p; lglPaper *paper; - if (!papers) + if (!model) { lgl_db_init (); } @@ -296,10 +442,10 @@ lgl_db_lookup_paper_from_name (const gchar *name) if (name == NULL) { /* If no name, return first paper as a default */ - return lgl_paper_dup ((lglPaper *) papers->data); + return lgl_paper_dup ((lglPaper *) model->papers->data); } - for (p = papers; p != NULL; p = p->next) + for (p = model->papers; p != NULL; p = p->next) { paper = (lglPaper *) p->data; if (UTF8_EQUAL (paper->name, name)) @@ -327,7 +473,7 @@ lgl_db_lookup_paper_from_id (const gchar *id) GList *p; lglPaper *paper; - if (!papers) + if (!model) { lgl_db_init (); } @@ -335,10 +481,10 @@ lgl_db_lookup_paper_from_id (const gchar *id) if (id == NULL) { /* If no id, return first paper as a default */ - return lgl_paper_dup ((lglPaper *) papers->data); + return lgl_paper_dup ((lglPaper *) model->papers->data); } - for (p = papers; p != NULL; p = p->next) + for (p = model->papers; p != NULL; p = p->next) { paper = (lglPaper *) p->data; if (ASCII_EQUAL (paper->id, id)) @@ -426,7 +572,7 @@ lgl_db_is_paper_id_known (const gchar *id) GList *p; lglPaper *paper; - if (!papers) + if (!model) { lgl_db_init (); } @@ -436,7 +582,7 @@ lgl_db_is_paper_id_known (const gchar *id) return FALSE; } - for (p = papers; p != NULL; p = p->next) + for (p = model->papers; p != NULL; p = p->next) { paper = (lglPaper *) p->data; if (ASCII_EQUAL (paper->id, id)) @@ -559,12 +705,12 @@ lgl_db_print_known_papers (void) GList *p; lglPaper *paper; - if (!papers) { + if (!model) { lgl_db_init (); } g_print ("%s():\n", __FUNCTION__); - for (p = papers; p != NULL; p = p->next) { + for (p = model->papers; p != NULL; p = p->next) { paper = (lglPaper *) p->data; g_print ("PAPER id=\"%s\", name=\"%s\", width=%gpts, height=%gpts\n", @@ -595,12 +741,12 @@ lgl_db_get_category_id_list (void) GList *p; lglCategory *category; - if (!categories) + if (!model) { lgl_db_init (); } - for ( p=categories; p != NULL; p=p->next ) + for ( p=model->categories; p != NULL; p=p->next ) { category = (lglCategory *)p->data; ids = g_list_append (ids, g_strdup (category->id)); @@ -648,12 +794,12 @@ lgl_db_get_category_name_list (void) GList *p; lglCategory *category; - if (!categories) + if (!model) { lgl_db_init (); } - for ( p=categories; p != NULL; p=p->next ) + for ( p=model->categories; p != NULL; p=p->next ) { category = (lglCategory *)p->data; names = g_list_append (names, g_strdup (category->name)); @@ -701,7 +847,7 @@ lgl_db_lookup_category_from_name (const gchar *name) GList *p; lglCategory *category; - if (!categories) + if (!model) { lgl_db_init (); } @@ -709,10 +855,10 @@ lgl_db_lookup_category_from_name (const gchar *name) if (name == NULL) { /* If no name, return first category as a default */ - return lgl_category_dup ((lglCategory *) categories->data); + return lgl_category_dup ((lglCategory *) model->categories->data); } - for (p = categories; p != NULL; p = p->next) + for (p = model->categories; p != NULL; p = p->next) { category = (lglCategory *) p->data; if (UTF8_EQUAL (category->name, name)) @@ -740,7 +886,7 @@ lgl_db_lookup_category_from_id (const gchar *id) GList *p; lglCategory *category; - if (!categories) + if (!model) { lgl_db_init (); } @@ -748,10 +894,10 @@ lgl_db_lookup_category_from_id (const gchar *id) if (id == NULL) { /* If no id, return first category as a default */ - return lgl_category_dup ((lglCategory *) categories->data); + return lgl_category_dup ((lglCategory *) model->categories->data); } - for (p = categories; p != NULL; p = p->next) + for (p = model->categories; p != NULL; p = p->next) { category = (lglCategory *) p->data; if (ASCII_EQUAL (category->id, id)) @@ -839,7 +985,7 @@ lgl_db_is_category_id_known (const gchar *id) GList *p; lglCategory *category; - if (!categories) + if (!model) { lgl_db_init (); } @@ -849,7 +995,7 @@ lgl_db_is_category_id_known (const gchar *id) return FALSE; } - for (p = categories; p != NULL; p = p->next) + for (p = model->categories; p != NULL; p = p->next) { category = (lglCategory *) p->data; if (ASCII_EQUAL (category->id, id)) @@ -951,12 +1097,12 @@ lgl_db_print_known_categories (void) GList *p; lglCategory *category; - if (!categories) { + if (!model) { lgl_db_init (); } g_print ("%s():\n", __FUNCTION__); - for (p = categories; p != NULL; p = p->next) { + for (p = model->categories; p != NULL; p = p->next) { category = (lglCategory *) p->data; g_print ("CATEGORY id=\"%s\", name=\"%s\"\n", category->id, category->name); @@ -986,12 +1132,12 @@ lgl_db_get_vendor_name_list (void) GList *p; lglVendor *vendor; - if (!papers) + if (!model) { lgl_db_init (); } - for ( p=vendors; p != NULL; p=p->next ) + for ( p=model->vendors; p != NULL; p=p->next ) { vendor = (lglVendor *)p->data; names = g_list_append (names, g_strdup (vendor->name)); @@ -1039,7 +1185,7 @@ lgl_db_lookup_vendor_from_name (const gchar *name) GList *p; lglVendor *vendor; - if (!papers) + if (!model) { lgl_db_init (); } @@ -1047,10 +1193,10 @@ lgl_db_lookup_vendor_from_name (const gchar *name) if (name == NULL) { /* If no name, return first vendor as a default */ - return lgl_vendor_dup ((lglVendor *) vendors->data); + return lgl_vendor_dup ((lglVendor *) model->vendors->data); } - for (p = vendors; p != NULL; p = p->next) + for (p = model->vendors; p != NULL; p = p->next) { vendor = (lglVendor *) p->data; if (UTF8_EQUAL (vendor->name, name)) @@ -1078,7 +1224,7 @@ lgl_db_is_vendor_name_known (const gchar *name) GList *p; lglVendor *vendor; - if (!papers) + if (!model) { lgl_db_init (); } @@ -1088,7 +1234,7 @@ lgl_db_is_vendor_name_known (const gchar *name) return FALSE; } - for (p = vendors; p != NULL; p = p->next) + for (p = model->vendors; p != NULL; p = p->next) { vendor = (lglVendor *) p->data; if (UTF8_EQUAL (vendor->name, name)) @@ -1186,12 +1332,12 @@ lgl_db_print_known_vendors (void) GList *p; lglVendor *vendor; - if (!papers) { + if (!model) { lgl_db_init (); } g_print ("%s():\n", __FUNCTION__); - for (p = vendors; p != NULL; p = p->next) { + for (p = model->vendors; p != NULL; p = p->next) { vendor = (lglVendor *) p->data; g_print ("VENDOR name=\"%s\", url=\"%s\"\n", @@ -1228,12 +1374,12 @@ lgl_db_get_brand_list (const gchar *paper_id, lglTemplateAlias *alias; GList *brands = NULL; - if (!templates) + if (!model) { lgl_db_init (); } - for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) + for (p_tmplt = model->templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) { template = (lglTemplate *) p_tmplt->data; if (lgl_template_does_page_size_match (template, paper_id) && @@ -1292,7 +1438,7 @@ _lgl_db_register_template_internal (const lglTemplate *template) lglTemplate *template_copy; template_copy = lgl_template_dup (template); - templates = g_list_append (templates, template_copy); + model->templates = g_list_append (model->templates, template_copy); add_to_template_cache (template_copy); } @@ -1313,7 +1459,7 @@ lgl_db_register_template (const lglTemplate *template) gchar *dir, *filename, *abs_filename; gint bytes_written; - if (!templates) + if (!model) { lgl_db_init (); } @@ -1338,8 +1484,9 @@ lgl_db_register_template (const lglTemplate *template) { template_copy = lgl_template_dup (template); lgl_template_add_category (template_copy, "user-defined"); - templates = g_list_append (templates, template_copy); + model->templates = g_list_append (model->templates, template_copy); add_to_template_cache (template_copy); + g_signal_emit (G_OBJECT (model), signals[CHANGED], 0); return LGL_DB_REG_OK; } else @@ -1356,6 +1503,61 @@ lgl_db_register_template (const lglTemplate *template) } +lglDbDeleteStatus +lgl_db_delete_template_by_name (const gchar *name) +{ + lglTemplate *template, *template1; + gchar *dir, *filename, *abs_filename; + GList *p; + + if (!model) + { + lgl_db_init (); + } + + if (!lgl_db_does_template_name_exist (name)) + { + return LGL_DB_DELETE_DOES_NOT_EXIST; + } + + template = lgl_db_lookup_template_from_name (name); + if ( lgl_template_does_category_match (template, "user-defined") ) + { + dir = LGL_USER_DATA_DIR; + filename = g_strdup_printf ("%s_%s.template", template->brand, template->part); + abs_filename = g_build_filename (dir, filename, NULL); + + g_unlink (abs_filename); + + g_free (dir); + g_free (filename); + g_free (abs_filename); + + for ( p=model->templates; p != NULL; p=p->next ) + { + template1 = (lglTemplate *)p->data; + + if ( lgl_template_do_templates_match (template, template1) ) + { + model->templates = g_list_delete_link (model->templates, p); + g_hash_table_remove (model->template_cache, name); + break; + } + } + + lgl_template_free (template); + + g_signal_emit (G_OBJECT (model), signals[CHANGED], 0); + return LGL_DB_DELETE_OK; + } + else + { + return LGL_DB_DELETE_NOT_USER_DEFINED; + } + +} + + /** * lgl_db_does_template_exist: * @brand: Brand name. @@ -1373,7 +1575,7 @@ lgl_db_does_template_exist (const gchar *brand, lglTemplate *template; lglTemplateAlias *alias; - if (!templates) + if (!model) { lgl_db_init (); } @@ -1383,7 +1585,7 @@ lgl_db_does_template_exist (const gchar *brand, return FALSE; } - for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) + for (p_tmplt = model->templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) { template = (lglTemplate *) p_tmplt->data; for (p_alias = template->aliases; p_alias != NULL; p_alias = p_alias->next) @@ -1419,7 +1621,7 @@ lgl_db_does_template_name_exist (const gchar *name) lglTemplateAlias *alias; gchar *candidate_name; - if (!templates) + if (!model) { lgl_db_init (); } @@ -1429,7 +1631,7 @@ lgl_db_does_template_name_exist (const gchar *name) return FALSE; } - for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) + for (p_tmplt = model->templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) { template = (lglTemplate *) p_tmplt->data; for (p_alias = template->aliases; p_alias != NULL; p_alias = p_alias->next) @@ -1475,12 +1677,12 @@ lgl_db_get_template_name_list_unique (const gchar *brand, gchar *name; GList *names = NULL; - if (!templates) + if (!model) { lgl_db_init (); } - for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) + for (p_tmplt = model->templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) { template = (lglTemplate *) p_tmplt->data; @@ -1525,12 +1727,12 @@ lgl_db_get_template_name_list_all (const gchar *brand, gchar *name; GList *names = NULL; - if (!templates) + if (!model) { lgl_db_init (); } - for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) + for (p_tmplt = model->templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) { template = (lglTemplate *) p_tmplt->data; if (lgl_template_does_page_size_match (template, paper_id) && @@ -1574,7 +1776,7 @@ lgl_db_get_similar_template_name_list (const gchar *name) gchar *name2; GList *names = NULL; - if (!templates) + if (!model) { lgl_db_init (); } @@ -1602,7 +1804,7 @@ lgl_db_get_similar_template_name_list (const gchar *name) } } - for (p_tmplt = templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) + for (p_tmplt = model->templates; p_tmplt != NULL; p_tmplt = p_tmplt->next) { template2 = (lglTemplate *) p_tmplt->data; @@ -1667,7 +1869,7 @@ lgl_db_lookup_template_from_name (const gchar *name) gchar *candidate_name; lglTemplate *new_template; - if (!templates) + if (!model) { lgl_db_init (); } @@ -1675,10 +1877,10 @@ lgl_db_lookup_template_from_name (const gchar *name) if (name == NULL) { /* If no name, return first template as a default */ - return lgl_template_dup ((lglTemplate *) templates->data); + return lgl_template_dup ((lglTemplate *) model->templates->data); } - template = g_hash_table_lookup (template_cache, name); + template = g_hash_table_lookup (model->template_cache, name); if (template) { @@ -1703,7 +1905,7 @@ lgl_db_lookup_template_from_name (const gchar *name) } /* No matching template has been found so return the first template */ - return lgl_template_dup ((lglTemplate *) templates->data); + return lgl_template_dup ((lglTemplate *) model->templates->data); } @@ -1728,7 +1930,7 @@ lgl_db_lookup_template_from_brand_part(const gchar *brand, gchar *candidate_name; lglTemplate *new_template; - if (!templates) + if (!model) { lgl_db_init (); } @@ -1736,11 +1938,11 @@ lgl_db_lookup_template_from_brand_part(const gchar *brand, if ((brand == NULL) || (part == NULL)) { /* If no name, return first template as a default */ - return lgl_template_dup ((lglTemplate *) templates->data); + return lgl_template_dup ((lglTemplate *) model->templates->data); } name = g_strdup_printf ("%s %s", brand, part); - template = g_hash_table_lookup (template_cache, name); + template = g_hash_table_lookup (model->template_cache, name); if (template) { @@ -1767,14 +1969,7 @@ lgl_db_lookup_template_from_brand_part(const gchar *brand, /* No matching template has been found so return the first template */ g_free (name); - return lgl_template_dup ((lglTemplate *) templates->data); -} - - -static void -init_template_cache (void) -{ - template_cache = g_hash_table_new (g_str_hash, g_str_equal); + return lgl_template_dup ((lglTemplate *) model->templates->data); } @@ -1790,7 +1985,7 @@ add_to_template_cache (lglTemplate *template) alias = (lglTemplateAlias *)p_alias->data; name = g_strdup_printf ("%s %s", alias->brand, alias->part); - g_hash_table_insert (template_cache, name, template); + g_hash_table_insert (model->template_cache, name, template); } } @@ -1808,7 +2003,7 @@ read_templates (void) data_dir = LGL_USER_DATA_DIR; read_template_files_from_dir (data_dir); g_free (data_dir); - for ( p=templates; p != NULL; p=p->next ) + for ( p=model->templates; p != NULL; p=p->next ) { template = (lglTemplate *)p->data; lgl_template_add_category (template, "user-defined"); @@ -1821,7 +2016,7 @@ read_templates (void) read_template_files_from_dir (data_dir); g_free (data_dir); - if (templates == NULL) + if (model->templates == NULL) { g_critical (_("Unable to locate any template files. Libglabels may not be installed correctly!")); } @@ -1929,8 +2124,13 @@ lgl_db_print_known_templates (void) GList *p; lglTemplate *template; + if (!model) + { + lgl_db_init (); + } + g_print ("%s():\n", __FUNCTION__); - for (p=templates; p!=NULL; p=p->next) + for (p=model->templates; p!=NULL; p=p->next) { template = (lglTemplate *)p->data; @@ -1956,6 +2156,11 @@ lgl_db_print_aliases (const lglTemplate *template) GList *p; lglTemplateAlias *alias; + if (!model) + { + lgl_db_init (); + } + g_print ("%s():\n", __FUNCTION__); for (p=template->aliases; p!=NULL; p=p->next) { diff --git a/libglabels/db.h b/libglabels/db.h index 343573eb..ddd162a1 100644 --- a/libglabels/db.h +++ b/libglabels/db.h @@ -38,12 +38,37 @@ typedef enum LGL_DB_REG_FILE_WRITE_ERROR = -3 } lglDbRegStatus; +typedef enum +{ + LGL_DB_DELETE_OK = 0, + LGL_DB_DELETE_DOES_NOT_EXIST = -1, + LGL_DB_DELETE_NOT_USER_DEFINED = -2, + LGL_DB_DELETE_FILE_ERROR = -3 +} lglDbDeleteStatus; + + +typedef void (*lglDbNotifyFunc) (gpointer user_data); + + + + /* * Module initialization */ void lgl_db_init (void); + +/* + * Notification + */ +gulong lgl_db_notify_add (lglDbNotifyFunc func, + gpointer user_data); + +void lgl_db_notify_remove (gulong id); + + + /* * Paper */ @@ -117,6 +142,8 @@ void lgl_db_free_brand_list (GList *brand */ lglDbRegStatus lgl_db_register_template (const lglTemplate *template); +lglDbDeleteStatus lgl_db_delete_template_by_name (const gchar *name); + gboolean lgl_db_does_template_exist (const gchar *brand, const gchar *part); diff --git a/src/Makefile.am b/src/Makefile.am index 9c9f5f15..d18b29e9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS= pixmaps stock-pixmaps +SUBDIRS= ../libglabels pixmaps stock-pixmaps bin_PROGRAMS = glabels-3 glabels-3-batch diff --git a/src/media-select.c b/src/media-select.c index ae7860ab..ea56e03b 100644 --- a/src/media-select.c +++ b/src/media-select.c @@ -31,6 +31,7 @@ #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" @@ -57,6 +58,8 @@ enum { struct _glMediaSelectPrivate { + gulong db_notify_id; + GtkBuilder *builder; GtkWidget *notebook; @@ -79,6 +82,16 @@ struct _glMediaSelectPrivate { 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; }; @@ -93,7 +106,7 @@ enum { /* Private globals */ /*===========================================*/ -static gint media_select_signals[LAST_SIGNAL] = { 0 }; +static gint signals[LAST_SIGNAL] = { 0 }; /*===========================================*/ @@ -104,22 +117,37 @@ static void gl_media_select_finalize (GObject *object); static void gl_media_select_construct (glMediaSelect *this); -static void filter_changed_cb (GtkComboBox *combo, - gpointer user_data); +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, GtkNotebookPage *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, @@ -143,7 +171,7 @@ gl_media_select_class_init (glMediaSelectClass *class) object_class->finalize = gl_media_select_finalize; - media_select_signals[CHANGED] = + signals[CHANGED] = g_signal_new ("changed", G_OBJECT_CLASS_TYPE(object_class), G_SIGNAL_RUN_LAST, @@ -177,6 +205,11 @@ gl_media_select_finalize (GObject *object) 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); @@ -216,7 +249,9 @@ gl_media_select_construct (glMediaSelect *this) { gchar *builder_filename; GtkBuilder *builder; - static gchar *object_ids[] = { "media_select_hbox", NULL }; + static gchar *object_ids[] = { "media_select_hbox", + "custom_buttons_sizegroup", + NULL }; GError *error = NULL; GtkWidget *hbox; GList *recent_list = NULL; @@ -226,10 +261,12 @@ gl_media_select_construct (glMediaSelect *this) 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"); @@ -258,6 +295,12 @@ gl_media_select_construct (glMediaSelect *this) "category_combo", &this->priv->category_combo, "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); @@ -269,6 +312,9 @@ gl_media_select_construct (glMediaSelect *this) 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); gtk_widget_show_all (GTK_WIDGET (this)); @@ -347,22 +393,60 @@ gl_media_select_construct (glMediaSelect *this) 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 (G_OBJECT (this->priv->brand_combo), "changed", - G_CALLBACK (filter_changed_cb), - this); - g_signal_connect (G_OBJECT (this->priv->page_size_combo), "changed", - G_CALLBACK (filter_changed_cb), - this); - g_signal_connect (G_OBJECT (this->priv->category_combo), "changed", - G_CALLBACK (filter_changed_cb), - this); + 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); @@ -381,6 +465,8 @@ gl_media_select_construct (glMediaSelect *this) } 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"); } @@ -389,10 +475,8 @@ gl_media_select_construct (glMediaSelect *this) /* PRIVATE. modify widget due to change in selection */ /*--------------------------------------------------------------------------*/ static void -filter_changed_cb (GtkComboBox *combo, - gpointer user_data) +filter_changed_cb (glMediaSelect *this) { - glMediaSelect *this = GL_MEDIA_SELECT (user_data); gchar *brand; gchar *page_size_name, *page_size_id; gchar *category_name, *category_id; @@ -432,8 +516,7 @@ filter_changed_cb (GtkComboBox *combo, g_free (category_id); /* Emit our "changed" signal */ - g_signal_emit (G_OBJECT (user_data), - media_select_signals[CHANGED], 0); + g_signal_emit (G_OBJECT (this), signals[CHANGED], 0); } g_free (brand); g_free (page_size_name); @@ -453,20 +536,89 @@ static void selection_changed_cb (GtkTreeSelection *selection, gpointer user_data) { - glMediaSelect *this = GL_MEDIA_SELECT (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 ); + + if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_NONE) + /* Emit our "changed" signal */ - g_signal_emit (G_OBJECT (user_data), - media_select_signals[CHANGED], 0); + 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) +{ +} + + +/*--------------------------------------------------------------------------*/ +/* 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; + + 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); + + lgl_db_delete_template_by_name (name); + + g_free (name); + } + + this->priv->stop_signals = FALSE; +} + + /*--------------------------------------------------------------------------*/ /* PRIVATE. modify widget due to change in selection */ /*--------------------------------------------------------------------------*/ @@ -488,13 +640,67 @@ page_changed_cb (GtkNotebook *notebook, this->priv->current_page_num = page_num; /* Emit our "changed" signal */ - g_signal_emit (G_OBJECT (user_data), - media_select_signals[CHANGED], 0); + 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 search all page. */ + brand = gtk_combo_box_get_active_text (GTK_COMBO_BOX (this->priv->brand_combo)); + page_size_name = gtk_combo_box_get_active_text (GTK_COMBO_BOX (this->priv->page_size_combo)); + category_name = gtk_combo_box_get_active_text (GTK_COMBO_BOX (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, _("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. */ /****************************************************************************/ @@ -518,6 +724,10 @@ gl_media_select_get_name (glMediaSelect *this) { 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); @@ -728,7 +938,7 @@ load_recent_list (glMediaSelect *this, 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 from the \"Search all templates\" page.")); + "%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, @@ -836,6 +1046,104 @@ load_search_all_list (glMediaSelect *this, } +/*--------------------------------------------------------------------------*/ +/* 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 ("%s: %s\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 -- 2.39.5