diff -r 80cd9b67a1bd src/contrib/attribute-default-iterator.cc --- a/src/contrib/attribute-default-iterator.cc Mon Feb 15 14:58:45 2010 +0000 +++ b/src/contrib/attribute-default-iterator.cc Tue Feb 16 15:41:15 2010 +0100 @@ -1,15 +1,35 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Faker Moatamri + * Mathieu Lacage + */ + #include "attribute-default-iterator.h" -#include "ns3/type-id.h" #include "ns3/attribute.h" #include "ns3/object-vector.h" #include "ns3/pointer.h" #include "ns3/global-value.h" #include "ns3/string.h" -namespace ns3 { +namespace ns3 +{ AttributeDefaultIterator::~AttributeDefaultIterator () -{} +{ +} void AttributeDefaultIterator::Iterate (void) { @@ -17,72 +37,87 @@ { TypeId tid = TypeId::GetRegistered (i); if (tid.MustHideFromDocumentation ()) - { - continue; - } + { + continue; + } bool calledStart = false; for (uint32_t j = 0; j < tid.GetAttributeN (); j++) - { - uint32_t flags = tid.GetAttributeFlags (j); - if (!(flags & TypeId::ATTR_CONSTRUCT)) - { - // we can't construct the attribute, so, there is no - // initial value for the attribute - continue; - } - Ptr accessor = tid.GetAttributeAccessor (j); - if (accessor == 0) - { - continue; - } - if (!accessor->HasSetter ()) - { - continue; - } - Ptr checker = tid.GetAttributeChecker (j); - if (checker == 0) - { - continue; - } - Ptr value = tid.GetAttributeInitialValue (j); - if (value == 0) - { - continue; - } - Ptr vector = DynamicCast (value); - if (vector != 0) - { - continue; - } - Ptr pointer = DynamicCast (value); - if (pointer != 0) - { - continue; - } - if (!calledStart) - { - StartVisitTypeId (tid.GetName ()); - } - VisitAttribute (tid.GetAttributeName (j), - value->SerializeToString (checker)); - calledStart = true; - } + { + uint32_t flags = tid.GetAttributeFlags (j); + if (!(flags & TypeId::ATTR_CONSTRUCT)) + { + // we can't construct the attribute, so, there is no + // initial value for the attribute + continue; + } + Ptr accessor = tid.GetAttributeAccessor (j); + //No accessor, go to next attribute + if (accessor == 0) + { + continue; + } + if (!accessor->HasSetter ()) + { + //skip this attribute it doesn't have an setter + continue; + } + Ptr checker = tid.GetAttributeChecker (j); + if (checker == 0) + { + //skip, it doesn't have a checker + continue; + } + Ptr value = tid.GetAttributeInitialValue (j); + if (value == 0) + { + //No value, check next attribute + continue; + } + Ptr vector = DynamicCast (value); + if (vector != 0) + { + //a vector value, won't take it + continue; + } + Ptr pointer = DynamicCast (value); + if (pointer != 0) + { + //pointer value, won't take it + continue; + } + //We take only values, no pointers or vectors + if (!calledStart) + { + StartVisitTypeId (tid.GetName ()); + } + VisitAttribute (tid, tid.GetAttributeName (j), value->SerializeToString (checker), j); + calledStart = true; + } if (calledStart) - { - EndVisitTypeId (); - } + { + EndVisitTypeId (); + } } } void AttributeDefaultIterator::StartVisitTypeId (std::string name) -{} +{ +} void AttributeDefaultIterator::EndVisitTypeId (void) -{} +{ +} + void -AttributeDefaultIterator::VisitAttribute (std::string name, std::string defaultValue) -{} +AttributeDefaultIterator::DoVisitAttribute (std::string name, std::string defaultValue) +{ +} +void +AttributeDefaultIterator::VisitAttribute (TypeId tid, std::string name, std::string defaultValue, uint32_t index) +{ + DoVisitAttribute (name, defaultValue); +} } // namespace ns3 diff -r 80cd9b67a1bd src/contrib/attribute-default-iterator.h --- a/src/contrib/attribute-default-iterator.h Mon Feb 15 14:58:45 2010 +0000 +++ b/src/contrib/attribute-default-iterator.h Tue Feb 16 15:41:15 2010 +0100 @@ -1,6 +1,26 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Faker Moatamri + * Mathieu Lacage + */ + #ifndef ATTRIBUTE_DEFAULT_ITERATOR_H #define ATTRIBUTE_DEFAULT_ITERATOR_H +#include "ns3/type-id.h" #include namespace ns3 { @@ -9,11 +29,30 @@ { public: virtual ~AttributeDefaultIterator () = 0; + /** + * \brief This function will go through all the TypeIds and get only the attributes which are + * explicit values (not vectors or pointer or arrays) and apply StartVisitTypeId + * and VisitAttribute on the attributes in one TypeId. At the end of each TypeId + * EndVisitTypeId is called. + */ void Iterate (void); private: + /** + * \brief Just an interface that needs to be implemented + */ virtual void StartVisitTypeId (std::string name); + /** + * \brief Just an interface that needs to be implemented + */ virtual void EndVisitTypeId (void); - virtual void VisitAttribute (std::string name, std::string defaultValue); + /** + * \brief This method can be implemented, otherwise, it will call DoVisitAttribute + */ + virtual void VisitAttribute (TypeId tid, std::string name, std::string defaultValue, uint32_t index); + /** + * \brief This method is just an interface and needs to be implemented + */ + virtual void DoVisitAttribute (std::string name, std::string defaultValue); }; } // namespace ns3 diff -r 80cd9b67a1bd src/contrib/attribute-iterator.cc --- a/src/contrib/attribute-iterator.cc Mon Feb 15 14:58:45 2010 +0000 +++ b/src/contrib/attribute-iterator.cc Tue Feb 16 15:41:15 2010 +0100 @@ -1,3 +1,21 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + #include "attribute-iterator.h" #include "ns3/config.h" #include "ns3/log.h" @@ -13,10 +31,12 @@ AttributeIterator::AttributeIterator () -{} +{ +} AttributeIterator::~AttributeIterator () -{} +{ +} void AttributeIterator::Iterate (void) @@ -38,9 +58,9 @@ for (uint32_t i = 0; i < m_examined.size (); ++i) { if (object == m_examined[i]) - { - return true; - } + { + return true; + } } return false; } @@ -74,28 +94,36 @@ void AttributeIterator::DoStartVisitObject (Ptr object) -{} +{ +} void AttributeIterator::DoEndVisitObject (void) -{} +{ +} void AttributeIterator::DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr item) -{} +{ +} void AttributeIterator::DoEndVisitPointerAttribute (void) -{} +{ +} void AttributeIterator::DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector) -{} +{ +} void AttributeIterator::DoEndVisitArrayAttribute (void) -{} +{ +} void AttributeIterator::DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item) -{} +{ +} void AttributeIterator::DoEndVisitArrayItem (void) -{} +{ +} void AttributeIterator::VisitAttribute (Ptr object, std::string name) @@ -174,58 +202,59 @@ { 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) - { - StartVisitPointerAttribute (object, tid.GetAttributeName (i), tmp); - m_examined.push_back (object); - DoIterate (tmp); - m_examined.pop_back (); - EndVisitPointerAttribute (); - } - 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); - StartVisitArrayAttribute (object, 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); - StartVisitArrayItem (vector, j, tmp); - m_examined.push_back (object); - DoIterate (tmp); - m_examined.pop_back (); - EndVisitArrayItem (); - } - EndVisitArrayAttribute (); - 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 ()) - { - VisitAttribute (object, tid.GetAttributeName (i)); - } - else - { - NS_LOG_DEBUG ("could not store " << tid.GetAttributeName (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) + { + StartVisitPointerAttribute (object, tid.GetAttributeName (i), + tmp); + m_examined.push_back (object); + DoIterate (tmp); + m_examined.pop_back (); + EndVisitPointerAttribute (); + } + 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); + StartVisitArrayAttribute (object, 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); + StartVisitArrayItem (vector, j, tmp); + m_examined.push_back (object); + DoIterate (tmp); + m_examined.pop_back (); + EndVisitArrayItem (); + } + EndVisitArrayAttribute (); + 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 ()) + { + VisitAttribute (object, tid.GetAttributeName (i)); + } + else + { + NS_LOG_DEBUG ("could not store " << tid.GetAttributeName (i)); + } + } } Object::AggregateIterator iter = object->GetAggregateIterator (); bool recursiveAggregate = false; @@ -233,22 +262,22 @@ { Ptr tmp = iter.Next (); if (IsExamined (tmp)) - { - recursiveAggregate = true; - } + { + recursiveAggregate = true; + } } if (!recursiveAggregate) { iter = object->GetAggregateIterator (); while (iter.HasNext ()) - { - Ptr tmp = const_cast (PeekPointer (iter.Next ())); - StartVisitObject (tmp); - m_examined.push_back (object); - DoIterate (tmp); - m_examined.pop_back (); - EndVisitObject (); - } + { + Ptr tmp = const_cast (PeekPointer (iter.Next ())); + StartVisitObject (tmp); + m_examined.push_back (object); + DoIterate (tmp); + m_examined.pop_back (); + EndVisitObject (); + } } } diff -r 80cd9b67a1bd src/contrib/attribute-iterator.h --- a/src/contrib/attribute-iterator.h Mon Feb 15 14:58:45 2010 +0000 +++ b/src/contrib/attribute-iterator.h Tue Feb 16 15:41:15 2010 +0100 @@ -1,3 +1,21 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + #ifndef ATTRIBUTE_ITERATOR_H #define ATTRIBUTE_ITERATOR_H diff -r 80cd9b67a1bd src/contrib/display-functions.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/display-functions.cc Tue Feb 16 15:41:15 2010 +0100 @@ -0,0 +1,594 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Faker Moatamri + * Mathieu Lacage + */ +#include "display-functions.h" +#include "raw-text-config.h" +#include "ns3/config.h" +#include "ns3/string.h" +#include "ns3/pointer.h" + +namespace ns3 { +/** + * This function includes the name of the attribute or the editable value + * in the second column + */ +void +cell_data_function_col_1 (GtkTreeViewColumn *col, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) +{ + ModelNode *node; + gtk_tree_model_get (model, iter, COL_NODE, &node, -1); + if (node->type == ModelNode::NODE_ATTRIBUTE) + { + StringValue str; + node->object->GetAttribute (node->name, str); + g_object_set (renderer, "text", str.Get ().c_str (), (char*) 0); + g_object_set (renderer, "editable", TRUE, (char*) 0); + } + else + { + g_object_set (renderer, "text", "", (char*) 0); + g_object_set (renderer, "editable", FALSE, (char*) 0); + } +} +/** + * This function includes the name of the object, pointer, vector or vector item + * in the first column + */ +void +cell_data_function_col_0 (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, + GtkTreeIter *iter, gpointer user_data) +{ + ModelNode *node; + gtk_tree_model_get (model, iter, COL_NODE, &node, -1); + g_object_set (renderer, "editable", FALSE, (char*) 0); + switch (node->type) + { + case ModelNode::NODE_OBJECT: + g_object_set (renderer, "text", node->object->GetInstanceTypeId ().GetName ().c_str (), (char*) 0); + break; + case ModelNode::NODE_POINTER: + g_object_set (renderer, "text", node->name.c_str (), (char*) 0); + break; + case ModelNode::NODE_VECTOR: + g_object_set (renderer, "text", node->name.c_str (), (char*) 0); + break; + case ModelNode::NODE_VECTOR_ITEM: + { + std::stringstream oss; + oss << node->index; + g_object_set (renderer, "text", oss.str ().c_str (), (char*) 0); + } + break; + case ModelNode::NODE_ATTRIBUTE: + g_object_set (renderer, "text", node->name.c_str (), (char*) 0); + break; + } +} + +/** + * This is the callback called when the value of an attribute is changed + */ +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); + ModelNode *node; + gtk_tree_model_get (model, &iter, COL_NODE, &node, -1); + NS_ASSERT (node->type == ModelNode::NODE_ATTRIBUTE); + node->object->SetAttribute (node->name, StringValue (new_text)); +} + +/** + * This function gets the column number 0 or 1 from the mouse + * click + */ +int +get_col_number_from_tree_view_column (GtkTreeViewColumn *col) +{ + GList *cols; + int num; + g_return_val_if_fail (col != 0, -1); + g_return_val_if_fail (col->tree_view != 0, -1); + cols = gtk_tree_view_get_columns (GTK_TREE_VIEW (col->tree_view)); + num = g_list_index (cols, (gpointer) col); + g_list_free (cols); + return num; +} + +/** + * This function displays the tooltip for an object, pointer, vector + * item or an attribute + */ +gboolean +cell_tooltip_callback (GtkWidget *widget, gint x, gint y, gboolean keyboard_tip, + GtkTooltip *tooltip, gpointer user_data) +{ + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreeViewColumn * column; + if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), &x, &y, + keyboard_tip, &model, 0, &iter)) + { + return FALSE; + } + if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), x, y, 0, &column, 0, 0)) + { + return FALSE; + } + int col = get_col_number_from_tree_view_column (column); + + ModelNode *node; + gtk_tree_model_get (model, &iter, COL_NODE, &node, -1); + + switch (node->type) + { + case ModelNode::NODE_OBJECT: + if (col == 0) + { + std::string tip = "This object is of type " + + node->object->GetInstanceTypeId ().GetName (); + gtk_tooltip_set_text (tooltip, tip.c_str ()); + return TRUE; + } + break; + case ModelNode::NODE_POINTER: + if (col == 0) + { + PointerValue ptr; + node->object->GetAttribute (node->name, ptr); + std::string tip = "This object is of type " + + ptr.GetObject ()->GetInstanceTypeId ().GetName (); + gtk_tooltip_set_text (tooltip, tip.c_str ()); + return TRUE; + } + break; + case ModelNode::NODE_VECTOR: + break; + case ModelNode::NODE_VECTOR_ITEM: + if (col == 0) + { + std::string tip = "This object is of type " + + node->object->GetInstanceTypeId ().GetName (); + gtk_tooltip_set_text (tooltip, tip.c_str ()); + return TRUE; + } + break; + case ModelNode::NODE_ATTRIBUTE: + { + uint32_t attrIndex = 0; + TypeId tid; + for (tid = node->object->GetInstanceTypeId (); tid.HasParent (); tid + = tid.GetParent ()) + { + for (uint32_t i = 0; i < tid.GetAttributeN (); ++i) + { + if (tid.GetAttributeName (i) == node->name) + { + attrIndex = i; + goto out; + } + } + } +out: if (col == 0) + { + std::string tip = tid.GetAttributeHelp (attrIndex); + gtk_tooltip_set_text (tooltip, tip.c_str ()); + } + else + { + Ptr checker = tid.GetAttributeChecker ( + attrIndex); + std::string tip; + tip = "This attribute is of type " + checker->GetValueTypeName (); + if (checker->HasUnderlyingTypeInformation ()) + { + tip += " " + checker->GetUnderlyingTypeInformation (); + } + gtk_tooltip_set_text (tooltip, tip.c_str ()); + } + return TRUE; + } + break; + } + return FALSE; +} + +/** + * This is the main view opening the widget, getting tooltips and drawing the + * tree of attributes... + */ +GtkWidget * +create_view (GtkTreeStore *model) +{ + GtkTreeViewColumn *col; + GtkCellRenderer *renderer; + GtkWidget *view; + + view = gtk_tree_view_new (); + g_object_set (view, "has-tooltip", TRUE, (char*) 0); + g_signal_connect (view, "query-tooltip", (GCallback) cell_tooltip_callback, 0); + + gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_BOTH); + gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE); + + 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_set_cell_data_func (col, renderer, cell_data_function_col_0, 0, 0); + g_object_set (renderer, "editable", FALSE, (char*) 0); + + 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_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, cell_data_function_col_1, 0, 0); + + gtk_tree_view_set_model (GTK_TREE_VIEW (view), GTK_TREE_MODEL (model)); + + g_object_unref (model); /* destroy model automatically with view */ + + return view; +} + +/** + * This is the action done when the user presses on the save button. + * It will save the config to a file. + */ +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, (char *) 0); + 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)); + RawTextConfigSave config; + config.SetFilename (filename); + config.Attributes (); + g_free (filename); + } + + gtk_widget_destroy (dialog); +} + +/** + * If the user presses the button load, it will load the config file into memory. + */ +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, (char *) 0); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + char *filename; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + RawTextConfigLoad config; + config.SetFilename (filename); + config.Attributes (); + } + + gtk_widget_destroy (dialog); +} + +/** + * Exit the window when exit button is pressed + */ +void +exit_clicked_callback (GtkButton *button, gpointer user_data) +{ + gtk_main_quit (); + gtk_widget_hide (GTK_WIDGET (user_data)); +} + +/** + * Exit the application + */ +gboolean +delete_event_callback (GtkWidget *widget, GdkEvent *event, gpointer user_data) +{ + gtk_main_quit (); + gtk_widget_hide (GTK_WIDGET (user_data)); + return TRUE; +} + +/** + * Delete the tree model contents + */ +gboolean +clean_model_callback (GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + ModelNode *node; + gtk_tree_model_get (GTK_TREE_MODEL (model), iter, COL_NODE, &node, -1); + delete node; + gtk_tree_store_set (GTK_TREE_STORE (model), iter, COL_NODE, (ModelNode*) 0, + -1); + return FALSE; +} + +/************************** display functions used by default configurator **********************/ +/** + * This function writes data in the second column, this data is going to be editable + * if it is a NODE_ATTRIBUTE + */ +void +cell_data_function_col_1_config_default (GtkTreeViewColumn *col, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, + gpointer user_data) +{ + ModelTypeid *node; + gtk_tree_model_get (model, iter, COL_TYPEID, &node, -1); + if (node->type == ModelTypeid::NODE_ATTRIBUTE) + { + g_object_set (renderer, "text", node->defaultValue.c_str (), (char*) 0); + g_object_set (renderer, "editable", TRUE, (char*) 0); + } + else + { + g_object_set (renderer, "text", "", (char*) 0); + g_object_set (renderer, "editable", FALSE, (char*) 0); + } +} +/** + * This function writes the attribute or typeid name in the column 0 + */ +void +cell_data_function_col_0_config_default (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, + GtkTreeIter *iter, gpointer user_data) +{ + ModelTypeid *node; + gtk_tree_model_get (model, iter, COL_NODE, &node, -1); + g_object_set (renderer, "editable", FALSE, (char*) 0); + switch (node->type) + { + case ModelTypeid::NODE_TYPEID: + g_object_set (renderer, "text", node->tid.GetName ().c_str (), (char*) 0); + break; + case ModelTypeid::NODE_ATTRIBUTE: + g_object_set (renderer, "text", node->name.c_str (), (char*) 0); + break; + } +} + + +/** + * This functions is called whenever there is a change in the value of an attribute + * If the input value is ok, it will be updated in the default value and in the + * gui, otherwise, it won't be updated in both. + */ +void +cell_edited_callback_config_default (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); + ModelTypeid *node; + gtk_tree_model_get (model, &iter, COL_NODE, &node, -1); + NS_ASSERT (node->type == ModelTypeid::NODE_ATTRIBUTE); + if (Config::SetDefaultFailSafe (node->tid.GetAttributeFullName (node->index),StringValue (new_text))) + { + node->defaultValue = new_text; + } +} + +/** + * This function is used to display a tooltip whenever the user puts the mouse + * over a type ID or an attribute. It will give the type and the possible values of + * an attribute value and the type of the object for an attribute object or a + * typeID object + */ +gboolean +cell_tooltip_callback_config_default (GtkWidget *widget, gint x, gint y, + gboolean keyboard_tip, GtkTooltip *tooltip, gpointer user_data) +{ + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreeViewColumn * column; + if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), &x, &y, + keyboard_tip, &model, 0, &iter)) + { + return FALSE; + } + if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), x, y, 0, &column, 0, 0)) + { + return FALSE; + } + int col = get_col_number_from_tree_view_column (column); + + ModelTypeid *node; + gtk_tree_model_get (model, &iter, COL_NODE, &node, -1); + + switch (node->type) + { + case ModelTypeid::NODE_TYPEID: + if (col == 0) + { + std::string tip = "This object is of type " + node->tid.GetName (); + gtk_tooltip_set_text (tooltip, tip.c_str ()); + return TRUE; + } + break; + case ModelTypeid::NODE_ATTRIBUTE: + { + uint32_t attrIndex = node->index; + if (col == 0) + { + std::string tip = node->tid.GetAttributeHelp (attrIndex); + gtk_tooltip_set_text (tooltip, tip.c_str ()); + } + else + { + Ptr checker = node->tid.GetAttributeChecker (attrIndex); + std::string tip; + tip = "This attribute is of type " + checker->GetValueTypeName (); + if (checker->HasUnderlyingTypeInformation ()) + { + tip += " " + checker->GetUnderlyingTypeInformation (); + } + gtk_tooltip_set_text (tooltip, tip.c_str ()); + } + return TRUE; + } + break; + } + return FALSE; +} + +/** + * This is the action done when the user presses on the save button. + * It will save the config to a file. + */ +void +save_clicked_default (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, (char *) 0); + 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)); + RawTextConfigSave config; + config.SetFilename (filename); + config.Default (); + g_free (filename); + } + + gtk_widget_destroy (dialog); +} + +/** + * If the user presses the button load, it will load the config file into memory. + */ +void +load_clicked_default (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, (char *) 0); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + char *filename; + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + RawTextConfigLoad config; + config.SetFilename (filename); + config.Default (); + } + + gtk_widget_destroy (dialog); +} + +/** + * This is the main view opening the widget, getting tooltips and drawing the + * tree of attributes + */ +GtkWidget * +create_view_config_default (GtkTreeStore *model) +{ + GtkTreeViewColumn *col; + GtkCellRenderer *renderer; + GtkWidget *view; + + view = gtk_tree_view_new (); + g_object_set (view, "has-tooltip", TRUE, (char*) 0); + g_signal_connect (view, "query-tooltip", (GCallback) cell_tooltip_callback_config_default, 0); + + gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_BOTH); + gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE); + + 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_set_cell_data_func (col, renderer, cell_data_function_col_0_config_default, 0, 0); + g_object_set (renderer, "editable", FALSE, (char*) 0); + + 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_signal_connect (renderer, "edited", (GCallback) cell_edited_callback_config_default, model); + gtk_tree_view_column_pack_start (col, renderer, TRUE); + gtk_tree_view_column_set_cell_data_func (col, renderer, cell_data_function_col_1_config_default, 0, 0); + + gtk_tree_view_set_model (GTK_TREE_VIEW (view), GTK_TREE_MODEL (model)); + + g_object_unref (model); /* destroy model automatically with view */ + + return view; +} + +/** + * Delete the tree model contents + */ +gboolean +clean_model_callback_config_default (GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + ModelTypeid *node; + gtk_tree_model_get (GTK_TREE_MODEL (model), iter, COL_TYPEID, &node, -1); + delete node; + gtk_tree_store_set (GTK_TREE_STORE (model), iter, COL_TYPEID, (ModelTypeid*) 0, -1); + return FALSE; +} + + +}//end ns3 namespace + diff -r 80cd9b67a1bd src/contrib/display-functions.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/display-functions.h Tue Feb 16 15:41:15 2010 +0100 @@ -0,0 +1,150 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Faker Moatamri + * Mathieu Lacage + */ +#ifndef DISPLAY_FUNCTIONS_H +#define DISPLAY_FUNCTIONS_H + +#include "model-node-creator.h" +#include "model-typeid-creator.h" +#include + +namespace ns3 { +/** + * This function includes the name of the attribute or the editable value + * in the second column + */ +void +cell_data_function_col_1 (GtkTreeViewColumn *col, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data); +/** + * This function includes the name of the object, pointer, vector or vector item + * in the first column + */ +void +cell_data_function_col_0 (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, + GtkTreeIter *iter, gpointer user_data); +/** + * This is the callback called when the value of an attribute is changed + */ +void +cell_edited_callback (GtkCellRendererText *cell, gchar *path_string, + gchar *new_text, gpointer user_data); +/** + * This function gets the column number 0 or 1 from the mouse + * click + */ +int +get_col_number_from_tree_view_column (GtkTreeViewColumn *col); +/** + * This function displays the tooltip for an object, pointer, vector + * item or an attribute + */ +gboolean +cell_tooltip_callback (GtkWidget *widget, gint x, gint y, gboolean keyboard_tip, + GtkTooltip *tooltip, gpointer user_data); +/** + * This is the main view opening the widget, getting tooltips and drawing the + * tree of attributes... + */ +GtkWidget * +create_view (GtkTreeStore *model); +/** + * This is the action done when the user presses on the save button. + * It will save the config to a file. + */ +void +save_clicked (GtkButton *button, gpointer user_data); +/** + * If the user presses the button load, it will load the config file into memory. + */ +void +load_clicked (GtkButton *button, gpointer user_data); +/** + * Exit the window when exit button is pressed + */ +void +exit_clicked_callback (GtkButton *button, gpointer user_data); +/** + * Exit the application + */ +gboolean +delete_event_callback (GtkWidget *widget, GdkEvent *event, gpointer user_data); +/** + * Delete the tree model contents + */ +gboolean +clean_model_callback (GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data); +/************************** display functions used by default configurator **********************/ +/** + * This function writes data in the second column, this data is going to be editable + * if it is a NODE_ATTRIBUTE + */ +void +cell_data_function_col_1_config_default (GtkTreeViewColumn *col, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, + gpointer user_data); +/** + * This function writes the attribute or typeid name in the column 0 + */ +void +cell_data_function_col_0_config_default (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, + GtkTreeIter *iter, gpointer user_data); +/** + * This is the action done when the user presses on the save button. + * It will save the config to a file. + */ +void +save_clicked_default (GtkButton *button, gpointer user_data); +/** + * If the user presses the button load, it will load the config file into memory. + */ +void +load_clicked_default (GtkButton *button, gpointer user_data); +/** + * This functions is called whenever there is a change in the value of an attribute + * If the input value is ok, it will be updated in the default value and in the + * gui, otherwise, it won't be updated in both. + */ +void +cell_edited_callback_config_default (GtkCellRendererText *cell, gchar *path_string, + gchar *new_text, gpointer user_data); +/** + * This function is used to display a tooltip whenever the user puts the mouse + * over a type ID or an attribute. It will give the type and the possible values of + * an attribute value and the type of the object for an attribute object or a + * typeID object + */ +gboolean +cell_tooltip_callback_config_default (GtkWidget *widget, gint x, gint y, + gboolean keyboard_tip, GtkTooltip *tooltip, gpointer user_data); +/** + * This is the main view opening the widget, getting tooltips and drawing the + * tree of attributes + */ +GtkWidget * +create_view_config_default (GtkTreeStore *model); +/** + * Delete the tree model contents + */ +gboolean +clean_model_callback_config_default (GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data); +}//end namespace ns3 + +#endif \ No newline at end of file diff -r 80cd9b67a1bd src/contrib/gtk-config-store.cc --- a/src/contrib/gtk-config-store.cc Mon Feb 15 14:58:45 2010 +0000 +++ b/src/contrib/gtk-config-store.cc Tue Feb 16 15:41:15 2010 +0100 @@ -1,11 +1,26 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Faker Moatamri + * Mathieu Lacage + */ + #include "gtk-config-store.h" -#include "attribute-iterator.h" #include "raw-text-config.h" -#include "ns3/config.h" -#include "ns3/string.h" -#include "ns3/pointer.h" +#include "display-functions.h" #include "ns3/log.h" -#include #include @@ -13,474 +28,61 @@ NS_LOG_COMPONENT_DEFINE ("GtkconfigStore"); -enum { - COL_NODE = 0, - COL_LAST -}; -struct ModelNode +GtkConfigStore::GtkConfigStore () { - enum { - // store object + attribute name - NODE_ATTRIBUTE, - // store object + attribute name - NODE_POINTER, - // store object + attribute name - NODE_VECTOR, - // store index + value (object) - NODE_VECTOR_ITEM, - // store object - NODE_OBJECT - } type; - std::string name; - Ptr object; - uint32_t index; -}; - -class ModelCreator : public AttributeIterator -{ -public: - ModelCreator (); - - void Build (GtkTreeStore *treestore); -private: - virtual void DoVisitAttribute (Ptr object, std::string name); - virtual void DoStartVisitObject (Ptr object); - virtual void DoEndVisitObject (void); - virtual void DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr value); - virtual void DoEndVisitPointerAttribute (void); - virtual void DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector); - virtual void DoEndVisitArrayAttribute (void); - virtual void DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item); - virtual void DoEndVisitArrayItem (void); - void Add (ModelNode *node); - void Remove (void); - - GtkTreeStore *m_treestore; - std::vector m_iters; -}; - -ModelCreator::ModelCreator () -{} -void -ModelCreator::Build (GtkTreeStore *treestore) -{ - m_treestore = treestore; - m_iters.push_back (0); - Iterate (); - NS_ASSERT (m_iters.size () == 1); } +void +GtkConfigStore::ConfigureDefaults (void) +{ + //this function should be called before running the script to enable the user + //to configure the default values for the objects he wants to use + GtkWidget *window; + GtkWidget *view; + GtkWidget *scroll; -void -ModelCreator::Add (ModelNode *node) -{ - 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_NODE, node, - -1); - m_iters.push_back (current); + gtk_init (0, 0); + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "ns-3 Default attributes."); + gtk_window_set_default_size (GTK_WINDOW (window), 600, 600); + + g_signal_connect (window, "delete_event", (GCallback)delete_event_callback, window); + GtkTreeStore *model = gtk_tree_store_new (COL_LAST, G_TYPE_POINTER); + ModelTypeidCreator creator; + creator.Build (model); + + view = create_view_config_default (model); + scroll = gtk_scrolled_window_new (0, 0); + gtk_container_add (GTK_CONTAINER (scroll), view); + + GtkWidget *vbox = gtk_vbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (vbox), scroll, 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_default, 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_default, window); + gtk_box_pack_end (GTK_BOX (hbox), load, FALSE, FALSE, 0); + GtkWidget *exit = gtk_button_new_with_label ("Run Simulation"); + g_signal_connect (exit, "clicked", (GCallback) exit_clicked_callback, window); + 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 (); + + gtk_tree_model_foreach (GTK_TREE_MODEL (model), + clean_model_callback_config_default, + 0); + + gtk_widget_destroy (window); } -void -ModelCreator::Remove (void) -{ - GtkTreeIter *iter = m_iters.back (); - g_free (iter); - m_iters.pop_back (); -} - -void -ModelCreator::DoVisitAttribute (Ptr object, std::string name) -{ - ModelNode *node = new ModelNode (); - node->type = ModelNode::NODE_ATTRIBUTE; - node->object = object; - node->name = name; - Add (node); - Remove (); -} -void -ModelCreator::DoStartVisitObject (Ptr object) -{ - ModelNode *node = new ModelNode (); - node->type = ModelNode::NODE_OBJECT; - node->object = object; - Add (node); -} -void -ModelCreator::DoEndVisitObject (void) -{ - Remove (); -} -void -ModelCreator::DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr value) -{ - ModelNode *node = new ModelNode (); - node->type = ModelNode::NODE_POINTER; - node->object = object; - node->name = name; - Add (node); -} -void -ModelCreator::DoEndVisitPointerAttribute (void) -{ - Remove (); -} -void -ModelCreator::DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector) -{ - ModelNode *node = new ModelNode (); - node->type = ModelNode::NODE_VECTOR; - node->object = object; - node->name = name; - Add (node); -} -void -ModelCreator::DoEndVisitArrayAttribute (void) -{ - Remove (); -} -void -ModelCreator::DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item) -{ - GtkTreeIter *parent = m_iters.back (); - GtkTreeIter *current = g_new (GtkTreeIter, 1); - ModelNode *node = new ModelNode (); - node->type = ModelNode::NODE_VECTOR_ITEM; - node->object = item; - node->index = index; - gtk_tree_store_append (m_treestore, current, parent); - gtk_tree_store_set (m_treestore, current, - COL_NODE, node, - -1); - m_iters.push_back (current); -} -void -ModelCreator::DoEndVisitArrayItem (void) -{ - GtkTreeIter *iter = m_iters.back (); - g_free (iter); - m_iters.pop_back (); -} - -static void -cell_data_function_col_1 (GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer user_data) -{ - ModelNode *node; - gtk_tree_model_get (model, iter, COL_NODE, &node, -1); - if (node->type == ModelNode::NODE_ATTRIBUTE) - { - StringValue str; - node->object->GetAttribute (node->name, str); - g_object_set(renderer, "text", str.Get ().c_str (), (char*)0); - g_object_set(renderer, "editable", TRUE, (char*)0); - } - else - { - g_object_set(renderer, "text", "", (char*)0); - g_object_set(renderer, "editable", FALSE, (char*)0); - } -} - -static void -cell_data_function_col_0 (GtkTreeViewColumn *col, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer user_data) -{ - ModelNode *node; - gtk_tree_model_get (model, iter, COL_NODE, &node, -1); - g_object_set (renderer, "editable", FALSE, (char*)0); - switch (node->type) { - case ModelNode::NODE_OBJECT: - g_object_set(renderer, "text", node->object->GetInstanceTypeId ().GetName ().c_str (), (char*)0); - break; - case ModelNode::NODE_POINTER: - g_object_set(renderer, "text", node->name.c_str (), (char*)0); - break; - case ModelNode::NODE_VECTOR: - g_object_set(renderer, "text", node->name.c_str (), (char*)0); - break; - case ModelNode::NODE_VECTOR_ITEM: { - std::stringstream oss; - oss << node->index; - g_object_set(renderer, "text", oss.str ().c_str (), (char*)0); - } break; - case ModelNode::NODE_ATTRIBUTE: - g_object_set(renderer, "text", node->name.c_str (), (char*)0); - break; - } -} - - -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); - ModelNode *node; - gtk_tree_model_get (model, &iter, COL_NODE, &node, -1); - NS_ASSERT (node->type == ModelNode::NODE_ATTRIBUTE); - node->object->SetAttribute (node->name, StringValue (new_text)); -} - -static int -get_col_number_from_tree_view_column (GtkTreeViewColumn *col) -{ - GList *cols; - int num; - g_return_val_if_fail ( col != 0, -1 ); - g_return_val_if_fail ( col->tree_view != 0, -1 ); - cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view)); - num = g_list_index(cols, (gpointer) col); - g_list_free(cols); - return num; -} - -static gboolean -cell_tooltip_callback (GtkWidget *widget, - gint x, - gint y, - gboolean keyboard_tip, - GtkTooltip *tooltip, - gpointer user_data) -{ - GtkTreeModel *model; - GtkTreeIter iter; - GtkTreeViewColumn * column; - if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), - &x, &y, keyboard_tip, - &model, 0, &iter)) - { - return FALSE; - } - if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), - x, y, 0, &column, 0, 0)) - { - return FALSE; - } - int col = get_col_number_from_tree_view_column (column); - - ModelNode *node; - gtk_tree_model_get (model, &iter, COL_NODE, &node, -1); - - switch (node->type) { - case ModelNode::NODE_OBJECT: - if (col == 0) - { - std::string tip = "This object is of type " + node->object->GetInstanceTypeId ().GetName (); - gtk_tooltip_set_text (tooltip, tip.c_str ()); - return TRUE; - } - break; - case ModelNode::NODE_POINTER: - if (col == 0) - { - PointerValue ptr; - node->object->GetAttribute (node->name, ptr); - std::string tip = "This object is of type " + ptr.GetObject ()->GetInstanceTypeId ().GetName (); - gtk_tooltip_set_text (tooltip, tip.c_str ()); - return TRUE; - } - break; - case ModelNode::NODE_VECTOR: - break; - case ModelNode::NODE_VECTOR_ITEM: - if (col == 0) - { - std::string tip = "This object is of type " + node->object->GetInstanceTypeId ().GetName (); - gtk_tooltip_set_text (tooltip, tip.c_str ()); - return TRUE; - } - break; - case ModelNode::NODE_ATTRIBUTE: { - uint32_t attrIndex = 0; - TypeId tid; - for (tid = node->object->GetInstanceTypeId (); tid.HasParent (); tid = tid.GetParent ()) - { - for (uint32_t i = 0; i < tid.GetAttributeN (); ++i) - { - if (tid.GetAttributeName (i) == node->name) - { - attrIndex = i; - goto out; - } - } - } - out: - if (col == 0) - { - std::string tip = tid.GetAttributeHelp (attrIndex); - gtk_tooltip_set_text (tooltip, tip.c_str ()); - } - else - { - Ptr checker = tid.GetAttributeChecker (attrIndex); - std::string tip; - tip = "This attribute is of type " + checker->GetValueTypeName (); - if (checker->HasUnderlyingTypeInformation ()) - { - tip += " " + checker->GetUnderlyingTypeInformation (); - } - gtk_tooltip_set_text (tooltip, tip.c_str ()); - } - return TRUE; - } break; - } - return FALSE; -} - - -static GtkWidget * -create_view (GtkTreeStore *model) -{ - GtkTreeViewColumn *col; - GtkCellRenderer *renderer; - GtkWidget *view; - - view = gtk_tree_view_new(); - g_object_set (view, "has-tooltip", TRUE, (char*)0); - g_signal_connect (view, "query-tooltip", (GCallback) cell_tooltip_callback, 0); - - gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_BOTH); - gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE); - - 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_set_cell_data_func(col, renderer, cell_data_function_col_0, 0, 0); - g_object_set(renderer, "editable", FALSE, (char*)0); - - 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_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, cell_data_function_col_1, 0, 0); - - - 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, - (char *)0); - 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)); - RawTextConfigSave config; - config.SetFilename (filename); - config.Attributes (); - 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, - (char *)0); - - if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) - { - char *filename; - - filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); - RawTextConfigLoad config; - config.SetFilename (filename); - config.Attributes (); - } - - gtk_widget_destroy (dialog); -} - -static void -exit_clicked_callback (GtkButton *button, - gpointer user_data) -{ - gtk_main_quit (); - gtk_widget_hide (GTK_WIDGET (user_data)); -} - -static gboolean -delete_event_callback (GtkWidget *widget, - GdkEvent *event, - gpointer user_data) -{ - gtk_main_quit (); - gtk_widget_hide (GTK_WIDGET (user_data)); - return TRUE; -} - -static gboolean -clean_model_callback (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data) -{ - ModelNode *node; - gtk_tree_model_get (GTK_TREE_MODEL (model), iter, - COL_NODE, &node, - -1); - delete node; - gtk_tree_store_set (GTK_TREE_STORE (model), iter, - COL_NODE, (ModelNode*)0, - -1); - return FALSE; -} - -GtkConfigStore::GtkConfigStore () -{} - -void -GtkConfigStore::ConfigureDefaults (void) -{} void GtkConfigStore::ConfigureAttributes (void) @@ -494,7 +96,7 @@ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "ns-3 Object attributes."); gtk_window_set_default_size (GTK_WINDOW (window), 600, 600); - + g_signal_connect (window, "delete_event", (GCallback)delete_event_callback, window); @@ -528,8 +130,8 @@ gtk_main (); gtk_tree_model_foreach (GTK_TREE_MODEL (model), - clean_model_callback, - 0); + clean_model_callback, + 0); gtk_widget_destroy (window); } diff -r 80cd9b67a1bd src/contrib/gtk-config-store.h --- a/src/contrib/gtk-config-store.h Mon Feb 15 14:58:45 2010 +0000 +++ b/src/contrib/gtk-config-store.h Tue Feb 16 15:41:15 2010 +0100 @@ -1,3 +1,22 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Faker Moatamri + * Mathieu Lacage + */ + #ifndef GTK_CONFIG_STORE_H #define GTK_CONFIG_STORE_H diff -r 80cd9b67a1bd src/contrib/model-node-creator.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/model-node-creator.cc Tue Feb 16 15:41:15 2010 +0100 @@ -0,0 +1,130 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Faker Moatamri + * Mathieu Lacage + */ + +#include "model-node-creator.h" +namespace ns3 { + +ModelCreator::ModelCreator () +{ +} +void + +ModelCreator::Build (GtkTreeStore *treestore) +{ + m_treestore = treestore; + m_iters.push_back (0); + //this function will go through all the objects and call on them + //DoStartVisitObject, DoIterate and DoEndVisitObject + Iterate (); + NS_ASSERT (m_iters.size () == 1); +} + + +void +ModelCreator::Add (ModelNode *node) +{ + 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_NODE, node, -1); + m_iters.push_back (current); +} +void +ModelCreator::Remove (void) +{ + GtkTreeIter *iter = m_iters.back (); + g_free (iter); + m_iters.pop_back (); +} + +void +ModelCreator::DoVisitAttribute (Ptr object, std::string name) +{ + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_ATTRIBUTE; + node->object = object; + node->name = name; + Add (node); + Remove (); +} +void +ModelCreator::DoStartVisitObject (Ptr object) +{ + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_OBJECT; + node->object = object; + Add (node); +} +void +ModelCreator::DoEndVisitObject (void) +{ + Remove (); +} +void +ModelCreator::DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr value) +{ + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_POINTER; + node->object = object; + node->name = name; + Add (node); +} +void +ModelCreator::DoEndVisitPointerAttribute (void) +{ + Remove (); +} +void +ModelCreator::DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector) +{ + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_VECTOR; + node->object = object; + node->name = name; + Add (node); +} +void +ModelCreator::DoEndVisitArrayAttribute (void) +{ + Remove (); +} +void +ModelCreator::DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr item) +{ + GtkTreeIter *parent = m_iters.back (); + GtkTreeIter *current = g_new (GtkTreeIter, 1); + ModelNode *node = new ModelNode (); + node->type = ModelNode::NODE_VECTOR_ITEM; + node->object = item; + node->index = index; + gtk_tree_store_append (m_treestore, current, parent); + gtk_tree_store_set (m_treestore, current, + COL_NODE, node, + -1); + m_iters.push_back (current); +} +void +ModelCreator::DoEndVisitArrayItem (void) +{ + GtkTreeIter *iter = m_iters.back (); + g_free (iter); + m_iters.pop_back (); +} +}//end namespace ns3 \ No newline at end of file diff -r 80cd9b67a1bd src/contrib/model-node-creator.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/model-node-creator.h Tue Feb 16 15:41:15 2010 +0100 @@ -0,0 +1,73 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Faker Moatamri + * Mathieu Lacage + */ + +#include "attribute-iterator.h" +#include + +namespace ns3 +{ + +enum +{ + COL_NODE = 0, COL_LAST +}; + +struct ModelNode +{ + enum + { + // store object + attribute name + NODE_ATTRIBUTE, + // store object + attribute name + NODE_POINTER, + // store object + attribute name + NODE_VECTOR, + // store index + value (object) + NODE_VECTOR_ITEM, + // store object + NODE_OBJECT + } type; + std::string name; + Ptr object; + uint32_t index; +}; +class ModelCreator : public AttributeIterator +{ +public: + ModelCreator (); + + void Build (GtkTreeStore *treestore); +private: + virtual void DoVisitAttribute (Ptr object, std::string name); + virtual void DoStartVisitObject (Ptr object); + virtual void DoEndVisitObject (void); + virtual void DoStartVisitPointerAttribute (Ptr object, std::string name, Ptr value); + virtual void DoEndVisitPointerAttribute (void); + virtual void DoStartVisitArrayAttribute (Ptr object, std::string name, const ObjectVectorValue &vector); + virtual void DoEndVisitArrayAttribute (void); + virtual void DoStartVisitArrayItem (const ObjectVectorValue &vector, + uint32_t index, Ptr item); + virtual void DoEndVisitArrayItem (void); + void Add (ModelNode *node); + void Remove (void); + + GtkTreeStore *m_treestore; + std::vector m_iters; +}; +} \ No newline at end of file diff -r 80cd9b67a1bd src/contrib/model-typeid-creator.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/model-typeid-creator.cc Tue Feb 16 15:41:15 2010 +0100 @@ -0,0 +1,81 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Faker Moatamri + */ + +#include "model-typeid-creator.h" + +namespace ns3 { + +ModelTypeidCreator::ModelTypeidCreator () +{ +} +void + +ModelTypeidCreator::Build (GtkTreeStore *treestore) +{ + m_treestore = treestore; + m_iters.push_back (0); + Iterate (); + NS_ASSERT (m_iters.size () == 1); +} + +void +ModelTypeidCreator::Add (ModelTypeid *node) +{ + 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_TYPEID, node, -1); + m_iters.push_back (current); +} + +void +ModelTypeidCreator::Remove (void) +{ + GtkTreeIter *iter = m_iters.back (); + g_free (iter); + m_iters.pop_back (); +} + +void +ModelTypeidCreator::VisitAttribute (TypeId tid, std::string name, std::string defaultValue, uint32_t index) +{ + ModelTypeid *node = new ModelTypeid (); + node->type = ModelTypeid::NODE_ATTRIBUTE; + node->tid = tid; + node->name = name; + node->defaultValue = defaultValue; + node->index = index; + Add (node); + Remove (); +} + +void +ModelTypeidCreator::StartVisitTypeId (std::string name) +{ + ModelTypeid *node = new ModelTypeid (); + node->type = ModelTypeid::NODE_TYPEID; + node->tid = TypeId::LookupByName (name); + Add (node); +} + +void +ModelTypeidCreator::EndVisitTypeId (void) +{ + Remove (); +} +}//end namespace ns3 \ No newline at end of file diff -r 80cd9b67a1bd src/contrib/model-typeid-creator.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/contrib/model-typeid-creator.h Tue Feb 16 15:41:15 2010 +0100 @@ -0,0 +1,82 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Moatamri Faker + */ + +#include "attribute-default-iterator.h" +#include "ns3/type-id.h" +#include +#include + +namespace ns3 { + +enum +{ + COL_TYPEID = 0, COL_LASTID +}; + +struct ModelTypeid +{ + enum + { + // store TypeId + attribute name +defaultValue and index + NODE_ATTRIBUTE, + // store TypeId + NODE_TYPEID + } type; + std::string name; + std::string defaultValue; + //The TypeId object and if it is an attribute, it's the TypeId object of the attribute + TypeId tid; + //stores the index of the attribute in list of attributes for a given TypeId + uint32_t index; +}; +class ModelTypeidCreator : public AttributeDefaultIterator +{ +public: + ModelTypeidCreator (); + /** + * \brief This method will iterate on typeIds having default attributes and create a model + * for them, this model will be used by the view. + */ + void Build (GtkTreeStore *treestore); +private: + /** + * \brief This method will add a ModelTypeid to the GtkTreeIterator + */ + virtual void VisitAttribute (TypeId tid, std::string name, std::string defaultValue, uint32_t index); + /** + * \brief Add a node for the new TypeId object + */ + virtual void StartVisitTypeId (std::string name); + /** + * \brief Remove the last gtk tree iterator + */ + virtual void EndVisitTypeId (void); + /** + * \brief Adds a treestore iterator to m_treestore model + */ + void Add (ModelTypeid *node); + /** + * Removes the last GtkTreeIterator from m_iters + */ + void Remove (void); + //this is the TreeStore model corresponding to the view + GtkTreeStore *m_treestore; + //This contains a vector of iterators used to build the TreeStore + std::vector m_iters; +}; +} \ No newline at end of file diff -r 80cd9b67a1bd src/contrib/raw-text-config.cc --- a/src/contrib/raw-text-config.cc Mon Feb 15 14:58:45 2010 +0000 +++ b/src/contrib/raw-text-config.cc Tue Feb 16 15:41:15 2010 +0100 @@ -41,7 +41,7 @@ virtual void StartVisitTypeId (std::string name) { m_typeId = name; } - virtual void VisitAttribute (std::string name, std::string defaultValue) { + virtual void DoVisitAttribute (std::string name, std::string defaultValue) { *m_os << "default " << m_typeId << "::" << name << " \"" << defaultValue << "\"" << std::endl; } std::string m_typeId; diff -r 80cd9b67a1bd src/contrib/wscript --- a/src/contrib/wscript Mon Feb 15 14:58:45 2010 +0000 +++ b/src/contrib/wscript Tue Feb 16 15:41:15 2010 +0100 @@ -29,8 +29,11 @@ 'config-store.cc', 'flow-id-tag.cc', 'attribute-default-iterator.cc', + 'model-node-creator.cc', + 'model-typeid-creator.cc', 'file-config.cc', 'raw-text-config.cc', + 'display-functions.cc', ] headers = bld.new_task_gen('ns3header') diff -r 80cd9b67a1bd src/contrib/xml-config.cc --- a/src/contrib/xml-config.cc Mon Feb 15 14:58:45 2010 +0000 +++ b/src/contrib/xml-config.cc Tue Feb 16 15:41:15 2010 +0100 @@ -90,7 +90,7 @@ virtual void StartVisitTypeId (std::string name) { m_typeid = name; } - virtual void VisitAttribute (std::string name, std::string defaultValue) { + virtual void DoVisitAttribute (std::string name, std::string defaultValue) { int rc; rc = xmlTextWriterStartElement(m_writer, BAD_CAST "default"); if (rc < 0)