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 * label.c: GLabels label module
8 * Copyright (C) 2001-2007 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
29 #include <glib/gi18n.h>
37 /*========================================================*/
38 /* Private macros and constants. */
39 /*========================================================*/
41 /*========================================================*/
43 /*========================================================*/
45 struct _glLabelPrivate {
49 gboolean modified_flag;
50 gint untitled_instance;
54 GHashTable *pixbuf_cache;
67 /*========================================================*/
68 /* Private globals. */
69 /*========================================================*/
71 static guint signals[LAST_SIGNAL] = {0};
73 static guint untitled = 0;
75 /*========================================================*/
76 /* Private function prototypes. */
77 /*========================================================*/
79 static void gl_label_finalize (GObject *object);
81 static void object_changed_cb (glLabelObject *object,
84 static void object_moved_cb (glLabelObject *object,
90 /*****************************************************************************/
91 /* Boilerplate object stuff. */
92 /*****************************************************************************/
93 G_DEFINE_TYPE (glLabel, gl_label, G_TYPE_OBJECT);
96 gl_label_class_init (glLabelClass *class)
98 GObjectClass *object_class = G_OBJECT_CLASS (class);
100 gl_debug (DEBUG_LABEL, "START");
102 gl_label_parent_class = g_type_class_peek_parent (class);
104 object_class->finalize = gl_label_finalize;
107 g_signal_new ("changed",
108 G_OBJECT_CLASS_TYPE (object_class),
110 G_STRUCT_OFFSET (glLabelClass, changed),
112 gl_marshal_VOID__VOID,
115 signals[NAME_CHANGED] =
116 g_signal_new ("name_changed",
117 G_OBJECT_CLASS_TYPE (object_class),
119 G_STRUCT_OFFSET (glLabelClass, name_changed),
121 gl_marshal_VOID__VOID,
124 signals[MODIFIED_CHANGED] =
125 g_signal_new ("modified_changed",
126 G_OBJECT_CLASS_TYPE (object_class),
128 G_STRUCT_OFFSET (glLabelClass, modified_changed),
130 gl_marshal_VOID__VOID,
133 signals[MERGE_CHANGED] =
134 g_signal_new ("merge_changed",
135 G_OBJECT_CLASS_TYPE (object_class),
137 G_STRUCT_OFFSET (glLabelClass, merge_changed),
139 gl_marshal_VOID__VOID,
142 signals[SIZE_CHANGED] =
143 g_signal_new ("size_changed",
144 G_OBJECT_CLASS_TYPE (object_class),
146 G_STRUCT_OFFSET (glLabelClass, size_changed),
148 gl_marshal_VOID__VOID,
151 signals[OBJECT_ADDED] =
152 g_signal_new ("object_added",
153 G_OBJECT_CLASS_TYPE (object_class),
155 G_STRUCT_OFFSET (glLabelClass, object_added),
157 gl_marshal_VOID__OBJECT,
161 gl_debug (DEBUG_LABEL, "END");
165 gl_label_init (glLabel *label)
167 gl_debug (DEBUG_LABEL, "START");
169 label->template = NULL;
170 label->rotate_flag = FALSE;
171 label->objects = NULL;
173 label->priv = g_new0 (glLabelPrivate, 1);
175 label->priv->filename = NULL;
176 label->priv->merge = NULL;
177 label->priv->pixbuf_cache = gl_pixbuf_cache_new ();
179 gl_debug (DEBUG_LABEL, "END");
183 gl_label_finalize (GObject *object)
185 glLabel *label = GL_LABEL (object);
188 gl_debug (DEBUG_LABEL, "START");
190 g_return_if_fail (object && GL_IS_LABEL (object));
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));
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));
202 gl_pixbuf_cache_free (label->priv->pixbuf_cache);
204 g_free (label->priv);
206 G_OBJECT_CLASS (gl_label_parent_class)->finalize (object);
208 gl_debug (DEBUG_LABEL, "END");
216 gl_debug (DEBUG_LABEL, "START");
218 label = g_object_new (gl_label_get_type(), NULL);
220 label->priv->compression = 9;
222 label->priv->modified_flag = FALSE;
224 gl_debug (DEBUG_LABEL, "END");
226 return G_OBJECT (label);
230 /*****************************************************************************/
231 /* Add object to label. */
232 /*****************************************************************************/
234 gl_label_add_object (glLabel *label,
235 glLabelObject *object)
237 gl_debug (DEBUG_LABEL, "START");
239 g_return_if_fail (label && GL_IS_LABEL (label));
240 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
242 object->parent = label;
243 label->objects = g_list_append (label->objects, g_object_ref (object));
245 label->priv->modified_flag = TRUE;
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);
251 g_signal_connect (G_OBJECT(object), "changed",
252 G_CALLBACK(object_changed_cb), label);
254 g_signal_connect (G_OBJECT(object), "moved",
255 G_CALLBACK(object_moved_cb), label);
257 gl_debug (DEBUG_LABEL, "END");
260 /*****************************************************************************/
261 /* Remove object from label. */
262 /*****************************************************************************/
264 gl_label_remove_object (glLabel *label,
265 glLabelObject *object)
267 gl_debug (DEBUG_LABEL, "START");
269 g_return_if_fail (label && GL_IS_LABEL (label));
270 g_return_if_fail (GL_IS_LABEL_OBJECT (object));
272 object->parent = NULL;
273 label->objects = g_list_remove (label->objects, object);
275 if ( G_OBJECT(label)->ref_count /* not finalized */ ) {
277 g_signal_handlers_disconnect_by_func (object,
278 G_CALLBACK(object_changed_cb),
280 g_signal_handlers_disconnect_by_func (object,
281 G_CALLBACK(object_moved_cb),
284 label->priv->modified_flag = TRUE;
286 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
287 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
291 gl_debug (DEBUG_LABEL, "END");
294 /*---------------------------------------------------------------------------*/
295 /* PRIVATE. Object changed callback. */
296 /*---------------------------------------------------------------------------*/
298 object_changed_cb (glLabelObject *object,
302 if ( !label->priv->modified_flag ) {
304 label->priv->modified_flag = TRUE;
306 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
309 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
312 /*---------------------------------------------------------------------------*/
313 /* PRIVATE. Object moved callback. */
314 /*---------------------------------------------------------------------------*/
316 object_moved_cb (glLabelObject *object,
322 if ( !label->priv->modified_flag ) {
324 label->priv->modified_flag = TRUE;
326 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
329 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
332 /****************************************************************************/
333 /* Bring label object to front/top. */
334 /****************************************************************************/
336 gl_label_raise_object_to_top (glLabel *label,
337 glLabelObject *object)
339 gl_debug (DEBUG_LABEL, "START");
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);
345 label->priv->modified_flag = TRUE;
347 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
348 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
350 gl_debug (DEBUG_LABEL, "END");
353 /****************************************************************************/
354 /* Send label object to rear/bottom. */
355 /****************************************************************************/
357 gl_label_lower_object_to_bottom (glLabel *label,
358 glLabelObject *object)
360 gl_debug (DEBUG_LABEL, "START");
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);
366 label->priv->modified_flag = TRUE;
368 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
369 g_signal_emit (G_OBJECT(label), signals[CHANGED], 0);
371 gl_debug (DEBUG_LABEL, "END");
374 /****************************************************************************/
376 /****************************************************************************/
378 gl_label_set_template (glLabel *label,
379 lglTemplate *template)
383 gl_debug (DEBUG_LABEL, "START");
385 g_return_if_fail (label && GL_IS_LABEL (label));
386 g_return_if_fail (template);
388 if ((label->template == NULL) ||
389 !lgl_template_do_templates_match (template, label->template)) {
391 lgl_template_free (label->template);
392 label->template = lgl_template_dup (template);
394 label->priv->modified_flag = TRUE;
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);
400 name = lgl_template_get_name (template);
401 gl_prefs_add_recent_template (name);
405 gl_debug (DEBUG_LABEL, "END");
408 /****************************************************************************/
409 /* set rotate flag. */
410 /****************************************************************************/
412 gl_label_set_rotate_flag (glLabel *label,
413 gboolean rotate_flag)
415 gl_debug (DEBUG_LABEL, "START");
417 g_return_if_fail (label && GL_IS_LABEL (label));
419 if (rotate_flag != label->rotate_flag) {
421 label->rotate_flag = rotate_flag;
423 label->priv->modified_flag = TRUE;
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);
431 gl_debug (DEBUG_LABEL, "END");
434 /****************************************************************************/
435 /* Get label size. */
436 /****************************************************************************/
438 gl_label_get_size (glLabel *label,
442 lglTemplate *template;
443 const lglTemplateFrame *frame;
445 gl_debug (DEBUG_LABEL, "START");
447 g_return_if_fail (label && GL_IS_LABEL (label));
449 template = label->template;
451 gl_debug (DEBUG_LABEL, "END -- template NULL");
455 frame = (lglTemplateFrame *)template->frames->data;
457 if (!label->rotate_flag) {
458 lgl_template_frame_get_size (frame, w, h);
460 lgl_template_frame_get_size (frame, h, w);
463 gl_debug (DEBUG_LABEL, "END");
466 /****************************************************************************/
467 /* set merge information structure. */
468 /****************************************************************************/
470 gl_label_set_merge (glLabel *label,
473 gl_debug (DEBUG_LABEL, "START");
475 g_return_if_fail (label && GL_IS_LABEL (label));
477 if ( label->priv->merge != NULL ) {
478 g_object_unref (G_OBJECT(label->priv->merge));
480 label->priv->merge = gl_merge_dup (merge);
482 label->priv->modified_flag = TRUE;
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);
488 gl_debug (DEBUG_LABEL, "END");
491 /****************************************************************************/
492 /* Get merge information structure. */
493 /****************************************************************************/
495 gl_label_get_merge (glLabel *label)
497 gl_debug (DEBUG_LABEL, "START");
499 g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
501 gl_debug (DEBUG_LABEL, "END");
503 return gl_merge_dup (label->priv->merge);
506 /****************************************************************************/
507 /* return filename. */
508 /****************************************************************************/
510 gl_label_get_filename (glLabel *label)
512 gl_debug (DEBUG_LABEL, "");
514 return g_strdup ( label->priv->filename );
517 /****************************************************************************/
518 /* return short filename. */
519 /****************************************************************************/
521 gl_label_get_short_name (glLabel *label)
523 gl_debug (DEBUG_LABEL, "");
525 if ( label->priv->filename == NULL ) {
527 if ( label->priv->untitled_instance == 0 ) {
528 label->priv->untitled_instance = ++untitled;
531 return g_strdup_printf ( "%s %d", _("Untitled"),
532 label->priv->untitled_instance );
535 gchar *temp_name, *short_name;
537 temp_name = g_path_get_basename ( label->priv->filename );
538 short_name = gl_util_remove_extension (temp_name);
545 /****************************************************************************/
546 /* Get pixbuf cache. */
547 /****************************************************************************/
549 gl_label_get_pixbuf_cache (glLabel *label)
551 return label->priv->pixbuf_cache;
554 /****************************************************************************/
555 /* Is label modified? */
556 /****************************************************************************/
558 gl_label_is_modified (glLabel *label)
560 gl_debug (DEBUG_LABEL, "return %d", label->priv->modified_flag);
561 return label->priv->modified_flag;
564 /****************************************************************************/
565 /* Is label untitled? */
566 /****************************************************************************/
568 gl_label_is_untitled (glLabel *label)
570 gl_debug (DEBUG_LABEL, "return %d",(label->priv->filename == NULL));
571 return (label->priv->filename == NULL);
574 /****************************************************************************/
576 /****************************************************************************/
578 gl_label_can_undo (glLabel *label)
584 /****************************************************************************/
586 /****************************************************************************/
588 gl_label_can_redo (glLabel *label)
594 /****************************************************************************/
596 /****************************************************************************/
598 gl_label_set_filename (glLabel *label,
599 const gchar *filename)
601 label->priv->filename = g_strdup (filename);
603 g_signal_emit (G_OBJECT(label), signals[NAME_CHANGED], 0);
606 /****************************************************************************/
607 /* Clear modified flag. */
608 /****************************************************************************/
610 gl_label_clear_modified (glLabel *label)
613 if ( label->priv->modified_flag ) {
615 label->priv->modified_flag = FALSE;
617 g_signal_emit (G_OBJECT(label), signals[MODIFIED_CHANGED], 0);
623 /****************************************************************************/
624 /* Set compression level. */
625 /****************************************************************************/
627 gl_label_set_compression (glLabel *label,
630 gl_debug (DEBUG_LABEL, "set %d", compression);
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)) {
638 gl_debug (DEBUG_LABEL, "actual set %d", compression);
639 label->priv->compression = compression;
643 /****************************************************************************/
644 /* Get compression level. */
645 /****************************************************************************/
647 gl_label_get_compression (glLabel *label)
649 gl_debug (DEBUG_LABEL, "return %d", label->priv->compression);
650 return label->priv->compression;
654 /****************************************************************************/
656 /****************************************************************************/
658 gl_label_draw (glLabel *label,
660 gboolean screen_flag,
661 glMergeRecord *record)
664 glLabelObject *object;
666 g_return_if_fail (label && GL_IS_LABEL (label));
668 for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next)
670 object = GL_LABEL_OBJECT (p_obj->data);
672 gl_label_object_draw (object, cr, screen_flag, record);