Code

NR:: => Geom:: for much of src/ui and src/widgets
[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 GType sp_attribute_widget_get_type(void)
50 {
51     static GtkType type = 0;
52     if (!type) {
53         GTypeInfo info = {
54             sizeof(SPAttributeWidgetClass),
55             0, // base_init
56             0, // base_finalize
57             (GClassInitFunc)sp_attribute_widget_class_init,
58             0, // class_finalize
59             0, // class_data
60             sizeof(SPAttributeWidget),
61             0, // n_preallocs
62             (GInstanceInitFunc)sp_attribute_widget_init,
63             0 // value_table
64         };
65         type = g_type_register_static(GTK_TYPE_ENTRY, "SPAttributeWidget", &info, static_cast<GTypeFlags>(0));
66     }
67     return type;
68 } // end of sp_attribute_widget_get_type()
72 static void
73 sp_attribute_widget_class_init (SPAttributeWidgetClass *klass)
74 {
75     GtkObjectClass *object_class;
76     GtkWidgetClass *widget_class;
77     GtkEditableClass *editable_class;
79     object_class = GTK_OBJECT_CLASS (klass);
80     widget_class = GTK_WIDGET_CLASS (klass);
81     editable_class = GTK_EDITABLE_CLASS (klass);
83     parent_class = (GtkEntryClass*)gtk_type_class (GTK_TYPE_ENTRY);
85     object_class->destroy = sp_attribute_widget_destroy;
87     editable_class->changed = sp_attribute_widget_changed;
89 } // end of sp_attribute_widget_class_init()
93 static void
94 sp_attribute_widget_init (SPAttributeWidget *spaw)
95 {
96     spaw->blocked = FALSE;
97     spaw->hasobj = FALSE;
99     spaw->src.object = NULL;
101     spaw->attribute = NULL;
103     new (&spaw->modified_connection) sigc::connection();
104     new (&spaw->release_connection) sigc::connection();
109 static void
110 sp_attribute_widget_destroy (GtkObject *object)
113     SPAttributeWidget *spaw;
115     spaw = SP_ATTRIBUTE_WIDGET (object);
117     if (spaw->attribute) {
118         g_free (spaw->attribute);
119         spaw->attribute = NULL;
120     }
123     if (spaw->hasobj) {
125         if (spaw->src.object) {
126             spaw->modified_connection.disconnect();
127             spaw->release_connection.disconnect();
128             spaw->src.object = NULL;
129         }
130     } else {
132         if (spaw->src.repr) {
133             spaw->src.repr = Inkscape::GC::release(spaw->src.repr);
134         }
135     } // end of if()
137     spaw->modified_connection.~connection();
138     spaw->release_connection.~connection();
140     ((GtkObjectClass *) parent_class)->destroy (object);
146 static void
147 sp_attribute_widget_changed (GtkEditable *editable)
150     SPAttributeWidget *spaw;
152     spaw = SP_ATTRIBUTE_WIDGET (editable);
154     if (!spaw->blocked) {
156         const gchar *text;
157         spaw->blocked = TRUE;
158         text = gtk_entry_get_text (GTK_ENTRY (spaw));
159         if (!*text)
160             text = NULL;
162         if (spaw->hasobj && spaw->src.object) {
163         
164             SP_OBJECT_REPR (spaw->src.object)->setAttribute(spaw->attribute, text, false);
165             sp_document_done (SP_OBJECT_DOCUMENT (spaw->src.object), SP_VERB_NONE,
166                               _("Set attribute"));
168         } else if (spaw->src.repr) {
170             spaw->src.repr->setAttribute(spaw->attribute, text, false);
171             /* TODO: Warning! Undo will not be flushed in given case */
172         }
173         spaw->blocked = FALSE;
174     }
176 } // end of sp_attribute_widget_changed()
180 GtkWidget *
181 sp_attribute_widget_new ( SPObject *object, const gchar *attribute )
183     SPAttributeWidget *spaw;
185     g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL);
186     g_return_val_if_fail (!object || attribute, NULL);
188     spaw = (SPAttributeWidget*)gtk_type_new (SP_TYPE_ATTRIBUTE_WIDGET);
190     sp_attribute_widget_set_object (spaw, object, attribute);
192     return GTK_WIDGET (spaw);
194 } // end of sp_attribute_widget_new()
198 GtkWidget *
199 sp_attribute_widget_new_repr ( Inkscape::XML::Node *repr, const gchar *attribute )
201     SPAttributeWidget *spaw;
203     spaw = (SPAttributeWidget*)gtk_type_new (SP_TYPE_ATTRIBUTE_WIDGET);
205     sp_attribute_widget_set_repr (spaw, repr, attribute);
207     return GTK_WIDGET (spaw);
212 void
213 sp_attribute_widget_set_object ( SPAttributeWidget *spaw,
214                                  SPObject *object,
215                                  const gchar *attribute )
218     g_return_if_fail (spaw != NULL);
219     g_return_if_fail (SP_IS_ATTRIBUTE_WIDGET (spaw));
220     g_return_if_fail (!object || SP_IS_OBJECT (object));
221     g_return_if_fail (!object || attribute);
222     g_return_if_fail (attribute != NULL);
224     if (spaw->attribute) {
225         g_free (spaw->attribute);
226         spaw->attribute = NULL;
227     }
229     if (spaw->hasobj) {
231         if (spaw->src.object) {
232             spaw->modified_connection.disconnect();
233             spaw->release_connection.disconnect();
234             spaw->src.object = NULL;
235         }
236     } else {
238         if (spaw->src.repr) {
239             spaw->src.repr = Inkscape::GC::release(spaw->src.repr);
240         }
241     }
243     spaw->hasobj = TRUE;
245     if (object) {
246         const gchar *val;
248         spaw->blocked = TRUE;
249         spaw->src.object = object;
251         spaw->modified_connection = object->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_attribute_widget_object_modified), spaw));
252         spaw->release_connection = object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_attribute_widget_object_release), 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 )
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             spaw->modified_connection.disconnect();
286             spaw->release_connection.disconnect();
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 )
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 )
350     sp_attribute_widget_set_object (spaw, NULL, NULL);
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 GType sp_attribute_table_get_type(void)
372     static GtkType type = 0;
373     if (!type) {
374         GTypeInfo info = {
375             sizeof(SPAttributeTableClass),
376             0, // base_init
377             0, // base_finalize
378             (GClassInitFunc)sp_attribute_table_class_init,
379             0, // class_finalize
380             0, // class_data
381             sizeof(SPAttributeTable),
382             0, // n_preallocs
383             (GInstanceInitFunc)sp_attribute_table_init,
384             0 // value_table
385         };
386         type = g_type_register_static(GTK_TYPE_VBOX, "SPAttributeTable", &info, static_cast<GTypeFlags>(0));
387     }
388     return type;
389 } // end of sp_attribute_table_get_type()
393 static void
394 sp_attribute_table_class_init (SPAttributeTableClass *klass)
396     GtkObjectClass *object_class;
397     GtkWidgetClass *widget_class;
399     object_class = GTK_OBJECT_CLASS (klass);
400     widget_class = GTK_WIDGET_CLASS (klass);
402     table_parent_class = (GtkVBoxClass*)gtk_type_class (GTK_TYPE_VBOX);
404     object_class->destroy = sp_attribute_table_destroy;
406 } // end of sp_attribute_table_class_init()
410 static void
411 sp_attribute_table_init ( SPAttributeTable *spat )
413     spat->blocked = FALSE;
414     spat->hasobj = FALSE;
415     spat->table = NULL;
416     spat->src.object = NULL;
417     spat->num_attr = 0;
418     spat->attributes = NULL;
419     spat->entries = NULL;
421     new (&spat->modified_connection) sigc::connection();
422     new (&spat->release_connection) sigc::connection();
425 static void
426 sp_attribute_table_destroy ( GtkObject *object )
428     SPAttributeTable *spat;
430     spat = SP_ATTRIBUTE_TABLE (object);
432     if (spat->attributes) {
433         gint i;
434         for (i = 0; i < spat->num_attr; i++) {
435             g_free (spat->attributes[i]);
436         }
437         g_free (spat->attributes);
438         spat->attributes = NULL;
439     }
441     if (spat->hasobj) {
443         if (spat->src.object) {
444             spat->modified_connection.disconnect();
445             spat->release_connection.disconnect();
446             spat->src.object = NULL;
447         }
448     } else {
449         if (spat->src.repr) {
450             spat->src.repr = Inkscape::GC::release(spat->src.repr);
451         }
452     } // end of if()
454     spat->modified_connection.~connection();
455     spat->release_connection.~connection();
457     if (spat->entries) {
458         g_free (spat->entries);
459         spat->entries = NULL;
460     }
462     spat->table = NULL;
464     if (((GtkObjectClass *) table_parent_class)->destroy) {
465         (* ((GtkObjectClass *) table_parent_class)->destroy) (object);
466     }
468 } // end of sp_attribute_table_destroy()
471 GtkWidget *
472 sp_attribute_table_new ( SPObject *object,
473                          gint num_attr,
474                          const gchar **labels,
475                          const gchar **attributes )
477     SPAttributeTable *spat;
479     g_return_val_if_fail (!object || SP_IS_OBJECT (object), NULL);
480     g_return_val_if_fail (!object || (num_attr > 0), NULL);
481     g_return_val_if_fail (!num_attr || (labels && attributes), NULL);
483     spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE);
485     sp_attribute_table_set_object (spat, object, num_attr, labels, attributes);
487     return GTK_WIDGET (spat);
489 } // end of sp_attribute_table_new()
493 GtkWidget *
494 sp_attribute_table_new_repr ( Inkscape::XML::Node *repr,
495                               gint num_attr,
496                               const gchar **labels,
497                               const gchar **attributes )
499     SPAttributeTable *spat;
501     g_return_val_if_fail (!num_attr || (labels && attributes), NULL);
503     spat = (SPAttributeTable*)gtk_type_new (SP_TYPE_ATTRIBUTE_TABLE);
505     sp_attribute_table_set_repr (spat, repr, num_attr, labels, attributes);
507     return GTK_WIDGET (spat);
509 } // end of sp_attribute_table_new_repr()
513 #define XPAD 4
514 #define YPAD 0
516 void
517 sp_attribute_table_set_object ( SPAttributeTable *spat,
518                                 SPObject *object,
519                                 gint num_attr,
520                                 const gchar **labels,
521                                 const gchar **attributes )
524     g_return_if_fail (spat != NULL);
525     g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat));
526     g_return_if_fail (!object || SP_IS_OBJECT (object));
527     g_return_if_fail (!object || (num_attr > 0));
528     g_return_if_fail (!num_attr || (labels && attributes));
530     if (spat->table) {
531         gtk_widget_destroy (spat->table);
532         spat->table = NULL;
533     }
535     if (spat->attributes) {
536         gint i;
537         for (i = 0; i < spat->num_attr; i++) {
538             g_free (spat->attributes[i]);
539         }
540         g_free (spat->attributes);
541         spat->attributes = NULL;
542     }
544     if (spat->entries) {
545         g_free (spat->entries);
546         spat->entries = NULL;
547     }
549     if (spat->hasobj) {
550         if (spat->src.object) {
551             spat->modified_connection.disconnect();
552             spat->release_connection.disconnect();
553             spat->src.object = NULL;
554         }
555     } else {
556         if (spat->src.repr) {
557             spat->src.repr = Inkscape::GC::release(spat->src.repr);
558         }
559     }
561     spat->hasobj = TRUE;
563     if (object) {
564         gint i;
566         spat->blocked = TRUE;
568         /* Set up object */
569         spat->src.object = object;
570         spat->num_attr = num_attr;
572         spat->modified_connection = object->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_attribute_table_object_modified), spat));
573         spat->release_connection = object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_attribute_table_object_release), spat));
575         /* Create table */
576         spat->table = gtk_table_new (num_attr, 2, FALSE);
577         gtk_container_add (GTK_CONTAINER (spat), spat->table);
578         /* Arrays */
579         spat->attributes = g_new0 (gchar *, num_attr);
580         spat->entries = g_new0 (GtkWidget *, num_attr);
581         /* Fill rows */
582         for (i = 0; i < num_attr; i++) {
583             GtkWidget *w;
584             const gchar *val;
586             spat->attributes[i] = g_strdup (attributes[i]);
587             w = gtk_label_new (_(labels[i]));
588             gtk_widget_show (w);
589             gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5);
590             gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1,
591                                GTK_FILL,
592                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
593                                XPAD, YPAD );
594             w = gtk_entry_new ();
595             gtk_widget_show (w);
596             val = SP_OBJECT_REPR (object)->attribute(attributes[i]);
597             gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) "");
598             gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1,
599                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
600                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
601                                XPAD, YPAD );
602             spat->entries[i] = w;
603             g_signal_connect ( G_OBJECT (w), "changed",
604                                G_CALLBACK (sp_attribute_table_entry_changed),
605                                spat );
606         }
607         /* Show table */
608         gtk_widget_show (spat->table);
610         spat->blocked = FALSE;
611     }
613     gtk_widget_set_sensitive ( GTK_WIDGET (spat),
614                                (spat->src.object != NULL) );
616 } // end of sp_attribute_table_set_object()
620 void
621 sp_attribute_table_set_repr ( SPAttributeTable *spat,
622                               Inkscape::XML::Node *repr,
623                               gint num_attr,
624                               const gchar **labels,
625                               const gchar **attributes )
627     g_return_if_fail (spat != NULL);
628     g_return_if_fail (SP_IS_ATTRIBUTE_TABLE (spat));
629     g_return_if_fail (!num_attr || (labels && attributes));
631     if (spat->table) {
632         gtk_widget_destroy (spat->table);
633         spat->table = NULL;
634     }
636     if (spat->attributes) {
637         gint i;
638         for (i = 0; i < spat->num_attr; i++) {
639             g_free (spat->attributes[i]);
640         }
641         g_free (spat->attributes);
642         spat->attributes = NULL;
643     }
645     if (spat->entries) {
646         g_free (spat->entries);
647         spat->entries = NULL;
648     }
650     if (spat->hasobj) {
651         if (spat->src.object) {
652             spat->modified_connection.disconnect();
653             spat->release_connection.disconnect();
654             spat->src.object = NULL;
655         }
656     } else {
657         if (spat->src.repr) {
658             spat->src.repr = Inkscape::GC::release(spat->src.repr);
659         }
660     }
662     spat->hasobj = FALSE;
664     if (repr) {
665         gint i;
667         spat->blocked = TRUE;
669         /* Set up repr */
670         spat->src.repr = Inkscape::GC::anchor(repr);
671         spat->num_attr = num_attr;
672         /* Create table */
673         spat->table = gtk_table_new (num_attr, 2, FALSE);
674         gtk_container_add (GTK_CONTAINER (spat), spat->table);
675         /* Arrays */
676         spat->attributes = g_new0 (gchar *, num_attr);
677         spat->entries = g_new0 (GtkWidget *, num_attr);
679         /* Fill rows */
680         for (i = 0; i < num_attr; i++) {
681             GtkWidget *w;
682             const gchar *val;
684             spat->attributes[i] = g_strdup (attributes[i]);
685             w = gtk_label_new (labels[i]);
686             gtk_widget_show (w);
687             gtk_misc_set_alignment (GTK_MISC (w), 1.0, 0.5);
688             gtk_table_attach ( GTK_TABLE (spat->table), w, 0, 1, i, i + 1,
689                                GTK_FILL,
690                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
691                                XPAD, YPAD );
692             w = gtk_entry_new ();
693             gtk_widget_show (w);
694             val = repr->attribute(attributes[i]);
695             gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) "");
696             gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1,
697                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
698                                (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
699                                XPAD, YPAD );
700             spat->entries[i] = w;
701             g_signal_connect ( G_OBJECT (w), "changed",
702                                G_CALLBACK (sp_attribute_table_entry_changed),
703                                spat );
704         }
705         /* Show table */
706         gtk_widget_show (spat->table);
708         spat->blocked = FALSE;
709     }
711     gtk_widget_set_sensitive (GTK_WIDGET (spat), (spat->src.repr != NULL));
713 } // end of sp_attribute_table_set_repr()
717 static void
718 sp_attribute_table_object_modified ( SPObject */*object*/,
719                                      guint flags,
720                                      SPAttributeTable *spat )
722     if (flags && SP_OBJECT_MODIFIED_FLAG)
723     {
724         gint i;
725         for (i = 0; i < spat->num_attr; i++) {
726             const gchar *val, *text;
727             val = SP_OBJECT_REPR (spat->src.object)->attribute(spat->attributes[i]);
728             text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i]));
729             if (val || text) {
730                 if (!val || !text || strcmp (val, text)) {
731                     /* We are different */
732                     spat->blocked = TRUE;
733                     gtk_entry_set_text ( GTK_ENTRY (spat->entries[i]),
734                                          val ? val : (const gchar *) "");
735                     spat->blocked = FALSE;
736                 }
737             }
738         }
739     } // end of if()
741 } // end of sp_attribute_table_object_modified()
745 static void
746 sp_attribute_table_object_release (SPObject */*object*/, SPAttributeTable *spat)
748     sp_attribute_table_set_object (spat, NULL, 0, NULL, NULL);
753 static void
754 sp_attribute_table_entry_changed ( GtkEditable *editable,
755                                    SPAttributeTable *spat )
757     if (!spat->blocked)
758     {
759         gint i;
760         for (i = 0; i < spat->num_attr; i++) {
762             if (GTK_WIDGET (editable) == spat->entries[i]) {
763                 const gchar *text;
764                 spat->blocked = TRUE;
765                 text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i]));
767                 if (!*text)
768                     text = NULL;
770                 if (spat->hasobj && spat->src.object) {
771                     SP_OBJECT_REPR (spat->src.object)->setAttribute(spat->attributes[i], text, false);
772                     sp_document_done (SP_OBJECT_DOCUMENT (spat->src.object), SP_VERB_NONE,
773                                       _("Set attribute"));
775                 } else if (spat->src.repr) {
777                     spat->src.repr->setAttribute(spat->attributes[i], text, false);
778                     /* TODO: Warning! Undo will not be flushed in given case */
779                 }
780                 spat->blocked = FALSE;
781                 return;
782             }
783         }
784         g_warning ("file %s: line %d: Entry signalled change, but there is no such entry", __FILE__, __LINE__);
785     } // end of if()
787 } // end of sp_attribute_table_entry_changed()
789 /*
790   Local Variables:
791   mode:c++
792   c-file-style:"stroustrup"
793   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
794   indent-tabs-mode:nil
795   fill-column:99
796   End:
797 */
798 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :