00001 #include "gtk-config-store.h"
00002 #include "attribute-iterator.h"
00003 #include "ns3/config.h"
00004 #include "ns3/string.h"
00005 #include "ns3/pointer.h"
00006 #include "ns3/log.h"
00007 #include <gtk/gtk.h>
00008 #include <fstream>
00009
00010
00011 namespace ns3 {
00012
00013 NS_LOG_COMPONENT_DEFINE ("GtkconfigStore");
00014
00015 enum {
00016 COL_NODE = 0,
00017 COL_LAST
00018 };
00019
00020 struct ModelNode
00021 {
00022 enum {
00023
00024 NODE_ATTRIBUTE,
00025
00026 NODE_POINTER,
00027
00028 NODE_VECTOR,
00029
00030 NODE_VECTOR_ITEM,
00031
00032 NODE_OBJECT
00033 } type;
00034 std::string name;
00035 Ptr<Object> object;
00036 uint32_t index;
00037 };
00038
00039 class ModelCreator : public AttributeIterator
00040 {
00041 public:
00042 ModelCreator ();
00043
00044 void Build (GtkTreeStore *treestore);
00045 private:
00046 virtual void DoVisitAttribute (Ptr<Object> object, std::string name);
00047 virtual void DoStartVisitObject (Ptr<Object> object);
00048 virtual void DoEndVisitObject (void);
00049 virtual void DoStartVisitPointerAttribute (Ptr<Object> object, std::string name, Ptr<Object> value);
00050 virtual void DoEndVisitPointerAttribute (void);
00051 virtual void DoStartVisitArrayAttribute (Ptr<Object> object, std::string name, const ObjectVectorValue &vector);
00052 virtual void DoEndVisitArrayAttribute (void);
00053 virtual void DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr<Object> item);
00054 virtual void DoEndVisitArrayItem (void);
00055 void Add (ModelNode *node);
00056 void Remove (void);
00057
00058 GtkTreeStore *m_treestore;
00059 std::vector<GtkTreeIter *> m_iters;
00060 };
00061
00062 ModelCreator::ModelCreator ()
00063 {}
00064 void
00065 ModelCreator::Build (GtkTreeStore *treestore)
00066 {
00067 m_treestore = treestore;
00068 m_iters.push_back (0);
00069 Iterate ();
00070 NS_ASSERT (m_iters.size () == 1);
00071 }
00072
00073
00074 void
00075 ModelCreator::Add (ModelNode *node)
00076 {
00077 GtkTreeIter *parent = m_iters.back ();
00078 GtkTreeIter *current = g_new (GtkTreeIter, 1);
00079 gtk_tree_store_append (m_treestore, current, parent);
00080 gtk_tree_store_set (m_treestore, current,
00081 COL_NODE, node,
00082 -1);
00083 m_iters.push_back (current);
00084 }
00085 void
00086 ModelCreator::Remove (void)
00087 {
00088 GtkTreeIter *iter = m_iters.back ();
00089 g_free (iter);
00090 m_iters.pop_back ();
00091 }
00092
00093 void
00094 ModelCreator::DoVisitAttribute (Ptr<Object> object, std::string name)
00095 {
00096 ModelNode *node = new ModelNode ();
00097 node->type = ModelNode::NODE_ATTRIBUTE;
00098 node->object = object;
00099 node->name = name;
00100 Add (node);
00101 Remove ();
00102 }
00103 void
00104 ModelCreator::DoStartVisitObject (Ptr<Object> object)
00105 {
00106 ModelNode *node = new ModelNode ();
00107 node->type = ModelNode::NODE_OBJECT;
00108 node->object = object;
00109 Add (node);
00110 }
00111 void
00112 ModelCreator::DoEndVisitObject (void)
00113 {
00114 Remove ();
00115 }
00116 void
00117 ModelCreator::DoStartVisitPointerAttribute (Ptr<Object> object, std::string name, Ptr<Object> value)
00118 {
00119 ModelNode *node = new ModelNode ();
00120 node->type = ModelNode::NODE_POINTER;
00121 node->object = object;
00122 node->name = name;
00123 Add (node);
00124 }
00125 void
00126 ModelCreator::DoEndVisitPointerAttribute (void)
00127 {
00128 Remove ();
00129 }
00130 void
00131 ModelCreator::DoStartVisitArrayAttribute (Ptr<Object> object, std::string name, const ObjectVectorValue &vector)
00132 {
00133 ModelNode *node = new ModelNode ();
00134 node->type = ModelNode::NODE_VECTOR;
00135 node->object = object;
00136 node->name = name;
00137 Add (node);
00138 }
00139 void
00140 ModelCreator::DoEndVisitArrayAttribute (void)
00141 {
00142 Remove ();
00143 }
00144 void
00145 ModelCreator::DoStartVisitArrayItem (const ObjectVectorValue &vector, uint32_t index, Ptr<Object> item)
00146 {
00147 GtkTreeIter *parent = m_iters.back ();
00148 GtkTreeIter *current = g_new (GtkTreeIter, 1);
00149 ModelNode *node = new ModelNode ();
00150 node->type = ModelNode::NODE_VECTOR_ITEM;
00151 node->object = item;
00152 node->index = index;
00153 gtk_tree_store_append (m_treestore, current, parent);
00154 gtk_tree_store_set (m_treestore, current,
00155 COL_NODE, node,
00156 -1);
00157 m_iters.push_back (current);
00158 }
00159 void
00160 ModelCreator::DoEndVisitArrayItem (void)
00161 {
00162 GtkTreeIter *iter = m_iters.back ();
00163 g_free (iter);
00164 m_iters.pop_back ();
00165 }
00166
00167 static void
00168 cell_data_function_col_1 (GtkTreeViewColumn *col,
00169 GtkCellRenderer *renderer,
00170 GtkTreeModel *model,
00171 GtkTreeIter *iter,
00172 gpointer user_data)
00173 {
00174 ModelNode *node;
00175 gtk_tree_model_get (model, iter, COL_NODE, &node, -1);
00176 if (node->type == ModelNode::NODE_ATTRIBUTE)
00177 {
00178 StringValue str;
00179 node->object->GetAttribute (node->name, str);
00180 g_object_set(renderer, "text", str.Get ().c_str (), (char*)0);
00181 g_object_set(renderer, "editable", TRUE, (char*)0);
00182 }
00183 else
00184 {
00185 g_object_set(renderer, "text", "", (char*)0);
00186 g_object_set(renderer, "editable", FALSE, (char*)0);
00187 }
00188 }
00189
00190 static void
00191 cell_data_function_col_0 (GtkTreeViewColumn *col,
00192 GtkCellRenderer *renderer,
00193 GtkTreeModel *model,
00194 GtkTreeIter *iter,
00195 gpointer user_data)
00196 {
00197 ModelNode *node;
00198 gtk_tree_model_get (model, iter, COL_NODE, &node, -1);
00199 g_object_set (renderer, "editable", FALSE, (char*)0);
00200 switch (node->type) {
00201 case ModelNode::NODE_OBJECT:
00202 g_object_set(renderer, "text", node->object->GetInstanceTypeId ().GetName ().c_str (), (char*)0);
00203 break;
00204 case ModelNode::NODE_POINTER:
00205 g_object_set(renderer, "text", node->name.c_str (), (char*)0);
00206 break;
00207 case ModelNode::NODE_VECTOR:
00208 g_object_set(renderer, "text", node->name.c_str (), (char*)0);
00209 break;
00210 case ModelNode::NODE_VECTOR_ITEM: {
00211 std::stringstream oss;
00212 oss << node->index;
00213 g_object_set(renderer, "text", oss.str ().c_str (), (char*)0);
00214 } break;
00215 case ModelNode::NODE_ATTRIBUTE:
00216 g_object_set(renderer, "text", node->name.c_str (), (char*)0);
00217 break;
00218 }
00219 }
00220
00221
00222 static void
00223 cell_edited_callback (GtkCellRendererText *cell,
00224 gchar *path_string,
00225 gchar *new_text,
00226 gpointer user_data)
00227 {
00228 GtkTreeModel *model = GTK_TREE_MODEL (user_data);
00229 GtkTreeIter iter;
00230 gtk_tree_model_get_iter_from_string (model, &iter, path_string);
00231 ModelNode *node;
00232 gtk_tree_model_get (model, &iter, COL_NODE, &node, -1);
00233 NS_ASSERT (node->type == ModelNode::NODE_ATTRIBUTE);
00234 node->object->SetAttribute (node->name, StringValue (new_text));
00235 }
00236
00237 static int
00238 get_col_number_from_tree_view_column (GtkTreeViewColumn *col)
00239 {
00240 GList *cols;
00241 int num;
00242 g_return_val_if_fail ( col != 0, -1 );
00243 g_return_val_if_fail ( col->tree_view != 0, -1 );
00244 cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view));
00245 num = g_list_index(cols, (gpointer) col);
00246 g_list_free(cols);
00247 return num;
00248 }
00249
00250 static gboolean
00251 cell_tooltip_callback (GtkWidget *widget,
00252 gint x,
00253 gint y,
00254 gboolean keyboard_tip,
00255 GtkTooltip *tooltip,
00256 gpointer user_data)
00257 {
00258 GtkTreeModel *model;
00259 GtkTreeIter iter;
00260 GtkTreeViewColumn * column;
00261 if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
00262 &x, &y, keyboard_tip,
00263 &model, 0, &iter))
00264 {
00265 return FALSE;
00266 }
00267 if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
00268 x, y, 0, &column, 0, 0))
00269 {
00270 return FALSE;
00271 }
00272 int col = get_col_number_from_tree_view_column (column);
00273
00274 ModelNode *node;
00275 gtk_tree_model_get (model, &iter, COL_NODE, &node, -1);
00276
00277 switch (node->type) {
00278 case ModelNode::NODE_OBJECT:
00279 if (col == 0)
00280 {
00281 std::string tip = "This object is of type " + node->object->GetInstanceTypeId ().GetName ();
00282 gtk_tooltip_set_text (tooltip, tip.c_str ());
00283 return TRUE;
00284 }
00285 break;
00286 case ModelNode::NODE_POINTER:
00287 if (col == 0)
00288 {
00289 PointerValue ptr;
00290 node->object->GetAttribute (node->name, ptr);
00291 std::string tip = "This object is of type " + ptr.GetObject ()->GetInstanceTypeId ().GetName ();
00292 gtk_tooltip_set_text (tooltip, tip.c_str ());
00293 return TRUE;
00294 }
00295 break;
00296 case ModelNode::NODE_VECTOR:
00297 break;
00298 case ModelNode::NODE_VECTOR_ITEM:
00299 if (col == 0)
00300 {
00301 std::string tip = "This object is of type " + node->object->GetInstanceTypeId ().GetName ();
00302 gtk_tooltip_set_text (tooltip, tip.c_str ());
00303 return TRUE;
00304 }
00305 break;
00306 case ModelNode::NODE_ATTRIBUTE: {
00307 uint32_t attrIndex = 0;
00308 TypeId tid;
00309 for (tid = node->object->GetInstanceTypeId (); tid.HasParent (); tid = tid.GetParent ())
00310 {
00311 for (uint32_t i = 0; i < tid.GetAttributeN (); ++i)
00312 {
00313 if (tid.GetAttributeName (i) == node->name)
00314 {
00315 attrIndex = i;
00316 goto out;
00317 }
00318 }
00319 }
00320 out:
00321 if (col == 0)
00322 {
00323 std::string tip = tid.GetAttributeHelp (attrIndex);
00324 gtk_tooltip_set_text (tooltip, tip.c_str ());
00325 }
00326 else
00327 {
00328 Ptr<const AttributeChecker> checker = tid.GetAttributeChecker (attrIndex);
00329 std::string tip;
00330 tip = "This attribute is of type " + checker->GetValueTypeName ();
00331 if (checker->HasUnderlyingTypeInformation ())
00332 {
00333 tip += " " + checker->GetUnderlyingTypeInformation ();
00334 }
00335 gtk_tooltip_set_text (tooltip, tip.c_str ());
00336 }
00337 return TRUE;
00338 } break;
00339 }
00340 return FALSE;
00341 }
00342
00343
00344 static GtkWidget *
00345 create_view (GtkTreeStore *model)
00346 {
00347 GtkTreeViewColumn *col;
00348 GtkCellRenderer *renderer;
00349 GtkWidget *view;
00350
00351 view = gtk_tree_view_new();
00352 g_object_set (view, "has-tooltip", TRUE, (char*)0);
00353 g_signal_connect (view, "query-tooltip", (GCallback) cell_tooltip_callback, 0);
00354
00355 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_BOTH);
00356 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE);
00357
00358 col = gtk_tree_view_column_new();
00359 gtk_tree_view_column_set_title(col, "Object Attributes");
00360 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
00361 renderer = gtk_cell_renderer_text_new ();
00362 gtk_tree_view_column_pack_start(col, renderer, TRUE);
00363 gtk_tree_view_column_set_cell_data_func(col, renderer, cell_data_function_col_0, 0, 0);
00364 g_object_set(renderer, "editable", FALSE, (char*)0);
00365
00366 col = gtk_tree_view_column_new();
00367 gtk_tree_view_column_set_title(col, "Attribute Value");
00368 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
00369 renderer = gtk_cell_renderer_text_new();
00370 g_signal_connect(renderer, "edited", (GCallback) cell_edited_callback, model);
00371 gtk_tree_view_column_pack_start(col, renderer, TRUE);
00372 gtk_tree_view_column_set_cell_data_func(col, renderer, cell_data_function_col_1, 0, 0);
00373
00374
00375 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL (model));
00376
00377 g_object_unref(model);
00378
00379
00380 return view;
00381 }
00382
00383 static void
00384 save_clicked (GtkButton *button,
00385 gpointer user_data)
00386 {
00387 GtkWidget *parent_window = GTK_WIDGET (user_data);
00388 GtkWidget *dialog;
00389
00390 dialog = gtk_file_chooser_dialog_new ("Save File",
00391 GTK_WINDOW (parent_window),
00392 GTK_FILE_CHOOSER_ACTION_SAVE,
00393 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
00394 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
00395 (char *)0);
00396 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
00397
00398 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "config.txt");
00399
00400
00401 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
00402 {
00403 char *filename;
00404
00405 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
00406 std::ofstream os;
00407 os.open (filename);
00408 TextFileAttributeIterator file = TextFileAttributeIterator (os);
00409 file.Save ();
00410 os.close ();
00411 g_free (filename);
00412 }
00413
00414 gtk_widget_destroy (dialog);
00415 }
00416
00417 static void
00418 load_clicked (GtkButton *button,
00419 gpointer user_data)
00420 {
00421 GtkWidget *parent_window = GTK_WIDGET (user_data);
00422 GtkWidget *dialog;
00423
00424 dialog = gtk_file_chooser_dialog_new ("Open File",
00425 GTK_WINDOW (parent_window),
00426 GTK_FILE_CHOOSER_ACTION_OPEN,
00427 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
00428 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
00429 (char *)0);
00430
00431 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
00432 {
00433 char *filename;
00434
00435 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
00436 std::ifstream is;
00437 is.open (filename, std::ios::in);
00438 std::string path, value;
00439 while (is.good())
00440 {
00441 is >> path >> value;
00442 Config::Set (path, StringValue (value));
00443 }
00444 g_free (filename);
00445 }
00446
00447 gtk_widget_destroy (dialog);
00448 }
00449
00450 static void
00451 exit_clicked_callback (GtkButton *button,
00452 gpointer user_data)
00453 {
00454 gtk_main_quit ();
00455 gtk_widget_hide (GTK_WIDGET (user_data));
00456 }
00457
00458 static gboolean
00459 delete_event_callback (GtkWidget *widget,
00460 GdkEvent *event,
00461 gpointer user_data)
00462 {
00463 gtk_main_quit ();
00464 gtk_widget_hide (GTK_WIDGET (user_data));
00465 return TRUE;
00466 }
00467
00468 static gboolean
00469 clean_model_callback (GtkTreeModel *model,
00470 GtkTreePath *path,
00471 GtkTreeIter *iter,
00472 gpointer data)
00473 {
00474 ModelNode *node;
00475 gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
00476 COL_NODE, &node,
00477 -1);
00478 delete node;
00479 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
00480 COL_NODE, (ModelNode*)0,
00481 -1);
00482 return FALSE;
00483 }
00484
00485 GtkConfigStore::GtkConfigStore ()
00486 {}
00487
00488 void
00489 GtkConfigStore::Configure (void)
00490 {
00491 GtkWidget *window;
00492 GtkWidget *view;
00493 GtkWidget *scroll;
00494
00495 gtk_init (0, 0);
00496
00497 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
00498 gtk_window_set_title (GTK_WINDOW (window), "ns-3 Object attributes.");
00499 gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);
00500
00501 g_signal_connect (window, "delete_event", (GCallback)delete_event_callback, window);
00502
00503
00504 GtkTreeStore *model = gtk_tree_store_new (COL_LAST, G_TYPE_POINTER);
00505 ModelCreator creator;
00506 creator.Build (model);
00507
00508 view = create_view (model);
00509 scroll = gtk_scrolled_window_new (0, 0);
00510 gtk_container_add (GTK_CONTAINER (scroll), view);
00511
00512 GtkWidget *vbox = gtk_vbox_new (FALSE, 5);
00513 gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0);
00514 gtk_box_pack_end (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, FALSE, 0);
00515 GtkWidget *hbox = gtk_hbox_new (FALSE, 5);
00516 gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
00517 GtkWidget *save = gtk_button_new_with_label ("Save");
00518 g_signal_connect (save, "clicked", (GCallback) save_clicked, window);
00519 gtk_box_pack_end (GTK_BOX (hbox), save, FALSE, FALSE, 0);
00520 GtkWidget *load = gtk_button_new_with_label ("Load");
00521 g_signal_connect (load, "clicked", (GCallback) load_clicked, window);
00522 gtk_box_pack_end (GTK_BOX (hbox), load, FALSE, FALSE, 0);
00523 GtkWidget *exit = gtk_button_new_with_label ("Run Simulation");
00524 g_signal_connect (exit, "clicked", (GCallback) exit_clicked_callback, window);
00525 gtk_box_pack_end (GTK_BOX (hbox), exit, FALSE, FALSE, 0);
00526
00527 gtk_container_add (GTK_CONTAINER (window), vbox);
00528
00529 gtk_widget_show_all (window);
00530
00531 gtk_main ();
00532
00533 gtk_tree_model_foreach (GTK_TREE_MODEL (model),
00534 clean_model_callback,
00535 0);
00536
00537 gtk_widget_destroy (window);
00538 }
00539
00540 }