]> git.sur5r.net Git - glabels/blob - src/label.c
Imported Upstream version 2.2.8
[glabels] / src / label.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  *  label.c:  GLabels label module
7  *
8  *  Copyright (C) 2001-2007  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
25 #include <config.h>
26
27 #include "label.h"
28
29 #include <glib/gi18n.h>
30
31 #include "marshal.h"
32 #include "prefs.h"
33 #include "util.h"
34
35 #include "debug.h"
36
37 /*========================================================*/
38 /* Private macros and constants.                          */
39 /*========================================================*/
40
41 /*========================================================*/
42 /* Private types.                                         */
43 /*========================================================*/
44
45 struct _glLabelPrivate {
46
47         gchar       *filename;
48         gint         compression;
49         gboolean     modified_flag;
50         gint         untitled_instance;
51
52         glMerge     *merge;
53
54         GHashTable  *pixbuf_cache;
55 };
56
57 enum {
58         CHANGED,
59         NAME_CHANGED,
60         MODIFIED_CHANGED,
61         MERGE_CHANGED,
62         SIZE_CHANGED,
63         OBJECT_ADDED,
64         LAST_SIGNAL
65 };
66
67 /*========================================================*/
68 /* Private globals.                                       */
69 /*========================================================*/
70
71 static guint signals[LAST_SIGNAL] = {0};
72
73 static guint untitled = 0;
74
75 /*========================================================*/
76 /* Private function prototypes.                           */
77 /*========================================================*/
78
79 static void gl_label_finalize      (GObject *object);
80
81 static void object_changed_cb      (glLabelObject *object,
82                                     glLabel       *label);
83
84 static void object_moved_cb        (glLabelObject *object,
85                                     gdouble        x,
86                                     gdouble        y,
87                                     glLabel       *label);
88
89 \f
90 /*****************************************************************************/
91 /* Boilerplate object stuff.                                                 */
92 /*****************************************************************************/
93 G_DEFINE_TYPE (glLabel, gl_label, G_TYPE_OBJECT);
94
95 static void
96 gl_label_class_init (glLabelClass *class)
97 {
98         GObjectClass *object_class = G_OBJECT_CLASS (class);
99
100         gl_debug (DEBUG_LABEL, "START");
101
102         gl_label_parent_class = g_type_class_peek_parent (class);
103
104         object_class->finalize = gl_label_finalize;
105
106         signals[CHANGED] =
107                 g_signal_new ("changed",
108                               G_OBJECT_CLASS_TYPE (object_class),
109                               G_SIGNAL_RUN_LAST,
110                               G_STRUCT_OFFSET (glLabelClass, changed),
111                               NULL, NULL,
112                               gl_marshal_VOID__VOID,
113                               G_TYPE_NONE,
114                               0);
115         signals[NAME_CHANGED] =
116                 g_signal_new ("name_changed",
117                               G_OBJECT_CLASS_TYPE (object_class),
118                               G_SIGNAL_RUN_LAST,
119                               G_STRUCT_OFFSET (glLabelClass, name_changed),
120                               NULL, NULL,
121                               gl_marshal_VOID__VOID,
122                               G_TYPE_NONE,
123                               0);
124         signals[MODIFIED_CHANGED] =
125                 g_signal_new ("modified_changed",
126                               G_OBJECT_CLASS_TYPE (object_class),
127                               G_SIGNAL_RUN_LAST,
128                               G_STRUCT_OFFSET (glLabelClass, modified_changed),
129                               NULL, NULL,
130                               gl_marshal_VOID__VOID,
131                               G_TYPE_NONE,
132                               0);
133         signals[MERGE_CHANGED] =
134                 g_signal_new ("merge_changed",
135                               G_OBJECT_CLASS_TYPE (object_class),
136                               G_SIGNAL_RUN_LAST,
137                               G_STRUCT_OFFSET (glLabelClass, merge_changed),
138                               NULL, NULL,
139                               gl_marshal_VOID__VOID,
140                               G_TYPE_NONE,
141                               0);
142         signals[SIZE_CHANGED] =
143                 g_signal_new ("size_changed",
144                               G_OBJECT_CLASS_TYPE (object_class),
145                               G_SIGNAL_RUN_LAST,
146                               G_STRUCT_OFFSET (glLabelClass, size_changed),
147                               NULL, NULL,
148                               gl_marshal_VOID__VOID,
149                               G_TYPE_NONE,
150                               0);
151         signals[OBJECT_ADDED] =
152                 g_signal_new ("object_added",
153                               G_OBJECT_CLASS_TYPE (object_class),
154                               G_SIGNAL_RUN_LAST,
155                               G_STRUCT_OFFSET (glLabelClass, object_added),
156                               NULL, NULL,
157                               gl_marshal_VOID__OBJECT,
158                               G_TYPE_NONE,
159                               1, G_TYPE_OBJECT);
160
161         gl_debug (DEBUG_LABEL, "END");
162 }
163
164 static void
165 gl_label_init (glLabel *label)
166 {
167         gl_debug (DEBUG_LABEL, "START");
168
169         label->template     = NULL;
170         label->rotate_flag  = FALSE;
171         label->objects      = NULL;
172
173         label->priv = g_new0 (glLabelPrivate, 1);
174
175         label->priv->filename     = NULL;
176         label->priv->merge        = NULL;
177         label->priv->pixbuf_cache = gl_pixbuf_cache_new ();
178
179         gl_debug (DEBUG_LABEL, "END");
180 }
181
182 static void
183 gl_label_finalize (GObject *object)
184 {
185         glLabel *label = GL_LABEL (object);
186         GList   *p, *p_next;
187
188         gl_debug (DEBUG_LABEL, "START");
189
190         g_return_if_fail (object && GL_IS_LABEL (object));
191
192         for (p = label->objects; p != NULL; p = p_next) {
193                 p_next = p->next;       /* NOTE: p will be left dangling */
194                 g_object_unref (G_OBJECT(p->data));
195         }
196
197         lgl_template_free (label->template);
198         g_free (label->priv->filename);
199         if (label->priv->merge != NULL) {
200                 g_object_unref (G_OBJECT(label->priv->merge));
201         }
202         gl_pixbuf_cache_free (label->priv->pixbuf_cache);
203
204         g_free (label->priv);
205
206         G_OBJECT_CLASS (gl_label_parent_class)->finalize (object);
207
208         gl_debug (DEBUG_LABEL, "END");
209 }
210
211 GObject *
212 gl_label_new (void)
213 {
214         glLabel *label;
215
216         gl_debug (DEBUG_LABEL, "START");
217
218         label = g_object_new (gl_label_get_type(), NULL);
219
220         label->priv->compression = 9;
221
222         label->priv->modified_flag = FALSE;
223
224         gl_debug (DEBUG_LABEL, "END");
225
226         return G_OBJECT (label);
227 }
228
229
230 /*****************************************************************************/
231 /* Add object to label.                                                      */
232 /*****************************************************************************/
233 void
234 gl_label_add_object (glLabel       *label,
235                      glLabelObject *object)
236 {
237         gl_debug (DEBUG_LABEL, "START");
238
239         g_return_if_fail (label && GL_IS_LABEL (label));
240         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
241
242         object->parent = label;
243         label->objects = g_list_append (label->objects, g_object_ref (object));
244
245         label->priv->modified_flag = TRUE;
246
247         g_signal_emit (G_OBJECT(label), signals[OBJECT_ADDED], 0, object);
248         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
249         g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
250
251         g_signal_connect (G_OBJECT(object), "changed",
252                           G_CALLBACK(object_changed_cb), label);
253
254         g_signal_connect (G_OBJECT(object), "moved",
255                           G_CALLBACK(object_moved_cb), label);
256
257         gl_debug (DEBUG_LABEL, "END");
258 }
259
260 /*****************************************************************************/
261 /* Remove object from label.                                                 */
262 /*****************************************************************************/
263 void
264 gl_label_remove_object (glLabel       *label,
265                         glLabelObject *object)
266 {
267         gl_debug (DEBUG_LABEL, "START");
268
269         g_return_if_fail (label && GL_IS_LABEL (label));
270         g_return_if_fail (GL_IS_LABEL_OBJECT (object));
271
272         object->parent = NULL;
273         label->objects = g_list_remove (label->objects, object);
274
275         if ( G_OBJECT(label)->ref_count /* not finalized */ ) {
276
277                 g_signal_handlers_disconnect_by_func (object,
278                                                       G_CALLBACK(object_changed_cb),
279                                                       label);
280                 g_signal_handlers_disconnect_by_func (object,
281                                                       G_CALLBACK(object_moved_cb),
282                                                       label);
283
284                 label->priv->modified_flag = TRUE;
285
286                 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
287                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
288
289         }
290
291         gl_debug (DEBUG_LABEL, "END");
292 }
293
294 /*---------------------------------------------------------------------------*/
295 /* PRIVATE.  Object changed callback.                                        */
296 /*---------------------------------------------------------------------------*/
297 static void
298 object_changed_cb (glLabelObject *object,
299                    glLabel       *label)
300 {
301
302         if ( !label->priv->modified_flag ) {
303
304                 label->priv->modified_flag = TRUE;
305
306                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
307         }
308
309         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
310 }
311
312 /*---------------------------------------------------------------------------*/
313 /* PRIVATE.  Object moved callback.                                          */
314 /*---------------------------------------------------------------------------*/
315 static void
316 object_moved_cb (glLabelObject *object,
317                  gdouble        x,
318                  gdouble        y,
319                  glLabel       *label)
320 {
321
322         if ( !label->priv->modified_flag ) {
323
324                 label->priv->modified_flag = TRUE;
325
326                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
327         }
328
329         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
330 }
331
332 /****************************************************************************/
333 /* Bring label object to front/top.                                         */
334 /****************************************************************************/
335 void
336 gl_label_raise_object_to_top (glLabel       *label,
337                               glLabelObject *object)
338 {
339         gl_debug (DEBUG_LABEL, "START");
340
341         /* Move to end of list, representing front most object */
342         label->objects = g_list_remove (label->objects, object);
343         label->objects = g_list_append (label->objects, object);
344
345         label->priv->modified_flag = TRUE;
346
347         g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
348         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
349
350         gl_debug (DEBUG_LABEL, "END");
351 }
352
353 /****************************************************************************/
354 /* Send label object to rear/bottom.                                        */
355 /****************************************************************************/
356 void
357 gl_label_lower_object_to_bottom (glLabel       *label,
358                                  glLabelObject *object)
359 {
360         gl_debug (DEBUG_LABEL, "START");
361
362         /* Move to front of list, representing rear most object */
363         label->objects = g_list_remove (label->objects, object);
364         label->objects = g_list_prepend (label->objects, object);
365
366         label->priv->modified_flag = TRUE;
367
368         g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
369         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
370
371         gl_debug (DEBUG_LABEL, "END");
372 }
373
374 /****************************************************************************/
375 /* set template.                                                            */
376 /****************************************************************************/
377 extern void
378 gl_label_set_template (glLabel     *label,
379                        lglTemplate *template)
380 {
381         gchar *name;
382
383         gl_debug (DEBUG_LABEL, "START");
384
385         g_return_if_fail (label && GL_IS_LABEL (label));
386         g_return_if_fail (template);
387
388         if ((label->template == NULL) ||
389             !lgl_template_do_templates_match (template, label->template)) {
390
391                 lgl_template_free (label->template);
392                 label->template = lgl_template_dup (template);
393
394                 label->priv->modified_flag = TRUE;
395
396                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
397                 g_signal_emit (G_OBJECT(label), signals[SIZE_CHANGED], 0);
398                 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
399
400                 name = lgl_template_get_name (template);
401                 gl_prefs_add_recent_template (name);
402                 g_free (name);
403         }
404
405         gl_debug (DEBUG_LABEL, "END");
406 }
407
408 /****************************************************************************/
409 /* set rotate flag.                                                         */
410 /****************************************************************************/
411 extern void
412 gl_label_set_rotate_flag (glLabel *label,
413                           gboolean rotate_flag)
414 {
415         gl_debug (DEBUG_LABEL, "START");
416
417         g_return_if_fail (label && GL_IS_LABEL (label));
418
419         if (rotate_flag != label->rotate_flag) {
420
421                 label->rotate_flag = rotate_flag;
422
423                 label->priv->modified_flag = TRUE;
424
425                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
426                 g_signal_emit (G_OBJECT(label), signals[SIZE_CHANGED], 0);
427                 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
428
429         }
430
431         gl_debug (DEBUG_LABEL, "END");
432 }
433
434 /****************************************************************************/
435 /* Get label size.                                                          */
436 /****************************************************************************/
437 void
438 gl_label_get_size (glLabel *label,
439                    gdouble *w,
440                    gdouble *h)
441 {
442         lglTemplate            *template;
443         const lglTemplateFrame *frame;
444
445         gl_debug (DEBUG_LABEL, "START");
446
447         g_return_if_fail (label && GL_IS_LABEL (label));
448
449         template = label->template;
450         if ( !template ) {
451                 gl_debug (DEBUG_LABEL, "END -- template NULL");
452                 *w = *h = 0;
453                 return;
454         }
455         frame = (lglTemplateFrame *)template->frames->data;
456
457         if (!label->rotate_flag) {
458                 lgl_template_frame_get_size (frame, w, h);
459         } else {
460                 lgl_template_frame_get_size (frame, h, w);
461         }
462
463         gl_debug (DEBUG_LABEL, "END");
464 }
465
466 /****************************************************************************/
467 /* set merge information structure.                                         */
468 /****************************************************************************/
469 extern void
470 gl_label_set_merge (glLabel *label,
471                     glMerge *merge)
472 {
473         gl_debug (DEBUG_LABEL, "START");
474
475         g_return_if_fail (label && GL_IS_LABEL (label));
476
477         if ( label->priv->merge != NULL ) {
478                 g_object_unref (G_OBJECT(label->priv->merge));
479         }
480         label->priv->merge = gl_merge_dup (merge);
481
482         label->priv->modified_flag = TRUE;
483
484         g_signal_emit (G_OBJECT(label), signals[MERGE_CHANGED], 0);
485         g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
486         g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
487
488         gl_debug (DEBUG_LABEL, "END");
489 }
490
491 /****************************************************************************/
492 /* Get merge information structure.                                         */
493 /****************************************************************************/
494 glMerge *
495 gl_label_get_merge (glLabel *label)
496 {
497         gl_debug (DEBUG_LABEL, "START");
498
499         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
500
501         gl_debug (DEBUG_LABEL, "END");
502
503         return gl_merge_dup (label->priv->merge);
504 }
505
506 /****************************************************************************/
507 /* return filename.                                                         */
508 /****************************************************************************/
509 gchar *
510 gl_label_get_filename (glLabel *label)
511 {
512         gl_debug (DEBUG_LABEL, "");
513
514         return g_strdup ( label->priv->filename );
515 }
516
517 /****************************************************************************/
518 /* return short filename.                                                   */
519 /****************************************************************************/
520 gchar *
521 gl_label_get_short_name (glLabel *label)
522 {
523         gl_debug (DEBUG_LABEL, "");
524
525         if ( label->priv->filename == NULL ) {
526
527                 if ( label->priv->untitled_instance == 0 ) {
528                         label->priv->untitled_instance = ++untitled;
529                 }
530
531                 return g_strdup_printf ( "%s %d", _("Untitled"),
532                                          label->priv->untitled_instance );
533
534         } else {
535                 gchar *temp_name, *short_name;
536
537                 temp_name = g_path_get_basename ( label->priv->filename );
538                 short_name = gl_util_remove_extension (temp_name);
539                 g_free (temp_name);
540
541                 return short_name;
542         }
543 }
544
545 /****************************************************************************/
546 /* Get pixbuf cache.                                                        */
547 /****************************************************************************/
548 GHashTable *
549 gl_label_get_pixbuf_cache (glLabel       *label)
550 {
551         return label->priv->pixbuf_cache;
552 }
553
554 /****************************************************************************/
555 /* Is label modified?                                                       */
556 /****************************************************************************/
557 gboolean
558 gl_label_is_modified (glLabel *label)
559 {
560         gl_debug (DEBUG_LABEL, "return %d", label->priv->modified_flag);
561         return label->priv->modified_flag;
562 }
563
564 /****************************************************************************/
565 /* Is label untitled?                                                       */
566 /****************************************************************************/
567 gboolean
568 gl_label_is_untitled (glLabel *label)
569 {
570         gl_debug (DEBUG_LABEL, "return %d",(label->priv->filename == NULL));
571         return (label->priv->filename == NULL);
572 }
573
574 /****************************************************************************/
575 /* Can undo?                                                                */
576 /****************************************************************************/
577 gboolean
578 gl_label_can_undo (glLabel *label)
579 {
580         return FALSE;
581 }
582
583
584 /****************************************************************************/
585 /* Can redo?                                                                */
586 /****************************************************************************/
587 gboolean
588 gl_label_can_redo (glLabel *label)
589 {
590         return FALSE;
591 }
592
593
594 /****************************************************************************/
595 /* Set filename.                                                            */
596 /****************************************************************************/
597 void
598 gl_label_set_filename (glLabel     *label,
599                        const gchar *filename)
600 {
601         label->priv->filename = g_strdup (filename);
602
603         g_signal_emit (G_OBJECT(label), signals[NAME_CHANGED], 0);
604 }
605
606 /****************************************************************************/
607 /* Clear modified flag.                                                     */
608 /****************************************************************************/
609 void
610 gl_label_clear_modified (glLabel *label)
611 {
612
613         if ( label->priv->modified_flag ) {
614
615                 label->priv->modified_flag = FALSE;
616
617                 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
618         }
619
620 }
621
622
623 /****************************************************************************/
624 /* Set compression level.                                                   */
625 /****************************************************************************/
626 void
627 gl_label_set_compression (glLabel  *label,
628                           gint      compression)
629 {
630         gl_debug (DEBUG_LABEL, "set %d", compression);
631
632         /* Older versions of libxml2 always return a -1 for documents "read in," so
633          * default to 9.  Also, default to 9 for anything else out of range. */
634         if ((compression < 0) || (compression >9)) {
635                 compression = 9;
636         }
637
638         gl_debug (DEBUG_LABEL, "actual set %d", compression);
639         label->priv->compression = compression;
640 }
641
642
643 /****************************************************************************/
644 /* Get compression level.                                                   */
645 /****************************************************************************/
646 gint
647 gl_label_get_compression (glLabel *label)
648 {
649         gl_debug (DEBUG_LABEL, "return %d", label->priv->compression);
650         return label->priv->compression;
651 }
652
653
654 /****************************************************************************/
655 /* Draw label.                                                              */
656 /****************************************************************************/
657 void
658 gl_label_draw (glLabel       *label,
659                cairo_t       *cr,
660                gboolean       screen_flag,
661                glMergeRecord *record)
662 {
663         GList            *p_obj;
664         glLabelObject    *object;
665
666         g_return_if_fail (label && GL_IS_LABEL (label));
667
668         for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next)
669         {
670                 object = GL_LABEL_OBJECT (p_obj->data);
671
672                 gl_label_object_draw (object, cr, screen_flag, record);
673         }
674 }