1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 * (GLABELS) Label and Business Card Creation program for GNOME
6 * merge.c: document merge module
8 * Copyright (C) 2001-2002 Jim Evins <evins@snaught.com>.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <glib/gi18n.h>
29 #include <gobject/gvaluecollector.h>
32 #include <libglabels/str.h>
36 /*========================================================*/
38 /*========================================================*/
40 struct _glMergePrivate {
44 glMergeSrcType src_type;
58 glMergeSrcType src_type;
65 /*========================================================*/
66 /* Private globals. */
67 /*========================================================*/
69 static GList *backends = NULL;
71 /*========================================================*/
72 /* Private function prototypes. */
73 /*========================================================*/
75 static void gl_merge_finalize (GObject *object);
77 static void merge_open (glMerge *merge);
79 static void merge_close (glMerge *merge);
81 static glMergeRecord *merge_get_record (glMerge *merge);
83 static void merge_free_record (glMergeRecord **record);
85 static glMergeRecord *merge_dup_record (glMergeRecord *record);
87 static void merge_free_record_list (GList **record_list);
89 static GList *merge_dup_record_list (GList *record_list);
94 /*****************************************************************************/
95 /* Register a new merge backend. */
96 /*****************************************************************************/
98 gl_merge_register_backend (GType type,
101 glMergeSrcType src_type,
102 const gchar *first_arg_name,
111 guint n_params = 0, n_alloced_params = 16;
113 backend = g_new0 (Backend, 1);
115 backend->type = type;
116 backend->name = g_strdup (name);
117 backend->description = g_strdup (description);
118 backend->src_type = src_type;
120 params = g_new (GParameter, n_alloced_params);
121 va_start (args, first_arg_name);
122 for ( pname=first_arg_name; pname != NULL; pname=va_arg (args,gchar *) ) {
125 class = g_type_class_ref (type);
127 g_message ("%s: unknown object type %d",
128 G_STRLOC, (int)type);
131 pspec = g_object_class_find_property (class, pname);
133 g_message ("%s: object class `%s' has no property named `%s'",
134 G_STRLOC, g_type_name (type), pname);
137 if (n_params >= n_alloced_params) {
138 n_alloced_params += 16;
139 params = g_renew (GParameter, params, n_alloced_params);
141 params[n_params].name = pname;
142 params[n_params].value.g_type = 0;
143 g_value_init (¶ms[n_params].value, pspec->value_type);
144 G_VALUE_COLLECT (¶ms[n_params].value, args, 0, &error);
146 g_message ("%s: %s", G_STRLOC, error);
155 backend->n_params = n_params;
156 backend->params = params;
158 backends = g_list_append (backends, backend);
162 /*****************************************************************************/
163 /* Get list of registered backend descriptions. */
164 /*****************************************************************************/
166 gl_merge_get_descriptions (void)
168 GList *descriptions = NULL;
172 descriptions = g_list_append (descriptions, g_strdup(_("None")));
174 for ( p=backends; p!=NULL; p=p->next) {
175 backend = (Backend *)p->data;
176 descriptions = g_list_append (descriptions,
177 g_strdup(backend->description));
183 /*****************************************************************************/
184 /* Free list of descriptions. */
185 /*****************************************************************************/
187 gl_merge_free_descriptions (GList **descriptions)
191 gl_debug (DEBUG_MERGE, "START");
193 for (p = *descriptions; p != NULL; p = p->next) {
198 g_list_free (*descriptions);
199 *descriptions = NULL;
201 gl_debug (DEBUG_MERGE, "END");
204 /*****************************************************************************/
205 /* Lookup name of backend from description. */
206 /*****************************************************************************/
208 gl_merge_description_to_name (gchar *description)
213 if (lgl_str_utf8_casecmp(description, _("None")) == 0) {
214 return g_strdup("None");
217 for ( p=backends; p!=NULL; p=p->next) {
218 backend = (Backend *)p->data;
219 if (lgl_str_utf8_casecmp(description, backend->description) == 0) {
220 return g_strdup(backend->name);
224 return g_strdup("None");
227 /*****************************************************************************/
228 /* Boilerplate object stuff. */
229 /*****************************************************************************/
230 G_DEFINE_TYPE (glMerge, gl_merge, G_TYPE_OBJECT);
233 gl_merge_class_init (glMergeClass *class)
235 GObjectClass *object_class = G_OBJECT_CLASS (class);
237 gl_debug (DEBUG_MERGE, "START");
239 gl_merge_parent_class = g_type_class_peek_parent (class);
241 object_class->finalize = gl_merge_finalize;
243 gl_debug (DEBUG_MERGE, "END");
247 gl_merge_init (glMerge *merge)
249 gl_debug (DEBUG_MERGE, "START");
251 merge->priv = g_new0 (glMergePrivate, 1);
253 gl_debug (DEBUG_MERGE, "END");
257 gl_merge_finalize (GObject *object)
259 glMerge *merge = GL_MERGE (object);
261 gl_debug (DEBUG_MERGE, "START");
263 g_return_if_fail (object && GL_IS_MERGE (object));
265 merge_free_record_list (&merge->priv->record_list);
266 g_free (merge->priv->name);
267 g_free (merge->priv->description);
268 g_free (merge->priv->src);
269 g_free (merge->priv);
271 G_OBJECT_CLASS (gl_merge_parent_class)->finalize (object);
273 gl_debug (DEBUG_MERGE, "END");
276 /*****************************************************************************/
277 /* New merge object. */
278 /*****************************************************************************/
280 gl_merge_new (gchar *name)
282 glMerge *merge = NULL;
286 gl_debug (DEBUG_MERGE, "START");
288 for (p=backends; p!=NULL; p=p->next) {
289 backend = (Backend *)p->data;
291 if (g_strcasecmp(name, backend->name) == 0) {
293 merge = GL_MERGE (g_object_newv (backend->type,
297 merge->priv->name = g_strdup (name);
298 merge->priv->description = g_strdup (backend->description);
299 merge->priv->src_type = backend->src_type;
305 if ( (merge == NULL) && (g_strcasecmp (name, "None") != 0)) {
306 g_message ("Unknown merge backend \"%s\"", name);
309 gl_debug (DEBUG_MERGE, "END");
314 /*****************************************************************************/
315 /* Duplicate merge. */
316 /*****************************************************************************/
318 gl_merge_dup (glMerge *src_merge)
322 gl_debug (DEBUG_MERGE, "START");
324 if (src_merge == NULL) {
325 gl_debug (DEBUG_MERGE, "END (NULL)");
329 g_return_val_if_fail (GL_IS_MERGE (src_merge), NULL);
331 dst_merge = g_object_new (G_OBJECT_TYPE(src_merge), NULL);
332 dst_merge->priv->name = g_strdup (src_merge->priv->name);
333 dst_merge->priv->description = g_strdup (src_merge->priv->description);
334 dst_merge->priv->src = g_strdup (src_merge->priv->src);
335 dst_merge->priv->src_type = src_merge->priv->src_type;
336 dst_merge->priv->record_list
337 = merge_dup_record_list (src_merge->priv->record_list);
339 if ( GL_MERGE_GET_CLASS(src_merge)->copy != NULL ) {
341 /* We have an object specific method, use it */
342 GL_MERGE_GET_CLASS(src_merge)->copy (dst_merge, src_merge);
346 gl_debug (DEBUG_MERGE, "END");
351 /*****************************************************************************/
352 /* Get name of merge. */
353 /*****************************************************************************/
355 gl_merge_get_name (glMerge *merge)
357 gl_debug (DEBUG_MERGE, "");
360 return g_strdup("None");
363 g_return_val_if_fail (GL_IS_MERGE (merge), g_strdup("None"));
365 return g_strdup(merge->priv->name);
368 /*****************************************************************************/
369 /* Get description of merge. */
370 /*****************************************************************************/
372 gl_merge_get_description (glMerge *merge)
374 gl_debug (DEBUG_MERGE, "");
377 return g_strdup(_("None"));
380 g_return_val_if_fail (GL_IS_MERGE (merge), g_strdup(_("None")));
382 return g_strdup(merge->priv->description);
385 /*****************************************************************************/
386 /* Get source type of merge. */
387 /*****************************************************************************/
389 gl_merge_get_src_type (glMerge *merge)
391 gl_debug (DEBUG_MERGE, "");
394 return GL_MERGE_SRC_IS_FIXED;
397 g_return_val_if_fail (GL_IS_MERGE (merge), GL_MERGE_SRC_IS_FIXED);
399 return merge->priv->src_type;
402 /*****************************************************************************/
403 /* Set src of merge. */
404 /*****************************************************************************/
406 gl_merge_set_src (glMerge *merge,
409 GList *record_list = NULL;
410 glMergeRecord *record;
412 gl_debug (DEBUG_MERGE, "START");
416 gl_debug (DEBUG_MERGE, "END (NULL)");
420 g_return_if_fail (GL_IS_MERGE (merge));
425 if ( merge->priv->src != NULL )
427 g_free (merge->priv->src);
429 merge->priv->src = NULL;
430 merge_free_record_list (&merge->priv->record_list);
436 if ( merge->priv->src != NULL )
438 g_free(merge->priv->src);
440 merge->priv->src = g_strdup (src);
442 merge_free_record_list (&merge->priv->record_list);
445 while ( (record = merge_get_record (merge)) != NULL )
447 record_list = g_list_append( record_list, record );
450 merge->priv->record_list = record_list;
455 gl_debug (DEBUG_MERGE, "END");
458 /*****************************************************************************/
459 /* Get src of merge. */
460 /*****************************************************************************/
462 gl_merge_get_src (glMerge *merge)
464 gl_debug (DEBUG_MERGE, "");
470 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
472 return g_strdup(merge->priv->src);
475 /*****************************************************************************/
477 /*****************************************************************************/
479 gl_merge_get_key_list (glMerge *merge)
481 GList *key_list = NULL;
483 gl_debug (DEBUG_MERGE, "START");
489 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
491 if ( GL_MERGE_GET_CLASS(merge)->get_key_list != NULL ) {
493 key_list = GL_MERGE_GET_CLASS(merge)->get_key_list (merge);
497 gl_debug (DEBUG_MERGE, "END");
502 /*****************************************************************************/
503 /* Free a list of keys. */
504 /*****************************************************************************/
506 gl_merge_free_key_list (GList **key_list)
510 gl_debug (DEBUG_MERGE, "START");
512 for (p = *key_list; p != NULL; p = p->next) {
517 g_list_free (*key_list);
520 gl_debug (DEBUG_MERGE, "END");
523 /*****************************************************************************/
525 /*****************************************************************************/
527 gl_merge_get_primary_key (glMerge *merge)
531 gl_debug (DEBUG_MERGE, "START");
537 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
539 if ( GL_MERGE_GET_CLASS(merge)->get_primary_key != NULL ) {
541 key = GL_MERGE_GET_CLASS(merge)->get_primary_key (merge);
545 gl_debug (DEBUG_MERGE, "END");
550 /*---------------------------------------------------------------------------*/
551 /* Open merge source. */
552 /*---------------------------------------------------------------------------*/
554 merge_open (glMerge *merge)
556 gl_debug (DEBUG_MERGE, "START");
558 g_return_if_fail (merge && GL_IS_MERGE (merge));
560 if ( GL_MERGE_GET_CLASS(merge)->open != NULL ) {
562 GL_MERGE_GET_CLASS(merge)->open (merge);
566 gl_debug (DEBUG_MERGE, "END");
569 /*---------------------------------------------------------------------------*/
570 /* Close merge source. */
571 /*---------------------------------------------------------------------------*/
573 merge_close (glMerge *merge)
575 gl_debug (DEBUG_MERGE, "START");
577 g_return_if_fail (merge && GL_IS_MERGE (merge));
579 if ( GL_MERGE_GET_CLASS(merge)->close != NULL ) {
581 GL_MERGE_GET_CLASS(merge)->close (merge);
585 gl_debug (DEBUG_MERGE, "END");
588 /*---------------------------------------------------------------------------*/
589 /* Get next record (list of fields) from opened merge source. */
590 /*---------------------------------------------------------------------------*/
591 static glMergeRecord *
592 merge_get_record (glMerge *merge)
594 glMergeRecord *record = NULL;
596 gl_debug (DEBUG_MERGE, "START");
598 g_return_val_if_fail (merge && GL_IS_MERGE (merge), NULL);
600 if ( GL_MERGE_GET_CLASS(merge)->get_record != NULL ) {
602 record = GL_MERGE_GET_CLASS(merge)->get_record (merge);
606 gl_debug (DEBUG_MERGE, "END");
611 /*---------------------------------------------------------------------------*/
612 /* Free a merge record (list of fields) */
613 /*---------------------------------------------------------------------------*/
615 merge_free_record (glMergeRecord **record)
620 gl_debug (DEBUG_MERGE, "START");
622 for (p = (*record)->field_list; p != NULL; p = p->next) {
623 field = (glMergeField *) p->data;
627 g_free (field->value);
634 g_list_free ((*record)->field_list);
635 (*record)->field_list = NULL;
640 gl_debug (DEBUG_MERGE, "END");
643 /*---------------------------------------------------------------------------*/
644 /* Duplicate a merge record (list of fields) */
645 /*---------------------------------------------------------------------------*/
646 static glMergeRecord *
647 merge_dup_record (glMergeRecord *record)
649 glMergeRecord *dest_record;
651 glMergeField *dest_field, *field;
653 gl_debug (DEBUG_MERGE, "START");
655 dest_record = g_new0 (glMergeRecord, 1);
656 dest_record->select_flag = record->select_flag;
658 for (p = record->field_list; p != NULL; p = p->next) {
659 field = (glMergeField *) p->data;
661 dest_field = g_new0 (glMergeField, 1);
663 dest_field->key = g_strdup (field->key);
664 dest_field->value = g_strdup (field->value);
666 dest_record->field_list =
667 g_list_append (dest_record->field_list, dest_field);
671 gl_debug (DEBUG_MERGE, "END");
676 /*****************************************************************************/
677 /* Find key in given record and evaluate. */
678 /*****************************************************************************/
680 gl_merge_eval_key (glMergeRecord *record,
688 gl_debug (DEBUG_MERGE, "START");
690 if ( (record != NULL) ) {
691 for (p = record->field_list; p != NULL; p = p->next) {
692 field = (glMergeField *) p->data;
694 if (strcmp (key, field->key) == 0) {
695 val = g_strdup (field->value);
701 gl_debug (DEBUG_MERGE, "END");
706 /*****************************************************************************/
707 /* Read all records from merge source. */
708 /*****************************************************************************/
710 gl_merge_get_record_list (glMerge *merge)
712 gl_debug (DEBUG_MERGE, "");
714 if ( merge != NULL ) {
715 return merge->priv->record_list;
721 /*---------------------------------------------------------------------------*/
722 /* Free a list of records. */
723 /*---------------------------------------------------------------------------*/
725 merge_free_record_list (GList **record_list)
728 glMergeRecord *record;
730 gl_debug (DEBUG_MERGE, "START");
732 for (p = *record_list; p != NULL; p = p->next) {
733 record = (glMergeRecord *) p->data;
735 merge_free_record( &record );
739 g_list_free (*record_list);
742 gl_debug (DEBUG_MERGE, "END");
745 /*---------------------------------------------------------------------------*/
746 /* Duplicate a list of records. */
747 /*---------------------------------------------------------------------------*/
749 merge_dup_record_list (GList *record_list)
751 GList *dest_list = NULL, *p;
752 glMergeRecord *dest_record, *record;
754 gl_debug (DEBUG_MERGE, "START");
756 for (p = record_list; p != NULL; p = p->next) {
757 record = (glMergeRecord *) p->data;
759 dest_record = merge_dup_record( record );
760 dest_list = g_list_append (dest_list, dest_record);
764 gl_debug (DEBUG_MERGE, "END");
769 /*****************************************************************************/
770 /* Count selected records. */
771 /*****************************************************************************/
773 gl_merge_get_record_count (glMerge *merge)
776 glMergeRecord *record;
779 gl_debug (DEBUG_MERGE, "START");
782 for ( p=merge->priv->record_list; p!=NULL; p=p->next ) {
783 record = (glMergeRecord *)p->data;
785 if ( record->select_flag ) count ++;
788 gl_debug (DEBUG_MERGE, "END");