config-store: GtkConfig bug fixes

This commit is contained in:
Tommaso Pecorella
2020-12-25 00:19:20 +00:00
parent b6478609ff
commit fda2c4f87d
7 changed files with 271 additions and 150 deletions

View File

@@ -64,6 +64,8 @@ SOURCEFIGS = \
figures/plot-2d.png \
figures/plot-2d-with-error-bars.png \
figures/plot-3d.png \
figures/gtk-config-lena-dual-stripe-device-view.png \
figures/gtk-config-lena-dual-stripe-eNB-tx-power.png \
${SRC}/stats/doc/Stat-framework-arch.png \
${SRC}/stats/doc/Wifi-default.png \
${SRC}/stats/doc/dcf-overview.dia \

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -27,29 +27,29 @@ In the course of this chapter we will discuss the various ways to set or
modify the values used by |ns3| model objects. In increasing order of
specificity, these are:
+---------------------------------------+-------------------------------------+
+-------------------------------------+------------------------------------+
| Method | Scope |
+=======================================+=====================================+
+=====================================+====================================+
| Default Attribute values set when | Affect all instances of the class. |
| Attributes are defined in | |
| :cpp:func:`GetTypeId ()`. | |
+---------------------------------------+-------------------------------------+
| | :cpp:class:`CommandLine` | Affect all future instances. |
| | :cpp:func:`Config::SetDefault()` | |
| | :cpp:class:`ConfigStore` | |
+---------------------------------------+-------------------------------------+
+-------------------------------------+------------------------------------+
| :cpp:class:`CommandLine` | Affect all future instances. |
| :cpp:func:`Config::SetDefault()` | |
| :cpp:class:`ConfigStore` | |
+-------------------------------------+------------------------------------+
| :cpp:class:`ObjectFactory` | Affects all instances created with |
| | the factory. |
+---------------------------------------+-------------------------------------+
+-------------------------------------+------------------------------------+
| Helper methods with (string/ | Affects all instances created by |
| AttributeValue) parameter pairs | the helper. |
+---------------------------------------+-------------------------------------+
| | :cpp:func:`MyClass::SetX ()` | Alters this particular instance. |
| | :cpp:func:`Object::SetAttribute ()` | Generally this is the only form |
| | :cpp:func:`Config::Set()` | which can be scheduled to alter |
+-------------------------------------+------------------------------------+
| :cpp:func:`MyClass::SetX ()` | Alters this particular instance. |
| :cpp:func:`Object::SetAttribute ()` | Generally this is the only form |
| :cpp:func:`Config::Set()` | which can be scheduled to alter |
| | an instance once the simulation |
| | is running. |
+---------------------------------------+-------------------------------------+
+-------------------------------------+------------------------------------+
By "specificity" we mean that methods in later rows in the table
override the values set by, and typically affect fewer instances than,
@@ -1158,20 +1158,61 @@ write out the resulting attributes to a separate file called
Simulator::Run ();
}
ConfigStore use cases (pre- and post-simulation)
++++++++++++++++++++++++++++++++++++++++++++++++
It is worth stressing that ConfigStore can be used for different purposes, and this is
reflected in where in the script ConfigStore is invoked.
The typical use-cases are:
* Change an Object default attributes
* Inspect/change a *specific* Object attributes
* Inspect the simulation Objects and their attributes
As a matter of fact, some Objects might be created when the simulation starts.
Hence, ConfigStore will not "report" their attributes if invoked earlier in the code.
A typical workflow might involve running the simulation, calling ConfigStore
at the end of the simulation (after ``Simulator::Run ()`` and before ``Simulator::Destroy ()``)
This will show all the attributes in the Objects, both those with default values, and those
with values changed during the simulation execution.
To change these values, you'll need to either change the default (class-wide) attribute values
(in this case call ConfigStore before the Object creation), or specific object attribute
(in this case call ConfigStore after the Object creation, typically just before ``Simulator::Run ()``.
ConfigStore GUI
+++++++++++++++
There is a GTK-based front end for the ConfigStore. This allows users to use a
GUI to access and change variables. Screenshots of this feature are available
in the `|ns3| Overview <http://www.nsnam.org/docs/ns-3-overview.pdf>`_
presentation.
GUI to access and change variables.
To use this feature, one must install ``libgtk`` and ``libgtk-dev``; an example
Some screenshots are presented here. They are the result of using GtkConfig on
``src/lte/examples/lena-dual-stripe.cc`` after ``Simulator::Run ()``.
.. _GtkConfig:
.. figure:: figures/gtk-config-lena-dual-stripe-device-view.*
.. figure:: figures/gtk-config-lena-dual-stripe-eNB-tx-power.*
To use this feature, one must install ``libgtk-3-dev``; an example
Ubuntu installation command is:
.. sourcecode:: bash
$ sudo apt-get install libgtk2.0-0 libgtk2.0-dev
$ sudo apt-get install libgtk-3-dev
On a MacOS it is possible to install GTK-3 using `Homebrew <https://brew.sh>`_.
The installation command is:
.. sourcecode:: bash
$ brew install gtk+3 adwaita-icon-theme
To check whether it is configured or not, check the output of the step:
@@ -1183,7 +1224,7 @@ To check whether it is configured or not, check the output of the step:
Python Bindings : enabled
Python API Scanning Support : enabled
NS-3 Click Integration : enabled
GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found)
GtkConfigStore : not enabled (library 'gtk+-3.0 >= 3.0' not found)
In the above example, it was not enabled, so it cannot be used until a suitable
version is installed and:
@@ -1206,3 +1247,9 @@ are no :cpp:class:`ConfigStore` attributes involved::
Now, when you run the script, a GUI should pop up, allowing you to open menus of
attributes on different nodes/objects, and then launch the simulation execution
when you are done.
Note that "launch the simulation" means to proceed with the simulation script.
If GtkConfigStore has been called after ``Simulator::Run ()`` the simulation will
not be started again - it will just end.

View File

@@ -16,6 +16,7 @@
* Authors: Faker Moatamri <faker.moatamri@sophia.inria.fr>
* Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "display-functions.h"
#include "raw-text-config.h"
#include "ns3/config.h"
@@ -31,8 +32,12 @@ void
cell_data_function_col_1 (GtkTreeViewColumn *col, GtkCellRenderer *renderer,
GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
{
ModelNode *node;
ModelNode *node = 0;
gtk_tree_model_get (model, iter, COL_NODE, &node, -1);
if (!node)
{
return;
}
if (node->type == ModelNode::NODE_ATTRIBUTE)
{
StringValue str;
@@ -54,9 +59,14 @@ void
cell_data_function_col_0 (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model,
GtkTreeIter *iter, gpointer user_data)
{
ModelNode *node;
ModelNode *node = 0;
gtk_tree_model_get (model, iter, COL_NODE, &node, -1);
g_object_set (renderer, "editable", FALSE, (char*) 0);
if (!node)
{
return;
}
switch (node->type)
{
case ModelNode::NODE_OBJECT:
@@ -91,8 +101,12 @@ cell_edited_callback (GtkCellRendererText *cell, gchar *path_string,
GtkTreeModel *model = GTK_TREE_MODEL (user_data);
GtkTreeIter iter;
gtk_tree_model_get_iter_from_string (model, &iter, path_string);
ModelNode *node;
ModelNode *node = 0;
gtk_tree_model_get (model, &iter, COL_NODE, &node, -1);
if (!node)
{
return;
}
NS_ASSERT (node->type == ModelNode::NODE_ATTRIBUTE);
node->object->SetAttribute (node->name, StringValue (new_text));
}
@@ -136,8 +150,12 @@ cell_tooltip_callback (GtkWidget *widget, gint x, gint y, gboolean keyboard_tip,
}
int col = get_col_number_from_tree_view_column (column);
ModelNode *node;
ModelNode *node = 0;
gtk_tree_model_get (model, &iter, COL_NODE, &node, -1);
if (!node)
{
return FALSE;
}
switch (node->type)
{
@@ -253,67 +271,6 @@ create_view (GtkTreeStore *model)
return view;
}
/**
* This is the action done when the user presses on the save button.
* It will save the config to a file.
*
* \param button (unused)
* \param user_data
*/
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,
"_Cancel", GTK_RESPONSE_CANCEL, "_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,
"_Cancel", GTK_RESPONSE_CANCEL, "_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
*/
@@ -342,9 +299,12 @@ gboolean
clean_model_callback (GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer data)
{
ModelNode *node;
ModelNode *node = 0;
gtk_tree_model_get (GTK_TREE_MODEL (model), iter, COL_NODE, &node, -1);
if (node)
{
delete node;
}
gtk_tree_store_set (GTK_TREE_STORE (model), iter, COL_NODE, (ModelNode*) 0,
-1);
return FALSE;
@@ -360,8 +320,12 @@ cell_data_function_col_1_config_default (GtkTreeViewColumn *col, GtkCellRenderer
GtkTreeModel *model, GtkTreeIter *iter,
gpointer user_data)
{
ModelTypeid *node;
ModelTypeid *node = 0;
gtk_tree_model_get (model, iter, COL_TYPEID, &node, -1);
if (!node)
{
return;
}
if (node->type == ModelTypeid::NODE_ATTRIBUTE)
{
g_object_set (renderer, "text", node->defaultValue.c_str (), (char*) 0);
@@ -380,9 +344,14 @@ void
cell_data_function_col_0_config_default (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model,
GtkTreeIter *iter, gpointer user_data)
{
ModelTypeid *node;
ModelTypeid *node = 0;
gtk_tree_model_get (model, iter, COL_NODE, &node, -1);
g_object_set (renderer, "editable", FALSE, (char*) 0);
if (!node)
{
return;
}
switch (node->type)
{
case ModelTypeid::NODE_TYPEID:
@@ -407,8 +376,12 @@ cell_edited_callback_config_default (GtkCellRendererText *cell, gchar *path_stri
GtkTreeModel *model = GTK_TREE_MODEL (user_data);
GtkTreeIter iter;
gtk_tree_model_get_iter_from_string (model, &iter, path_string);
ModelTypeid *node;
ModelTypeid *node = 0;
gtk_tree_model_get (model, &iter, COL_NODE, &node, -1);
if (!node)
{
return;
}
NS_ASSERT (node->type == ModelTypeid::NODE_ATTRIBUTE);
if (Config::SetDefaultFailSafe (node->tid.GetAttributeFullName (node->index),StringValue (new_text)))
{
@@ -448,8 +421,12 @@ cell_tooltip_callback_config_default (GtkWidget *widget, gint x, gint y,
}
int col = get_col_number_from_tree_view_column (column);
ModelTypeid *node;
ModelTypeid *node = 0;
gtk_tree_model_get (model, &iter, COL_NODE, &node, -1);
if (!node)
{
return FALSE;
}
switch (node->type)
{
@@ -497,29 +474,37 @@ cell_tooltip_callback_config_default (GtkWidget *widget, gint x, gint y,
void
save_clicked_default (GtkButton *button, gpointer user_data)
{
GtkWidget *parent_window = GTK_WIDGET (user_data);
GtkWidget *dialog;
GtkWindow *parent_window = GTK_WINDOW (user_data);
dialog = gtk_file_chooser_dialog_new ("Save File", GTK_WINDOW (parent_window), GTK_FILE_CHOOSER_ACTION_SAVE,
"_Cancel", GTK_RESPONSE_CANCEL, "_Save",
GTK_RESPONSE_ACCEPT, (char *) 0);
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
TRUE);
GtkFileChooserNative *native;
GtkFileChooser *chooser;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
gint res;
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "config.txt");
native = gtk_file_chooser_native_new ("Save File",
parent_window,
action,
"_Save",
"_Cancel");
chooser = GTK_FILE_CHOOSER (native);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
gtk_file_chooser_set_current_name (chooser, ("config-defaults.txt"));
res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
if (res == GTK_RESPONSE_ACCEPT)
{
char *filename;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
filename = gtk_file_chooser_get_filename (chooser);
RawTextConfigSave config;
config.SetFilename (filename);
config.Default ();
g_free (filename);
}
gtk_widget_destroy (dialog);
g_object_unref (native);
}
/**
@@ -531,24 +516,108 @@ save_clicked_default (GtkButton *button, gpointer user_data)
void
load_clicked_default (GtkButton *button, gpointer user_data)
{
GtkWidget *parent_window = GTK_WIDGET (user_data);
GtkWidget *dialog;
GtkWindow *parent_window = GTK_WINDOW (user_data);
GtkFileChooserNative *native;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
gint res;
dialog = gtk_file_chooser_dialog_new ("Open File", GTK_WINDOW (parent_window), GTK_FILE_CHOOSER_ACTION_OPEN,
"_Cancel", GTK_RESPONSE_CANCEL, "_Open",
GTK_RESPONSE_ACCEPT, (char *) 0);
native = gtk_file_chooser_native_new ("Open File",
parent_window,
action,
"_Open",
"_Cancel");
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
if (res == GTK_RESPONSE_ACCEPT)
{
char *filename;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
GtkFileChooser *chooser = GTK_FILE_CHOOSER (native);
filename = gtk_file_chooser_get_filename (chooser);
RawTextConfigLoad config;
config.SetFilename (filename);
config.Default ();
g_free (filename);
}
gtk_widget_destroy (dialog);
g_object_unref (native);
}
/**
* This is the action done when the user presses on the save button.
* It will save the config to a file.
*
* \param button (unused)
* \param user_data
*/
void
save_clicked_attribute (GtkButton *button, gpointer user_data)
{
GtkWindow *parent_window = GTK_WINDOW (user_data);
GtkFileChooserNative *native;
GtkFileChooser *chooser;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
gint res;
native = gtk_file_chooser_native_new ("Save File",
parent_window,
action,
"_Save",
"_Cancel");
chooser = GTK_FILE_CHOOSER (native);
gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
gtk_file_chooser_set_current_name (chooser, ("config-attributes.txt"));
res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
if (res == GTK_RESPONSE_ACCEPT)
{
char *filename;
filename = gtk_file_chooser_get_filename (chooser);
RawTextConfigSave config;
config.SetFilename (filename);
config.Attributes ();
g_free (filename);
}
g_object_unref (native);
}
/**
* If the user presses the button load, it will load the config file into memory.
*
* \param button (unused)
* \param user_data
*/
void
load_clicked_attribute (GtkButton *button, gpointer user_data)
{
GtkWindow *parent_window = GTK_WINDOW (user_data);
GtkFileChooserNative *native;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
gint res;
native = gtk_file_chooser_native_new ("Open File",
parent_window,
action,
"_Open",
"_Cancel");
res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
if (res == GTK_RESPONSE_ACCEPT)
{
char *filename;
GtkFileChooser *chooser = GTK_FILE_CHOOSER (native);
filename = gtk_file_chooser_get_filename (chooser);
RawTextConfigLoad config;
config.SetFilename (filename);
config.Attributes ();
g_free (filename);
}
g_object_unref (native);
}
/**
@@ -599,9 +668,12 @@ gboolean
clean_model_callback_config_default (GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer data)
{
ModelTypeid *node;
ModelTypeid *node = 0;
gtk_tree_model_get (GTK_TREE_MODEL (model), iter, COL_TYPEID, &node, -1);
if (node)
{
delete node;
}
gtk_tree_store_set (GTK_TREE_STORE (model), iter, COL_TYPEID, (ModelTypeid*) 0, -1);
return FALSE;
}

View File

@@ -63,17 +63,6 @@ cell_tooltip_callback (GtkWidget *widget, gint x, gint y, gboolean keyboard_tip,
*/
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
*/
@@ -106,16 +95,27 @@ 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.
* This is the action done when the user presses on the save button for the Default attributes.
* 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.
* If the user presses the button load, it will load the config file into memory for the Default attributes.
*/
void
load_clicked_default (GtkButton *button, gpointer user_data);
/**
* This is the action done when the user presses on the save button for the Attributes.
* It will save the config to a file.
*/
void
save_clicked_attribute (GtkButton *button, gpointer user_data);
/**
* If the user presses the button load, it will load the config file into memory for the Attributes.
*/
void
load_clicked_attribute (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

View File

@@ -113,10 +113,10 @@ GtkConfigStore::ConfigureAttributes (void)
GtkWidget *hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 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);
g_signal_connect (save, "clicked", (GCallback) save_clicked_attribute, 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);
g_signal_connect (load, "clicked", (GCallback) load_clicked_attribute, 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);