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));
161 } else if (spaw->src.repr) {
163 if (!sp_repr_set_attr (spaw->src.repr, spaw->attribute, text))
164 {
165 /* Cannot set attribute */
166 text = spaw->src.repr->attribute(spaw->attribute);
167 gtk_entry_set_text (GTK_ENTRY (spaw), text ? text : "");
168 }
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 )
180 {
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 )
198 {
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);
206 }
210 void
211 sp_attribute_widget_set_object ( SPAttributeWidget *spaw,
212 SPObject *object,
213 const gchar *attribute )
214 {
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 sp_signal_disconnect_by_data (spaw->src.object, spaw);
231 spaw->src.object = NULL;
232 }
233 } else {
235 if (spaw->src.repr) {
236 spaw->src.repr = Inkscape::GC::release(spaw->src.repr);
237 }
238 }
240 spaw->hasobj = TRUE;
242 if (object) {
243 const gchar *val;
245 spaw->blocked = TRUE;
246 spaw->src.object = object;
247 g_signal_connect ( G_OBJECT (object), "modified",
248 G_CALLBACK (sp_attribute_widget_object_modified),
249 spaw );
250 g_signal_connect ( G_OBJECT (object), "release",
251 G_CALLBACK (sp_attribute_widget_object_release),
252 spaw );
254 spaw->attribute = g_strdup (attribute);
256 val = SP_OBJECT_REPR (object)->attribute(attribute);
257 gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) "");
258 spaw->blocked = FALSE;
259 }
261 gtk_widget_set_sensitive (GTK_WIDGET (spaw), (spaw->src.object != NULL));
263 } // end of sp_attribute_widget_set_object()
267 void
268 sp_attribute_widget_set_repr ( SPAttributeWidget *spaw,
269 Inkscape::XML::Node *repr,
270 const gchar *attribute )
271 {
273 g_return_if_fail (spaw != NULL);
274 g_return_if_fail (SP_IS_ATTRIBUTE_WIDGET (spaw));
275 g_return_if_fail (attribute != NULL);
277 if (spaw->attribute) {
278 g_free (spaw->attribute);
279 spaw->attribute = NULL;
280 }
282 if (spaw->hasobj) {
284 if (spaw->src.object) {
285 sp_signal_disconnect_by_data (spaw->src.object, spaw);
286 spaw->src.object = NULL;
287 }
288 } else {
290 if (spaw->src.repr) {
291 spaw->src.repr = Inkscape::GC::release(spaw->src.repr);
292 }
293 }
295 spaw->hasobj = FALSE;
297 if (repr) {
298 const gchar *val;
300 spaw->blocked = TRUE;
301 spaw->src.repr = Inkscape::GC::anchor(repr);
302 spaw->attribute = g_strdup (attribute);
304 val = repr->attribute(attribute);
305 gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) "");
306 spaw->blocked = FALSE;
307 }
309 gtk_widget_set_sensitive (GTK_WIDGET (spaw), (spaw->src.repr != NULL));
311 } // end of sp_attribute_widget_set_repr()
315 static void
316 sp_attribute_widget_object_modified ( SPObject *object,
317 guint flags,
318 SPAttributeWidget *spaw )
319 {
321 if (flags && SP_OBJECT_MODIFIED_FLAG) {
323 const gchar *val, *text;
324 val = SP_OBJECT_REPR (spaw->src.object)->attribute(spaw->attribute);
325 text = gtk_entry_get_text (GTK_ENTRY (spaw));
327 if (val || text) {
329 if (!val || !text || strcmp (val, text)) {
330 /* We are different */
331 spaw->blocked = TRUE;
332 gtk_entry_set_text ( GTK_ENTRY (spaw),
333 val ? val : (const gchar *) "");
334 spaw->blocked = FALSE;
335 } // end of if()
337 } // end of if()
339 } //end of if()
341 } // end of sp_attribute_widget_object_modified()
345 static void
346 sp_attribute_widget_object_release ( SPObject *object,
347 SPAttributeWidget *spaw )
348 {
349 sp_attribute_widget_set_object (spaw, NULL, NULL);
350 }
354 /* SPAttributeTable */
356 static void sp_attribute_table_class_init (SPAttributeTableClass *klass);
357 static void sp_attribute_table_init (SPAttributeTable *widget);
358 static void sp_attribute_table_destroy (GtkObject *object);
360 static void sp_attribute_table_object_modified (SPObject *object, guint flags, SPAttributeTable *spaw);
361 static void sp_attribute_table_object_release (SPObject *object, SPAttributeTable *spaw);
362 static void sp_attribute_table_entry_changed (GtkEditable *editable, SPAttributeTable *spat);
364 static GtkVBoxClass *table_parent_class;
369 GtkType
370 sp_attribute_table_get_type (void)
371 {
372 static GtkType type = 0;
373 if (!type) {
374 static const GtkTypeInfo info = {
375 "SPAttributeTable",
376 sizeof (SPAttributeTable),
377 sizeof (SPAttributeTableClass),
378 (GtkClassInitFunc) sp_attribute_table_class_init,
379 (GtkObjectInitFunc) sp_attribute_table_init,
380 NULL, NULL, NULL
381 };
382 type = gtk_type_unique (GTK_TYPE_VBOX, &info);
383 }
384 return type;
386 } // end of sp_attribute_table_get_type()
390 static void
391 sp_attribute_table_class_init (SPAttributeTableClass *klass)
392 {
393 GtkObjectClass *object_class;
394 GtkWidgetClass *widget_class;
396 object_class = GTK_OBJECT_CLASS (klass);
397 widget_class = GTK_WIDGET_CLASS (klass);
399 table_parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
401 object_class->destroy = sp_attribute_table_destroy;
403 } // end of sp_attribute_table_class_init()
407 static void
408 sp_attribute_table_init ( SPAttributeTable *spat )
409 {
410 spat->blocked = FALSE;
411 spat->hasobj = FALSE;
412 spat->table = NULL;
413 spat->src.object = NULL;
414 spat->num_attr = 0;
415 spat->attributes = NULL;
416 spat->entries = NULL;
417 }
419 static void
420 sp_attribute_table_destroy ( GtkObject *object )
421 {
422 SPAttributeTable *spat;
424 spat = SP_ATTRIBUTE_TABLE (object);
426 if (spat->attributes) {
427 gint i;
428 for (i = 0; i < spat->num_attr; i++) {
429 g_free (spat->attributes[i]);
430 }
431 g_free (spat->attributes);
432 spat->attributes = NULL;
433 }
435 if (spat->hasobj) {
437 if (spat->src.object) {
438 sp_signal_disconnect_by_data (spat->src.object, spat);
439 spat->src.object = NULL;
440 }
441 } else {
442 if (spat->src.repr) {
443 spat->src.repr = Inkscape::GC::release(spat->src.repr);
444 }
445 } // end of if()
448 if (spat->entries) {
449 g_free (spat->entries);
450 spat->entries = NULL;
451 }
453 spat->table = NULL;
455 if (((GtkObjectClass *) table_parent_class)->destroy) {
456 (* ((GtkObjectClass *) table_parent_class)->destroy) (object);
457 }
459 } // end of sp_attribute_table_destroy()
462 GtkWidget *
463 sp_attribute_table_new ( SPObject *object,
464 gint num_attr,
465 const gchar **labels,
466 const gchar **attributes )
467 {
468 SPAttributeTable *spat;
470 g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL);
471 g_return_val_if_fail (!object || (num_attr > 0), NULL);
472 g_return_val_if_fail (!num_attr || (labels && attributes), NULL);
474 spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE);
476 sp_attribute_table_set_object (spat, object, num_attr, labels, attributes);
478 return GTK_WIDGET (spat);
480 } // end of sp_attribute_table_new()
484 GtkWidget *
485 sp_attribute_table_new_repr ( Inkscape::XML::Node *repr,
486 gint num_attr,
487 const gchar **labels,
488 const gchar **attributes )
489 {
490 SPAttributeTable *spat;
492 g_return_val_if_fail (!num_attr || (labels && attributes), NULL);
494 spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE);
496 sp_attribute_table_set_repr (spat, repr, num_attr, labels, attributes);
498 return GTK_WIDGET (spat);
500 } // end of sp_attribute_table_new_repr()
504 #define XPAD 4
505 #define YPAD 0
507 void
508 sp_attribute_table_set_object ( SPAttributeTable *spat,
509 SPObject *object,
510 gint num_attr,
511 const gchar **labels,
512 const gchar **attributes )
513 {
515 g_return_if_fail (spat != NULL);
516 g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat));
517 g_return_if_fail (!object || SP_IS_OBJECT (object));
518 g_return_if_fail (!object || (num_attr > 0));
519 g_return_if_fail (!num_attr || (labels && attributes));
521 if (spat->table) {
522 gtk_widget_destroy (spat->table);
523 spat->table = NULL;
524 }
526 if (spat->attributes) {
527 gint i;
528 for (i = 0; i < spat->num_attr; i++) {
529 g_free (spat->attributes[i]);
530 }
531 g_free (spat->attributes);
532 spat->attributes = NULL;
533 }
535 if (spat->entries) {
536 g_free (spat->entries);
537 spat->entries = NULL;
538 }
540 if (spat->hasobj) {
541 if (spat->src.object) {
542 sp_signal_disconnect_by_data (spat->src.object, spat);
543 spat->src.object = NULL;
544 }
545 } else {
546 if (spat->src.repr) {
547 spat->src.repr = Inkscape::GC::release(spat->src.repr);
548 }
549 }
551 spat->hasobj = TRUE;
553 if (object) {
554 gint i;
556 spat->blocked = TRUE;
558 /* Set up object */
559 spat->src.object = object;
560 spat->num_attr = num_attr;
561 g_signal_connect ( G_OBJECT (object), "modified",
562 G_CALLBACK (sp_attribute_table_object_modified),
563 spat );
564 g_signal_connect ( G_OBJECT (object), "release",
565 G_CALLBACK (sp_attribute_table_object_release),
566 spat );
567 /* Create table */
568 spat->table = gtk_table_new (num_attr, 2, FALSE);
569 gtk_container_add (GTK_CONTAINER (spat), spat->table);
570 /* Arrays */
571 spat->attributes = g_new0 (gchar *, num_attr);
572 spat->entries = g_new0 (GtkWidget *, num_attr);
573 /* Fill rows */
574 for (i = 0; i < num_attr; i++) {
575 GtkWidget *w;
576 const gchar *val;
578 spat->attributes[i] = g_strdup (attributes[i]);
579 w = gtk_label_new (_(labels[i]));
580 gtk_widget_show (w);
581 gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5);
582 gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1,
583 GTK_FILL,
584 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
585 XPAD, YPAD );
586 w = gtk_entry_new ();
587 gtk_widget_show (w);
588 val = SP_OBJECT_REPR (object)->attribute(attributes[i]);
589 gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) "");
590 gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1,
591 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
592 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
593 XPAD, YPAD );
594 spat->entries[i] = w;
595 g_signal_connect ( G_OBJECT (w), "changed",
596 G_CALLBACK (sp_attribute_table_entry_changed),
597 spat );
598 }
599 /* Show table */
600 gtk_widget_show (spat->table);
602 spat->blocked = FALSE;
603 }
605 gtk_widget_set_sensitive ( GTK_WIDGET (spat),
606 (spat->src.object != NULL) );
608 } // end of sp_attribute_table_set_object()
612 void
613 sp_attribute_table_set_repr ( SPAttributeTable *spat,
614 Inkscape::XML::Node *repr,
615 gint num_attr,
616 const gchar **labels,
617 const gchar **attributes )
618 {
619 g_return_if_fail (spat != NULL);
620 g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat));
621 g_return_if_fail (!num_attr || (labels && attributes));
623 if (spat->table) {
624 gtk_widget_destroy (spat->table);
625 spat->table = NULL;
626 }
628 if (spat->attributes) {
629 gint i;
630 for (i = 0; i < spat->num_attr; i++) {
631 g_free (spat->attributes[i]);
632 }
633 g_free (spat->attributes);
634 spat->attributes = NULL;
635 }
637 if (spat->entries) {
638 g_free (spat->entries);
639 spat->entries = NULL;
640 }
642 if (spat->hasobj) {
643 if (spat->src.object) {
644 sp_signal_disconnect_by_data (spat->src.object, spat);
645 spat->src.object = NULL;
646 }
647 } else {
648 if (spat->src.repr) {
649 spat->src.repr = Inkscape::GC::release(spat->src.repr);
650 }
651 }
653 spat->hasobj = FALSE;
655 if (repr) {
656 gint i;
658 spat->blocked = TRUE;
660 /* Set up repr */
661 spat->src.repr = Inkscape::GC::anchor(repr);
662 spat->num_attr = num_attr;
663 /* Create table */
664 spat->table = gtk_table_new (num_attr, 2, FALSE);
665 gtk_container_add (GTK_CONTAINER (spat), spat->table);
666 /* Arrays */
667 spat->attributes = g_new0 (gchar *, num_attr);
668 spat->entries = g_new0 (GtkWidget *, num_attr);
670 /* Fill rows */
671 for (i = 0; i < num_attr; i++) {
672 GtkWidget *w;
673 const gchar *val;
675 spat->attributes[i] = g_strdup (attributes[i]);
676 w = gtk_label_new (labels[i]);
677 gtk_widget_show (w);
678 gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5);
679 gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1,
680 GTK_FILL,
681 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
682 XPAD, YPAD );
683 w = gtk_entry_new ();
684 gtk_widget_show (w);
685 val = repr->attribute(attributes[i]);
686 gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) "");
687 gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1,
688 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
689 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
690 XPAD, YPAD );
691 spat->entries[i] = w;
692 g_signal_connect ( G_OBJECT (w), "changed",
693 G_CALLBACK (sp_attribute_table_entry_changed),
694 spat );
695 }
696 /* Show table */
697 gtk_widget_show (spat->table);
699 spat->blocked = FALSE;
700 }
702 gtk_widget_set_sensitive (GTK_WIDGET (spat), (spat->src.repr != NULL));
704 } // end of sp_attribute_table_set_repr()
708 static void
709 sp_attribute_table_object_modified ( SPObject *object,
710 guint flags,
711 SPAttributeTable *spat )
712 {
713 if (flags && SP_OBJECT_MODIFIED_FLAG)
714 {
715 gint i;
716 for (i = 0; i < spat->num_attr; i++) {
717 const gchar *val, *text;
718 val = SP_OBJECT_REPR (spat->src.object)->attribute(spat->attributes[i]);
719 text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i]));
720 if (val || text) {
721 if (!val || !text || strcmp (val, text)) {
722 /* We are different */
723 spat->blocked = TRUE;
724 gtk_entry_set_text ( GTK_ENTRY (spat->entries[i]),
725 val ? val : (const gchar *) "");
726 spat->blocked = FALSE;
727 }
728 }
729 }
730 } // end of if()
732 } // end of sp_attribute_table_object_modified()
736 static void
737 sp_attribute_table_object_release (SPObject *object, SPAttributeTable *spat)
738 {
739 sp_attribute_table_set_object (spat, NULL, 0, NULL, NULL);
740 }
744 static void
745 sp_attribute_table_entry_changed ( GtkEditable *editable,
746 SPAttributeTable *spat )
747 {
748 if (!spat->blocked)
749 {
750 gint i;
751 for (i = 0; i < spat->num_attr; i++) {
753 if (GTK_WIDGET (editable) == spat->entries[i]) {
754 const gchar *text;
755 spat->blocked = TRUE;
756 text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i]));
758 if (!*text)
759 text = NULL;
761 if (spat->hasobj && spat->src.object) {
762 if (!sp_repr_set_attr ( SP_OBJECT_REPR (spat->src.object),
763 spat->attributes[i], text))
764 {
765 /* Cannot set attribute */
766 text = SP_OBJECT_REPR (spat->src.object)->attribute(spat->attributes[i]);
767 gtk_entry_set_text ( GTK_ENTRY (spat->entries[i]),
768 text ? text : (const gchar *) "");
769 }
770 sp_document_done (SP_OBJECT_DOCUMENT (spat->src.object));
772 } else if (spat->src.repr) {
774 if (!sp_repr_set_attr (spat->src.repr,
775 spat->attributes[i], text))
776 {
777 /* Cannot set attribute */
778 text = spat->src.repr->attribute(spat->attributes[i]);
779 gtk_entry_set_text ( GTK_ENTRY (spat->entries[i]),
780 text ? text : (const gchar *) "" );
781 }
782 /* TODO: Warning! Undo will not be flushed in given case */
783 }
784 spat->blocked = FALSE;
785 return;
786 }
787 }
788 g_warning ("file %s: line %d: Entry signalled change, but there is no such entry", __FILE__, __LINE__);
789 } // end of if()
791 } // end of sp_attribute_table_entry_changed()
793 /*
794 Local Variables:
795 mode:c++
796 c-file-style:"stroustrup"
797 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
798 indent-tabs-mode:nil
799 fill-column:99
800 End:
801 */
802 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :