2 from __future__
import division, print_function
5 LAYOUT_ALGORITHM =
'neato' 6 REPRESENT_CHANNELS_AS_NODES = 1
7 DEFAULT_NODE_SIZE = 1.0
8 DEFAULT_TRANSMISSIONS_MEMORY = 5
13 PRIORITY_UPDATE_MODEL = -100
14 PRIORITY_UPDATE_VIEW = 200
18 if platform.system() ==
"Windows":
19 SHELL_FONT =
"Lucida Console 9" 21 SHELL_FONT =
"Luxi Mono 10" 36 gi.require_version(
'GooCanvas',
'2.0')
37 gi.require_version(
'Gtk',
'3.0')
38 from gi.repository
import GObject
39 from gi.repository
import GLib
41 gi.require_foreign(
"cairo")
43 from gi.repository
import Gtk
44 from gi.repository
import Gdk
45 from gi.repository
import Pango
46 from gi.repository
import GooCanvas
54 except ImportError
as _import_error:
55 import dummy_threading
as threading
60 import ipython_viewxxxxxxxxxx
64 from base
import InformationWindow, PyVizObject, Link, lookup_netdevice_traits, PIXELS_PER_METER
65 from base
import transform_distance_simulation_to_canvas, transform_point_simulation_to_canvas
66 from base
import transform_distance_canvas_to_simulation, transform_point_canvas_to_simulation
67 from base
import load_plugins, register_plugin, plugins
70 PI_TIMES_2 = math.pi*2
112 'query-extra-tooltip-info': (GObject.SignalFlags.RUN_LAST,
None, (object,)),
116 """ Initialize function. 117 @param self The object pointer. 118 @param visualizer: visualizer object 119 @param node_index: node index 144 def set_svg_icon(self, file_base_name, width=None, height=None, align_x=0.5, align_y=0.5):
146 Set a background SVG icon for the node. 148 @param file_base_name: base file name, including .svg 149 extension, of the svg file. Place the file in the folder 150 src/contrib/visualizer/resource. 152 @param width: scale to the specified width, in meters 153 @param height: scale to the specified height, in meters 155 @param align_x: horizontal alignment of the icon relative to 156 the node position, from 0 (icon fully to the left of the node) 157 to 1.0 (icon fully to the right of the node) 159 @param align_y: vertical alignment of the icon relative to the 160 node position, from 0 (icon fully to the top of the node) to 161 1.0 (icon fully to the bottom of the node) 163 @return a ValueError exception if invalid dimensions. 166 if width
is None and height
is None:
167 raise ValueError(
"either width or height must be given")
168 rsvg_handle = svgitem.rsvg_handle_factory(file_base_name)
173 self.
svg_item.props.pointer_events = GooCanvas.CanvasPointerEvents.NONE
175 self.
svg_item.props.visibility = GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD
176 if width
is not None:
178 if height
is not None:
192 Set a label for the node. 194 @param self: class object. 195 @param label: label to set 197 @return: an exception if invalid parameter. 199 assert isinstance(label, basestring)
207 @param self: class object. 222 @param self: class object. 223 @param tooltip: tooltip 228 ns3_node = ns.network.NodeList.GetNode(self.
node_index)
229 ipv4 = ns3_node.GetObject(ns.internet.Ipv4.GetTypeId())
230 ipv6 = ns3_node.GetObject(ns.internet.Ipv6.GetTypeId())
232 name =
'<b><u>Node %i</u></b>' % self.
node_index 233 node_name = ns.core.Names.FindName (ns3_node)
234 if len(node_name)!=0:
235 name +=
' <b>(' + node_name +
')</b>' 240 self.emit(
"query-extra-tooltip-info", lines)
242 mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
244 lines.append(
' <b>Mobility Model</b>: %s' % mob.GetInstanceTypeId().GetName())
246 for devI
in range(ns3_node.GetNDevices()):
248 lines.append(
' <u>NetDevice %i:</u>' % devI)
249 dev = ns3_node.GetDevice(devI)
250 name = ns.core.Names.FindName(dev)
252 lines.append(
' <b>Name:</b> %s' % name)
253 devname = dev.GetInstanceTypeId().GetName()
254 lines.append(
' <b>Type:</b> %s' % devname)
257 ipv4_idx = ipv4.GetInterfaceForDevice(dev)
260 '%s/%s' % (ipv4.GetAddress(ipv4_idx, i).GetLocal(),
261 ipv4.GetAddress(ipv4_idx, i).GetMask())
262 for i
in range(ipv4.GetNAddresses(ipv4_idx))]
263 lines.append(
' <b>IPv4 Addresses:</b> %s' %
'; '.join(addresses))
266 ipv6_idx = ipv6.GetInterfaceForDevice(dev)
269 '%s/%s' % (ipv6.GetAddress(ipv6_idx, i).GetAddress(),
270 ipv6.GetAddress(ipv6_idx, i).GetPrefix())
271 for i
in range(ipv6.GetNAddresses(ipv6_idx))]
272 lines.append(
' <b>IPv6 Addresses:</b> %s' %
'; '.join(addresses))
274 lines.append(
' <b>MAC Address:</b> %s' % (dev.GetAddress(),))
276 tooltip.set_markup(
'\n'.join(lines))
282 On Enter event handle. 284 @param self: class object. 286 @param target: target 293 On Leave event handle. 295 @param self: class object. 297 @param target: target 305 Set selected function. 307 @param self: class object. 308 @param value: selected value 315 Get selected function. 317 @param self: class object. 318 @return selected status 322 selected = property(_get_selected, _set_selected)
326 Set highlighted function. 328 @param self: class object. 329 @param value: selected value 336 Get highlighted function. 338 @param self: class object. 339 @return highlighted status 343 highlighted = property(_get_highlighted, _set_highlighted)
349 @param self: class object. 350 @param size: selected size 358 Update the node aspect to reflect the selected/highlighted state 360 @param self: class object. 369 fill_color_rgba = (self.
_color & 0xffffff00) | alpha
370 self.
canvas_item.set_properties(radius_x=size, radius_y=size,
371 fill_color_rgba=fill_color_rgba)
375 line_width = size*.15
377 stroke_color =
'yellow' 379 stroke_color =
'black' 380 self.
canvas_item.set_properties(line_width=line_width, stroke_color=stroke_color)
382 if self.
_label is not None:
385 font=
"Sans Serif 10",
386 fill_color_rgba=0x808080ff,
387 alignment=Pango.Alignment.CENTER,
388 anchor=GooCanvas.CanvasAnchorType.N,
389 parent=self.
visualizer.canvas.get_root_item(),
390 pointer_events=GooCanvas.CanvasPointerEvents.NONE)
393 self.
_label_canvas_item.set_properties(visibility=GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD,
399 Set position function. 401 @param self: class object. 411 for link
in self.
links:
422 (min_x, min_y, max_x, max_y) = bounds
424 min_x =
min(x, min_x)
425 min_y =
min(y, min_y)
426 max_x =
max(x, max_x)
427 max_y =
max(y, max_y)
429 new_bounds = (min_x, min_y, max_x, max_y)
431 if new_bounds != bounds:
432 self.
visualizer.canvas.set_bounds(*new_bounds)
439 Get position function. 441 @param self: class object. 442 @return x and y position 448 Update position function. 450 @param self: class object. 460 @param self: class object. 461 @param color: color to set. 464 if isinstance(color, str):
465 color = Gdk.color_parse(color)
466 color = ((color.red>>8) << 24) | ((color.green>>8) << 16) | ((color.blue>>8) << 8) | 0xff
474 @param self: class object. 475 @param link: link to add. 478 assert isinstance(link, Link)
479 self.
links.append(link)
483 Remove link function. 485 @param self: class object. 486 @param link: link to add. 489 assert isinstance(link, Link)
490 self.
links.remove(link)
495 Has mobility function. 497 @param self: class object. 498 @return modility option 501 node = ns.network.NodeList.GetNode(self.
node_index)
502 mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
518 Initializer function. 520 @param self: class object. 521 @param channel: channel. 525 self.
canvas_item = GooCanvas.CanvasEllipse(radius_x=30, radius_y=30,
527 stroke_color=
"grey", line_width=2.0,
528 line_dash=GooCanvas.LineDash([10.0, 10.0 ]),
529 visibility=GooCanvas.CanvasItemVisibility.VISIBLE)
535 Initializer function. 537 @param self: class object. 538 @param x: x position. 539 @param y: y position. 545 for link
in self.
links:
550 Initializer function. 552 @param self: class object. 553 @return x / y position. 569 Initializer function. 571 @param self: class object. 572 @param node1: class object. 573 @param node2: class object. 576 assert isinstance(node1, Node)
577 assert isinstance(node2, (Node, Channel))
580 self.
canvas_item = GooCanvas.CanvasPath(line_width=1.0, stroke_color=
"black")
582 self.
node1.links.append(self)
583 self.
node2.links.append(self)
587 Update points function. 589 @param self: class object. 592 pos1_x, pos1_y = self.
node1.get_position()
593 pos2_x, pos2_y = self.
node2.get_position()
594 self.
canvas_item.set_property(
"data",
"M %r %r L %r %r" % (pos1_x, pos1_y, pos2_x, pos2_y))
615 Initializer function. 617 @param self: class object. 618 @param viz: class object. 621 super(SimulationThread, self).
__init__()
622 assert isinstance(viz, Visualizer)
625 self.
go = threading.Event()
634 Set nodes of interest function. 636 @param self: class object. 637 @param nodes: class object. 648 Initializer function. 650 @param self: class object. 664 if ns3.core.Simulator.IsFinished():
665 self.
viz.play_button.set_sensitive(
False)
673 GLib.idle_add(self.
viz.update_model, priority=PRIORITY_UPDATE_MODEL)
700 if _import_error
is None:
704 'populate-node-menu': (GObject.SignalFlags.RUN_LAST,
None, (object, Gtk.Menu,)),
708 'simulation-periodic-update': (GObject.SignalFlags.RUN_LAST,
None, ()),
711 'topology-scanned': (GObject.SignalFlags.RUN_LAST,
None, ()),
714 'update-view': (GObject.SignalFlags.RUN_LAST,
None, ()),
720 Initializer function. 722 @param self: class object. 725 assert Visualizer.INSTANCE
is None 726 Visualizer.INSTANCE = self
727 super(Visualizer, self).__init__()
732 self.time_label =
None 733 self.play_button =
None 735 self._scrolled_window =
None 737 self.links_group = GooCanvas.CanvasGroup()
738 self.channels_group = GooCanvas.CanvasGroup()
739 self.nodes_group = GooCanvas.CanvasGroup()
741 self._update_timeout_id =
None 743 self.selected_node =
None 745 self.information_windows = []
746 self._transmission_arrows = []
747 self._last_transmissions = []
748 self._drop_arrows = []
749 self._last_drops = []
750 self._show_transmissions_mode =
None 751 self.set_show_transmissions_mode(ShowTransmissionsMode.ALL)
752 self._panning_state =
None 753 self.node_size_adjustment =
None 754 self.transmissions_smoothing_adjustment =
None 755 self.sample_period = SAMPLE_PERIOD
756 self.node_drag_state =
None 757 self.follow_node =
None 758 self.shell_window =
None 762 for plugin
in plugins:
765 def set_show_transmissions_mode(self, mode):
767 Set show transmission mode. 769 @param self: class object. 770 @param mode: mode to set. 773 assert isinstance(mode, ShowTransmissionsMode)
774 self._show_transmissions_mode = mode
775 if self._show_transmissions_mode == ShowTransmissionsMode.ALL:
776 self.simulation.set_nodes_of_interest(range(ns.network.NodeList.GetNNodes()))
777 elif self._show_transmissions_mode == ShowTransmissionsMode.NONE:
778 self.simulation.set_nodes_of_interest([])
779 elif self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
780 if self.selected_node
is None:
781 self.simulation.set_nodes_of_interest([])
783 self.simulation.set_nodes_of_interest([self.selected_node.node_index])
785 def _create_advanced_controls(self):
787 Create advanced controls. 789 @param self: class object. 792 expander = Gtk.Expander.new(
"Advanced")
795 main_vbox = GObject.new(Gtk.VBox, border_width=8, visible=
True)
796 expander.add(main_vbox)
798 main_hbox1 = GObject.new(Gtk.HBox, border_width=8, visible=
True)
799 main_vbox.pack_start(main_hbox1,
True,
True, 0)
801 show_transmissions_group = GObject.new(Gtk.HeaderBar,
802 title=
"Show transmissions",
804 main_hbox1.pack_start(show_transmissions_group,
False,
False, 8)
806 vbox = Gtk.VBox(homogeneous=
True, spacing=4)
808 show_transmissions_group.add(vbox)
810 all_nodes = Gtk.RadioButton.new(
None)
811 all_nodes.set_label(
"All nodes")
812 all_nodes.set_active(
True)
816 selected_node = Gtk.RadioButton.new_from_widget(all_nodes)
818 selected_node.set_label(
"Selected node")
819 selected_node.set_active(
False)
820 vbox.add(selected_node)
822 no_node = Gtk.RadioButton.new_from_widget(all_nodes)
824 no_node.set_label(
"Disabled")
825 no_node.set_active(
False)
829 if radio.get_active():
830 self.set_show_transmissions_mode(ShowTransmissionsMode.ALL)
831 all_nodes.connect(
"toggled", toggled)
834 if radio.get_active():
835 self.set_show_transmissions_mode(ShowTransmissionsMode.NONE)
836 no_node.connect(
"toggled", toggled)
839 if radio.get_active():
840 self.set_show_transmissions_mode(ShowTransmissionsMode.SELECTED)
841 selected_node.connect(
"toggled", toggled)
844 misc_settings_group = GObject.new(Gtk.HeaderBar, title=
"Misc Settings", visible=
True)
845 main_hbox1.pack_start(misc_settings_group,
False,
False, 8)
846 settings_hbox = GObject.new(Gtk.HBox, border_width=8, visible=
True)
847 misc_settings_group.add(settings_hbox)
850 vbox = GObject.new(Gtk.VBox, border_width=0, visible=
True)
851 scale = GObject.new(Gtk.HScale, visible=
True, digits=2)
852 vbox.pack_start(scale,
True,
True, 0)
853 vbox.pack_start(GObject.new(Gtk.Label, label=
"Node Size", visible=
True),
True,
True, 0)
854 settings_hbox.pack_start(vbox,
False,
False, 6)
855 self.node_size_adjustment = scale.get_adjustment()
856 def node_size_changed(adj):
857 for node
in self.nodes.itervalues():
858 node.set_size(adj.get_value())
859 self.node_size_adjustment.connect(
"value-changed", node_size_changed)
860 self.node_size_adjustment.set_lower(0.01)
861 self.node_size_adjustment.set_upper(20)
862 self.node_size_adjustment.set_step_increment(0.1)
863 self.node_size_adjustment.set_value(DEFAULT_NODE_SIZE)
866 vbox = GObject.new(Gtk.VBox, border_width=0, visible=
True)
867 scale = GObject.new(Gtk.HScale, visible=
True, digits=1)
868 vbox.pack_start(scale,
True,
True, 0)
869 vbox.pack_start(GObject.new(Gtk.Label, label=
"Tx. Smooth Factor (s)", visible=
True),
True,
True, 0)
870 settings_hbox.pack_start(vbox,
False,
False, 6)
871 self.transmissions_smoothing_adjustment = scale.get_adjustment()
872 adj = self.transmissions_smoothing_adjustment
875 adj.set_step_increment(0.1)
876 adj.set_value(DEFAULT_TRANSMISSIONS_MEMORY*0.1)
881 class _PanningState(object):
884 __slots__ = [
'initial_mouse_pos',
'initial_canvas_pos',
'motion_signal']
886 def _begin_panning(self, widget, event):
888 Set show trnamission mode. 890 @param self: class object. 891 @param mode: mode to set. 894 display = self.canvas.get_window().get_display()
895 cursor = Gdk.Cursor.new_for_display(display, Gdk.CursorType.FLEUR)
896 self.canvas.get_window().set_cursor(cursor)
897 self._panning_state = self._PanningState()
898 pos = widget.get_window().get_device_position(event.device)
899 self._panning_state.initial_mouse_pos = (pos.x, pos.y)
900 x = self._scrolled_window.get_hadjustment().get_value()
901 y = self._scrolled_window.get_vadjustment().get_value()
902 self._panning_state.initial_canvas_pos = (x, y)
903 self._panning_state.motion_signal = self.canvas.connect(
"motion-notify-event", self._panning_motion)
905 def _end_panning(self, event):
907 End panning function. 909 @param self: class object. 910 @param event: active event. 913 if self._panning_state
is None:
915 self.canvas.get_window().set_cursor(
None)
916 self.canvas.disconnect(self._panning_state.motion_signal)
917 self._panning_state =
None 919 def _panning_motion(self, widget, event):
921 Panning motion function. 923 @param self: class object. 924 @param widget: widget. 926 @return true if successful 928 assert self._panning_state
is not None 930 pos = widget.get_window().get_device_position(event.device)
933 x, y = event.x, event.y
935 hadj = self._scrolled_window.get_hadjustment()
936 vadj = self._scrolled_window.get_vadjustment()
937 mx0, my0 = self._panning_state.initial_mouse_pos
938 cx0, cy0 = self._panning_state.initial_canvas_pos
942 hadj.set_value(cx0 - dx)
943 vadj.set_value(cy0 - dy)
946 def _canvas_button_press(self, widget, event):
947 if event.button == 2:
948 self._begin_panning(widget, event)
952 def _canvas_button_release(self, dummy_widget, event):
953 if event.button == 2:
954 self._end_panning(event)
958 def _canvas_scroll_event(self, dummy_widget, event):
959 if event.direction == Gdk.ScrollDirection.UP:
960 self.zoom.set_value(self.zoom.get_value() * 1.25)
962 elif event.direction == Gdk.ScrollDirection.DOWN:
963 self.zoom.set_value(self.zoom.get_value() / 1.25)
967 def get_hadjustment(self):
968 return self._scrolled_window.get_hadjustment()
969 def get_vadjustment(self):
970 return self._scrolled_window.get_vadjustment()
972 def create_gui(self):
973 self.window = Gtk.Window()
976 self.window.add(vbox)
979 self.canvas = GooCanvas.Canvas()
980 self.canvas.connect_after(
"button-press-event", self._canvas_button_press)
981 self.canvas.connect_after(
"button-release-event", self._canvas_button_release)
982 self.canvas.connect(
"scroll-event", self._canvas_scroll_event)
983 self.canvas.props.has_tooltip =
True 984 self.canvas.connect(
"query-tooltip", self._canvas_tooltip_cb)
986 sw = Gtk.ScrolledWindow(); sw.show()
987 self._scrolled_window = sw
989 vbox.pack_start(sw,
True,
True, 4)
990 self.canvas.set_size_request(600, 450)
991 self.canvas.
set_bounds(-10000, -10000, 10000, 10000)
992 self.canvas.scroll_to(0, 0)
995 self.canvas.get_root_item().add_child(self.links_group, -1)
996 self.links_group.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
998 self.canvas.get_root_item().add_child(self.channels_group, -1)
999 self.channels_group.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1000 self.channels_group.raise_(self.links_group)
1002 self.canvas.get_root_item().add_child(self.nodes_group, -1)
1003 self.nodes_group.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1004 self.nodes_group.raise_(self.channels_group)
1008 hbox = Gtk.HBox(); hbox.show()
1009 vbox.pack_start(hbox,
False,
False, 4)
1012 zoom_adj = Gtk.Adjustment(value=1.0, lower=0.01, upper=10.0,
1013 step_increment=0.02,
1016 self.zoom = zoom_adj
1017 def _zoom_changed(adj):
1018 self.canvas.set_scale(adj.get_value())
1019 zoom_adj.connect(
"value-changed", _zoom_changed)
1020 zoom = Gtk.SpinButton.new(zoom_adj, 0.1, 1)
1023 hbox.pack_start(GObject.new(Gtk.Label, label=
" Zoom:", visible=
True),
False,
False, 4)
1024 hbox.pack_start(zoom,
False,
False, 4)
1025 _zoom_changed(zoom_adj)
1028 speed_adj = Gtk.Adjustment(value=1.0, lower=0.01, upper=10.0,
1029 step_increment=0.02,
1030 page_increment=1.0, page_size=0)
1031 def _speed_changed(adj):
1032 self.speed = adj.get_value()
1033 self.sample_period = SAMPLE_PERIOD*adj.get_value()
1034 self._start_update_timer()
1035 speed_adj.connect(
"value-changed", _speed_changed)
1036 speed = Gtk.SpinButton.new(speed_adj, 1, 0)
1039 hbox.pack_start(GObject.new(Gtk.Label, label=
" Speed:", visible=
True),
False,
False, 4)
1040 hbox.pack_start(speed,
False,
False, 4)
1041 _speed_changed(speed_adj)
1044 self.time_label = GObject.new(Gtk.Label, label=
" Speed:", visible=
True)
1045 self.time_label.set_width_chars(20)
1046 hbox.pack_start(self.time_label,
False,
False, 4)
1049 screenshot_button = GObject.new(Gtk.Button,
1051 relief=Gtk.ReliefStyle.NONE, focus_on_click=
False,
1053 hbox.pack_start(screenshot_button,
False,
False, 4)
1055 def load_button_icon(button, icon_name):
1059 sys.stderr.write(
"Could not load icon %s due to missing gnomedesktop Python module\n" % icon_name)
1061 icon = gnomedesktop.find_icon(Gtk.IconTheme.get_default(), icon_name, 16, 0)
1062 if icon
is not None:
1063 button.props.image = GObject.new(Gtk.Image, file=icon, visible=
True)
1065 load_button_icon(screenshot_button,
"applets-screenshooter")
1066 screenshot_button.connect(
"clicked", self._take_screenshot)
1069 if ipython_view
is not None:
1070 shell_button = GObject.new(Gtk.Button,
1072 relief=Gtk.ReliefStyle.NONE, focus_on_click=
False,
1074 hbox.pack_start(shell_button,
False,
False, 4)
1075 load_button_icon(shell_button,
"gnome-terminal")
1076 shell_button.connect(
"clicked", self._start_shell)
1079 self.play_button = GObject.new(Gtk.ToggleButton,
1080 image=GObject.new(Gtk.Image, stock=Gtk.STOCK_MEDIA_PLAY, visible=
True),
1081 label=
"Simulate (F3)",
1082 relief=Gtk.ReliefStyle.NONE, focus_on_click=
False,
1083 use_stock=
True, visible=
True)
1084 accel_group = Gtk.AccelGroup()
1085 self.window.add_accel_group(accel_group)
1086 self.play_button.add_accelerator(
"clicked", accel_group,
1087 Gdk.KEY_F3, 0, Gtk.AccelFlags.VISIBLE)
1088 self.play_button.connect(
"toggled", self._on_play_button_toggled)
1089 hbox.pack_start(self.play_button,
False,
False, 4)
1091 self.canvas.get_root_item().connect(
"button-press-event", self.on_root_button_press_event)
1093 vbox.pack_start(self._create_advanced_controls(),
False,
False, 4)
1095 display = Gdk.Display.get_default()
1096 monitor = display.get_primary_monitor()
1097 geometry = monitor.get_geometry()
1098 scale_factor = monitor.get_scale_factor()
1099 width = scale_factor * geometry.width
1100 height = scale_factor * geometry.height
1101 self.window.set_default_size(width * 2 / 3, height * 2 / 3)
1104 def scan_topology(self):
1105 print(
"scanning topology: %i nodes..." % (ns.network.NodeList.GetNNodes(),))
1106 graph = pygraphviz.AGraph()
1108 for nodeI
in range(ns.network.NodeList.GetNNodes()):
1110 if seen_nodes == 100:
1111 print(
"scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns.network.NodeList.GetNNodes()))
1113 node = ns.network.NodeList.GetNode(nodeI)
1114 node_name =
"Node %i" % nodeI
1115 node_view = self.get_node(nodeI)
1117 mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1118 if mobility
is not None:
1119 node_view.set_color(
"red")
1120 pos = mobility.GetPosition()
1124 graph.add_node(node_name)
1126 for devI
in range(node.GetNDevices()):
1127 device = node.GetDevice(devI)
1129 if device_traits.is_wireless:
1131 if device_traits.is_virtual:
1133 channel = device.GetChannel()
1134 if channel.GetNDevices() > 2:
1135 if REPRESENT_CHANNELS_AS_NODES:
1137 if mobility
is None:
1138 channel_name =
"Channel %s" % id(channel)
1139 graph.add_edge(node_name, channel_name)
1140 self.get_channel(channel)
1141 self.create_link(self.get_node(nodeI), self.get_channel(channel))
1144 for otherDevI
in range(channel.GetNDevices()):
1145 otherDev = channel.GetDevice(otherDevI)
1146 otherNode = otherDev.GetNode()
1147 otherNodeView = self.get_node(otherNode.GetId())
1148 if otherNode
is not node:
1149 if mobility
is None and not otherNodeView.has_mobility:
1150 other_node_name =
"Node %i" % otherNode.GetId()
1151 graph.add_edge(node_name, other_node_name)
1152 self.create_link(self.get_node(nodeI), otherNodeView)
1154 for otherDevI
in range(channel.GetNDevices()):
1155 otherDev = channel.GetDevice(otherDevI)
1156 otherNode = otherDev.GetNode()
1157 otherNodeView = self.get_node(otherNode.GetId())
1158 if otherNode
is not node:
1159 if mobility
is None and not otherNodeView.has_mobility:
1160 other_node_name =
"Node %i" % otherNode.GetId()
1161 graph.add_edge(node_name, other_node_name)
1162 self.create_link(self.get_node(nodeI), otherNodeView)
1164 print(
"scanning topology: calling graphviz layout")
1165 graph.layout(LAYOUT_ALGORITHM)
1166 for node
in graph.iternodes():
1168 node_type, node_id = node.split(
' ')
1169 pos_x, pos_y = [float(s)
for s
in node.attr[
'pos'].split(
',')]
1170 if node_type ==
'Node':
1171 obj = self.nodes[int(node_id)]
1172 elif node_type ==
'Channel':
1173 obj = self.channels[int(node_id)]
1174 obj.set_position(pos_x, pos_y)
1176 print(
"scanning topology: all done.")
1177 self.emit(
"topology-scanned")
1179 def get_node(self, index):
1181 return self.nodes[index]
1183 node =
Node(self, index)
1184 self.nodes[index] = node
1185 self.nodes_group.add_child(node.canvas_item, -1)
1186 node.canvas_item.connect(
"button-press-event", self.on_node_button_press_event, node)
1187 node.canvas_item.connect(
"button-release-event", self.on_node_button_release_event, node)
1190 def get_channel(self, ns3_channel):
1192 return self.channels[id(ns3_channel)]
1194 channel =
Channel(ns3_channel)
1195 self.channels[id(ns3_channel)] = channel
1196 self.channels_group.add_child(channel.canvas_item, -1)
1199 def create_link(self, node, node_or_channel):
1201 self.links_group.add_child(link.canvas_item, -1)
1202 link.canvas_item.lower(
None)
1204 def update_view(self):
1207 self.time_label.set_text(
"Time: %f s" % ns.core.Simulator.Now().GetSeconds())
1209 self._update_node_positions()
1212 for info_win
in self.information_windows:
1215 self._update_transmissions_view()
1216 self._update_drops_view()
1218 self.emit(
"update-view")
1220 def _update_node_positions(self):
1221 for node
in self.nodes.itervalues():
1222 if node.has_mobility:
1223 ns3_node = ns.network.NodeList.GetNode(node.node_index)
1224 mobility = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1225 if mobility
is not None:
1226 pos = mobility.GetPosition()
1228 node.set_position(x, y)
1229 if node
is self.follow_node:
1230 hadj = self._scrolled_window.get_hadjustment()
1231 vadj = self._scrolled_window.get_vadjustment()
1232 px, py = self.canvas.convert_to_pixels(x, y)
1233 hadj.set_value(px - hadj.get_page_size() / 2)
1234 vadj.set_value(py - vadj.get_page_size() / 2)
1236 def center_on_node(self, node):
1237 if isinstance(node, ns.network.Node):
1238 node = self.nodes[node.GetId()]
1239 elif isinstance(node, (int, long)):
1240 node = self.nodes[node]
1241 elif isinstance(node, Node):
1244 raise TypeError(
"expected int, viz.Node or ns.network.Node, not %r" % node)
1246 x, y = node.get_position()
1247 hadj = self._scrolled_window.get_hadjustment()
1248 vadj = self._scrolled_window.get_vadjustment()
1249 px, py = self.canvas.convert_to_pixels(x, y)
1250 hadj.set_value(px - hadj.get_page_size() / 2)
1251 vadj.set_value(py - vadj.get_page_size() / 2)
1253 def update_model(self):
1254 self.simulation.lock.acquire()
1256 self.emit(
"simulation-periodic-update")
1258 self.simulation.lock.release()
1260 def do_simulation_periodic_update(self):
1261 smooth_factor = int(self.transmissions_smoothing_adjustment.get_value()*10)
1263 transmissions = self.simulation.sim_helper.GetTransmissionSamples()
1264 self._last_transmissions.append(transmissions)
1265 while len(self._last_transmissions) > smooth_factor:
1266 self._last_transmissions.pop(0)
1268 drops = self.simulation.sim_helper.GetPacketDropSamples()
1269 self._last_drops.append(drops)
1270 while len(self._last_drops) > smooth_factor:
1271 self._last_drops.pop(0)
1273 def _get_label_over_line_position(self, pos1_x, pos1_y, pos2_x, pos2_y):
1274 hadj = self._scrolled_window.get_hadjustment()
1275 vadj = self._scrolled_window.get_vadjustment()
1276 bounds_x1, bounds_y1 = self.canvas.convert_from_pixels(hadj.get_value(), vadj.get_value())
1277 bounds_x2, bounds_y2 = self.canvas.convert_from_pixels(hadj.get_value() + hadj.get_page_size(),
1278 vadj.get_value() + vadj.get_page_size())
1279 pos1_x, pos1_y, pos2_x, pos2_y = ns.visualizer.PyViz.LineClipping(bounds_x1, bounds_y1,
1280 bounds_x2, bounds_y2,
1283 return (pos1_x + pos2_x)/2, (pos1_y + pos2_y)/2
1285 def _update_transmissions_view(self):
1286 transmissions_average = {}
1287 for transmission_set
in self._last_transmissions:
1288 for transmission
in transmission_set:
1289 key = (transmission.transmitter.GetId(), transmission.receiver.GetId())
1290 rx_bytes, count = transmissions_average.get(key, (0, 0))
1291 rx_bytes += transmission.bytes
1293 transmissions_average[key] = rx_bytes, count
1295 old_arrows = self._transmission_arrows
1296 for arrow, label
in old_arrows:
1297 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1298 label.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1301 k = self.node_size_adjustment.get_value()/5
1303 for (transmitter_id, receiver_id), (rx_bytes, rx_count)
in transmissions_average.iteritems():
1304 transmitter = self.get_node(transmitter_id)
1305 receiver = self.get_node(receiver_id)
1307 arrow, label = old_arrows.pop()
1309 arrow = GooCanvas.CanvasPolyline(line_width=2.0, stroke_color_rgba=0x00C000C0, close_path=
False, end_arrow=
True, pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1310 arrow.set_property(
"parent", self.canvas.get_root_item())
1313 label = GooCanvas.CanvasText(parent=self.canvas.get_root_item(), pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1316 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1317 line_width =
max(0.1, math.log(float(rx_bytes)/rx_count/self.sample_period)*k)
1318 arrow.set_property(
"line-width", line_width)
1320 pos1_x, pos1_y = transmitter.get_position()
1321 pos2_x, pos2_y = receiver.get_position()
1322 points = GooCanvas.CanvasPoints.new(2)
1323 points.set_point(0, pos1_x, pos1_y)
1324 points.set_point(1, pos2_x, pos2_y)
1325 arrow.set_property(
"points", points)
1327 kbps = float(rx_bytes*8)/1e3/rx_count/self.sample_period
1328 label.set_properties(visibility=GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD,
1329 visibility_threshold=0.5,
1330 font=(
"Sans Serif %f" % int(1+BITRATE_FONT_SIZE*k)))
1331 angle = math.atan2((pos2_y - pos1_y), (pos2_x - pos1_x))
1332 if -PI_OVER_2 <= angle <= PI_OVER_2:
1333 label.set_properties(text=(
"%.2f kbit/s →" % (kbps,)),
1334 alignment=Pango.Alignment.CENTER,
1335 anchor=GooCanvas.CanvasAnchorType.S,
1336 x=0, y=-line_width/2)
1338 label.set_properties(text=(
"← %.2f kbit/s" % (kbps,)),
1339 alignment=Pango.Alignment.CENTER,
1340 anchor=GooCanvas.CanvasAnchorType.N,
1341 x=0, y=line_width/2)
1343 lx, ly = self._get_label_over_line_position(pos1_x, pos1_y,
1348 label.set_transform(M)
1351 warnings.warn(
"PyGobject bug causing label position error; " 1352 "should be fixed in PyGObject >= 3.29.1")
1353 label.set_properties(x=(lx + label.props.x),
1354 y=(ly + label.props.y))
1356 new_arrows.append((arrow, label))
1358 self._transmission_arrows = new_arrows + old_arrows
1361 def _update_drops_view(self):
1363 for drop_set
in self._last_drops:
1364 for drop
in drop_set:
1365 key = drop.transmitter.GetId()
1366 drop_bytes, count = drops_average.get(key, (0, 0))
1367 drop_bytes += drop.bytes
1369 drops_average[key] = drop_bytes, count
1371 old_arrows = self._drop_arrows
1372 for arrow, label
in old_arrows:
1373 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1374 label.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1378 vadjustment = self._scrolled_window.get_vadjustment()
1379 bottom_y = vadjustment.get_value() + vadjustment.get_page_size()
1380 dummy, edge_y = self.canvas.convert_from_pixels(0, bottom_y)
1382 k = self.node_size_adjustment.get_value()/5
1384 for transmitter_id, (drop_bytes, drop_count)
in drops_average.iteritems():
1385 transmitter = self.get_node(transmitter_id)
1387 arrow, label = old_arrows.pop()
1389 arrow = GooCanvas.CanvasPolyline(line_width=2.0, stroke_color_rgba=0xC00000C0, close_path=
False, end_arrow=
True, pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1390 arrow.set_property(
"parent", self.canvas.get_root_item())
1393 label = GooCanvas.CanvasText(pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1394 label.set_property(
"parent", self.canvas.get_root_item())
1397 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1398 arrow.set_property(
"line-width",
max(0.1, math.log(float(drop_bytes)/drop_count/self.sample_period)*k))
1399 pos1_x, pos1_y = transmitter.get_position()
1400 pos2_x, pos2_y = pos1_x, edge_y
1401 points = GooCanvas.CanvasPoints.new(2)
1402 points.set_point(0, pos1_x, pos1_y)
1403 points.set_point(1, pos2_x, pos2_y)
1404 arrow.set_property(
"points", points)
1406 label.set_properties(visibility=GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD,
1407 visibility_threshold=0.5,
1408 font=(
"Sans Serif %i" % int(1+BITRATE_FONT_SIZE*k)),
1409 text=(
"%.2f kbit/s" % (float(drop_bytes*8)/1e3/drop_count/self.sample_period,)),
1410 alignment=Pango.Alignment.CENTER,
1411 x=(pos1_x + pos2_x)/2,
1412 y=(pos1_y + pos2_y)/2)
1414 new_arrows.append((arrow, label))
1416 self._drop_arrows = new_arrows + old_arrows
1419 def update_view_timeout(self):
1423 while not self.simulation.lock.acquire(
False):
1424 while Gtk.events_pending():
1425 Gtk.main_iteration()
1426 pause_messages = self.simulation.pause_messages
1427 self.simulation.pause_messages = []
1430 self.simulation.target_time = ns.core.Simulator.Now ().GetSeconds () + self.sample_period
1433 self.simulation.lock.release()
1437 dialog = Gtk.MessageDialog(parent=self.window, flags=0, type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK,
1438 message_format=
'\n'.join(pause_messages))
1439 dialog.connect(
"response",
lambda d, r: d.destroy())
1441 self.play_button.set_active(
False)
1444 if not self.play_button.get_active():
1445 self._update_timeout_id =
None 1449 self.simulation.go.set()
1453 def _start_update_timer(self):
1454 if self._update_timeout_id
is not None:
1455 GLib.source_remove(self._update_timeout_id)
1457 self._update_timeout_id = GLib.timeout_add(int(SAMPLE_PERIOD/
min(self.speed, 1)*1e3),
1458 self.update_view_timeout,
1459 priority=PRIORITY_UPDATE_VIEW)
1461 def _on_play_button_toggled(self, button):
1462 if button.get_active():
1463 self._start_update_timer()
1465 if self._update_timeout_id
is not None:
1466 GLib.source_remove(self._update_timeout_id)
1468 def _quit(self, *dummy_args):
1469 if self._update_timeout_id
is not None:
1470 GLib.source_remove(self._update_timeout_id)
1471 self._update_timeout_id =
None 1472 self.simulation.quit =
True 1473 self.simulation.go.set()
1474 self.simulation.join()
1477 def _monkey_patch_ipython(self):
1484 original_runcode = self.ipython.runcode
1485 def runcode(ip, *args):
1487 self.simulation.lock.acquire()
1489 return original_runcode(*args)
1492 self.simulation.lock.release()
1494 self.ipython.runcode = types.MethodType(runcode, self.ipython)
1496 def autoscale_view(self):
1499 self._update_node_positions()
1500 positions = [node.get_position()
for node
in self.nodes.itervalues()]
1501 min_x, min_y =
min(x
for (x,y)
in positions),
min(y
for (x,y)
in positions)
1502 max_x, max_y =
max(x
for (x,y)
in positions),
max(y
for (x,y)
in positions)
1503 min_x_px, min_y_px = self.canvas.convert_to_pixels(min_x, min_y)
1504 max_x_px, max_y_px = self.canvas.convert_to_pixels(max_x, max_y)
1507 dx_px = max_x_px - min_x_px
1508 dy_px = max_y_px - min_y_px
1509 hadj = self._scrolled_window.get_hadjustment()
1510 vadj = self._scrolled_window.get_vadjustment()
1511 new_dx, new_dy = 1.5*dx_px, 1.5*dy_px
1513 if new_dx == 0
or new_dy == 0:
1516 self.zoom.set_value(
min(hadj.get_page_size()/new_dx, vadj.get_page_size()/new_dy))
1518 x1, y1 = self.canvas.convert_from_pixels(hadj.get_value(), vadj.get_value())
1519 x2, y2 = self.canvas.convert_from_pixels((hadj.get_value() +
1520 hadj.get_page_size()),
1522 vadj.get_page_size()))
1525 center_x = (min_x + max_x) / 2
1526 center_y = (min_y + max_y) / 2
1528 self.canvas.scroll_to(center_x - width/2, center_y - height/2)
1533 self.scan_topology()
1534 self.window.connect(
"delete-event", self._quit)
1536 GLib.timeout_add(200, self.autoscale_view)
1537 self.simulation.
start()
1544 self._monkey_patch_ipython()
1549 def on_root_button_press_event(self, view, target, event):
1550 if event.button == 1:
1551 self.select_node(
None)
1554 def on_node_button_press_event(self, view, target, event, node):
1555 button = event.button
1557 self.select_node(node)
1560 self.popup_node_menu(node, event)
1563 self.begin_node_drag(node, event)
1567 def on_node_button_release_event(self, view, target, event, node):
1568 if event.button == 2:
1569 self.end_node_drag(node)
1573 class NodeDragState(object):
1574 def __init__(self, canvas_x0, canvas_y0, sim_x0, sim_y0):
1575 self.canvas_x0 = canvas_x0
1576 self.canvas_y0 = canvas_y0
1577 self.sim_x0 = sim_x0
1578 self.sim_y0 = sim_y0
1579 self.motion_signal =
None 1581 def begin_node_drag(self, node, event):
1582 self.simulation.lock.acquire()
1584 ns3_node = ns.network.NodeList.GetNode(node.node_index)
1585 mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1588 if self.node_drag_state
is not None:
1590 pos = mob.GetPosition()
1592 self.simulation.lock.release()
1593 devpos = self.canvas.get_window().get_device_position(event.device)
1594 x0, y0 = self.canvas.convert_from_pixels(devpos.x, devpos.y)
1595 self.node_drag_state = self.NodeDragState(x0, y0, pos.x, pos.y)
1596 self.node_drag_state.motion_signal = node.canvas_item.connect(
"motion-notify-event", self.node_drag_motion, node)
1598 def node_drag_motion(self, item, targe_item, event, node):
1599 self.simulation.lock.acquire()
1601 ns3_node = ns.network.NodeList.GetNode(node.node_index)
1602 mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1605 if self.node_drag_state
is None:
1607 devpos = self.canvas.get_window().get_device_position(event.device)
1608 canvas_x, canvas_y = self.canvas.convert_from_pixels(devpos.x, devpos.y)
1609 dx = (canvas_x - self.node_drag_state.canvas_x0)
1610 dy = (canvas_y - self.node_drag_state.canvas_y0)
1611 pos = mob.GetPosition()
1615 mob.SetPosition(pos)
1618 self.simulation.lock.release()
1621 def end_node_drag(self, node):
1622 if self.node_drag_state
is None:
1624 node.canvas_item.disconnect(self.node_drag_state.motion_signal)
1625 self.node_drag_state =
None 1627 def popup_node_menu(self, node, event):
1629 self.emit(
"populate-node-menu", node, menu)
1630 menu.popup(
None,
None,
None,
None, event.button, event.time)
1632 def _update_ipython_selected_node(self):
1641 if self.selected_node
is None:
1644 self.simulation.lock.acquire()
1646 ns3_node = ns.network.NodeList.GetNode(self.selected_node.node_index)
1648 self.simulation.lock.release()
1649 self.ipython.updateNamespace({
'selected_node': ns3_node})
1652 def select_node(self, node):
1653 if isinstance(node, ns.network.Node):
1654 node = self.nodes[node.GetId()]
1655 elif isinstance(node, (int, long)):
1656 node = self.nodes[node]
1657 elif isinstance(node, Node):
1662 raise TypeError(
"expected None, int, viz.Node or ns.network.Node, not %r" % node)
1664 if node
is self.selected_node:
1667 if self.selected_node
is not None:
1668 self.selected_node.selected =
False 1669 self.selected_node = node
1670 if self.selected_node
is not None:
1671 self.selected_node.selected =
True 1673 if self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
1674 if self.selected_node
is None:
1675 self.simulation.set_nodes_of_interest([])
1677 self.simulation.set_nodes_of_interest([self.selected_node.node_index])
1679 self._update_ipython_selected_node()
1682 def add_information_window(self, info_win):
1683 self.information_windows.append(info_win)
1684 self.simulation.lock.acquire()
1688 self.simulation.lock.release()
1690 def remove_information_window(self, info_win):
1691 self.information_windows.remove(info_win)
1693 def _canvas_tooltip_cb(self, canvas, x, y, keyboard_mode, tooltip):
1695 hadj = self._scrolled_window.get_hadjustment()
1696 vadj = self._scrolled_window.get_vadjustment()
1697 x, y = self.canvas.convert_from_pixels(hadj.get_value() + x, vadj.get_value() + y)
1698 item = self.canvas.get_item_at(x, y,
True)
1702 while item
is not None:
1703 obj = getattr(item,
"pyviz_object",
None)
1705 obj.tooltip_query(tooltip)
1707 item = item.props.parent
1710 def _get_export_file_name(self):
1711 sel = Gtk.FileChooserDialog(
"Save...", self.canvas.get_toplevel(),
1712 Gtk.FileChooserAction.SAVE,
1713 (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
1714 Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
1715 sel.set_default_response(Gtk.ResponseType.OK)
1716 sel.set_local_only(
True)
1717 sel.set_do_overwrite_confirmation(
True)
1718 sel.set_current_name(
"Unnamed.pdf")
1720 filter = Gtk.FileFilter()
1721 filter.set_name(
"Embedded PostScript")
1722 filter.add_mime_type(
"image/x-eps")
1723 sel.add_filter(filter)
1725 filter = Gtk.FileFilter()
1726 filter.set_name(
"Portable Document Graphics")
1727 filter.add_mime_type(
"application/pdf")
1728 sel.add_filter(filter)
1730 filter = Gtk.FileFilter()
1731 filter.set_name(
"Scalable Vector Graphics")
1732 filter.add_mime_type(
"image/svg+xml")
1733 sel.add_filter(filter)
1736 if resp != Gtk.ResponseType.OK:
1740 file_name = sel.get_filename()
1744 def _take_screenshot(self, dummy_button):
1746 file_name = self._get_export_file_name()
1747 if file_name
is None:
1751 x1 = self._scrolled_window.get_hadjustment().get_value()
1752 y1 = self._scrolled_window.get_vadjustment().get_value()
1753 x2 = x1 + self._scrolled_window.get_hadjustment().get_page_size()
1754 y2 = y1 + self._scrolled_window.get_vadjustment().get_page_size()
1755 bounds = GooCanvas.CanvasBounds()
1756 bounds.x1, bounds.y1 = self.canvas.convert_from_pixels(x1, y1)
1757 bounds.x2, bounds.y2 = self.canvas.convert_from_pixels(x2, y2)
1758 dest_width = bounds.x2 - bounds.x1
1759 dest_height = bounds.y2 - bounds.y1
1762 dummy, extension = os.path.splitext(file_name)
1763 extension = extension.lower()
1764 if extension ==
'.eps':
1765 surface = cairo.PSSurface(file_name, dest_width, dest_height)
1766 elif extension ==
'.pdf':
1767 surface = cairo.PDFSurface(file_name, dest_width, dest_height)
1768 elif extension ==
'.svg':
1769 surface = cairo.SVGSurface(file_name, dest_width, dest_height)
1771 dialog = Gtk.MessageDialog(parent = self.canvas.get_toplevel(),
1772 flags = Gtk.DialogFlags.DESTROY_WITH_PARENT,
1773 type = Gtk.MessageType.ERROR,
1774 buttons = Gtk.ButtonsType.OK,
1775 message_format =
"Unknown extension '%s' (valid extensions are '.eps', '.svg', and '.pdf')" 1782 cr = cairo.Context(surface)
1783 cr.translate(-bounds.x1, -bounds.y1)
1784 self.canvas.render(cr, bounds, self.zoom.get_value())
1788 def set_follow_node(self, node):
1789 if isinstance(node, ns.network.Node):
1790 node = self.nodes[node.GetId()]
1791 self.follow_node = node
1793 def _start_shell(self, dummy_button):
1794 if self.shell_window
is not None:
1795 self.shell_window.present()
1798 self.shell_window = Gtk.Window()
1799 self.shell_window.set_size_request(750,550)
1800 self.shell_window.set_resizable(
True)
1801 scrolled_window = Gtk.ScrolledWindow()
1802 scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,
1803 Gtk.PolicyType.AUTOMATIC)
1805 self.ipython.modify_font(Pango.FontDescription(SHELL_FONT))
1806 self.ipython.set_wrap_mode(Gtk.WrapMode.CHAR)
1808 scrolled_window.add(self.ipython)
1809 scrolled_window.show()
1810 self.shell_window.add(scrolled_window)
1811 self.shell_window.show()
1812 self.shell_window.connect(
'destroy', self._on_shell_window_destroy)
1814 self._update_ipython_selected_node()
1815 self.ipython.updateNamespace({
'viz': self})
1818 def _on_shell_window_destroy(self, window):
1819 self.shell_window =
None 1822 initialization_hooks = []
1826 Adds a callback to be called after 1827 the visualizer is initialized, like this:: 1828 initialization_hook(visualizer, *args) 1830 global initialization_hooks
1831 initialization_hooks.append((hook, args))
1840 viz.canvas.set_bounds(cx1, cy1, cx2, cy2)
1845 assert Visualizer.INSTANCE
is None 1846 if _import_error
is not None:
1848 print(
"No visualization support (%s)." % (str(_import_error),),
1850 ns.core.Simulator.Run()
1854 for hook, args
in initialization_hooks:
1855 GLib.idle_add(hook, viz, *args)
1856 ns.network.Packet.EnablePrinting()
_label_canvas_item
label canvas
def on_enter_notify_event(self, view, target, event)
On Enter event handle.
def transform_distance_simulation_to_canvas(d)
def __init__(self, viz)
Initializer function.
def _set_selected(self, value)
Set selected function.
_highlighted
is highlighted
def set_position(self, x, y)
Set position function.
def __init__(self, channel)
Initializer function.
def set_svg_icon(self, file_base_name, width=None, height=None, align_x=0.5, align_y=0.5)
Set a background SVG icon for the node.
def add_link(self, link)
Add link function.
def set_label(self, label)
Set a label for the node.
def _update_svg_position(self, x, y)
Update svg position.
def _update_appearance(self)
Update the node aspect to reflect the selected/highlighted state.
def __init__(self, node1, node2)
Initializer function.
def get_position(self)
Get position function.
pause_messages
pause messages
def on_leave_notify_event(self, view, target, event)
On Leave event handle.
def transform_point_simulation_to_canvas(x, y)
_has_mobility
has mobility model
def set_bounds(x1, y1, x2, y2)
highlighted
highlighted property
def _update_position(self)
Update position function.
visualizer
visualier object
def get_position(self)
Initializer function.
def remove_link(self, link)
Remove link function.
def _get_highlighted(self)
Get highlighted function.
def add_initialization_hook(hook, args)
def update_points(self)
Update points function.
def tooltip_query(self, tooltip)
Query tooltip.
def __init__(self, visualizer, node_index)
def set_position(self, x, y)
Initializer function.
def set_color(self, color)
Set color function.
def lookup_netdevice_traits(class_type)
def _get_selected(self)
Get selected function.
sim_helper
helper function
def _set_highlighted(self, value)
Set highlighted function.
def set_nodes_of_interest(self, nodes)
Set nodes of interest function.
def has_mobility(self)
Has mobility function.
def run(self)
Initializer function.
def set_size(self, size)
Set size function.
def transform_distance_canvas_to_simulation(d)