]> git.sur5r.net Git - glabels/blob - src/merge.c
Imported Upstream version 2.2.8
[glabels] / src / merge.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  merge.c:  document merge module
7  *
8  *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
9  *
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.
14  *
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.
19  *
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
23  */
24 #include <config.h>
25
26 #include "merge.h"
27
28 #include <glib/gi18n.h>
29 #include <gobject/gvaluecollector.h>
30 #include <string.h>
31
32 #include "debug.h"
33
34 /*========================================================*/
35 /* Private types.                                         */
36 /*========================================================*/
37
38 struct _glMergePrivate {
39         gchar             *name;
40         gchar             *description;
41         gchar             *src;
42         glMergeSrcType     src_type;
43
44         GList             *record_list;
45 };
46
47 enum {
48         LAST_SIGNAL
49 };
50
51 typedef struct {
52
53         GType              type;
54         gchar             *name;
55         gchar             *description;
56         glMergeSrcType     src_type;
57
58         guint              n_params;
59         GParameter        *params;
60
61 } Backend;
62
63 /*========================================================*/
64 /* Private globals.                                       */
65 /*========================================================*/
66
67 static GList *backends = NULL;
68
69 /*========================================================*/
70 /* Private function prototypes.                           */
71 /*========================================================*/
72
73 static void           gl_merge_finalize      (GObject        *object);
74
75 static void           merge_open             (glMerge        *merge);
76
77 static void           merge_close            (glMerge        *merge);
78
79 static glMergeRecord *merge_get_record       (glMerge        *merge);
80
81 static void           merge_free_record      (glMergeRecord **record);
82
83 static glMergeRecord *merge_dup_record       (glMergeRecord  *record);
84
85 static void           merge_free_record_list (GList         **record_list);
86
87 static GList         *merge_dup_record_list  (GList          *record_list);
88
89
90
91 \f
92 /*****************************************************************************/
93 /* Register a new merge backend.                                             */
94 /*****************************************************************************/
95 void
96 gl_merge_register_backend (GType              type,
97                            gchar             *name,
98                            gchar             *description,
99                            glMergeSrcType     src_type,
100                            const gchar       *first_arg_name,
101                            ...)
102 {
103         Backend      *backend;
104         va_list       args;
105         const gchar  *pname;
106         GObjectClass *class;
107         GParamSpec   *pspec;
108         GParameter   *params;
109         guint         n_params = 0, n_alloced_params = 16;
110
111         backend = g_new0 (Backend, 1);
112
113         backend->type        = type;
114         backend->name        = g_strdup (name);
115         backend->description = g_strdup (description);
116         backend->src_type    = src_type;
117
118         params = g_new (GParameter, n_alloced_params);
119         va_start (args, first_arg_name);
120         for ( pname=first_arg_name; pname != NULL; pname=va_arg (args,gchar *) ) {
121                 gchar *error = NULL;
122
123                 class = g_type_class_ref (type);
124                 if (class == NULL) {
125                         g_message ("%s: unknown object type %d",
126                                    G_STRLOC, (int)type);
127                         break;
128                 }
129                 pspec = g_object_class_find_property (class, pname);
130                 if (pspec == NULL) {
131                         g_message ("%s: object class `%s' has no property named `%s'",
132                                    G_STRLOC, g_type_name (type), pname);
133                         break;
134                 }
135                 if (n_params >= n_alloced_params) {
136                         n_alloced_params += 16;
137                         params = g_renew (GParameter, params, n_alloced_params);
138                 }
139                 params[n_params].name = pname;
140                 params[n_params].value.g_type = 0;
141                 g_value_init (&params[n_params].value, pspec->value_type);
142                 G_VALUE_COLLECT (&params[n_params].value, args, 0, &error);
143                 if (error) {
144                         g_message ("%s: %s", G_STRLOC, error);
145                         g_free (error);
146                         break;
147                 }
148
149                 n_params++;
150         }
151         va_end (args);
152
153         backend->n_params = n_params;
154         backend->params   = params;
155
156         backends = g_list_append (backends, backend);
157
158 }
159
160 /*****************************************************************************/
161 /* Get list of registered backend descriptions.                              */
162 /*****************************************************************************/
163 GList *
164 gl_merge_get_descriptions (void)
165 {
166         GList   *descriptions = NULL;
167         GList   *p;
168         Backend *backend;
169
170         descriptions = g_list_append (descriptions, g_strdup(_("None")));
171
172         for ( p=backends; p!=NULL; p=p->next) {
173                 backend = (Backend *)p->data;
174                 descriptions = g_list_append (descriptions,
175                                               g_strdup(backend->description));
176         }
177
178         return descriptions;
179 }
180
181 /*****************************************************************************/
182 /* Free list of descriptions.                                                */
183 /*****************************************************************************/
184 void
185 gl_merge_free_descriptions (GList **descriptions)
186 {
187         GList *p;
188
189         gl_debug (DEBUG_MERGE, "START");
190
191         for (p = *descriptions; p != NULL; p = p->next) {
192                 g_free (p->data);
193                 p->data = NULL;
194         }
195
196         g_list_free (*descriptions);
197         *descriptions = NULL;
198
199         gl_debug (DEBUG_MERGE, "END");
200 }
201
202 /*****************************************************************************/
203 /* Lookup name of backend from description.                                  */
204 /*****************************************************************************/
205 gchar *
206 gl_merge_description_to_name (gchar *description)
207 {
208         GList   *p;
209         Backend *backend;
210
211         if (g_strcasecmp(description, _("None")) == 0) {
212                 return g_strdup("None");
213         }
214
215         for ( p=backends; p!=NULL; p=p->next) {
216                 backend = (Backend *)p->data;
217                 if (g_strcasecmp(description, backend->description) == 0) {
218                         return g_strdup(backend->name);
219                 }
220         }
221
222         return g_strdup("None");
223 }
224
225 /*****************************************************************************/
226 /* Boilerplate object stuff.                                                 */
227 /*****************************************************************************/
228 G_DEFINE_TYPE (glMerge, gl_merge, G_TYPE_OBJECT);
229
230 static void
231 gl_merge_class_init (glMergeClass *class)
232 {
233         GObjectClass *object_class = G_OBJECT_CLASS (class);
234
235         gl_debug (DEBUG_MERGE, "START");
236
237         gl_merge_parent_class = g_type_class_peek_parent (class);
238
239         object_class->finalize = gl_merge_finalize;
240
241         gl_debug (DEBUG_MERGE, "END");
242 }
243
244 static void
245 gl_merge_init (glMerge *merge)
246 {
247         gl_debug (DEBUG_MERGE, "START");
248
249         merge->priv = g_new0 (glMergePrivate, 1);
250
251         gl_debug (DEBUG_MERGE, "END");
252 }
253
254 static void
255 gl_merge_finalize (GObject *object)
256 {
257         glMerge *merge = GL_MERGE (object);
258
259         gl_debug (DEBUG_MERGE, "START");
260
261         g_return_if_fail (object && GL_IS_MERGE (object));
262
263         merge_free_record_list (&merge->priv->record_list);
264         g_free (merge->priv->name);
265         g_free (merge->priv->description);
266         g_free (merge->priv->src);
267         g_free (merge->priv);
268
269         G_OBJECT_CLASS (gl_merge_parent_class)->finalize (object);
270
271         gl_debug (DEBUG_MERGE, "END");
272 }
273
274 /*****************************************************************************/
275 /* New merge object.                                                         */
276 /*****************************************************************************/
277 glMerge *
278 gl_merge_new (gchar *name)
279 {
280         glMerge *merge = NULL;
281         GList   *p;
282         Backend *backend;
283
284         gl_debug (DEBUG_MERGE, "START");
285
286         for (p=backends; p!=NULL; p=p->next) {
287                 backend = (Backend *)p->data;
288
289                 if (g_strcasecmp(name, backend->name) == 0) {
290
291                         merge = GL_MERGE (g_object_newv (backend->type,
292                                                          backend->n_params,
293                                                          backend->params));
294
295                         merge->priv->name        = g_strdup (name);
296                         merge->priv->description = g_strdup (backend->description);
297                         merge->priv->src_type    = backend->src_type;
298
299                         break;
300                 }
301         }
302
303         if ( (merge == NULL) && (g_strcasecmp (name, "None") != 0)) {
304                 g_message ("Unknown merge backend \"%s\"", name);
305         }
306
307         gl_debug (DEBUG_MERGE, "END");
308
309         return merge;
310 }
311
312 /*****************************************************************************/
313 /* Duplicate merge.                                                         */
314 /*****************************************************************************/
315 glMerge *
316 gl_merge_dup (glMerge *src_merge)
317 {
318         glMerge    *dst_merge;
319
320         gl_debug (DEBUG_MERGE, "START");
321
322         if (src_merge == NULL) {
323                 gl_debug (DEBUG_MERGE, "END (NULL)");
324                 return NULL;
325         }
326
327         g_return_val_if_fail (GL_IS_MERGE (src_merge), NULL);
328
329         dst_merge = g_object_new (G_OBJECT_TYPE(src_merge), NULL);
330         dst_merge->priv->name        = g_strdup (src_merge->priv->name);
331         dst_merge->priv->description = g_strdup (src_merge->priv->description);
332         dst_merge->priv->src         = g_strdup (src_merge->priv->src);
333         dst_merge->priv->src_type    = src_merge->priv->src_type;
334         dst_merge->priv->record_list 
335                 = merge_dup_record_list (src_merge->priv->record_list);
336
337         if ( GL_MERGE_GET_CLASS(src_merge)->copy != NULL ) {
338
339                 /* We have an object specific method, use it */
340                 GL_MERGE_GET_CLASS(src_merge)->copy (dst_merge, src_merge);
341
342         }
343
344         gl_debug (DEBUG_MERGE, "END");
345
346         return dst_merge;
347 }
348
349 /*****************************************************************************/
350 /* Get name of merge.                                                        */
351 /*****************************************************************************/
352 gchar *
353 gl_merge_get_name (glMerge *merge)
354 {
355         gl_debug (DEBUG_MERGE, "");
356
357         if (merge == NULL) {
358                 return g_strdup("None");
359         }
360
361         g_return_val_if_fail (GL_IS_MERGE (merge), g_strdup("None"));
362
363         return g_strdup(merge->priv->name);
364 }
365
366 /*****************************************************************************/
367 /* Get description of merge.                                                 */
368 /*****************************************************************************/
369 gchar *
370 gl_merge_get_description (glMerge *merge)
371 {
372         gl_debug (DEBUG_MERGE, "");
373
374         if (merge == NULL) {
375                 return g_strdup(_("None"));
376         }
377
378         g_return_val_if_fail (GL_IS_MERGE (merge), g_strdup(_("None")));
379
380         return g_strdup(merge->priv->description);
381 }
382
383 /*****************************************************************************/
384 /* Get source type of merge.                                                 */
385 /*****************************************************************************/
386 glMergeSrcType
387 gl_merge_get_src_type (glMerge *merge)
388 {
389         gl_debug (DEBUG_MERGE, "");
390
391         if (merge == NULL) {
392                 return GL_MERGE_SRC_IS_FIXED;
393         }
394
395         g_return_val_if_fail (GL_IS_MERGE (merge), GL_MERGE_SRC_IS_FIXED);
396
397         return merge->priv->src_type;
398 }
399
400 /*****************************************************************************/
401 /* Set src of merge.                                                         */
402 /*****************************************************************************/
403 void
404 gl_merge_set_src (glMerge *merge,
405                   gchar   *src)
406 {
407         GList         *record_list = NULL;
408         glMergeRecord *record;
409
410         gl_debug (DEBUG_MERGE, "START");
411
412         if (merge == NULL)
413         {
414                 gl_debug (DEBUG_MERGE, "END (NULL)");
415                 return;
416         }
417
418         g_return_if_fail (GL_IS_MERGE (merge));
419
420         if ( src == NULL)
421         {
422
423                 if ( merge->priv->src != NULL )
424                 {
425                         g_free (merge->priv->src);
426                 }
427                 merge->priv->src = NULL;
428                 merge_free_record_list (&merge->priv->record_list);
429
430         }
431         else
432         {
433
434                 if ( merge->priv->src != NULL )
435                 {
436                         g_free(merge->priv->src);
437                 }
438                 merge->priv->src = g_strdup (src);
439
440                 merge_free_record_list (&merge->priv->record_list);
441                         
442                 merge_open (merge);
443                 while ( (record = merge_get_record (merge)) != NULL )
444                 {
445                         record_list = g_list_append( record_list, record );
446                 }
447                 merge_close (merge);
448                 merge->priv->record_list = record_list;
449
450         }
451                      
452
453         gl_debug (DEBUG_MERGE, "END");
454 }
455
456 /*****************************************************************************/
457 /* Get src of merge.                                                         */
458 /*****************************************************************************/
459 gchar *
460 gl_merge_get_src (glMerge *merge)
461 {
462         gl_debug (DEBUG_MERGE, "");
463
464         if (merge == NULL) {
465                 return NULL;
466         }
467
468         g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
469
470         return g_strdup(merge->priv->src);
471 }
472
473 /*****************************************************************************/
474 /* Get Key List.                                                             */
475 /*****************************************************************************/
476 GList *
477 gl_merge_get_key_list (glMerge *merge)
478 {
479         GList *key_list = NULL;
480
481         gl_debug (DEBUG_MERGE, "START");
482
483         if (merge == NULL) {
484                 return NULL;
485         }
486
487         g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
488
489         if ( GL_MERGE_GET_CLASS(merge)->get_key_list != NULL ) {
490
491                 key_list = GL_MERGE_GET_CLASS(merge)->get_key_list (merge);
492
493         }
494
495         gl_debug (DEBUG_MERGE, "END");
496
497         return key_list;
498 }
499
500 /*****************************************************************************/
501 /* Free a list of keys.                                                      */
502 /*****************************************************************************/
503 void
504 gl_merge_free_key_list (GList **key_list)
505 {
506         GList *p;
507
508         gl_debug (DEBUG_MERGE, "START");
509
510         for (p = *key_list; p != NULL; p = p->next) {
511                 g_free (p->data);
512                 p->data = NULL;
513         }
514
515         g_list_free (*key_list);
516         *key_list = NULL;
517
518         gl_debug (DEBUG_MERGE, "END");
519 }
520
521 /*****************************************************************************/
522 /* Get Key List.                                                             */
523 /*****************************************************************************/
524 gchar *
525 gl_merge_get_primary_key (glMerge *merge)
526 {
527         gchar *key = NULL;
528
529         gl_debug (DEBUG_MERGE, "START");
530
531         if (merge == NULL) {
532                 return NULL;
533         }
534
535         g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
536
537         if ( GL_MERGE_GET_CLASS(merge)->get_primary_key != NULL ) {
538
539                 key = GL_MERGE_GET_CLASS(merge)->get_primary_key (merge);
540
541         }
542
543         gl_debug (DEBUG_MERGE, "END");
544
545         return key;
546 }
547
548 /*---------------------------------------------------------------------------*/
549 /* Open merge source.                                                        */
550 /*---------------------------------------------------------------------------*/
551 static void
552 merge_open (glMerge *merge)
553 {
554         gl_debug (DEBUG_MERGE, "START");
555
556         g_return_if_fail (merge && GL_IS_MERGE (merge));
557
558         if ( GL_MERGE_GET_CLASS(merge)->open != NULL ) {
559
560                 GL_MERGE_GET_CLASS(merge)->open (merge);
561
562         }
563
564         gl_debug (DEBUG_MERGE, "END");
565 }
566
567 /*---------------------------------------------------------------------------*/
568 /* Close merge source.                                                       */
569 /*---------------------------------------------------------------------------*/
570 static void
571 merge_close (glMerge *merge)
572 {
573         gl_debug (DEBUG_MERGE, "START");
574
575         g_return_if_fail (merge && GL_IS_MERGE (merge));
576
577         if ( GL_MERGE_GET_CLASS(merge)->close != NULL ) {
578
579                 GL_MERGE_GET_CLASS(merge)->close (merge);
580
581         }
582
583         gl_debug (DEBUG_MERGE, "END");
584 }
585
586 /*---------------------------------------------------------------------------*/
587 /* Get next record (list of fields) from opened merge source.                */
588 /*---------------------------------------------------------------------------*/
589 static glMergeRecord *
590 merge_get_record (glMerge *merge)
591 {
592         glMergeRecord *record = NULL;
593
594         gl_debug (DEBUG_MERGE, "START");
595
596         g_return_val_if_fail (merge && GL_IS_MERGE (merge), NULL);
597
598         if ( GL_MERGE_GET_CLASS(merge)->get_record != NULL ) {
599
600                 record = GL_MERGE_GET_CLASS(merge)->get_record (merge);
601
602         }
603
604         gl_debug (DEBUG_MERGE, "END");
605
606         return record;
607 }
608
609 /*---------------------------------------------------------------------------*/
610 /* Free a merge record (list of fields)                                      */
611 /*---------------------------------------------------------------------------*/
612 static void
613 merge_free_record (glMergeRecord **record)
614 {
615         GList *p;
616         glMergeField *field;
617
618         gl_debug (DEBUG_MERGE, "START");
619
620         for (p = (*record)->field_list; p != NULL; p = p->next) {
621                 field = (glMergeField *) p->data;
622
623                 g_free (field->key);
624                 field->key = NULL;
625                 g_free (field->value);
626                 field->value = NULL;
627
628                 g_free (p->data);
629                 p->data = NULL;
630
631         }
632         g_list_free ((*record)->field_list);
633         (*record)->field_list = NULL;
634
635         g_free (*record);
636         *record = NULL;
637
638         gl_debug (DEBUG_MERGE, "END");
639 }
640
641 /*---------------------------------------------------------------------------*/
642 /* Duplicate a merge record (list of fields)                                 */
643 /*---------------------------------------------------------------------------*/
644 static glMergeRecord *
645 merge_dup_record (glMergeRecord *record)
646 {
647         glMergeRecord *dest_record;
648         GList         *p;
649         glMergeField  *dest_field, *field;
650
651         gl_debug (DEBUG_MERGE, "START");
652
653         dest_record = g_new0 (glMergeRecord, 1);
654         dest_record->select_flag = record->select_flag;
655
656         for (p = record->field_list; p != NULL; p = p->next) {
657                 field = (glMergeField *) p->data;
658
659                 dest_field = g_new0 (glMergeField, 1);
660
661                 dest_field->key   = g_strdup (field->key);
662                 dest_field->value = g_strdup (field->value);
663
664                 dest_record->field_list =
665                         g_list_append (dest_record->field_list, dest_field);
666
667         }
668
669         gl_debug (DEBUG_MERGE, "END");
670
671         return dest_record;
672 }
673
674 /*****************************************************************************/
675 /* Find key in given record and evaluate.                                    */
676 /*****************************************************************************/
677 gchar *
678 gl_merge_eval_key (glMergeRecord *record,
679                    gchar         *key)
680                    
681 {
682         GList        *p;
683         glMergeField *field;
684         gchar        *val = NULL;
685
686         gl_debug (DEBUG_MERGE, "START");
687
688         if ( (record != NULL) && (key != NULL) ) {
689                 for (p = record->field_list; p != NULL; p = p->next) {
690                         field = (glMergeField *) p->data;
691
692                         if (strcmp (key, field->key) == 0) {
693                                 val = g_strdup (field->value);
694                         }
695
696                 }
697         }
698
699         gl_debug (DEBUG_MERGE, "END");
700
701         return val;
702 }
703
704 /*****************************************************************************/
705 /* Read all records from merge source.                                       */
706 /*****************************************************************************/
707 const GList *
708 gl_merge_get_record_list (glMerge *merge)
709 {
710         gl_debug (DEBUG_MERGE, "");
711               
712         if ( merge != NULL ) {
713                 return merge->priv->record_list;
714         } else {
715                 return NULL;
716         }
717 }
718
719 /*---------------------------------------------------------------------------*/
720 /* Free a list of records.                                                   */
721 /*---------------------------------------------------------------------------*/
722 static void
723 merge_free_record_list (GList **record_list)
724 {
725         GList *p;
726         glMergeRecord *record;
727
728         gl_debug (DEBUG_MERGE, "START");
729
730         for (p = *record_list; p != NULL; p = p->next) {
731                 record = (glMergeRecord *) p->data;
732
733                 merge_free_record( &record );
734
735         }
736
737         g_list_free (*record_list);
738         *record_list = NULL;
739
740         gl_debug (DEBUG_MERGE, "END");
741 }
742
743 /*---------------------------------------------------------------------------*/
744 /* Duplicate a list of records.                                              */
745 /*---------------------------------------------------------------------------*/
746 static GList *
747 merge_dup_record_list (GList *record_list)
748 {
749         GList         *dest_list = NULL, *p;
750         glMergeRecord *dest_record, *record;
751
752         gl_debug (DEBUG_MERGE, "START");
753
754         for (p = record_list; p != NULL; p = p->next) {
755                 record = (glMergeRecord *) p->data;
756
757                 dest_record = merge_dup_record( record );
758                 dest_list = g_list_append (dest_list, dest_record);
759         }
760
761
762         gl_debug (DEBUG_MERGE, "END");
763
764         return dest_list;
765 }
766
767 /*****************************************************************************/
768 /* Count selected records.                                                   */
769 /*****************************************************************************/
770 gint
771 gl_merge_get_record_count (glMerge *merge)
772 {
773         GList *p;
774         glMergeRecord *record;
775         gint count;
776
777         gl_debug (DEBUG_MERGE, "START");
778
779         count = 0;
780         for ( p=merge->priv->record_list; p!=NULL; p=p->next ) {
781                 record = (glMergeRecord *)p->data;
782
783                 if ( record->select_flag ) count ++;
784         }
785
786         gl_debug (DEBUG_MERGE, "END");
787
788         return count;
789 }
790
791