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" 34 if sys.version_info > (3,):
39 gi.require_version(
'GooCanvas',
'2.0')
40 gi.require_version(
'Gtk',
'3.0')
41 gi.require_version(
'Gdk',
'3.0')
42 from gi.repository
import GObject
43 from gi.repository
import GLib
45 gi.require_foreign(
"cairo")
47 from gi.repository
import Gtk
48 from gi.repository
import Gdk
49 from gi.repository
import Pango
50 from gi.repository
import GooCanvas
58 except ImportError
as e:
60 import dummy_threading
as threading
65 import ipython_viewxxxxxxxxxx
69 from .base
import InformationWindow, PyVizObject, Link, lookup_netdevice_traits, PIXELS_PER_METER
70 from .base
import transform_distance_simulation_to_canvas, transform_point_simulation_to_canvas
71 from .base
import transform_distance_canvas_to_simulation, transform_point_canvas_to_simulation
72 from .base
import load_plugins, register_plugin, plugins
75 PI_TIMES_2 = math.pi*2
117 'query-extra-tooltip-info': (GObject.SignalFlags.RUN_LAST,
None, (object,)),
121 """ Initialize function. 122 @param self The object pointer. 123 @param visualizer: visualizer object 124 @param node_index: node index 149 def set_svg_icon(self, file_base_name, width=None, height=None, align_x=0.5, align_y=0.5):
151 Set a background SVG icon for the node. 153 @param file_base_name: base file name, including .svg 154 extension, of the svg file. Place the file in the folder 155 src/contrib/visualizer/resource. 157 @param width: scale to the specified width, in meters 158 @param height: scale to the specified height, in meters 160 @param align_x: horizontal alignment of the icon relative to 161 the node position, from 0 (icon fully to the left of the node) 162 to 1.0 (icon fully to the right of the node) 164 @param align_y: vertical alignment of the icon relative to the 165 node position, from 0 (icon fully to the top of the node) to 166 1.0 (icon fully to the bottom of the node) 168 @return a ValueError exception if invalid dimensions. 171 if width
is None and height
is None:
172 raise ValueError(
"either width or height must be given")
173 rsvg_handle = svgitem.rsvg_handle_factory(file_base_name)
178 self.
svg_item.props.pointer_events = GooCanvas.CanvasPointerEvents.NONE
180 self.
svg_item.props.visibility = GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD
181 if width
is not None:
183 if height
is not None:
197 Set a label for the node. 199 @param self: class object. 200 @param label: label to set 202 @return: an exception if invalid parameter. 204 assert isinstance(label, basestring)
212 @param self: class object. 227 @param self: class object. 228 @param tooltip: tooltip 233 ns3_node = ns.network.NodeList.GetNode(self.
node_index)
234 ipv4 = ns3_node.GetObject(ns.internet.Ipv4.GetTypeId())
235 ipv6 = ns3_node.GetObject(ns.internet.Ipv6.GetTypeId())
237 name =
'<b><u>Node %i</u></b>' % self.
node_index 238 node_name = ns.core.Names.FindName (ns3_node)
239 if len(node_name)!=0:
240 name +=
' <b>(' + node_name +
')</b>' 245 self.emit(
"query-extra-tooltip-info", lines)
247 mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
249 lines.append(
' <b>Mobility Model</b>: %s' % mob.GetInstanceTypeId().GetName())
251 for devI
in range(ns3_node.GetNDevices()):
253 lines.append(
' <u>NetDevice %i:</u>' % devI)
254 dev = ns3_node.GetDevice(devI)
255 name = ns.core.Names.FindName(dev)
257 lines.append(
' <b>Name:</b> %s' % name)
258 devname = dev.GetInstanceTypeId().GetName()
259 lines.append(
' <b>Type:</b> %s' % devname)
262 ipv4_idx = ipv4.GetInterfaceForDevice(dev)
265 '%s/%s' % (ipv4.GetAddress(ipv4_idx, i).GetLocal(),
266 ipv4.GetAddress(ipv4_idx, i).GetMask())
267 for i
in range(ipv4.GetNAddresses(ipv4_idx))]
268 lines.append(
' <b>IPv4 Addresses:</b> %s' %
'; '.join(addresses))
271 ipv6_idx = ipv6.GetInterfaceForDevice(dev)
274 '%s/%s' % (ipv6.GetAddress(ipv6_idx, i).GetAddress(),
275 ipv6.GetAddress(ipv6_idx, i).GetPrefix())
276 for i
in range(ipv6.GetNAddresses(ipv6_idx))]
277 lines.append(
' <b>IPv6 Addresses:</b> %s' %
'; '.join(addresses))
279 lines.append(
' <b>MAC Address:</b> %s' % (dev.GetAddress(),))
281 tooltip.set_markup(
'\n'.join(lines))
287 On Enter event handle. 289 @param self: class object. 291 @param target: target 298 On Leave event handle. 300 @param self: class object. 302 @param target: target 310 Set selected function. 312 @param self: class object. 313 @param value: selected value 320 Get selected function. 322 @param self: class object. 323 @return selected status 327 selected = property(_get_selected, _set_selected)
331 Set highlighted function. 333 @param self: class object. 334 @param value: selected value 341 Get highlighted function. 343 @param self: class object. 344 @return highlighted status 348 highlighted = property(_get_highlighted, _set_highlighted)
354 @param self: class object. 355 @param size: selected size 363 Update the node aspect to reflect the selected/highlighted state 365 @param self: class object. 374 fill_color_rgba = (self.
_color & 0xffffff00) | alpha
375 self.
canvas_item.set_properties(radius_x=size, radius_y=size,
376 fill_color_rgba=fill_color_rgba)
380 line_width = size*.15
382 stroke_color =
'yellow' 384 stroke_color =
'black' 385 self.
canvas_item.set_properties(line_width=line_width, stroke_color=stroke_color)
387 if self.
_label is not None:
390 font=
"Sans Serif 10",
391 fill_color_rgba=0x808080ff,
392 alignment=Pango.Alignment.CENTER,
393 anchor=GooCanvas.CanvasAnchorType.N,
394 parent=self.
visualizer.canvas.get_root_item(),
395 pointer_events=GooCanvas.CanvasPointerEvents.NONE)
398 self.
_label_canvas_item.set_properties(visibility=GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD,
404 Set position function. 406 @param self: class object. 416 for link
in self.
links:
427 (min_x, min_y, max_x, max_y) = bounds
429 min_x =
min(x, min_x)
430 min_y =
min(y, min_y)
431 max_x =
max(x, max_x)
432 max_y =
max(y, max_y)
434 new_bounds = (min_x, min_y, max_x, max_y)
436 if new_bounds != bounds:
437 self.
visualizer.canvas.set_bounds(*new_bounds)
444 Get position function. 446 @param self: class object. 447 @return x and y position 453 Update position function. 455 @param self: class object. 465 @param self: class object. 466 @param color: color to set. 469 if isinstance(color, str):
470 color = Gdk.color_parse(color)
471 color = ((color.red>>8) << 24) | ((color.green>>8) << 16) | ((color.blue>>8) << 8) | 0xff
479 @param self: class object. 480 @param link: link to add. 483 assert isinstance(link, Link)
484 self.
links.append(link)
488 Remove link function. 490 @param self: class object. 491 @param link: link to add. 494 assert isinstance(link, Link)
495 self.
links.remove(link)
500 Has mobility function. 502 @param self: class object. 503 @return modility option 506 node = ns.network.NodeList.GetNode(self.
node_index)
507 mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
523 Initializer function. 525 @param self: class object. 526 @param channel: channel. 536 self.
canvas_item.line_dash=GooCanvas.CanvasLineDash([10.0, 10.0])
537 self.
canvas_item.visibility=GooCanvas.CanvasItemVisibility.VISIBLE
543 Initializer function. 545 @param self: class object. 546 @param x: x position. 547 @param y: y position. 553 for link
in self.
links:
558 Initializer function. 560 @param self: class object. 561 @return x / y position. 577 Initializer function. 579 @param self: class object. 580 @param node1: class object. 581 @param node2: class object. 584 assert isinstance(node1, Node)
585 assert isinstance(node2, (Node, Channel))
588 self.
canvas_item = GooCanvas.CanvasPath(line_width=1.0, stroke_color=
"black")
590 self.
node1.links.append(self)
591 self.
node2.links.append(self)
595 Update points function. 597 @param self: class object. 600 pos1_x, pos1_y = self.
node1.get_position()
601 pos2_x, pos2_y = self.
node2.get_position()
602 self.
canvas_item.set_property(
"data",
"M %r %r L %r %r" % (pos1_x, pos1_y, pos2_x, pos2_y))
623 Initializer function. 625 @param self: class object. 626 @param viz: class object. 629 super(SimulationThread, self).
__init__()
630 assert isinstance(viz, Visualizer)
633 self.
go = threading.Event()
642 Set nodes of interest function. 644 @param self: class object. 645 @param nodes: class object. 656 Initializer function. 658 @param self: class object. 672 if ns3.core.Simulator.IsFinished():
673 self.
viz.play_button.set_sensitive(
False)
681 GLib.idle_add(self.
viz.update_model, priority=PRIORITY_UPDATE_MODEL)
708 if _import_error
is None:
712 'populate-node-menu': (GObject.SignalFlags.RUN_LAST,
None, (object, Gtk.Menu,)),
716 'simulation-periodic-update': (GObject.SignalFlags.RUN_LAST,
None, ()),
719 'topology-scanned': (GObject.SignalFlags.RUN_LAST,
None, ()),
722 'update-view': (GObject.SignalFlags.RUN_LAST,
None, ()),
728 Initializer function. 730 @param self: class object. 733 assert Visualizer.INSTANCE
is None 734 Visualizer.INSTANCE = self
735 super(Visualizer, self).__init__()
740 self.time_label =
None 741 self.play_button =
None 743 self._scrolled_window =
None 745 self.links_group = GooCanvas.CanvasGroup()
746 self.channels_group = GooCanvas.CanvasGroup()
747 self.nodes_group = GooCanvas.CanvasGroup()
749 self._update_timeout_id =
None 751 self.selected_node =
None 753 self.information_windows = []
754 self._transmission_arrows = []
755 self._last_transmissions = []
756 self._drop_arrows = []
757 self._last_drops = []
758 self._show_transmissions_mode =
None 759 self.set_show_transmissions_mode(ShowTransmissionsMode.ALL)
760 self._panning_state =
None 761 self.node_size_adjustment =
None 762 self.transmissions_smoothing_adjustment =
None 763 self.sample_period = SAMPLE_PERIOD
764 self.node_drag_state =
None 765 self.follow_node =
None 766 self.shell_window =
None 770 for plugin
in plugins:
773 def set_show_transmissions_mode(self, mode):
775 Set show transmission mode. 777 @param self: class object. 778 @param mode: mode to set. 781 assert isinstance(mode, ShowTransmissionsMode)
782 self._show_transmissions_mode = mode
783 if self._show_transmissions_mode == ShowTransmissionsMode.ALL:
784 self.simulation.set_nodes_of_interest(
list(range(ns.network.NodeList.GetNNodes())))
785 elif self._show_transmissions_mode == ShowTransmissionsMode.NONE:
786 self.simulation.set_nodes_of_interest([])
787 elif self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
788 if self.selected_node
is None:
789 self.simulation.set_nodes_of_interest([])
791 self.simulation.set_nodes_of_interest([self.selected_node.node_index])
793 def _create_advanced_controls(self):
795 Create advanced controls. 797 @param self: class object. 800 expander = Gtk.Expander.new(
"Advanced")
803 main_vbox = GObject.new(Gtk.VBox, border_width=8, visible=
True)
804 expander.add(main_vbox)
806 main_hbox1 = GObject.new(Gtk.HBox, border_width=8, visible=
True)
807 main_vbox.pack_start(main_hbox1,
True,
True, 0)
809 show_transmissions_group = GObject.new(Gtk.HeaderBar,
810 title=
"Show transmissions",
812 main_hbox1.pack_start(show_transmissions_group,
False,
False, 8)
814 vbox = Gtk.VBox(homogeneous=
True, spacing=4)
816 show_transmissions_group.add(vbox)
818 all_nodes = Gtk.RadioButton.new(
None)
819 all_nodes.set_label(
"All nodes")
820 all_nodes.set_active(
True)
824 selected_node = Gtk.RadioButton.new_from_widget(all_nodes)
826 selected_node.set_label(
"Selected node")
827 selected_node.set_active(
False)
828 vbox.add(selected_node)
830 no_node = Gtk.RadioButton.new_from_widget(all_nodes)
832 no_node.set_label(
"Disabled")
833 no_node.set_active(
False)
837 if radio.get_active():
838 self.set_show_transmissions_mode(ShowTransmissionsMode.ALL)
839 all_nodes.connect(
"toggled", toggled)
842 if radio.get_active():
843 self.set_show_transmissions_mode(ShowTransmissionsMode.NONE)
844 no_node.connect(
"toggled", toggled)
847 if radio.get_active():
848 self.set_show_transmissions_mode(ShowTransmissionsMode.SELECTED)
849 selected_node.connect(
"toggled", toggled)
852 misc_settings_group = GObject.new(Gtk.HeaderBar, title=
"Misc Settings", visible=
True)
853 main_hbox1.pack_start(misc_settings_group,
False,
False, 8)
854 settings_hbox = GObject.new(Gtk.HBox, border_width=8, visible=
True)
855 misc_settings_group.add(settings_hbox)
858 vbox = GObject.new(Gtk.VBox, border_width=0, visible=
True)
859 scale = GObject.new(Gtk.HScale, visible=
True, digits=2)
860 vbox.pack_start(scale,
True,
True, 0)
861 vbox.pack_start(GObject.new(Gtk.Label, label=
"Node Size", visible=
True),
True,
True, 0)
862 settings_hbox.pack_start(vbox,
False,
False, 6)
863 self.node_size_adjustment = scale.get_adjustment()
864 def node_size_changed(adj):
865 for node
in self.nodes.values():
866 node.set_size(adj.get_value())
867 self.node_size_adjustment.connect(
"value-changed", node_size_changed)
868 self.node_size_adjustment.set_lower(0.01)
869 self.node_size_adjustment.set_upper(20)
870 self.node_size_adjustment.set_step_increment(0.1)
871 self.node_size_adjustment.set_value(DEFAULT_NODE_SIZE)
874 vbox = GObject.new(Gtk.VBox, border_width=0, visible=
True)
875 scale = GObject.new(Gtk.HScale, visible=
True, digits=1)
876 vbox.pack_start(scale,
True,
True, 0)
877 vbox.pack_start(GObject.new(Gtk.Label, label=
"Tx. Smooth Factor (s)", visible=
True),
True,
True, 0)
878 settings_hbox.pack_start(vbox,
False,
False, 6)
879 self.transmissions_smoothing_adjustment = scale.get_adjustment()
880 adj = self.transmissions_smoothing_adjustment
883 adj.set_step_increment(0.1)
884 adj.set_value(DEFAULT_TRANSMISSIONS_MEMORY*0.1)
889 class _PanningState(object):
892 __slots__ = [
'initial_mouse_pos',
'initial_canvas_pos',
'motion_signal']
894 def _begin_panning(self, widget, event):
896 Set show trnamission mode. 898 @param self: class object. 899 @param mode: mode to set. 902 display = self.canvas.get_window().get_display()
903 cursor = Gdk.Cursor.new_for_display(display, Gdk.CursorType.FLEUR)
904 self.canvas.get_window().set_cursor(cursor)
905 self._panning_state = self._PanningState()
906 pos = widget.get_window().get_device_position(event.device)
907 self._panning_state.initial_mouse_pos = (pos.x, pos.y)
908 x = self._scrolled_window.get_hadjustment().get_value()
909 y = self._scrolled_window.get_vadjustment().get_value()
910 self._panning_state.initial_canvas_pos = (x, y)
911 self._panning_state.motion_signal = self.canvas.connect(
"motion-notify-event", self._panning_motion)
913 def _end_panning(self, event):
915 End panning function. 917 @param self: class object. 918 @param event: active event. 921 if self._panning_state
is None:
923 self.canvas.get_window().set_cursor(
None)
924 self.canvas.disconnect(self._panning_state.motion_signal)
925 self._panning_state =
None 927 def _panning_motion(self, widget, event):
929 Panning motion function. 931 @param self: class object. 932 @param widget: widget. 934 @return true if successful 936 assert self._panning_state
is not None 938 pos = widget.get_window().get_device_position(event.device)
941 x, y = event.x, event.y
943 hadj = self._scrolled_window.get_hadjustment()
944 vadj = self._scrolled_window.get_vadjustment()
945 mx0, my0 = self._panning_state.initial_mouse_pos
946 cx0, cy0 = self._panning_state.initial_canvas_pos
950 hadj.set_value(cx0 - dx)
951 vadj.set_value(cy0 - dy)
954 def _canvas_button_press(self, widget, event):
955 if event.button == 2:
956 self._begin_panning(widget, event)
960 def _canvas_button_release(self, dummy_widget, event):
961 if event.button == 2:
962 self._end_panning(event)
966 def _canvas_scroll_event(self, dummy_widget, event):
967 if event.direction == Gdk.ScrollDirection.UP:
968 self.zoom.set_value(self.zoom.get_value() * 1.25)
970 elif event.direction == Gdk.ScrollDirection.DOWN:
971 self.zoom.set_value(self.zoom.get_value() / 1.25)
975 def get_hadjustment(self):
976 return self._scrolled_window.get_hadjustment()
977 def get_vadjustment(self):
978 return self._scrolled_window.get_vadjustment()
980 def create_gui(self):
981 self.window = Gtk.Window()
984 self.window.add(vbox)
987 self.canvas = GooCanvas.Canvas()
988 self.canvas.connect_after(
"button-press-event", self._canvas_button_press)
989 self.canvas.connect_after(
"button-release-event", self._canvas_button_release)
990 self.canvas.connect(
"scroll-event", self._canvas_scroll_event)
991 self.canvas.props.has_tooltip =
True 992 self.canvas.connect(
"query-tooltip", self._canvas_tooltip_cb)
994 sw = Gtk.ScrolledWindow(); sw.show()
995 self._scrolled_window = sw
997 vbox.pack_start(sw,
True,
True, 4)
998 self.canvas.set_size_request(600, 450)
999 self.canvas.
set_bounds(-10000, -10000, 10000, 10000)
1000 self.canvas.scroll_to(0, 0)
1003 self.canvas.get_root_item().add_child(self.links_group, -1)
1004 self.links_group.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1006 self.canvas.get_root_item().add_child(self.channels_group, -1)
1007 self.channels_group.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1008 self.channels_group.raise_(self.links_group)
1010 self.canvas.get_root_item().add_child(self.nodes_group, -1)
1011 self.nodes_group.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1012 self.nodes_group.raise_(self.channels_group)
1016 hbox = Gtk.HBox(); hbox.show()
1017 vbox.pack_start(hbox,
False,
False, 4)
1020 zoom_adj = Gtk.Adjustment(value=1.0, lower=0.01, upper=10.0,
1021 step_increment=0.02,
1024 self.zoom = zoom_adj
1025 def _zoom_changed(adj):
1026 self.canvas.set_scale(adj.get_value())
1027 zoom_adj.connect(
"value-changed", _zoom_changed)
1028 zoom = Gtk.SpinButton.new(zoom_adj, 0.1, 1)
1031 hbox.pack_start(GObject.new(Gtk.Label, label=
" Zoom:", visible=
True),
False,
False, 4)
1032 hbox.pack_start(zoom,
False,
False, 4)
1033 _zoom_changed(zoom_adj)
1036 speed_adj = Gtk.Adjustment(value=1.0, lower=0.01, upper=10.0,
1037 step_increment=0.02,
1038 page_increment=1.0, page_size=0)
1039 def _speed_changed(adj):
1040 self.speed = adj.get_value()
1041 self.sample_period = SAMPLE_PERIOD*adj.get_value()
1042 self._start_update_timer()
1043 speed_adj.connect(
"value-changed", _speed_changed)
1044 speed = Gtk.SpinButton.new(speed_adj, 1, 0)
1047 hbox.pack_start(GObject.new(Gtk.Label, label=
" Speed:", visible=
True),
False,
False, 4)
1048 hbox.pack_start(speed,
False,
False, 4)
1049 _speed_changed(speed_adj)
1052 self.time_label = GObject.new(Gtk.Label, label=
" Speed:", visible=
True)
1053 self.time_label.set_width_chars(20)
1054 hbox.pack_start(self.time_label,
False,
False, 4)
1057 screenshot_button = GObject.new(Gtk.Button,
1059 relief=Gtk.ReliefStyle.NONE, focus_on_click=
False,
1061 hbox.pack_start(screenshot_button,
False,
False, 4)
1063 def load_button_icon(button, icon_name):
1067 sys.stderr.write(
"Could not load icon %s due to missing gnomedesktop Python module\n" % icon_name)
1069 icon = gnomedesktop.find_icon(Gtk.IconTheme.get_default(), icon_name, 16, 0)
1070 if icon
is not None:
1071 button.props.image = GObject.new(Gtk.Image, file=icon, visible=
True)
1073 load_button_icon(screenshot_button,
"applets-screenshooter")
1074 screenshot_button.connect(
"clicked", self._take_screenshot)
1077 if ipython_view
is not None:
1078 shell_button = GObject.new(Gtk.Button,
1080 relief=Gtk.ReliefStyle.NONE, focus_on_click=
False,
1082 hbox.pack_start(shell_button,
False,
False, 4)
1083 load_button_icon(shell_button,
"gnome-terminal")
1084 shell_button.connect(
"clicked", self._start_shell)
1087 self.play_button = GObject.new(Gtk.ToggleButton,
1088 image=GObject.new(Gtk.Image, stock=Gtk.STOCK_MEDIA_PLAY, visible=
True),
1089 label=
"Simulate (F3)",
1090 relief=Gtk.ReliefStyle.NONE, focus_on_click=
False,
1091 use_stock=
True, visible=
True)
1092 accel_group = Gtk.AccelGroup()
1093 self.window.add_accel_group(accel_group)
1094 self.play_button.add_accelerator(
"clicked", accel_group,
1095 Gdk.KEY_F3, 0, Gtk.AccelFlags.VISIBLE)
1096 self.play_button.connect(
"toggled", self._on_play_button_toggled)
1097 hbox.pack_start(self.play_button,
False,
False, 4)
1099 self.canvas.get_root_item().connect(
"button-press-event", self.on_root_button_press_event)
1101 vbox.pack_start(self._create_advanced_controls(),
False,
False, 4)
1103 display = Gdk.Display.get_default()
1105 monitor = display.get_primary_monitor()
1106 geometry = monitor.get_geometry()
1107 scale_factor = monitor.get_scale_factor()
1108 except AttributeError:
1109 screen = display.get_default_screen()
1110 monitor_id = screen.get_primary_monitor()
1111 geometry = screen.get_monitor_geometry(monitor_id)
1112 scale_factor = screen.get_monitor_scale_factor(monitor_id)
1113 width = scale_factor * geometry.width
1114 height = scale_factor * geometry.height
1115 self.window.set_default_size(width * 2 / 3, height * 2 / 3)
1118 def scan_topology(self):
1119 print(
"scanning topology: %i nodes..." % (ns.network.NodeList.GetNNodes(),))
1120 graph = pygraphviz.AGraph()
1122 for nodeI
in range(ns.network.NodeList.GetNNodes()):
1124 if seen_nodes == 100:
1125 print(
"scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns.network.NodeList.GetNNodes()))
1127 node = ns.network.NodeList.GetNode(nodeI)
1128 node_name =
"Node %i" % nodeI
1129 node_view = self.get_node(nodeI)
1131 mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1132 if mobility
is not None:
1133 node_view.set_color(
"red")
1134 pos = mobility.GetPosition()
1138 graph.add_node(node_name)
1140 for devI
in range(node.GetNDevices()):
1141 device = node.GetDevice(devI)
1143 if device_traits.is_wireless:
1145 if device_traits.is_virtual:
1147 channel = device.GetChannel()
1148 if channel.GetNDevices() > 2:
1149 if REPRESENT_CHANNELS_AS_NODES:
1151 if mobility
is None:
1152 channel_name =
"Channel %s" % id(channel)
1153 graph.add_edge(node_name, channel_name)
1154 self.get_channel(channel)
1155 self.create_link(self.get_node(nodeI), self.get_channel(channel))
1158 for otherDevI
in range(channel.GetNDevices()):
1159 otherDev = channel.GetDevice(otherDevI)
1160 otherNode = otherDev.GetNode()
1161 otherNodeView = self.get_node(otherNode.GetId())
1162 if otherNode
is not node:
1163 if mobility
is None and not otherNodeView.has_mobility:
1164 other_node_name =
"Node %i" % otherNode.GetId()
1165 graph.add_edge(node_name, other_node_name)
1166 self.create_link(self.get_node(nodeI), otherNodeView)
1168 for otherDevI
in range(channel.GetNDevices()):
1169 otherDev = channel.GetDevice(otherDevI)
1170 otherNode = otherDev.GetNode()
1171 otherNodeView = self.get_node(otherNode.GetId())
1172 if otherNode
is not node:
1173 if mobility
is None and not otherNodeView.has_mobility:
1174 other_node_name =
"Node %i" % otherNode.GetId()
1175 graph.add_edge(node_name, other_node_name)
1176 self.create_link(self.get_node(nodeI), otherNodeView)
1178 print(
"scanning topology: calling graphviz layout")
1179 graph.layout(LAYOUT_ALGORITHM)
1180 for node
in graph.iternodes():
1182 node_type, node_id = node.split(
' ')
1183 pos_x, pos_y = [float(s)
for s
in node.attr[
'pos'].split(
',')]
1184 if node_type ==
'Node':
1185 obj = self.nodes[int(node_id)]
1186 elif node_type ==
'Channel':
1187 obj = self.channels[int(node_id)]
1188 obj.set_position(pos_x, pos_y)
1190 print(
"scanning topology: all done.")
1191 self.emit(
"topology-scanned")
1193 def get_node(self, index):
1195 return self.nodes[index]
1197 node =
Node(self, index)
1198 self.nodes[index] = node
1199 self.nodes_group.add_child(node.canvas_item, -1)
1200 node.canvas_item.connect(
"button-press-event", self.on_node_button_press_event, node)
1201 node.canvas_item.connect(
"button-release-event", self.on_node_button_release_event, node)
1204 def get_channel(self, ns3_channel):
1206 return self.channels[id(ns3_channel)]
1208 channel =
Channel(ns3_channel)
1209 self.channels[id(ns3_channel)] = channel
1210 self.channels_group.add_child(channel.canvas_item, -1)
1213 def create_link(self, node, node_or_channel):
1215 self.links_group.add_child(link.canvas_item, -1)
1216 link.canvas_item.lower(
None)
1218 def update_view(self):
1221 self.time_label.set_text(
"Time: %f s" % ns.core.Simulator.Now().GetSeconds())
1223 self._update_node_positions()
1226 for info_win
in self.information_windows:
1229 self._update_transmissions_view()
1230 self._update_drops_view()
1232 self.emit(
"update-view")
1234 def _update_node_positions(self):
1235 for node
in self.nodes.values():
1236 if node.has_mobility:
1237 ns3_node = ns.network.NodeList.GetNode(node.node_index)
1238 mobility = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1239 if mobility
is not None:
1240 pos = mobility.GetPosition()
1242 node.set_position(x, y)
1243 if node
is self.follow_node:
1244 hadj = self._scrolled_window.get_hadjustment()
1245 vadj = self._scrolled_window.get_vadjustment()
1246 px, py = self.canvas.convert_to_pixels(x, y)
1247 hadj.set_value(px - hadj.get_page_size() / 2)
1248 vadj.set_value(py - vadj.get_page_size() / 2)
1250 def center_on_node(self, node):
1251 if isinstance(node, ns.network.Node):
1252 node = self.nodes[node.GetId()]
1253 elif isinstance(node, (int, long)):
1254 node = self.nodes[node]
1255 elif isinstance(node, Node):
1258 raise TypeError(
"expected int, viz.Node or ns.network.Node, not %r" % node)
1260 x, y = node.get_position()
1261 hadj = self._scrolled_window.get_hadjustment()
1262 vadj = self._scrolled_window.get_vadjustment()
1263 px, py = self.canvas.convert_to_pixels(x, y)
1264 hadj.set_value(px - hadj.get_page_size() / 2)
1265 vadj.set_value(py - vadj.get_page_size() / 2)
1267 def update_model(self):
1268 self.simulation.lock.acquire()
1270 self.emit(
"simulation-periodic-update")
1272 self.simulation.lock.release()
1274 def do_simulation_periodic_update(self):
1275 smooth_factor = int(self.transmissions_smoothing_adjustment.get_value()*10)
1277 transmissions = self.simulation.sim_helper.GetTransmissionSamples()
1278 self._last_transmissions.append(transmissions)
1279 while len(self._last_transmissions) > smooth_factor:
1280 self._last_transmissions.pop(0)
1282 drops = self.simulation.sim_helper.GetPacketDropSamples()
1283 self._last_drops.append(drops)
1284 while len(self._last_drops) > smooth_factor:
1285 self._last_drops.pop(0)
1287 def _get_label_over_line_position(self, pos1_x, pos1_y, pos2_x, pos2_y):
1288 hadj = self._scrolled_window.get_hadjustment()
1289 vadj = self._scrolled_window.get_vadjustment()
1290 bounds_x1, bounds_y1 = self.canvas.convert_from_pixels(hadj.get_value(), vadj.get_value())
1291 bounds_x2, bounds_y2 = self.canvas.convert_from_pixels(hadj.get_value() + hadj.get_page_size(),
1292 vadj.get_value() + vadj.get_page_size())
1293 pos1_x, pos1_y, pos2_x, pos2_y = ns.visualizer.PyViz.LineClipping(bounds_x1, bounds_y1,
1294 bounds_x2, bounds_y2,
1297 return (pos1_x + pos2_x)/2, (pos1_y + pos2_y)/2
1299 def _update_transmissions_view(self):
1300 transmissions_average = {}
1301 for transmission_set
in self._last_transmissions:
1302 for transmission
in transmission_set:
1303 key = (transmission.transmitter.GetId(), transmission.receiver.GetId())
1304 rx_bytes, count = transmissions_average.get(key, (0, 0))
1305 rx_bytes += transmission.bytes
1307 transmissions_average[key] = rx_bytes, count
1309 old_arrows = self._transmission_arrows
1310 for arrow, label
in old_arrows:
1311 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1312 label.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1315 k = self.node_size_adjustment.get_value()/5
1317 for (transmitter_id, receiver_id), (rx_bytes, rx_count)
in transmissions_average.items():
1318 transmitter = self.get_node(transmitter_id)
1319 receiver = self.get_node(receiver_id)
1321 arrow, label = old_arrows.pop()
1323 arrow = GooCanvas.CanvasPolyline(line_width=2.0, stroke_color_rgba=0x00C000C0, close_path=
False, end_arrow=
True, pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1324 arrow.set_property(
"parent", self.canvas.get_root_item())
1327 label = GooCanvas.CanvasText(parent=self.canvas.get_root_item(), pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1330 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1331 line_width =
max(0.1, math.log(float(rx_bytes)/rx_count/self.sample_period)*k)
1332 arrow.set_property(
"line-width", line_width)
1334 pos1_x, pos1_y = transmitter.get_position()
1335 pos2_x, pos2_y = receiver.get_position()
1336 points = GooCanvas.CanvasPoints.new(2)
1337 points.set_point(0, pos1_x, pos1_y)
1338 points.set_point(1, pos2_x, pos2_y)
1339 arrow.set_property(
"points", points)
1341 kbps = float(rx_bytes*8)/1e3/rx_count/self.sample_period
1342 label.set_properties(visibility=GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD,
1343 visibility_threshold=0.5,
1344 font=(
"Sans Serif %f" % int(1+BITRATE_FONT_SIZE*k)))
1345 angle = math.atan2((pos2_y - pos1_y), (pos2_x - pos1_x))
1346 if -PI_OVER_2 <= angle <= PI_OVER_2:
1347 label.set_properties(text=(
"%.2f kbit/s →" % (kbps,)),
1348 alignment=Pango.Alignment.CENTER,
1349 anchor=GooCanvas.CanvasAnchorType.S,
1350 x=0, y=-line_width/2)
1352 label.set_properties(text=(
"← %.2f kbit/s" % (kbps,)),
1353 alignment=Pango.Alignment.CENTER,
1354 anchor=GooCanvas.CanvasAnchorType.N,
1355 x=0, y=line_width/2)
1357 lx, ly = self._get_label_over_line_position(pos1_x, pos1_y,
1362 label.set_transform(M)
1365 warnings.warn(
"PyGobject bug causing label position error; " 1366 "should be fixed in PyGObject >= 3.29.1")
1367 label.set_properties(x=(lx + label.props.x),
1368 y=(ly + label.props.y))
1370 new_arrows.append((arrow, label))
1372 self._transmission_arrows = new_arrows + old_arrows
1375 def _update_drops_view(self):
1377 for drop_set
in self._last_drops:
1378 for drop
in drop_set:
1379 key = drop.transmitter.GetId()
1380 drop_bytes, count = drops_average.get(key, (0, 0))
1381 drop_bytes += drop.bytes
1383 drops_average[key] = drop_bytes, count
1385 old_arrows = self._drop_arrows
1386 for arrow, label
in old_arrows:
1387 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1388 label.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1392 vadjustment = self._scrolled_window.get_vadjustment()
1393 bottom_y = vadjustment.get_value() + vadjustment.get_page_size()
1394 dummy, edge_y = self.canvas.convert_from_pixels(0, bottom_y)
1396 k = self.node_size_adjustment.get_value()/5
1398 for transmitter_id, (drop_bytes, drop_count)
in drops_average.items():
1399 transmitter = self.get_node(transmitter_id)
1401 arrow, label = old_arrows.pop()
1403 arrow = GooCanvas.CanvasPolyline(line_width=2.0, stroke_color_rgba=0xC00000C0, close_path=
False, end_arrow=
True, pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1404 arrow.set_property(
"parent", self.canvas.get_root_item())
1407 label = GooCanvas.CanvasText(pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1408 label.set_property(
"parent", self.canvas.get_root_item())
1411 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1412 arrow.set_property(
"line-width",
max(0.1, math.log(float(drop_bytes)/drop_count/self.sample_period)*k))
1413 pos1_x, pos1_y = transmitter.get_position()
1414 pos2_x, pos2_y = pos1_x, edge_y
1415 points = GooCanvas.CanvasPoints.new(2)
1416 points.set_point(0, pos1_x, pos1_y)
1417 points.set_point(1, pos2_x, pos2_y)
1418 arrow.set_property(
"points", points)
1420 label.set_properties(visibility=GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD,
1421 visibility_threshold=0.5,
1422 font=(
"Sans Serif %i" % int(1+BITRATE_FONT_SIZE*k)),
1423 text=(
"%.2f kbit/s" % (float(drop_bytes*8)/1e3/drop_count/self.sample_period,)),
1424 alignment=Pango.Alignment.CENTER,
1425 x=(pos1_x + pos2_x)/2,
1426 y=(pos1_y + pos2_y)/2)
1428 new_arrows.append((arrow, label))
1430 self._drop_arrows = new_arrows + old_arrows
1433 def update_view_timeout(self):
1437 while not self.simulation.lock.acquire(
False):
1438 while Gtk.events_pending():
1439 Gtk.main_iteration()
1440 pause_messages = self.simulation.pause_messages
1441 self.simulation.pause_messages = []
1444 self.simulation.target_time = ns.core.Simulator.Now ().GetSeconds () + self.sample_period
1447 self.simulation.lock.release()
1451 dialog = Gtk.MessageDialog(parent=self.window, flags=0, type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK,
1452 message_format=
'\n'.join(pause_messages))
1453 dialog.connect(
"response",
lambda d, r: d.destroy())
1455 self.play_button.set_active(
False)
1458 if not self.play_button.get_active():
1459 self._update_timeout_id =
None 1463 self.simulation.go.set()
1467 def _start_update_timer(self):
1468 if self._update_timeout_id
is not None:
1469 GLib.source_remove(self._update_timeout_id)
1471 self._update_timeout_id = GLib.timeout_add(int(SAMPLE_PERIOD/
min(self.speed, 1)*1e3),
1472 self.update_view_timeout,
1473 priority=PRIORITY_UPDATE_VIEW)
1475 def _on_play_button_toggled(self, button):
1476 if button.get_active():
1477 self._start_update_timer()
1479 if self._update_timeout_id
is not None:
1480 GLib.source_remove(self._update_timeout_id)
1482 def _quit(self, *dummy_args):
1483 if self._update_timeout_id
is not None:
1484 GLib.source_remove(self._update_timeout_id)
1485 self._update_timeout_id =
None 1486 self.simulation.quit =
True 1487 self.simulation.go.set()
1488 self.simulation.join()
1491 def _monkey_patch_ipython(self):
1498 original_runcode = self.ipython.runcode
1499 def runcode(ip, *args):
1501 self.simulation.lock.acquire()
1503 return original_runcode(*args)
1506 self.simulation.lock.release()
1508 self.ipython.runcode = types.MethodType(runcode, self.ipython)
1510 def autoscale_view(self):
1513 self._update_node_positions()
1514 positions = [node.get_position()
for node
in self.nodes.values()]
1515 min_x, min_y =
min(x
for (x,y)
in positions),
min(y
for (x,y)
in positions)
1516 max_x, max_y =
max(x
for (x,y)
in positions),
max(y
for (x,y)
in positions)
1517 min_x_px, min_y_px = self.canvas.convert_to_pixels(min_x, min_y)
1518 max_x_px, max_y_px = self.canvas.convert_to_pixels(max_x, max_y)
1521 dx_px = max_x_px - min_x_px
1522 dy_px = max_y_px - min_y_px
1523 hadj = self._scrolled_window.get_hadjustment()
1524 vadj = self._scrolled_window.get_vadjustment()
1525 new_dx, new_dy = 1.5*dx_px, 1.5*dy_px
1527 if new_dx == 0
or new_dy == 0:
1530 self.zoom.set_value(
min(hadj.get_page_size()/new_dx, vadj.get_page_size()/new_dy))
1532 x1, y1 = self.canvas.convert_from_pixels(hadj.get_value(), vadj.get_value())
1533 x2, y2 = self.canvas.convert_from_pixels((hadj.get_value() +
1534 hadj.get_page_size()),
1536 vadj.get_page_size()))
1539 center_x = (min_x + max_x) / 2
1540 center_y = (min_y + max_y) / 2
1542 self.canvas.scroll_to(center_x - width/2, center_y - height/2)
1547 self.scan_topology()
1548 self.window.connect(
"delete-event", self._quit)
1550 GLib.timeout_add(200, self.autoscale_view)
1551 self.simulation.
start()
1558 self._monkey_patch_ipython()
1563 def on_root_button_press_event(self, view, target, event):
1564 if event.button == 1:
1565 self.select_node(
None)
1568 def on_node_button_press_event(self, view, target, event, node):
1569 button = event.button
1571 self.select_node(node)
1574 self.popup_node_menu(node, event)
1577 self.begin_node_drag(node, event)
1581 def on_node_button_release_event(self, view, target, event, node):
1582 if event.button == 2:
1583 self.end_node_drag(node)
1587 class NodeDragState(object):
1588 def __init__(self, canvas_x0, canvas_y0, sim_x0, sim_y0):
1589 self.canvas_x0 = canvas_x0
1590 self.canvas_y0 = canvas_y0
1591 self.sim_x0 = sim_x0
1592 self.sim_y0 = sim_y0
1593 self.motion_signal =
None 1595 def begin_node_drag(self, node, event):
1596 self.simulation.lock.acquire()
1598 ns3_node = ns.network.NodeList.GetNode(node.node_index)
1599 mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1602 if self.node_drag_state
is not None:
1604 pos = mob.GetPosition()
1606 self.simulation.lock.release()
1607 devpos = self.canvas.get_window().get_device_position(event.device)
1608 x0, y0 = self.canvas.convert_from_pixels(devpos.x, devpos.y)
1609 self.node_drag_state = self.NodeDragState(x0, y0, pos.x, pos.y)
1610 self.node_drag_state.motion_signal = node.canvas_item.connect(
"motion-notify-event", self.node_drag_motion, node)
1612 def node_drag_motion(self, item, targe_item, event, node):
1613 self.simulation.lock.acquire()
1615 ns3_node = ns.network.NodeList.GetNode(node.node_index)
1616 mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1619 if self.node_drag_state
is None:
1621 devpos = self.canvas.get_window().get_device_position(event.device)
1622 canvas_x, canvas_y = self.canvas.convert_from_pixels(devpos.x, devpos.y)
1623 dx = (canvas_x - self.node_drag_state.canvas_x0)
1624 dy = (canvas_y - self.node_drag_state.canvas_y0)
1625 pos = mob.GetPosition()
1629 mob.SetPosition(pos)
1632 self.simulation.lock.release()
1635 def end_node_drag(self, node):
1636 if self.node_drag_state
is None:
1638 node.canvas_item.disconnect(self.node_drag_state.motion_signal)
1639 self.node_drag_state =
None 1641 def popup_node_menu(self, node, event):
1643 self.emit(
"populate-node-menu", node, menu)
1644 menu.popup(
None,
None,
None,
None, event.button, event.time)
1646 def _update_ipython_selected_node(self):
1655 if self.selected_node
is None:
1658 self.simulation.lock.acquire()
1660 ns3_node = ns.network.NodeList.GetNode(self.selected_node.node_index)
1662 self.simulation.lock.release()
1663 self.ipython.updateNamespace({
'selected_node': ns3_node})
1666 def select_node(self, node):
1667 if isinstance(node, ns.network.Node):
1668 node = self.nodes[node.GetId()]
1669 elif isinstance(node, (int, long)):
1670 node = self.nodes[node]
1671 elif isinstance(node, Node):
1676 raise TypeError(
"expected None, int, viz.Node or ns.network.Node, not %r" % node)
1678 if node
is self.selected_node:
1681 if self.selected_node
is not None:
1682 self.selected_node.selected =
False 1683 self.selected_node = node
1684 if self.selected_node
is not None:
1685 self.selected_node.selected =
True 1687 if self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
1688 if self.selected_node
is None:
1689 self.simulation.set_nodes_of_interest([])
1691 self.simulation.set_nodes_of_interest([self.selected_node.node_index])
1693 self._update_ipython_selected_node()
1696 def add_information_window(self, info_win):
1697 self.information_windows.append(info_win)
1698 self.simulation.lock.acquire()
1702 self.simulation.lock.release()
1704 def remove_information_window(self, info_win):
1705 self.information_windows.remove(info_win)
1707 def _canvas_tooltip_cb(self, canvas, x, y, keyboard_mode, tooltip):
1709 hadj = self._scrolled_window.get_hadjustment()
1710 vadj = self._scrolled_window.get_vadjustment()
1711 x, y = self.canvas.convert_from_pixels(hadj.get_value() + x, vadj.get_value() + y)
1712 item = self.canvas.get_item_at(x, y,
True)
1716 while item
is not None:
1717 obj = getattr(item,
"pyviz_object",
None)
1719 obj.tooltip_query(tooltip)
1721 item = item.props.parent
1724 def _get_export_file_name(self):
1725 sel = Gtk.FileChooserDialog(
"Save...", self.canvas.get_toplevel(),
1726 Gtk.FileChooserAction.SAVE,
1727 (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
1728 Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
1729 sel.set_default_response(Gtk.ResponseType.OK)
1730 sel.set_local_only(
True)
1731 sel.set_do_overwrite_confirmation(
True)
1732 sel.set_current_name(
"Unnamed.pdf")
1734 filter = Gtk.FileFilter()
1735 filter.set_name(
"Embedded PostScript")
1736 filter.add_mime_type(
"image/x-eps")
1737 sel.add_filter(filter)
1739 filter = Gtk.FileFilter()
1740 filter.set_name(
"Portable Document Graphics")
1741 filter.add_mime_type(
"application/pdf")
1742 sel.add_filter(filter)
1744 filter = Gtk.FileFilter()
1745 filter.set_name(
"Scalable Vector Graphics")
1746 filter.add_mime_type(
"image/svg+xml")
1747 sel.add_filter(filter)
1750 if resp != Gtk.ResponseType.OK:
1754 file_name = sel.get_filename()
1758 def _take_screenshot(self, dummy_button):
1760 file_name = self._get_export_file_name()
1761 if file_name
is None:
1765 x1 = self._scrolled_window.get_hadjustment().get_value()
1766 y1 = self._scrolled_window.get_vadjustment().get_value()
1767 x2 = x1 + self._scrolled_window.get_hadjustment().get_page_size()
1768 y2 = y1 + self._scrolled_window.get_vadjustment().get_page_size()
1769 bounds = GooCanvas.CanvasBounds()
1770 bounds.x1, bounds.y1 = self.canvas.convert_from_pixels(x1, y1)
1771 bounds.x2, bounds.y2 = self.canvas.convert_from_pixels(x2, y2)
1772 dest_width = bounds.x2 - bounds.x1
1773 dest_height = bounds.y2 - bounds.y1
1776 dummy, extension = os.path.splitext(file_name)
1777 extension = extension.lower()
1778 if extension ==
'.eps':
1779 surface = cairo.PSSurface(file_name, dest_width, dest_height)
1780 elif extension ==
'.pdf':
1781 surface = cairo.PDFSurface(file_name, dest_width, dest_height)
1782 elif extension ==
'.svg':
1783 surface = cairo.SVGSurface(file_name, dest_width, dest_height)
1785 dialog = Gtk.MessageDialog(parent = self.canvas.get_toplevel(),
1786 flags = Gtk.DialogFlags.DESTROY_WITH_PARENT,
1787 type = Gtk.MessageType.ERROR,
1788 buttons = Gtk.ButtonsType.OK,
1789 message_format =
"Unknown extension '%s' (valid extensions are '.eps', '.svg', and '.pdf')" 1796 cr = cairo.Context(surface)
1797 cr.translate(-bounds.x1, -bounds.y1)
1798 self.canvas.render(cr, bounds, self.zoom.get_value())
1802 def set_follow_node(self, node):
1803 if isinstance(node, ns.network.Node):
1804 node = self.nodes[node.GetId()]
1805 self.follow_node = node
1807 def _start_shell(self, dummy_button):
1808 if self.shell_window
is not None:
1809 self.shell_window.present()
1812 self.shell_window = Gtk.Window()
1813 self.shell_window.set_size_request(750,550)
1814 self.shell_window.set_resizable(
True)
1815 scrolled_window = Gtk.ScrolledWindow()
1816 scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,
1817 Gtk.PolicyType.AUTOMATIC)
1819 self.ipython.modify_font(Pango.FontDescription(SHELL_FONT))
1820 self.ipython.set_wrap_mode(Gtk.WrapMode.CHAR)
1822 scrolled_window.add(self.ipython)
1823 scrolled_window.show()
1824 self.shell_window.add(scrolled_window)
1825 self.shell_window.show()
1826 self.shell_window.connect(
'destroy', self._on_shell_window_destroy)
1828 self._update_ipython_selected_node()
1829 self.ipython.updateNamespace({
'viz': self})
1832 def _on_shell_window_destroy(self, window):
1833 self.shell_window =
None 1836 initialization_hooks = []
1840 Adds a callback to be called after 1841 the visualizer is initialized, like this:: 1842 initialization_hook(visualizer, *args) 1844 global initialization_hooks
1845 initialization_hooks.append((hook, args))
1854 viz.canvas.set_bounds(cx1, cy1, cx2, cy2)
1859 assert Visualizer.INSTANCE
is None 1860 if _import_error
is not None:
1862 print(
"No visualization support (%s)." % (str(_import_error),),
1864 ns.core.Simulator.Run()
1868 for hook, args
in initialization_hooks:
1869 GLib.idle_add(hook, viz, *args)
1870 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)