Code

merge inline patch from Jimmy
[inkscape.git] / src / dialogs / sp-attribute-widget.cpp
1 #define __SP_ATTRIBUTE_WIDGET_C__
3 /**
4  * \brief  SPAttributeWidget
5  *
6  * Widget, that listens and modifies repr attributes
7  *
8  * Authors:
9  *  Lauris Kaplinski <lauris@ximian.com>
10  *
11  * Copyright (C) 2001 Ximian, Inc.
12  *
13  * Licensed under GNU GPL
14  */
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
19 #include <gtk/gtktable.h>
20 #include <gtk/gtklabel.h>
21 #include "xml/repr.h"
22 #include "macros.h"
23 #include "document.h"
24 #include "sp-object.h"
25 #include <glibmm/i18n.h>
27 #include <sigc++/functors/ptr_fun.h>
28 #include <sigc++/adaptors/bind.h>
30 #include "sp-attribute-widget.h"
32 static void sp_attribute_widget_class_init (SPAttributeWidgetClass *klass);
33 static void sp_attribute_widget_init (SPAttributeWidget *widget);
34 static void sp_attribute_widget_destroy (GtkObject *object);
36 static void sp_attribute_widget_changed (GtkEditable *editable);
38 static void sp_attribute_widget_object_modified ( SPObject *object,
39                                                   guint flags,
40                                                   SPAttributeWidget *spaw );
41 static void sp_attribute_widget_object_release ( SPObject *object,
42                                                  SPAttributeWidget *spaw );
44 static GtkEntryClass *parent_class;
49 GtkType
50 sp_attribute_widget_get_type (void)
51 {
52     static GtkType type = 0;
53     if (!type) {
54         static const GtkTypeInfo info = {
55             "SPAttributeWidget",
56             sizeof (SPAttributeWidget),
57             sizeof (SPAttributeWidgetClass),
58             (GtkClassInitFunc) sp_attribute_widget_class_init,
59             (GtkObjectInitFunc) sp_attribute_widget_init,
60             NULL, NULL, NULL
61         };
62         type = gtk_type_unique (GTK_TYPE_ENTRY, &info);
63     }
64     return type;
66 } // end of sp_attribute_widget_get_type()
70 static void
71 sp_attribute_widget_class_init (SPAttributeWidgetClass *klass)
72 {
73     GtkObjectClass *object_class;
74     GtkWidgetClass *widget_class;
75     GtkEditableClass *editable_class;
77     object_class = GTK_OBJECT_CLASS (klass);
78     widget_class = GTK_WIDGET_CLASS (klass);
79     editable_class = GTK_EDITABLE_CLASS (klass);
81     parent_class = (GtkEntryClass*)gtk_type_class (GTK_TYPE_ENTRY);
83     object_class->destroy = sp_attribute_widget_destroy;
85     editable_class->changed = sp_attribute_widget_changed;
87 } // end of sp_attribute_widget_class_init()
91 static void
92 sp_attribute_widget_init (SPAttributeWidget *spaw)
93 {
94     spaw->blocked = FALSE;
95     spaw->hasobj = FALSE;
97     spaw->src.object = NULL;
99     spaw->attribute = NULL;
101     new (&spaw->modified_connection) sigc::connection();
102     new (&spaw->release_connection) sigc::connection();
107 static void
108 sp_attribute_widget_destroy (GtkObject *object)
111     SPAttributeWidget *spaw;
113     spaw = SP_ATTRIBUTE_WIDGET (object);
115     if (spaw->attribute) {
116         g_free (spaw->attribute);
117         spaw->attribute = NULL;
118     }
121     if (spaw->hasobj) {
123         if (spaw->src.object) {
124             spaw->modified_connection.disconnect();
125             spaw->release_connection.disconnect();
126             spaw->src.object = NULL;
127         }
128     } else {
130         if (spaw->src.repr) {
131             spaw->src.repr = Inkscape::GC::release(spaw->src.repr);
132         }
133     } // end of if()
135     spaw->modified_connection.~connection();
136     spaw->release_connection.~connection();
138     ((GtkObjectClass *) parent_class)->destroy (object);
144 static void
145 sp_attribute_widget_changed (GtkEditable *editable)
148     SPAttributeWidget *spaw;
150     spaw = SP_ATTRIBUTE_WIDGET (editable);
152     if (!spaw->blocked) {
154         const gchar *text;
155         spaw->blocked = TRUE;
156         text = gtk_entry_get_text (GTK_ENTRY (spaw));
157         if (!*text)
158             text = NULL;
160         if (spaw->hasobj && spaw->src.object) {
161         
162             SP_OBJECT_REPR (spaw->src.object)->setAttribute(spaw->attribute, text, false);
163             sp_document_done (SP_OBJECT_DOCUMENT (spaw->src.object), SP_VERB_NONE,
164                               _("Set attribute"));
166         } else if (spaw->src.repr) {
168             spaw->src.repr->setAttribute(spaw->attribute, text, false);
169             /* TODO: Warning! Undo will not be flushed in given case */
170         }
171         spaw->blocked = FALSE;
172     }
174 } // end of sp_attribute_widget_changed()
178 GtkWidget *
179 sp_attribute_widget_new ( SPObject *object, const gchar *attribute )
181     SPAttributeWidget *spaw;
183     g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL);
184     g_return_val_if_fail (!object || attribute, NULL);
186     spaw = (SPAttributeWidget*)gtk_type_new (SP_TYPE_ATTRIBUTE_WIDGET);
188     sp_attribute_widget_set_object (spaw, object, attribute);
190     return GTK_WIDGET (spaw);
192 } // end of sp_attribute_widget_new()
196 GtkWidget *
197 sp_attribute_widget_new_repr ( Inkscape::XML::Node *repr, const gchar *attribute )
199     SPAttributeWidget *spaw;
201     spaw = (SPAttributeWidget*)gtk_type_new (SP_TYPE_ATTRIBUTE_WIDGET);
203     sp_attribute_widget_set_repr (spaw, repr, attribute);
205     return GTK_WIDGET (spaw);
210 void
211 sp_attribute_widget_set_object ( SPAttributeWidget *spaw,
212                                  SPObject *object,
213                                  const gchar *attribute )
216     g_return_if_fail (spaw != NULL);
217     g_return_if_fail (SP_IS_ATTRIBUTE_WIDGET (spaw));
218     g_return_if_fail (!object || SP_IS_OBJECT (object));
219     g_return_if_fail (!object || attribute);
220     g_return_if_fail (attribute != NULL);
222     if (spaw->attribute) {
223         g_free (spaw->attribute);
224         spaw->attribute = NULL;
225     }
227     if (spaw->hasobj) {
229         if (spaw->src.object) {
230             spaw->modified_connection.disconnect();
231             spaw->release_connection.disconnect();
232             spaw->src.object = NULL;
233         }
234     } else {
236         if (spaw->src.repr) {
237             spaw->src.repr = Inkscape::GC::release(spaw->src.repr);
238         }
239     }
241     spaw->hasobj = TRUE;
243     if (object) {
244         const gchar *val;
246         spaw->blocked = TRUE;
247         spaw->src.object = object;
249         spaw->modified_connection = object->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_attribute_widget_object_modified), spaw));
250         spaw->release_connection = object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_attribute_widget_object_release), spaw));
252         spaw->attribute = g_strdup (attribute);
254         val = SP_OBJECT_REPR (object)->attribute(attribute);
255         gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) "");
256         spaw->blocked = FALSE;
257     }
259     gtk_widget_set_sensitive (GTK_WIDGET (spaw), (spaw->src.object != NULL));
261 } // end of sp_attribute_widget_set_object()
265 void
266 sp_attribute_widget_set_repr ( SPAttributeWidget *spaw,
267                                Inkscape::XML::Node *repr,
268                                const gchar *attribute )
271     g_return_if_fail (spaw != NULL);
272     g_return_if_fail (SP_IS_ATTRIBUTE_WIDGET (spaw));
273     g_return_if_fail (attribute != NULL);
275     if (spaw->attribute) {
276         g_free (spaw->attribute);
277         spaw->attribute = NULL;
278     }
280     if (spaw->hasobj) {
282         if (spaw->src.object) {
283             spaw->modified_connection.disconnect();
284             spaw->release_connection.disconnect();
285             spaw->src.object = NULL;
286         }
287     } else {
289         if (spaw->src.repr) {
290             spaw->src.repr = Inkscape::GC::release(spaw->src.repr);
291         }
292     }
294     spaw->hasobj = FALSE;
296     if (repr) {
297         const gchar *val;
299         spaw->blocked = TRUE;
300         spaw->src.repr = Inkscape::GC::anchor(repr);
301         spaw->attribute = g_strdup (attribute);
303         val = repr->attribute(attribute);
304         gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) "");
305         spaw->blocked = FALSE;
306     }
308     gtk_widget_set_sensitive (GTK_WIDGET (spaw), (spaw->src.repr != NULL));
310 } // end of sp_attribute_widget_set_repr()
314 static void
315 sp_attribute_widget_object_modified ( SPObject */*object*/,
316                                       guint flags,
317                                       SPAttributeWidget *spaw )
320     if (flags && SP_OBJECT_MODIFIED_FLAG) {
322         const gchar *val, *text;
323         val = SP_OBJECT_REPR (spaw->src.object)->attribute(spaw->attribute);
324         text = gtk_entry_get_text (GTK_ENTRY (spaw));
326         if (val || text) {
328             if (!val || !text || strcmp (val, text)) {
329                 /* We are different */
330                 spaw->blocked = TRUE;
331                 gtk_entry_set_text ( GTK_ENTRY (spaw),
332                                      val ? val : (const gchar *) "");
333                 spaw->blocked = FALSE;
334             } // end of if()
336         } // end of if()
338     } //end of if()
340 } // end of sp_attribute_widget_object_modified()
344 static void
345 sp_attribute_widget_object_release ( SPObject */*object*/,
346                                      SPAttributeWidget *spaw )
348     sp_attribute_widget_set_object (spaw, NULL, NULL);
353 /* SPAttributeTable */
355 static void sp_attribute_table_class_init (SPAttributeTableClass *klass);
356 static void sp_attribute_table_init (SPAttributeTable *widget);
357 static void sp_attribute_table_destroy (GtkObject *object);
359 static void sp_attribute_table_object_modified (SPObject *object, guint flags, SPAttributeTable *spaw);
360 static void sp_attribute_table_object_release (SPObject *object, SPAttributeTable *spaw);
361 static void sp_attribute_table_entry_changed (GtkEditable *editable, SPAttributeTable *spat);
363 static GtkVBoxClass *table_parent_class;
368 GtkType
369 sp_attribute_table_get_type (void)
371     static GtkType type = 0;
372     if (!type) {
373         static const GtkTypeInfo info = {
374             "SPAttributeTable",
375             sizeof (SPAttributeTable),
376             sizeof (SPAttributeTableClass),
377             (GtkClassInitFunc) sp_attribute_table_class_init,
378             (GtkObjectInitFunc) sp_attribute_table_init,
379             NULL, NULL, NULL
380         };
381         type = gtk_type_unique (GTK_TYPE_VBOX, &info);
382     }
383     return type;
385 } // end of sp_attribute_table_get_type()
389 static void
390 sp_attribute_table_class_init (SPAttributeTableClass *klass)
392     GtkObjectClass *object_class;
393     GtkWidgetClass *widget_class;
395     object_class = GTK_OBJECT_CLASS (klass);
396     widget_class = GTK_WIDGET_CLASS (klass);
398     table_parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
400     object_class->destroy = sp_attribute_table_destroy;
402 } // end of sp_attribute_table_class_init()
406 static void
407 sp_attribute_table_init ( SPAttributeTable *spat )
409     spat->blocked = FALSE;
410     spat->hasobj = FALSE;
411     spat->table = NULL;
412     spat->src.object = NULL;
413     spat->num_attr = 0;
414     spat->attributes = NULL;
415     spat->entries = NULL;
417     new (&spat->modified_connection) sigc::connection();
418     new (&spat->release_connection) sigc::connection();
421 static void
422 sp_attribute_table_destroy ( GtkObject *object )
424     SPAttributeTable *spat;
426     spat = SP_ATTRIBUTE_TABLE (object);
428     if (spat->attributes) {
429         gint i;
430         for (i = 0; i < spat->num_attr; i++) {
431             g_free (spat->attributes[i]);
432         }
433         g_free (spat->attributes);
434         spat->attributes = NULL;
435     }
437     if (spat->hasobj) {
439         if (spat->src.object) {
440             spat->modified_connection.disconnect();
441             spat->release_connection.disconnect();
442             spat->src.object = NULL;
443         }
444     } else {
445         if (spat->src.repr) {
446             spat->src.repr = Inkscape::GC::release(spat->src.repr);
447         }
448     } // end of if()
450     spat->modified_connection.~connection();
451     spat->release_connection.~connection();
453     if (spat->entries) {
454         g_free (spat->entries);
455         spat->entries = NULL;
456     }
458     spat->table = NULL;
460     if (((GtkObjectClass *) table_parent_class)->destroy) {
461         (* ((GtkObjectClass *) table_parent_class)->destroy) (object);
462     }
464 } // end of sp_attribute_table_destroy()
467 GtkWidget *
468 sp_attribute_table_new ( SPObject *object,
469                          gint num_attr,
470                          const gchar **labels,
471                          const gchar **attributes )
473     SPAttributeTable *spat;
475     g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL);
476     g_return_val_if_fail (!object || (num_attr > 0), NULL);
477     g_return_val_if_fail (!num_attr || (labels && attributes), NULL);
479     spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE);
481     sp_attribute_table_set_object (spat, object, num_attr, labels, attributes);
483     return GTK_WIDGET (spat);
485 } // end of sp_attribute_table_new()
489 GtkWidget *
490 sp_attribute_table_new_repr ( Inkscape::XML::Node *repr,
491                               gint num_attr,
492                               const gchar **labels,
493                               const gchar **attributes )
495     SPAttributeTable *spat;
497     g_return_val_if_fail (!num_attr || (labels && attributes), NULL);
499     spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE);
501     sp_attribute_table_set_repr (spat, repr, num_attr, labels, attributes);
503     return GTK_WIDGET (spat);
505 } // end of sp_attribute_table_new_repr()
509 #define XPAD 4
510 #define YPAD 0
512 void
513 sp_attribute_table_set_object ( SPAttributeTable *spat,
514                                 SPObject *object,
515                                 gint num_attr,
516                                 const gchar **labels,
517                                 const gchar **attributes )
520     g_return_if_fail (spat != NULL);
521     g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat));
522     g_return_if_fail (!object || SP_IS_OBJECT (object));
523     g_return_if_fail (!object || (num_attr > 0));
524     g_return_if_fail (!num_attr || (labels && attributes));
526     if (spat->table) {
527         gtk_widget_destroy (spat->table);
528         spat->table = NULL;
529     }
531     if (spat->attributes) {
532         gint i;
533         for (i = 0; i < spat->num_attr; i++) {
534             g_free (spat->attributes[i]);
535         }
536         g_free (spat->attributes);
537         spat->attributes = NULL;
538     }
540     if (spat->entries) {
541         g_free (spat->entries);
542         spat->entries = NULL;
543     }
545     if (spat->hasobj) {
546         if (spat->src.object) {
547             spat->modified_connection.disconnect();
548             spat->release_connection.disconnect();
549             spat->src.object = NULL;
550         }
551     } else {
552         if (spat->src.repr) {
553             spat->src.repr = Inkscape::GC::release(spat->src.repr);
554         }
555     }
557     spat->hasobj = TRUE;
559     if (object) {
560         gint i;
562         spat->blocked = TRUE;
564         /* Set up object */
565         spat->src.object = object;
566         spat->num_attr = num_attr;
568         spat->modified_connection = object->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_attribute_table_object_modified), spat));
569         spat->release_connection = object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_attribute_table_object_release), spat));
571         /* Create table */
572         spat->table = gtk_table_new (num_attr, 2, FALSE);
573         gtk_container_add (GTK_CONTAINER (spat), spat->table);
574         /* Arrays */
575         spat->attributes = g_new0 (gchar *, num_attr);
576         spat->entries = g_new0 (GtkWidget *, num_attr);
577         /* Fill rows */
578         for (i = 0; i < num_attr; i++) {
579             GtkWidget *w;
580             const gchar *val;
582             spat->attributes[i] = g_strdup (attributes[i]);
583             w = gtk_label_new (_(labels[i]));
584             gtk_widget_show (w);
585             gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5);
586             gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1,
587                                GTK_FILL,
588                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
589                                XPAD, YPAD );
590             w = gtk_entry_new ();
591             gtk_widget_show (w);
592             val = SP_OBJECT_REPR (object)->attribute(attributes[i]);
593             gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) "");
594             gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1,
595                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
596                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
597                                XPAD, YPAD );
598             spat->entries[i] = w;
599             g_signal_connect ( G_OBJECT (w), "changed",
600                                G_CALLBACK (sp_attribute_table_entry_changed),
601                                spat );
602         }
603         /* Show table */
604         gtk_widget_show (spat->table);
606         spat->blocked = FALSE;
607     }
609     gtk_widget_set_sensitive ( GTK_WIDGET (spat),
610                                (spat->src.object != NULL) );
612 } // end of sp_attribute_table_set_object()
616 void
617 sp_attribute_table_set_repr ( SPAttributeTable *spat,
618                               Inkscape::XML::Node *repr,
619                               gint num_attr,
620                               const gchar **labels,
621                               const gchar **attributes )
623     g_return_if_fail (spat != NULL);
624     g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat));
625     g_return_if_fail (!num_attr || (labels && attributes));
627     if (spat->table) {
628         gtk_widget_destroy (spat->table);
629         spat->table = NULL;
630     }
632     if (spat->attributes) {
633         gint i;
634         for (i = 0; i < spat->num_attr; i++) {
635             g_free (spat->attributes[i]);
636         }
637         g_free (spat->attributes);
638         spat->attributes = NULL;
639     }
641     if (spat->entries) {
642         g_free (spat->entries);
643         spat->entries = NULL;
644     }
646     if (spat->hasobj) {
647         if (spat->src.object) {
648             spat->modified_connection.disconnect();
649             spat->release_connection.disconnect();
650             spat->src.object = NULL;
651         }
652     } else {
653         if (spat->src.repr) {
654             spat->src.repr = Inkscape::GC::release(spat->src.repr);
655         }
656     }
658     spat->hasobj = FALSE;
660     if (repr) {
661         gint i;
663         spat->blocked = TRUE;
665         /* Set up repr */
666         spat->src.repr = Inkscape::GC::anchor(repr);
667         spat->num_attr = num_attr;
668         /* Create table */
669         spat->table = gtk_table_new (num_attr, 2, FALSE);
670         gtk_container_add (GTK_CONTAINER (spat), spat->table);
671         /* Arrays */
672         spat->attributes = g_new0 (gchar *, num_attr);
673         spat->entries = g_new0 (GtkWidget *, num_attr);
675         /* Fill rows */
676         for (i = 0; i < num_attr; i++) {
677             GtkWidget *w;
678             const gchar *val;
680             spat->attributes[i] = g_strdup (attributes[i]);
681             w = gtk_label_new (labels[i]);
682             gtk_widget_show (w);
683             gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5);
684             gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1,
685                                GTK_FILL,
686                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
687                                XPAD, YPAD );
688             w = gtk_entry_new ();
689             gtk_widget_show (w);
690             val = repr->attribute(attributes[i]);
691             gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) "");
692             gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1,
693                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
694                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
695                                XPAD, YPAD );
696             spat->entries[i] = w;
697             g_signal_connect ( G_OBJECT (w), "changed",
698                                G_CALLBACK (sp_attribute_table_entry_changed),
699                                spat );
700         }
701         /* Show table */
702         gtk_widget_show (spat->table);
704         spat->blocked = FALSE;
705     }
707     gtk_widget_set_sensitive (GTK_WIDGET (spat), (spat->src.repr != NULL));
709 } // end of sp_attribute_table_set_repr()
713 static void
714 sp_attribute_table_object_modified ( SPObject */*object*/,
715                                      guint flags,
716                                      SPAttributeTable *spat )
718     if (flags && SP_OBJECT_MODIFIED_FLAG)
719     {
720         gint i;
721         for (i = 0; i < spat->num_attr; i++) {
722             const gchar *val, *text;
723             val = SP_OBJECT_REPR (spat->src.object)->attribute(spat->attributes[i]);
724             text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i]));
725             if (val || text) {
726                 if (!val || !text || strcmp (val, text)) {
727                     /* We are different */
728                     spat->blocked = TRUE;
729                     gtk_entry_set_text ( GTK_ENTRY (spat->entries[i]),
730                                          val ? val : (const gchar *) "");
731                     spat->blocked = FALSE;
732                 }
733             }
734         }
735     } // end of if()
737 } // end of sp_attribute_table_object_modified()
741 static void
742 sp_attribute_table_object_release (SPObject */*object*/, SPAttributeTable *spat)
744     sp_attribute_table_set_object (spat, NULL, 0, NULL, NULL);
749 static void
750 sp_attribute_table_entry_changed ( GtkEditable *editable,
751                                    SPAttributeTable *spat )
753     if (!spat->blocked)
754     {
755         gint i;
756         for (i = 0; i < spat->num_attr; i++) {
758             if (GTK_WIDGET (editable) == spat->entries[i]) {
759                 const gchar *text;
760                 spat->blocked = TRUE;
761                 text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i]));
763                 if (!*text)
764                     text = NULL;
766                 if (spat->hasobj && spat->src.object) {
767                     SP_OBJECT_REPR (spat->src.object)->setAttribute(spat->attributes[i], text, false);
768                     sp_document_done (SP_OBJECT_DOCUMENT (spat->src.object), SP_VERB_NONE,
769                                       _("Set attribute"));
771                 } else if (spat->src.repr) {
773                     spat->src.repr->setAttribute(spat->attributes[i], text, false);
774                     /* TODO: Warning! Undo will not be flushed in given case */
775                 }
776                 spat->blocked = FALSE;
777                 return;
778             }
779         }
780         g_warning ("file %s: line %d: Entry signalled change, but there is no such entry", __FILE__, __LINE__);
781     } // end of if()
783 } // end of sp_attribute_table_entry_changed()
785 /*
786   Local Variables:
787   mode:c++
788   c-file-style:"stroustrup"
789   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
790   indent-tabs-mode:nil
791   fill-column:99
792   End:
793 */
794 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :