670da965e763d8b10f75b26c6494be42006f3543
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 "sp-attribute-widget.h"
29 static void sp_attribute_widget_class_init (SPAttributeWidgetClass *klass);
30 static void sp_attribute_widget_init (SPAttributeWidget *widget);
31 static void sp_attribute_widget_destroy (GtkObject *object);
33 static void sp_attribute_widget_changed (GtkEditable *editable);
35 static void sp_attribute_widget_object_modified ( SPObject *object,
36 guint flags,
37 SPAttributeWidget *spaw );
38 static void sp_attribute_widget_object_release ( SPObject *object,
39 SPAttributeWidget *spaw );
41 static GtkEntryClass *parent_class;
46 GtkType
47 sp_attribute_widget_get_type (void)
48 {
49 static GtkType type = 0;
50 if (!type) {
51 static const GtkTypeInfo info = {
52 "SPAttributeWidget",
53 sizeof (SPAttributeWidget),
54 sizeof (SPAttributeWidgetClass),
55 (GtkClassInitFunc) sp_attribute_widget_class_init,
56 (GtkObjectInitFunc) sp_attribute_widget_init,
57 NULL, NULL, NULL
58 };
59 type = gtk_type_unique (GTK_TYPE_ENTRY, &info);
60 }
61 return type;
63 } // end of sp_attribute_widget_get_type()
67 static void
68 sp_attribute_widget_class_init (SPAttributeWidgetClass *klass)
69 {
70 GtkObjectClass *object_class;
71 GtkWidgetClass *widget_class;
72 GtkEditableClass *editable_class;
74 object_class = GTK_OBJECT_CLASS (klass);
75 widget_class = GTK_WIDGET_CLASS (klass);
76 editable_class = GTK_EDITABLE_CLASS (klass);
78 parent_class = (GtkEntryClass*)gtk_type_class (GTK_TYPE_ENTRY);
80 object_class->destroy = sp_attribute_widget_destroy;
82 editable_class->changed = sp_attribute_widget_changed;
84 } // end of sp_attribute_widget_class_init()
88 static void
89 sp_attribute_widget_init (SPAttributeWidget *spaw)
90 {
91 spaw->blocked = FALSE;
92 spaw->hasobj = FALSE;
94 spaw->src.object = NULL;
96 spaw->attribute = NULL;
97 }
101 static void
102 sp_attribute_widget_destroy (GtkObject *object)
103 {
105 SPAttributeWidget *spaw;
107 spaw = SP_ATTRIBUTE_WIDGET (object);
109 if (spaw->attribute) {
110 g_free (spaw->attribute);
111 spaw->attribute = NULL;
112 }
115 if (spaw->hasobj) {
117 if (spaw->src.object) {
118 sp_signal_disconnect_by_data (spaw->src.object, spaw);
119 spaw->src.object = NULL;
120 }
121 } else {
123 if (spaw->src.repr) {
124 spaw->src.repr = Inkscape::GC::release(spaw->src.repr);
125 }
126 } // end of if()
128 ((GtkObjectClass *) parent_class)->destroy (object);
130 }
134 static void
135 sp_attribute_widget_changed (GtkEditable *editable)
136 {
138 SPAttributeWidget *spaw;
140 spaw = SP_ATTRIBUTE_WIDGET (editable);
142 if (!spaw->blocked) {
144 const gchar *text;
145 spaw->blocked = TRUE;
146 text = gtk_entry_get_text (GTK_ENTRY (spaw));
147 if (!*text)
148 text = NULL;
150 if (spaw->hasobj && spaw->src.object) {
152 if (!sp_repr_set_attr ( SP_OBJECT_REPR (spaw->src.object),
153 spaw->attribute, text) )
154 {
155 /* Cannot set attribute */
156 text = SP_OBJECT_REPR (spaw->src.object)->attribute(spaw->attribute);
157 gtk_entry_set_text (GTK_ENTRY (spaw), text ? text : "");
158 }
159 sp_document_done (SP_OBJECT_DOCUMENT (spaw->src.object), SP_VERB_NONE,
160 /* TODO: annotate */ "sp-attribute-widget.cpp:160");
162 } else if (spaw->src.repr) {
164 if (!sp_repr_set_attr (spaw->src.repr, spaw->attribute, text))
165 {
166 /* Cannot set attribute */
167 text = spaw->src.repr->attribute(spaw->attribute);
168 gtk_entry_set_text (GTK_ENTRY (spaw), text ? text : "");
169 }
170 /* TODO: Warning! Undo will not be flushed in given case */
171 }
172 spaw->blocked = FALSE;
173 }
175 } // end of sp_attribute_widget_changed()
179 GtkWidget *
180 sp_attribute_widget_new ( SPObject *object, const gchar *attribute )
181 {
182 SPAttributeWidget *spaw;
184 g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL);
185 g_return_val_if_fail (!object || attribute, NULL);
187 spaw = (SPAttributeWidget*)gtk_type_new (SP_TYPE_ATTRIBUTE_WIDGET);
189 sp_attribute_widget_set_object (spaw, object, attribute);
191 return GTK_WIDGET (spaw);
193 } // end of sp_attribute_widget_new()
197 GtkWidget *
198 sp_attribute_widget_new_repr ( Inkscape::XML::Node *repr, const gchar *attribute )
199 {
200 SPAttributeWidget *spaw;
202 spaw = (SPAttributeWidget*)gtk_type_new (SP_TYPE_ATTRIBUTE_WIDGET);
204 sp_attribute_widget_set_repr (spaw, repr, attribute);
206 return GTK_WIDGET (spaw);
207 }
211 void
212 sp_attribute_widget_set_object ( SPAttributeWidget *spaw,
213 SPObject *object,
214 const gchar *attribute )
215 {
217 g_return_if_fail (spaw != NULL);
218 g_return_if_fail (SP_IS_ATTRIBUTE_WIDGET (spaw));
219 g_return_if_fail (!object || SP_IS_OBJECT (object));
220 g_return_if_fail (!object || attribute);
221 g_return_if_fail (attribute != NULL);
223 if (spaw->attribute) {
224 g_free (spaw->attribute);
225 spaw->attribute = NULL;
226 }
228 if (spaw->hasobj) {
230 if (spaw->src.object) {
231 sp_signal_disconnect_by_data (spaw->src.object, spaw);
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;
248 g_signal_connect ( G_OBJECT (object), "modified",
249 G_CALLBACK (sp_attribute_widget_object_modified),
250 spaw );
251 g_signal_connect ( G_OBJECT (object), "release",
252 G_CALLBACK (sp_attribute_widget_object_release),
253 spaw );
255 spaw->attribute = g_strdup (attribute);
257 val = SP_OBJECT_REPR (object)->attribute(attribute);
258 gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) "");
259 spaw->blocked = FALSE;
260 }
262 gtk_widget_set_sensitive (GTK_WIDGET (spaw), (spaw->src.object != NULL));
264 } // end of sp_attribute_widget_set_object()
268 void
269 sp_attribute_widget_set_repr ( SPAttributeWidget *spaw,
270 Inkscape::XML::Node *repr,
271 const gchar *attribute )
272 {
274 g_return_if_fail (spaw != NULL);
275 g_return_if_fail (SP_IS_ATTRIBUTE_WIDGET (spaw));
276 g_return_if_fail (attribute != NULL);
278 if (spaw->attribute) {
279 g_free (spaw->attribute);
280 spaw->attribute = NULL;
281 }
283 if (spaw->hasobj) {
285 if (spaw->src.object) {
286 sp_signal_disconnect_by_data (spaw->src.object, spaw);
287 spaw->src.object = NULL;
288 }
289 } else {
291 if (spaw->src.repr) {
292 spaw->src.repr = Inkscape::GC::release(spaw->src.repr);
293 }
294 }
296 spaw->hasobj = FALSE;
298 if (repr) {
299 const gchar *val;
301 spaw->blocked = TRUE;
302 spaw->src.repr = Inkscape::GC::anchor(repr);
303 spaw->attribute = g_strdup (attribute);
305 val = repr->attribute(attribute);
306 gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) "");
307 spaw->blocked = FALSE;
308 }
310 gtk_widget_set_sensitive (GTK_WIDGET (spaw), (spaw->src.repr != NULL));
312 } // end of sp_attribute_widget_set_repr()
316 static void
317 sp_attribute_widget_object_modified ( SPObject *object,
318 guint flags,
319 SPAttributeWidget *spaw )
320 {
322 if (flags && SP_OBJECT_MODIFIED_FLAG) {
324 const gchar *val, *text;
325 val = SP_OBJECT_REPR (spaw->src.object)->attribute(spaw->attribute);
326 text = gtk_entry_get_text (GTK_ENTRY (spaw));
328 if (val || text) {
330 if (!val || !text || strcmp (val, text)) {
331 /* We are different */
332 spaw->blocked = TRUE;
333 gtk_entry_set_text ( GTK_ENTRY (spaw),
334 val ? val : (const gchar *) "");
335 spaw->blocked = FALSE;
336 } // end of if()
338 } // end of if()
340 } //end of if()
342 } // end of sp_attribute_widget_object_modified()
346 static void
347 sp_attribute_widget_object_release ( SPObject *object,
348 SPAttributeWidget *spaw )
349 {
350 sp_attribute_widget_set_object (spaw, NULL, NULL);
351 }
355 /* SPAttributeTable */
357 static void sp_attribute_table_class_init (SPAttributeTableClass *klass);
358 static void sp_attribute_table_init (SPAttributeTable *widget);
359 static void sp_attribute_table_destroy (GtkObject *object);
361 static void sp_attribute_table_object_modified (SPObject *object, guint flags, SPAttributeTable *spaw);
362 static void sp_attribute_table_object_release (SPObject *object, SPAttributeTable *spaw);
363 static void sp_attribute_table_entry_changed (GtkEditable *editable, SPAttributeTable *spat);
365 static GtkVBoxClass *table_parent_class;
370 GtkType
371 sp_attribute_table_get_type (void)
372 {
373 static GtkType type = 0;
374 if (!type) {
375 static const GtkTypeInfo info = {
376 "SPAttributeTable",
377 sizeof (SPAttributeTable),
378 sizeof (SPAttributeTableClass),
379 (GtkClassInitFunc) sp_attribute_table_class_init,
380 (GtkObjectInitFunc) sp_attribute_table_init,
381 NULL, NULL, NULL
382 };
383 type = gtk_type_unique (GTK_TYPE_VBOX, &info);
384 }
385 return type;
387 } // end of sp_attribute_table_get_type()
391 static void
392 sp_attribute_table_class_init (SPAttributeTableClass *klass)
393 {
394 GtkObjectClass *object_class;
395 GtkWidgetClass *widget_class;
397 object_class = GTK_OBJECT_CLASS (klass);
398 widget_class = GTK_WIDGET_CLASS (klass);
400 table_parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
402 object_class->destroy = sp_attribute_table_destroy;
404 } // end of sp_attribute_table_class_init()
408 static void
409 sp_attribute_table_init ( SPAttributeTable *spat )
410 {
411 spat->blocked = FALSE;
412 spat->hasobj = FALSE;
413 spat->table = NULL;
414 spat->src.object = NULL;
415 spat->num_attr = 0;
416 spat->attributes = NULL;
417 spat->entries = NULL;
418 }
420 static void
421 sp_attribute_table_destroy ( GtkObject *object )
422 {
423 SPAttributeTable *spat;
425 spat = SP_ATTRIBUTE_TABLE (object);
427 if (spat->attributes) {
428 gint i;
429 for (i = 0; i < spat->num_attr; i++) {
430 g_free (spat->attributes[i]);
431 }
432 g_free (spat->attributes);
433 spat->attributes = NULL;
434 }
436 if (spat->hasobj) {
438 if (spat->src.object) {
439 sp_signal_disconnect_by_data (spat->src.object, spat);
440 spat->src.object = NULL;
441 }
442 } else {
443 if (spat->src.repr) {
444 spat->src.repr = Inkscape::GC::release(spat->src.repr);
445 }
446 } // end of if()
449 if (spat->entries) {
450 g_free (spat->entries);
451 spat->entries = NULL;
452 }
454 spat->table = NULL;
456 if (((GtkObjectClass *) table_parent_class)->destroy) {
457 (* ((GtkObjectClass *) table_parent_class)->destroy) (object);
458 }
460 } // end of sp_attribute_table_destroy()
463 GtkWidget *
464 sp_attribute_table_new ( SPObject *object,
465 gint num_attr,
466 const gchar **labels,
467 const gchar **attributes )
468 {
469 SPAttributeTable *spat;
471 g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL);
472 g_return_val_if_fail (!object || (num_attr > 0), NULL);
473 g_return_val_if_fail (!num_attr || (labels && attributes), NULL);
475 spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE);
477 sp_attribute_table_set_object (spat, object, num_attr, labels, attributes);
479 return GTK_WIDGET (spat);
481 } // end of sp_attribute_table_new()
485 GtkWidget *
486 sp_attribute_table_new_repr ( Inkscape::XML::Node *repr,
487 gint num_attr,
488 const gchar **labels,
489 const gchar **attributes )
490 {
491 SPAttributeTable *spat;
493 g_return_val_if_fail (!num_attr || (labels && attributes), NULL);
495 spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE);
497 sp_attribute_table_set_repr (spat, repr, num_attr, labels, attributes);
499 return GTK_WIDGET (spat);
501 } // end of sp_attribute_table_new_repr()
505 #define XPAD 4
506 #define YPAD 0
508 void
509 sp_attribute_table_set_object ( SPAttributeTable *spat,
510 SPObject *object,
511 gint num_attr,
512 const gchar **labels,
513 const gchar **attributes )
514 {
516 g_return_if_fail (spat != NULL);
517 g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat));
518 g_return_if_fail (!object || SP_IS_OBJECT (object));
519 g_return_if_fail (!object || (num_attr > 0));
520 g_return_if_fail (!num_attr || (labels && attributes));
522 if (spat->table) {
523 gtk_widget_destroy (spat->table);
524 spat->table = NULL;
525 }
527 if (spat->attributes) {
528 gint i;
529 for (i = 0; i < spat->num_attr; i++) {
530 g_free (spat->attributes[i]);
531 }
532 g_free (spat->attributes);
533 spat->attributes = NULL;
534 }
536 if (spat->entries) {
537 g_free (spat->entries);
538 spat->entries = NULL;
539 }
541 if (spat->hasobj) {
542 if (spat->src.object) {
543 sp_signal_disconnect_by_data (spat->src.object, spat);
544 spat->src.object = NULL;
545 }
546 } else {
547 if (spat->src.repr) {
548 spat->src.repr = Inkscape::GC::release(spat->src.repr);
549 }
550 }
552 spat->hasobj = TRUE;
554 if (object) {
555 gint i;
557 spat->blocked = TRUE;
559 /* Set up object */
560 spat->src.object = object;
561 spat->num_attr = num_attr;
562 g_signal_connect ( G_OBJECT (object), "modified",
563 G_CALLBACK (sp_attribute_table_object_modified),
564 spat );
565 g_signal_connect ( G_OBJECT (object), "release",
566 G_CALLBACK (sp_attribute_table_object_release),
567 spat );
568 /* Create table */
569 spat->table = gtk_table_new (num_attr, 2, FALSE);
570 gtk_container_add (GTK_CONTAINER (spat), spat->table);
571 /* Arrays */
572 spat->attributes = g_new0 (gchar *, num_attr);
573 spat->entries = g_new0 (GtkWidget *, num_attr);
574 /* Fill rows */
575 for (i = 0; i < num_attr; i++) {
576 GtkWidget *w;
577 const gchar *val;
579 spat->attributes[i] = g_strdup (attributes[i]);
580 w = gtk_label_new (_(labels[i]));
581 gtk_widget_show (w);
582 gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5);
583 gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1,
584 GTK_FILL,
585 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
586 XPAD, YPAD );
587 w = gtk_entry_new ();
588 gtk_widget_show (w);
589 val = SP_OBJECT_REPR (object)->attribute(attributes[i]);
590 gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) "");
591 gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1,
592 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
593 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
594 XPAD, YPAD );
595 spat->entries[i] = w;
596 g_signal_connect ( G_OBJECT (w), "changed",
597 G_CALLBACK (sp_attribute_table_entry_changed),
598 spat );
599 }
600 /* Show table */
601 gtk_widget_show (spat->table);
603 spat->blocked = FALSE;
604 }
606 gtk_widget_set_sensitive ( GTK_WIDGET (spat),
607 (spat->src.object != NULL) );
609 } // end of sp_attribute_table_set_object()
613 void
614 sp_attribute_table_set_repr ( SPAttributeTable *spat,
615 Inkscape::XML::Node *repr,
616 gint num_attr,
617 const gchar **labels,
618 const gchar **attributes )
619 {
620 g_return_if_fail (spat != NULL);
621 g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat));
622 g_return_if_fail (!num_attr || (labels && attributes));
624 if (spat->table) {
625 gtk_widget_destroy (spat->table);
626 spat->table = NULL;
627 }
629 if (spat->attributes) {
630 gint i;
631 for (i = 0; i < spat->num_attr; i++) {
632 g_free (spat->attributes[i]);
633 }
634 g_free (spat->attributes);
635 spat->attributes = NULL;
636 }
638 if (spat->entries) {
639 g_free (spat->entries);
640 spat->entries = NULL;
641 }
643 if (spat->hasobj) {
644 if (spat->src.object) {
645 sp_signal_disconnect_by_data (spat->src.object, spat);
646 spat->src.object = NULL;
647 }
648 } else {
649 if (spat->src.repr) {
650 spat->src.repr = Inkscape::GC::release(spat->src.repr);
651 }
652 }
654 spat->hasobj = FALSE;
656 if (repr) {
657 gint i;
659 spat->blocked = TRUE;
661 /* Set up repr */
662 spat->src.repr = Inkscape::GC::anchor(repr);
663 spat->num_attr = num_attr;
664 /* Create table */
665 spat->table = gtk_table_new (num_attr, 2, FALSE);
666 gtk_container_add (GTK_CONTAINER (spat), spat->table);
667 /* Arrays */
668 spat->attributes = g_new0 (gchar *, num_attr);
669 spat->entries = g_new0 (GtkWidget *, num_attr);
671 /* Fill rows */
672 for (i = 0; i < num_attr; i++) {
673 GtkWidget *w;
674 const gchar *val;
676 spat->attributes[i] = g_strdup (attributes[i]);
677 w = gtk_label_new (labels[i]);
678 gtk_widget_show (w);
679 gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5);
680 gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1,
681 GTK_FILL,
682 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
683 XPAD, YPAD );
684 w = gtk_entry_new ();
685 gtk_widget_show (w);
686 val = repr->attribute(attributes[i]);
687 gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) "");
688 gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1,
689 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
690 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
691 XPAD, YPAD );
692 spat->entries[i] = w;
693 g_signal_connect ( G_OBJECT (w), "changed",
694 G_CALLBACK (sp_attribute_table_entry_changed),
695 spat );
696 }
697 /* Show table */
698 gtk_widget_show (spat->table);
700 spat->blocked = FALSE;
701 }
703 gtk_widget_set_sensitive (GTK_WIDGET (spat), (spat->src.repr != NULL));
705 } // end of sp_attribute_table_set_repr()
709 static void
710 sp_attribute_table_object_modified ( SPObject *object,
711 guint flags,
712 SPAttributeTable *spat )
713 {
714 if (flags && SP_OBJECT_MODIFIED_FLAG)
715 {
716 gint i;
717 for (i = 0; i < spat->num_attr; i++) {
718 const gchar *val, *text;
719 val = SP_OBJECT_REPR (spat->src.object)->attribute(spat->attributes[i]);
720 text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i]));
721 if (val || text) {
722 if (!val || !text || strcmp (val, text)) {
723 /* We are different */
724 spat->blocked = TRUE;
725 gtk_entry_set_text ( GTK_ENTRY (spat->entries[i]),
726 val ? val : (const gchar *) "");
727 spat->blocked = FALSE;
728 }
729 }
730 }
731 } // end of if()
733 } // end of sp_attribute_table_object_modified()
737 static void
738 sp_attribute_table_object_release (SPObject *object, SPAttributeTable *spat)
739 {
740 sp_attribute_table_set_object (spat, NULL, 0, NULL, NULL);
741 }
745 static void
746 sp_attribute_table_entry_changed ( GtkEditable *editable,
747 SPAttributeTable *spat )
748 {
749 if (!spat->blocked)
750 {
751 gint i;
752 for (i = 0; i < spat->num_attr; i++) {
754 if (GTK_WIDGET (editable) == spat->entries[i]) {
755 const gchar *text;
756 spat->blocked = TRUE;
757 text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i]));
759 if (!*text)
760 text = NULL;
762 if (spat->hasobj && spat->src.object) {
763 if (!sp_repr_set_attr ( SP_OBJECT_REPR (spat->src.object),
764 spat->attributes[i], text))
765 {
766 /* Cannot set attribute */
767 text = SP_OBJECT_REPR (spat->src.object)->attribute(spat->attributes[i]);
768 gtk_entry_set_text ( GTK_ENTRY (spat->entries[i]),
769 text ? text : (const gchar *) "");
770 }
771 sp_document_done (SP_OBJECT_DOCUMENT (spat->src.object), SP_VERB_NONE,
772 /* TODO: annotate */ "sp-attribute-widget.cpp:772");
774 } else if (spat->src.repr) {
776 if (!sp_repr_set_attr (spat->src.repr,
777 spat->attributes[i], text))
778 {
779 /* Cannot set attribute */
780 text = spat->src.repr->attribute(spat->attributes[i]);
781 gtk_entry_set_text ( GTK_ENTRY (spat->entries[i]),
782 text ? text : (const gchar *) "" );
783 }
784 /* TODO: Warning! Undo will not be flushed in given case */
785 }
786 spat->blocked = FALSE;
787 return;
788 }
789 }
790 g_warning ("file %s: line %d: Entry signalled change, but there is no such entry", __FILE__, __LINE__);
791 } // end of if()
793 } // end of sp_attribute_table_entry_changed()
795 /*
796 Local Variables:
797 mode:c++
798 c-file-style:"stroustrup"
799 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
800 indent-tabs-mode:nil
801 fill-column:99
802 End:
803 */
804 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :