# HG changeset patch # User Mathieu Lacage # Date 1210723372 25200 # Node ID a1c532e3bf18c2da03e8b9db3582b161c51b14fc # Parent 81949bbc63499151bc9791b181fbe70343be10bd a basic but useful Gtk+-based config-store diff -r 81949bbc6349 -r a1c532e3bf18 src/contrib/attribute-iterator.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/attribute-iterator.cc Tue May 13 17:02:52 2008 -0700 @@ -0,0 +1,197 @@ +#include "attribute-iterator.h" +#include "ns3/config.h" +#include "ns3/log.h" +#include "ns3/pointer.h" +#include "ns3/object-vector.h" +#include "ns3/string.h" +#include + + +NS_LOG_COMPONENT_DEFINE ("AttributeIterator"); + +namespace ns3 { + + +AttributeIterator::AttributeIterator () +{} + +AttributeIterator::~AttributeIterator () +{} + +void +AttributeIterator::Iterate (void) +{ + for (uint32_t i = 0; i < Config::GetRootNamespaceObjectN (); ++i) + { + Ptr object = Config::GetRootNamespaceObject (i); + DoIterate (object); + } + NS_ASSERT (m_currentPath.empty ()); + NS_ASSERT (m_examined.empty ()); +} + +bool +AttributeIterator::IsExamined (Ptr object) +{ + for (uint32_t i = 0; i < m_examined.size (); ++i) + { + if (object == m_examined[i]) + { + return true; + } + } + return false; +} + + +std::string +AttributeIterator::GetCurrentPath (std::string attr) const +{ + std::ostringstream oss; + for (uint32_t i = 0; i < m_currentPath.size (); ++i) + { + oss << "/" << m_currentPath[i]; + } + if (attr != "") + { + oss << "/" << attr; + } + return oss.str (); +} + +void +AttributeIterator::Push (std::string name) +{ + m_currentPath.push_back (name); + DoPush (name, GetCurrentPath ("")); +} +void +AttributeIterator::Pop (void) +{ + DoPop (); + m_currentPath.pop_back (); +} +void +AttributeIterator::Visit (Ptr object, std::string name) +{ + DoVisit (object, name, GetCurrentPath (name)); +} + + +void +AttributeIterator::DoIterate (Ptr object) +{ + if (IsExamined (object)) + { + return; + } + TypeId tid = object->GetInstanceTypeId (); + Push ("$" + tid.GetName ()); + NS_LOG_DEBUG ("store " << tid.GetName ()); + for (uint32_t i = 0; i < tid.GetAttributeN (); ++i) + { + Ptr checker = tid.GetAttributeChecker (i); + const PointerChecker *ptrChecker = dynamic_cast (PeekPointer (checker)); + if (ptrChecker != 0) + { + NS_LOG_DEBUG ("pointer attribute " << tid.GetAttributeName (i)); + PointerValue ptr; + object->GetAttribute (tid.GetAttributeName (i), ptr); + Ptr tmp = ptr.Get (); + if (tmp != 0) + { + Push (tid.GetAttributeName (i)); + m_examined.push_back (object); + DoIterate (tmp); + m_examined.pop_back (); + Pop (); + } + continue; + } + // attempt to cast to an object vector. + const ObjectVectorChecker *vectorChecker = dynamic_cast (PeekPointer (checker)); + if (vectorChecker != 0) + { + NS_LOG_DEBUG ("vector attribute " << tid.GetAttributeName (i)); + ObjectVectorValue vector; + object->GetAttribute (tid.GetAttributeName (i), vector); + Push (tid.GetAttributeName (i)); + for (uint32_t j = 0; j < vector.GetN (); ++j) + { + NS_LOG_DEBUG ("vector attribute item " << j); + Ptr tmp = vector.Get (j); + std::ostringstream oss; + oss << j; + Push (oss.str ()); + m_examined.push_back (object); + DoIterate (tmp); + m_examined.pop_back (); + Pop (); + } + Pop (); + continue; + } + uint32_t flags = tid.GetAttributeFlags (i); + Ptr accessor = tid.GetAttributeAccessor (i); + if ((flags & TypeId::ATTR_GET) && accessor->HasGetter () && + (flags & TypeId::ATTR_SET) && accessor->HasSetter ()) + { + Visit (object, tid.GetAttributeName (i)); + } + else + { + NS_LOG_DEBUG ("could not store " << tid.GetAttributeName (i)); + } + } + Object::AggregateIterator iter = object->GetAggregateIterator (); + bool recursiveAggregate = false; + while (iter.HasNext ()) + { + Ptr tmp = iter.Next (); + if (IsExamined (tmp)) + { + recursiveAggregate = true; + } + } + if (!recursiveAggregate) + { + iter = object->GetAggregateIterator (); + while (iter.HasNext ()) + { + Ptr tmp = const_cast (PeekPointer (iter.Next ())); + m_examined.push_back (object); + DoIterate (tmp); + m_examined.pop_back (); + } + } + Pop (); +} + + + +TextFileAttributeIterator::TextFileAttributeIterator (std::ostream &os) + : m_os (os) +{} +void +TextFileAttributeIterator::DoVisit (Ptr object, std::string name, std::string path) +{ + StringValue str; + object->GetAttribute (name, str); + m_os << path << " " << str.Get () << std::endl; +} +void +TextFileAttributeIterator::DoPush (std::string name, std::string path) +{} +void +TextFileAttributeIterator::DoPop (void) +{} + +void +TextFileAttributeIterator::Save (void) +{ + Iterate (); +} + + + +} // namespace ns3 diff -r 81949bbc6349 -r a1c532e3bf18 src/contrib/attribute-iterator.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/attribute-iterator.h Tue May 13 17:02:52 2008 -0700 @@ -0,0 +1,49 @@ +#ifndef ATTRIBUTE_ITERATOR_H +#define ATTRIBUTE_ITERATOR_H + +#include "ns3/ptr.h" +#include "ns3/object.h" +#include + +namespace ns3 { + +class AttributeIterator +{ +public: + AttributeIterator (); + virtual ~AttributeIterator (); + + void Iterate (void); +private: + virtual void DoVisit (Ptr object, std::string name, std::string path) = 0; + virtual void DoPush (std::string name, std::string path) = 0; + virtual void DoPop (void) = 0; + + void DoIterate (Ptr object); + bool IsExamined (Ptr object); + std::string GetCurrentPath (std::string attr) const; + void Push (std::string name); + void Pop (void); + void Visit (Ptr object, std::string name); + + + std::vector > m_examined; + std::vector m_currentPath; +}; + +class TextFileAttributeIterator : public AttributeIterator +{ +public: + TextFileAttributeIterator (std::ostream &os); + void Save (void); +private: + virtual void DoVisit (Ptr object, std::string name, std::string path); + virtual void DoPush (std::string name, std::string path); + virtual void DoPop (void); + std::ostream &m_os; +}; + + +} // namespace ns3 + +#endif /* ATTRIBUTE_ITERATOR_H */ diff -r 81949bbc6349 -r a1c532e3bf18 src/contrib/config-store.cc --- a/src/contrib/config-store.cc Sun May 11 21:43:55 2008 -0700 +++ b/src/contrib/config-store.cc Tue May 13 17:02:52 2008 -0700 @@ -1,9 +1,9 @@ #include "config-store.h" +#include "attribute-iterator.h" #include "ns3/string.h" +#include "ns3/log.h" +#include "ns3/attribute-list.h" #include "ns3/config.h" -#include "ns3/object-vector.h" -#include "ns3/pointer.h" -#include "ns3/log.h" #include #include #include @@ -61,134 +61,15 @@ void ConfigStore::StoreTo (std::string filename) { + std::ofstream os; os.open (filename.c_str (), std::ios::out); - for (uint32_t i = 0; i < Config::GetRootNamespaceObjectN (); ++i) - { - Ptr object = Config::GetRootNamespaceObject (i); - Store (os, object); - } + TextFileAttributeIterator iter = TextFileAttributeIterator (os); + iter.Save (); os.close (); - NS_ASSERT (m_currentPath.empty ()); - NS_ASSERT (m_examined.empty ()); exit (0); } -bool -ConfigStore::IsExamined (Ptr object) -{ - for (uint32_t i = 0; i < m_examined.size (); ++i) - { - if (object == m_examined[i]) - { - return true; - } - } - return false; -} - -std::string -ConfigStore::GetCurrentPath (std::string attr) const -{ - std::ostringstream oss; - for (uint32_t i = 0; i < m_currentPath.size (); ++i) - { - oss << "/" << m_currentPath[i]; - } - oss << "/" << attr; - return oss.str (); -} - -void -ConfigStore::Store (std::ostream &os, Ptr object) -{ - if (IsExamined (object)) - { - return; - } - TypeId tid = object->GetInstanceTypeId (); - m_currentPath.push_back ("$" + tid.GetName ()); - NS_LOG_DEBUG ("store " << tid.GetName ()); - for (uint32_t i = 0; i < tid.GetAttributeN (); ++i) - { - Ptr checker = tid.GetAttributeChecker (i); - const PointerChecker *ptrChecker = dynamic_cast (PeekPointer (checker)); - if (ptrChecker != 0) - { - NS_LOG_DEBUG ("pointer attribute " << tid.GetAttributeName (i)); - PointerValue ptr; - object->GetAttribute (tid.GetAttributeName (i), ptr); - Ptr tmp = ptr.Get (); - if (tmp != 0) - { - m_currentPath.push_back (tid.GetAttributeName (i)); - m_examined.push_back (object); - Store (os, tmp); - m_examined.pop_back (); - m_currentPath.pop_back (); - } - continue; - } - // attempt to cast to an object vector. - const ObjectVectorChecker *vectorChecker = dynamic_cast (PeekPointer (checker)); - if (vectorChecker != 0) - { - NS_LOG_DEBUG ("vector attribute " << tid.GetAttributeName (i)); - ObjectVectorValue vector; - object->GetAttribute (tid.GetAttributeName (i), vector); - for (uint32_t j = 0; j < vector.GetN (); ++j) - { - NS_LOG_DEBUG ("vector attribute item " << j); - Ptr tmp = vector.Get (j); - std::ostringstream oss; - oss << tid.GetAttributeName (i) << "/" << j; - m_currentPath.push_back (oss.str ()); - m_examined.push_back (object); - Store (os, tmp); - m_examined.pop_back (); - m_currentPath.pop_back (); - } - continue; - } - uint32_t flags = tid.GetAttributeFlags (i); - Ptr accessor = tid.GetAttributeAccessor (i); - if ((flags & TypeId::ATTR_GET) && accessor->HasGetter () && - (flags & TypeId::ATTR_SET) && accessor->HasSetter ()) - { - StringValue str; - object->GetAttribute (tid.GetAttributeName (i), str); - os << GetCurrentPath (tid.GetAttributeName (i)) << " " << str.Get () << std::endl; - } - else - { - NS_LOG_DEBUG ("could not store " << tid.GetAttributeName (i)); - } - } - Object::AggregateIterator iter = object->GetAggregateIterator (); - bool recursiveAggregate = false; - while (iter.HasNext ()) - { - Ptr tmp = iter.Next (); - if (IsExamined (tmp)) - { - recursiveAggregate = true; - } - } - if (!recursiveAggregate) - { - iter = object->GetAggregateIterator (); - while (iter.HasNext ()) - { - Ptr tmp = iter.Next (); - m_examined.push_back (object); - Store (os, tmp); - m_examined.pop_back (); - } - } - m_currentPath.pop_back (); -} - - void ConfigStore::Configure (void) { diff -r 81949bbc6349 -r a1c532e3bf18 src/contrib/config-store.h --- a/src/contrib/config-store.h Sun May 11 21:43:55 2008 -0700 +++ b/src/contrib/config-store.h Tue May 13 17:02:52 2008 -0700 @@ -2,8 +2,6 @@ #define CONFIG_STORE_H #include "ns3/object-base.h" -#include "ns3/object.h" -#include namespace ns3 { @@ -29,14 +27,9 @@ private: void LoadFrom (std::string filename); void StoreTo (std::string filename); - void Store (std::ostream &os, Ptr object); - bool IsExamined (Ptr object); - std::string GetCurrentPath (std::string attr) const; std::string m_loadFilename; std::string m_storeFilename; - std::vector > m_examined; - std::vector m_currentPath; }; } // namespace ns3 diff -r 81949bbc6349 -r a1c532e3bf18 src/contrib/gtk-config-store.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/gtk-config-store.cc Tue May 13 17:02:52 2008 -0700 @@ -0,0 +1,267 @@ +#include "gtk-config-store.h" +#include "attribute-iterator.h" +#include "ns3/config.h" +#include "ns3/string.h" +#include +#include + + +namespace ns3 { + +enum { + COL_NAME = 0, + COL_VALUE, + COL_LAST +}; + +struct AttributeNode +{ + std::string name; + std::string path; + Ptr object; +}; + +class ModelCreator : public AttributeIterator +{ +public: + ModelCreator (); + + void Build (GtkTreeStore *treestore); +private: + virtual void DoVisit (Ptr object, std::string name, std::string path); + virtual void DoPush (std::string name, std::string path); + virtual void DoPop (void); + + GtkTreeStore *m_treestore; + std::vector m_iters; +}; + +ModelCreator::ModelCreator () +{} +void +ModelCreator::Build (GtkTreeStore *treestore) +{ + m_treestore = treestore; + m_iters.push_back (NULL); + Iterate (); + NS_ASSERT (m_iters.size () == 1); +} +void +ModelCreator::DoVisit (Ptr object, std::string name, std::string path) +{ + StringValue str; + object->GetAttribute (name, str); + GtkTreeIter *parent = m_iters.back (); + GtkTreeIter current; + gtk_tree_store_append (m_treestore, ¤t, parent); + AttributeNode *node = new AttributeNode (); + node->name = name; + node->path = path + "/" + str.Get (); + node->object = object; + gtk_tree_store_set (m_treestore, ¤t, + COL_NAME, g_strdup (name.c_str ()), + COL_VALUE, node, + -1); +} +void +ModelCreator::DoPush (std::string name, std::string path) +{ + GtkTreeIter *parent = m_iters.back (); + GtkTreeIter *current = g_new (GtkTreeIter, 1); + gtk_tree_store_append (m_treestore, current, parent); + gtk_tree_store_set (m_treestore, current, + COL_NAME, g_strdup (name.c_str ()), + COL_VALUE, NULL, + -1); + m_iters.push_back (current); +} +void +ModelCreator::DoPop (void) +{ + GtkTreeIter *current = m_iters.back (); + g_free (current); + m_iters.pop_back (); +} + +static void +attribute_cell_data_function (GtkTreeViewColumn *col, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + AttributeNode *node = 0; + gtk_tree_model_get (model, iter, COL_VALUE, &node, -1); + if (node != 0) + { + StringValue str; + node->object->GetAttribute (node->name, str); + g_object_set(renderer, "text", str.Get ().c_str (), NULL); + } + else + { + g_object_set(renderer, "text", "", NULL); + } +} + +static void +cell_edited_callback (GtkCellRendererText *cell, + gchar *path_string, + gchar *new_text, + gpointer user_data) +{ + GtkTreeModel *model = GTK_TREE_MODEL (user_data); + GtkTreeIter iter; + gtk_tree_model_get_iter_from_string (model, &iter, path_string); + AttributeNode *node; + gtk_tree_model_get (model, &iter, COL_VALUE, &node, -1); + node->object->SetAttribute (node->name, StringValue (new_text)); +} + + +static GtkWidget * +create_view_and_model (void) +{ + GtkTreeViewColumn *col; + GtkCellRenderer *renderer; + GtkWidget *view; + + GtkTreeStore *model = gtk_tree_store_new (COL_LAST, G_TYPE_STRING, G_TYPE_POINTER); + ModelCreator creator; + creator.Build (model); + + + view = gtk_tree_view_new(); + gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_BOTH); + + col = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(col, "Object Attributes"); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start(col, renderer, TRUE); + gtk_tree_view_column_add_attribute(col, renderer, "text", COL_NAME); + + col = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(col, "Attribute Value"); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); + renderer = gtk_cell_renderer_text_new(); + g_object_set(renderer, "editable", TRUE, NULL); + g_signal_connect(renderer, "edited", (GCallback) cell_edited_callback, model); + gtk_tree_view_column_pack_start(col, renderer, TRUE); + gtk_tree_view_column_set_cell_data_func(col, renderer, attribute_cell_data_function, NULL, NULL); + + + gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL (model)); + + g_object_unref(model); /* destroy model automatically with view */ + + + return view; +} + +static void +save_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *parent_window = GTK_WIDGET (user_data); + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new ("Save File", + GTK_WINDOW (parent_window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); + + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "config.txt"); + + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + char *filename; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + std::ofstream os; + os.open (filename); + TextFileAttributeIterator file = TextFileAttributeIterator (os); + file.Save (); + os.close (); + g_free (filename); + } + + gtk_widget_destroy (dialog); +} + +static void +load_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *parent_window = GTK_WIDGET (user_data); + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new ("Open File", + GTK_WINDOW (parent_window), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + char *filename; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + std::ifstream is; + is.open (filename, std::ios::in); + std::string path, value; + while (is.good()) + { + is >> path >> value; + Config::Set (path, StringValue (value)); + } + g_free (filename); + } + + gtk_widget_destroy (dialog); +} + +GtkConfigStore::GtkConfigStore () +{} + +void +GtkConfigStore::Configure (void) +{ + GtkWidget *window; + GtkWidget *view; + + gtk_init (0, 0); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "delete_event", gtk_main_quit, NULL); /* dirty */ + + view = create_view_and_model (); + + GtkWidget *vbox = gtk_vbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (vbox), view, TRUE, TRUE, 0); + gtk_box_pack_end (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, FALSE, 0); + GtkWidget *hbox = gtk_hbox_new (FALSE, 5); + gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + GtkWidget *save = gtk_button_new_with_label ("Save"); + g_signal_connect (save, "clicked", (GCallback) save_clicked, window); + gtk_box_pack_end (GTK_BOX (hbox), save, FALSE, FALSE, 0); + GtkWidget *load = gtk_button_new_with_label ("Load"); + g_signal_connect (load, "clicked", (GCallback) load_clicked, window); + gtk_box_pack_end (GTK_BOX (hbox), load, FALSE, FALSE, 0); + GtkWidget *exit = gtk_button_new_with_label ("Exit"); + g_signal_connect (exit, "clicked", (GCallback) gtk_main_quit, NULL); + gtk_box_pack_end (GTK_BOX (hbox), exit, FALSE, FALSE, 0); + + gtk_container_add (GTK_CONTAINER (window), vbox); + + gtk_widget_show_all (window); + + gtk_main (); +} + +} // namespace ns3 diff -r 81949bbc6349 -r a1c532e3bf18 src/contrib/gtk-config-store.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/gtk-config-store.h Tue May 13 17:02:52 2008 -0700 @@ -0,0 +1,17 @@ +#ifndef GTK_CONFIG_STORE_H +#define GTK_CONFIG_STORE_H + +namespace ns3 { + +class GtkConfigStore +{ +public: + GtkConfigStore (); + + void Configure (void); +}; + + +} // namespace ns3 + +#endif /* GTK_CONFIG_STORE_H */ diff -r 81949bbc6349 -r a1c532e3bf18 src/contrib/wscript --- a/src/contrib/wscript Sun May 11 21:43:55 2008 -0700 +++ b/src/contrib/wscript Tue May 13 17:02:52 2008 -0700 @@ -1,11 +1,20 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +def configure(conf): + check = conf.create_pkgconfig_configurator() + check.name = 'gtk+-2.0' + check.uselib = 'GTK_CONFIG_STORE' + check.mandatory = False + conf.env['ENABLE_GTK_CONFIG_STORE'] = check.run() + + def build(bld): module = bld.create_ns3_module('contrib', ['simulator']) module.source = [ 'event-garbage-collector.cc', 'gnuplot.cc', 'delay-jitter-estimation.cc', + 'attribute-iterator.cc', 'config-store.cc', ] @@ -17,3 +26,8 @@ 'delay-jitter-estimation.h', 'config-store.h', ] + + if bld.env()['ENABLE_GTK_CONFIG_STORE']: + headers.source.append ('gtk-config-store.h') + module.source.append ('gtk-config-store.cc') + module.uselib = 'GTK_CONFIG_STORE' diff -r 81949bbc6349 -r a1c532e3bf18 src/wscript --- a/src/wscript Sun May 11 21:43:55 2008 -0700 +++ b/src/wscript Tue May 13 17:02:52 2008 -0700 @@ -47,6 +47,7 @@ def configure(conf): conf.sub_config('core') conf.sub_config('simulator') + conf.sub_config('contrib') blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant())) conf.env['NS3_MODULE_PATH'] = [blddir] diff -r 81949bbc6349 -r a1c532e3bf18 wscript --- a/wscript Sun May 11 21:43:55 2008 -0700 +++ b/wscript Tue May 13 17:02:52 2008 -0700 @@ -305,6 +305,7 @@ lib.add_objects = list(modules) else: lib.add_objects = list(env['NS3_MODULES']) + lib.uselib_local = list(env['NS3_MODULES']) def get_command_template():