2from __future__
import division, print_function
5LAYOUT_ALGORITHM =
'neato'
6REPRESENT_CHANNELS_AS_NODES = 1
8DEFAULT_TRANSMISSIONS_MEMORY = 5
13PRIORITY_UPDATE_MODEL = -100
14PRIORITY_UPDATE_VIEW = 200
18if platform.system() ==
"Windows":
19 SHELL_FONT =
"Lucida Console 9"
21 SHELL_FONT =
"Luxi Mono 10"
34if 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
58except ImportError
as e:
60 import dummy_threading
as threading
65 import ipython_viewxxxxxxxxxx
69from .base
import InformationWindow, PyVizObject, Link, lookup_netdevice_traits, PIXELS_PER_METER
70from .base
import transform_distance_simulation_to_canvas, transform_point_simulation_to_canvas
71from .base
import transform_distance_canvas_to_simulation, transform_point_canvas_to_simulation
72from .base
import load_plugins, register_plugin, plugins
118 'query-extra-tooltip-info': (GObject.SignalFlags.RUN_LAST,
None, (object,)),
122 """! Initialize function.
123 @param self The object pointer.
124 @param visualizer visualizer object
125 @param node_index node index
150 def set_svg_icon(self, file_base_name, width=None, height=None, align_x=0.5, align_y=0.5):
152 Set a background SVG icon for the node.
154 @param file_base_name: base file name, including .svg
155 extension, of the svg file. Place the file
in the folder
156 src/contrib/visualizer/resource.
158 @param width: scale to the specified width,
in meters
159 @param height: scale to the specified height,
in meters
161 @param align_x: horizontal alignment of the icon relative to
162 the node position,
from 0 (icon fully to the left of the node)
163 to 1.0 (icon fully to the right of the node)
165 @param align_y: vertical alignment of the icon relative to the
166 node position,
from 0 (icon fully to the top of the node) to
167 1.0 (icon fully to the bottom of the node)
169 @return a ValueError exception
if invalid dimensions.
172 if width
is None and height
is None:
173 raise ValueError(
"either width or height must be given")
174 rsvg_handle = svgitem.rsvg_handle_factory(file_base_name)
179 self.
svg_item.props.pointer_events = GooCanvas.CanvasPointerEvents.NONE
181 self.
svg_item.props.visibility = GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD
182 if width
is not None:
184 if height
is not None:
198 Set a label for the node.
200 @param self:
class object.
201 @param label: label to set
203 @return: an exception
if invalid parameter.
205 assert isinstance(label, basestring)
213 @param self:
class object.
228 @param self:
class object.
229 @param tooltip: tooltip
234 ns3_node = ns.network.NodeList.GetNode(self.
node_index)
235 ipv4 = ns3_node.GetObject(ns.internet.Ipv4.GetTypeId())
236 ipv6 = ns3_node.GetObject(ns.internet.Ipv6.GetTypeId())
238 name =
'<b><u>Node %i</u></b>' % self.
node_index
239 node_name = ns.core.Names.FindName (ns3_node)
240 if len(node_name)!=0:
241 name +=
' <b>(' + node_name +
')</b>'
246 self.emit(
"query-extra-tooltip-info", lines)
248 mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
250 lines.append(
' <b>Mobility Model</b>: %s' % mob.GetInstanceTypeId().GetName())
252 for devI
in range(ns3_node.GetNDevices()):
254 lines.append(
' <u>NetDevice %i:</u>' % devI)
255 dev = ns3_node.GetDevice(devI)
256 name = ns.core.Names.FindName(dev)
258 lines.append(
' <b>Name:</b> %s' % name)
259 devname = dev.GetInstanceTypeId().GetName()
260 lines.append(
' <b>Type:</b> %s' % devname)
263 ipv4_idx = ipv4.GetInterfaceForDevice(dev)
266 '%s/%s' % (ipv4.GetAddress(ipv4_idx, i).GetLocal(),
267 ipv4.GetAddress(ipv4_idx, i).GetMask())
268 for i
in range(ipv4.GetNAddresses(ipv4_idx))]
269 lines.append(
' <b>IPv4 Addresses:</b> %s' %
'; '.join(addresses))
272 ipv6_idx = ipv6.GetInterfaceForDevice(dev)
275 '%s/%s' % (ipv6.GetAddress(ipv6_idx, i).GetAddress(),
276 ipv6.GetAddress(ipv6_idx, i).GetPrefix())
277 for i
in range(ipv6.GetNAddresses(ipv6_idx))]
278 lines.append(
' <b>IPv6 Addresses:</b> %s' %
'; '.join(addresses))
280 lines.append(
' <b>MAC Address:</b> %s' % (dev.GetAddress(),))
282 tooltip.set_markup(
'\n'.join(lines))
288 On Enter event handle.
290 @param self:
class object.
292 @param target: target
299 On Leave event handle.
301 @param self:
class object.
303 @param target: target
311 Set selected function.
313 @param self:
class object.
314 @param value: selected value
321 Get selected function.
323 @param self:
class object.
324 @return selected status
328 selected = property(_get_selected, _set_selected)
332 Set highlighted function.
334 @param self:
class object.
335 @param value: selected value
342 Get highlighted function.
344 @param self:
class object.
345 @return highlighted status
349 highlighted = property(_get_highlighted, _set_highlighted)
355 @param self:
class object.
356 @param size: selected size
364 Update the node aspect to reflect the selected/highlighted state
366 @param self:
class object.
375 fill_color_rgba = (self.
_color & 0xffffff00) | alpha
376 self.
canvas_item.set_properties(radius_x=size, radius_y=size,
377 fill_color_rgba=fill_color_rgba)
381 line_width = size*.15
383 stroke_color =
'yellow'
385 stroke_color =
'black'
386 self.
canvas_item.set_properties(line_width=line_width, stroke_color=stroke_color)
388 if self.
_label is not None:
391 font=
"Sans Serif 10",
392 fill_color_rgba=0x808080ff,
393 alignment=Pango.Alignment.CENTER,
394 anchor=GooCanvas.CanvasAnchorType.N,
395 parent=self.
visualizer.canvas.get_root_item(),
396 pointer_events=GooCanvas.CanvasPointerEvents.NONE)
399 self.
_label_canvas_item.set_properties(visibility=GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD,
405 Set position function.
407 @param self:
class object.
417 for link
in self.
links:
428 (min_x, min_y, max_x, max_y) = bounds
430 min_x =
min(x, min_x)
431 min_y =
min(y, min_y)
432 max_x =
max(x, max_x)
433 max_y =
max(y, max_y)
435 new_bounds = (min_x, min_y, max_x, max_y)
437 if new_bounds != bounds:
438 self.
visualizer.canvas.set_bounds(*new_bounds)
445 Get position function.
447 @param self:
class object.
448 @return x
and y position
454 Update position function.
456 @param self:
class object.
466 @param self:
class object.
467 @param color: color to set.
470 if isinstance(color, str):
471 color = Gdk.color_parse(color)
472 color = ((color.red>>8) << 24) | ((color.green>>8) << 16) | ((color.blue>>8) << 8) | 0xff
480 @param self:
class object.
481 @param link: link to add.
484 assert isinstance(link, Link)
485 self.
links.append(link)
489 Remove link function.
491 @param self:
class object.
492 @param link: link to add.
495 assert isinstance(link, Link)
496 self.
links.remove(link)
501 Has mobility function.
503 @param self:
class object.
504 @return modility option
507 node = ns.network.NodeList.GetNode(self.
node_index)
508 mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
524 Initializer function.
526 @param self:
class object.
527 @param channel: channel.
530 self.canvas_item = GooCanvas.CanvasEllipse(radius_x=30, radius_y=30,
532 stroke_color=
"grey", line_width=2.0,
533 line_dash=GooCanvas.CanvasLineDash.newv([10.0, 10.0 ]),
534 visibility=GooCanvas.CanvasItemVisibility.VISIBLE)
540 Initializer function.
542 @param self:
class object.
543 @param x: x position.
544 @param y: y position.
550 for link
in self.
links:
555 Initializer function.
557 @param self:
class object.
558 @return x / y position.
574 Initializer function.
576 @param self:
class object.
577 @param node1:
class object.
578 @param node2:
class object.
580 assert isinstance(node1, Node)
581 assert isinstance(node2, (Node, Channel))
584 self.
canvas_item = GooCanvas.CanvasPath(line_width=1.0, stroke_color=
"black")
586 self.
node1.links.append(self)
587 self.
node2.links.append(self)
591 Update points function.
593 @param self:
class object.
596 pos1_x, pos1_y = self.node1.get_position()
597 pos2_x, pos2_y = self.node2.get_position()
598 self.canvas_item.set_property("data",
"M %r %r L %r %r" % (pos1_x, pos1_y, pos2_x, pos2_y))
619 Initializer function.
621 @param self:
class object.
624 super(SimulationThread, self).__init__()
625 assert isinstance(viz, Visualizer)
628 self.
go = threading.Event()
637 Set nodes of interest function.
639 @param self:
class object.
640 @param nodes:
class object.
651 Initializer function.
653 @param self:
class object.
667 if ns3.core.Simulator.IsFinished():
668 self.
viz.play_button.set_sensitive(
False)
676 GLib.idle_add(self.
viz.update_model, priority=PRIORITY_UPDATE_MODEL)
703 if _import_error
is None:
707 'populate-node-menu': (GObject.SignalFlags.RUN_LAST,
None, (object, Gtk.Menu,)),
711 'simulation-periodic-update': (GObject.SignalFlags.RUN_LAST,
None, ()),
714 'topology-scanned': (GObject.SignalFlags.RUN_LAST,
None, ()),
717 'update-view': (GObject.SignalFlags.RUN_LAST,
None, ()),
723 Initializer function.
725 @param self:
class object.
728 assert Visualizer.INSTANCE
is None
729 Visualizer.INSTANCE = self
730 super(Visualizer, self).__init__()
735 self.time_label =
None
736 self.play_button =
None
738 self._scrolled_window =
None
740 self.links_group = GooCanvas.CanvasGroup()
741 self.channels_group = GooCanvas.CanvasGroup()
742 self.nodes_group = GooCanvas.CanvasGroup()
744 self._update_timeout_id =
None
746 self.selected_node =
None
748 self.information_windows = []
749 self._transmission_arrows = []
750 self._last_transmissions = []
751 self._drop_arrows = []
752 self._last_drops = []
753 self._show_transmissions_mode =
None
754 self.set_show_transmissions_mode(ShowTransmissionsMode.ALL)
755 self._panning_state =
None
756 self.node_size_adjustment =
None
757 self.transmissions_smoothing_adjustment =
None
758 self.sample_period = SAMPLE_PERIOD
759 self.node_drag_state =
None
760 self.follow_node =
None
761 self.shell_window =
None
765 for plugin
in plugins:
768 def set_show_transmissions_mode(self, mode):
770 Set show transmission mode.
772 @param self:
class object.
773 @param mode: mode to set.
776 assert isinstance(mode, ShowTransmissionsMode)
777 self._show_transmissions_mode = mode
778 if self._show_transmissions_mode == ShowTransmissionsMode.ALL:
779 self.simulation.set_nodes_of_interest(
list(range(ns.network.NodeList.GetNNodes())))
780 elif self._show_transmissions_mode == ShowTransmissionsMode.NONE:
781 self.simulation.set_nodes_of_interest([])
782 elif self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
783 if self.selected_node
is None:
784 self.simulation.set_nodes_of_interest([])
786 self.simulation.set_nodes_of_interest([self.selected_node.node_index])
788 def _create_advanced_controls(self):
790 Create advanced controls.
792 @param self:
class object.
795 expander = Gtk.Expander.new("Advanced")
798 main_vbox = GObject.new(Gtk.VBox, border_width=8, visible=
True)
799 expander.add(main_vbox)
801 main_hbox1 = GObject.new(Gtk.HBox, border_width=8, visible=
True)
802 main_vbox.pack_start(main_hbox1,
True,
True, 0)
804 show_transmissions_group = GObject.new(Gtk.HeaderBar,
805 title=
"Show transmissions",
807 main_hbox1.pack_start(show_transmissions_group,
False,
False, 8)
809 vbox = Gtk.VBox(homogeneous=
True, spacing=4)
811 show_transmissions_group.add(vbox)
813 all_nodes = Gtk.RadioButton.new(
None)
814 all_nodes.set_label(
"All nodes")
815 all_nodes.set_active(
True)
819 selected_node = Gtk.RadioButton.new_from_widget(all_nodes)
821 selected_node.set_label(
"Selected node")
822 selected_node.set_active(
False)
823 vbox.add(selected_node)
825 no_node = Gtk.RadioButton.new_from_widget(all_nodes)
827 no_node.set_label(
"Disabled")
828 no_node.set_active(
False)
832 if radio.get_active():
833 self.set_show_transmissions_mode(ShowTransmissionsMode.ALL)
834 all_nodes.connect(
"toggled", toggled)
837 if radio.get_active():
838 self.set_show_transmissions_mode(ShowTransmissionsMode.NONE)
839 no_node.connect(
"toggled", toggled)
842 if radio.get_active():
843 self.set_show_transmissions_mode(ShowTransmissionsMode.SELECTED)
844 selected_node.connect(
"toggled", toggled)
847 misc_settings_group = GObject.new(Gtk.HeaderBar, title=
"Misc Settings", visible=
True)
848 main_hbox1.pack_start(misc_settings_group,
False,
False, 8)
849 settings_hbox = GObject.new(Gtk.HBox, border_width=8, visible=
True)
850 misc_settings_group.add(settings_hbox)
853 vbox = GObject.new(Gtk.VBox, border_width=0, visible=
True)
854 scale = GObject.new(Gtk.HScale, visible=
True, digits=2)
855 vbox.pack_start(scale,
True,
True, 0)
856 vbox.pack_start(GObject.new(Gtk.Label, label=
"Node Size", visible=
True),
True,
True, 0)
857 settings_hbox.pack_start(vbox,
False,
False, 6)
858 self.node_size_adjustment = scale.get_adjustment()
859 def node_size_changed(adj):
860 for node
in self.nodes.values():
861 node.set_size(adj.get_value())
862 self.node_size_adjustment.connect(
"value-changed", node_size_changed)
863 self.node_size_adjustment.set_lower(0.01)
864 self.node_size_adjustment.set_upper(20)
865 self.node_size_adjustment.set_step_increment(0.1)
866 self.node_size_adjustment.set_value(DEFAULT_NODE_SIZE)
869 vbox = GObject.new(Gtk.VBox, border_width=0, visible=
True)
870 scale = GObject.new(Gtk.HScale, visible=
True, digits=1)
871 vbox.pack_start(scale,
True,
True, 0)
872 vbox.pack_start(GObject.new(Gtk.Label, label=
"Tx. Smooth Factor (s)", visible=
True),
True,
True, 0)
873 settings_hbox.pack_start(vbox,
False,
False, 6)
874 self.transmissions_smoothing_adjustment = scale.get_adjustment()
875 adj = self.transmissions_smoothing_adjustment
878 adj.set_step_increment(0.1)
879 adj.set_value(DEFAULT_TRANSMISSIONS_MEMORY*0.1)
884 class _PanningState(
object):
887 __slots__ = [
'initial_mouse_pos',
'initial_canvas_pos',
'motion_signal']
889 def _begin_panning(self, widget, event):
891 Set show trnamission mode.
893 @param self:
class object.
894 @param mode: mode to set.
897 display = self.canvas.get_window().get_display()
898 cursor = Gdk.Cursor.new_for_display(display, Gdk.CursorType.FLEUR)
899 self.canvas.get_window().set_cursor(cursor)
900 self._panning_state = self._PanningState()
901 pos = widget.get_window().get_device_position(event.device)
902 self._panning_state.initial_mouse_pos = (pos.x, pos.y)
903 x = self._scrolled_window.get_hadjustment().get_value()
904 y = self._scrolled_window.get_vadjustment().get_value()
905 self._panning_state.initial_canvas_pos = (x, y)
906 self._panning_state.motion_signal = self.canvas.connect("motion-notify-event", self._panning_motion)
908 def _end_panning(self, event):
910 End panning function.
912 @param self:
class object.
913 @param event: active event.
916 if self._panning_state
is None:
918 self.canvas.get_window().set_cursor(
None)
919 self.canvas.disconnect(self._panning_state.motion_signal)
920 self._panning_state =
None
922 def _panning_motion(self, widget, event):
924 Panning motion function.
926 @param self:
class object.
927 @param widget: widget.
929 @return true
if successful
931 assert self._panning_state
is not None
933 pos = widget.get_window().get_device_position(event.device)
936 x, y = event.x, event.y
938 hadj = self._scrolled_window.get_hadjustment()
939 vadj = self._scrolled_window.get_vadjustment()
940 mx0, my0 = self._panning_state.initial_mouse_pos
941 cx0, cy0 = self._panning_state.initial_canvas_pos
945 hadj.set_value(cx0 - dx)
946 vadj.set_value(cy0 - dy)
949 def _canvas_button_press(self, widget, event):
950 if event.button == 2:
951 self._begin_panning(widget, event)
955 def _canvas_button_release(self, dummy_widget, event):
956 if event.button == 2:
957 self._end_panning(event)
961 def _canvas_scroll_event(self, dummy_widget, event):
962 if event.direction == Gdk.ScrollDirection.UP:
963 self.zoom.set_value(self.zoom.get_value() * 1.25)
965 elif event.direction == Gdk.ScrollDirection.DOWN:
966 self.zoom.set_value(self.zoom.get_value() / 1.25)
970 def get_hadjustment(self):
971 return self._scrolled_window.get_hadjustment()
972 def get_vadjustment(self):
973 return self._scrolled_window.get_vadjustment()
975 def create_gui(self):
976 self.window = Gtk.Window()
979 self.window.add(vbox)
982 self.canvas = GooCanvas.Canvas()
983 self.canvas.connect_after(
"button-press-event", self._canvas_button_press)
984 self.canvas.connect_after(
"button-release-event", self._canvas_button_release)
985 self.canvas.connect(
"scroll-event", self._canvas_scroll_event)
986 self.canvas.props.has_tooltip =
True
987 self.canvas.connect(
"query-tooltip", self._canvas_tooltip_cb)
989 sw = Gtk.ScrolledWindow(); sw.show()
990 self._scrolled_window = sw
992 vbox.pack_start(sw,
True,
True, 4)
993 self.canvas.set_size_request(600, 450)
994 self.canvas.
set_bounds(-10000, -10000, 10000, 10000)
995 self.canvas.scroll_to(0, 0)
998 self.canvas.get_root_item().add_child(self.links_group, -1)
999 self.links_group.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1001 self.canvas.get_root_item().add_child(self.channels_group, -1)
1002 self.channels_group.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1003 self.channels_group.raise_(self.links_group)
1005 self.canvas.get_root_item().add_child(self.nodes_group, -1)
1006 self.nodes_group.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1007 self.nodes_group.raise_(self.channels_group)
1011 hbox = Gtk.HBox(); hbox.show()
1012 vbox.pack_start(hbox,
False,
False, 4)
1015 zoom_adj = Gtk.Adjustment(value=1.0, lower=0.01, upper=10.0,
1016 step_increment=0.02,
1019 self.zoom = zoom_adj
1020 def _zoom_changed(adj):
1021 self.canvas.set_scale(adj.get_value())
1022 zoom_adj.connect(
"value-changed", _zoom_changed)
1023 zoom = Gtk.SpinButton.new(zoom_adj, 0.1, 1)
1026 hbox.pack_start(GObject.new(Gtk.Label, label=
" Zoom:", visible=
True),
False,
False, 4)
1027 hbox.pack_start(zoom,
False,
False, 4)
1028 _zoom_changed(zoom_adj)
1031 speed_adj = Gtk.Adjustment(value=1.0, lower=0.01, upper=10.0,
1032 step_increment=0.02,
1033 page_increment=1.0, page_size=0)
1034 def _speed_changed(adj):
1035 self.speed = adj.get_value()
1036 self.sample_period = SAMPLE_PERIOD*adj.get_value()
1037 self._start_update_timer()
1038 speed_adj.connect(
"value-changed", _speed_changed)
1039 speed = Gtk.SpinButton.new(speed_adj, 1, 0)
1042 hbox.pack_start(GObject.new(Gtk.Label, label=
" Speed:", visible=
True),
False,
False, 4)
1043 hbox.pack_start(speed,
False,
False, 4)
1044 _speed_changed(speed_adj)
1047 self.time_label = GObject.new(Gtk.Label, label=
" Speed:", visible=
True)
1048 self.time_label.set_width_chars(20)
1049 hbox.pack_start(self.time_label,
False,
False, 4)
1052 screenshot_button = GObject.new(Gtk.Button,
1054 relief=Gtk.ReliefStyle.NONE, focus_on_click=
False,
1056 hbox.pack_start(screenshot_button,
False,
False, 4)
1058 def load_button_icon(button, icon_name):
1062 sys.stderr.write(
"Could not load icon %s due to missing gnomedesktop Python module\n" % icon_name)
1064 icon = gnomedesktop.find_icon(Gtk.IconTheme.get_default(), icon_name, 16, 0)
1065 if icon
is not None:
1066 button.props.image = GObject.new(Gtk.Image, file=icon, visible=
True)
1068 load_button_icon(screenshot_button,
"applets-screenshooter")
1069 screenshot_button.connect(
"clicked", self._take_screenshot)
1072 if ipython_view
is not None:
1073 shell_button = GObject.new(Gtk.Button,
1075 relief=Gtk.ReliefStyle.NONE, focus_on_click=
False,
1077 hbox.pack_start(shell_button,
False,
False, 4)
1078 load_button_icon(shell_button,
"gnome-terminal")
1079 shell_button.connect(
"clicked", self._start_shell)
1082 self.play_button = GObject.new(Gtk.ToggleButton,
1083 image=GObject.new(Gtk.Image, stock=Gtk.STOCK_MEDIA_PLAY, visible=
True),
1084 label=
"Simulate (F3)",
1085 relief=Gtk.ReliefStyle.NONE, focus_on_click=
False,
1086 use_stock=
True, visible=
True)
1087 accel_group = Gtk.AccelGroup()
1088 self.window.add_accel_group(accel_group)
1089 self.play_button.add_accelerator(
"clicked", accel_group,
1090 Gdk.KEY_F3, 0, Gtk.AccelFlags.VISIBLE)
1091 self.play_button.connect(
"toggled", self._on_play_button_toggled)
1092 hbox.pack_start(self.play_button,
False,
False, 4)
1094 self.canvas.get_root_item().connect(
"button-press-event", self.on_root_button_press_event)
1096 vbox.pack_start(self._create_advanced_controls(),
False,
False, 4)
1098 display = Gdk.Display.get_default()
1100 monitor = display.get_primary_monitor()
1101 geometry = monitor.get_geometry()
1102 scale_factor = monitor.get_scale_factor()
1103 except AttributeError:
1104 screen = display.get_default_screen()
1105 monitor_id = screen.get_primary_monitor()
1106 geometry = screen.get_monitor_geometry(monitor_id)
1107 scale_factor = screen.get_monitor_scale_factor(monitor_id)
1108 width = scale_factor * geometry.width
1109 height = scale_factor * geometry.height
1110 self.window.set_default_size(width * 2 / 3, height * 2 / 3)
1113 def scan_topology(self):
1114 print(
"scanning topology: %i nodes..." % (ns.network.NodeList.GetNNodes(),))
1115 graph = pygraphviz.AGraph()
1117 for nodeI
in range(ns.network.NodeList.GetNNodes()):
1119 if seen_nodes == 100:
1120 print(
"scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns.network.NodeList.GetNNodes()))
1122 node = ns.network.NodeList.GetNode(nodeI)
1123 node_name =
"Node %i" % nodeI
1124 node_view = self.get_node(nodeI)
1126 mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1127 if mobility
is not None:
1128 node_view.set_color(
"red")
1129 pos = mobility.GetPosition()
1133 graph.add_node(node_name)
1135 for devI
in range(node.GetNDevices()):
1136 device = node.GetDevice(devI)
1138 if device_traits.is_wireless:
1140 if device_traits.is_virtual:
1142 channel = device.GetChannel()
1143 if channel.GetNDevices() > 2:
1144 if REPRESENT_CHANNELS_AS_NODES:
1146 if mobility
is None:
1147 channel_name =
"Channel %s" % id(channel)
1148 graph.add_edge(node_name, channel_name)
1149 self.get_channel(channel)
1150 self.create_link(self.get_node(nodeI), self.get_channel(channel))
1153 for otherDevI
in range(channel.GetNDevices()):
1154 otherDev = channel.GetDevice(otherDevI)
1155 otherNode = otherDev.GetNode()
1156 otherNodeView = self.get_node(otherNode.GetId())
1157 if otherNode
is not node:
1158 if mobility
is None and not otherNodeView.has_mobility:
1159 other_node_name =
"Node %i" % otherNode.GetId()
1160 graph.add_edge(node_name, other_node_name)
1161 self.create_link(self.get_node(nodeI), otherNodeView)
1163 for otherDevI
in range(channel.GetNDevices()):
1164 otherDev = channel.GetDevice(otherDevI)
1165 otherNode = otherDev.GetNode()
1166 otherNodeView = self.get_node(otherNode.GetId())
1167 if otherNode
is not node:
1168 if mobility
is None and not otherNodeView.has_mobility:
1169 other_node_name =
"Node %i" % otherNode.GetId()
1170 graph.add_edge(node_name, other_node_name)
1171 self.create_link(self.get_node(nodeI), otherNodeView)
1173 print(
"scanning topology: calling graphviz layout")
1174 graph.layout(LAYOUT_ALGORITHM)
1175 for node
in graph.iternodes():
1177 node_type, node_id = node.split(
' ')
1178 pos_x, pos_y = [float(s)
for s
in node.attr[
'pos'].split(
',')]
1179 if node_type ==
'Node':
1180 obj = self.nodes[int(node_id)]
1181 elif node_type ==
'Channel':
1182 obj = self.channels[int(node_id)]
1183 obj.set_position(pos_x, pos_y)
1185 print(
"scanning topology: all done.")
1186 self.emit(
"topology-scanned")
1188 def get_node(self, index):
1190 return self.nodes[index]
1192 node =
Node(self, index)
1193 self.nodes[index] = node
1194 self.nodes_group.add_child(node.canvas_item, -1)
1195 node.canvas_item.connect(
"button-press-event", self.on_node_button_press_event, node)
1196 node.canvas_item.connect(
"button-release-event", self.on_node_button_release_event, node)
1199 def get_channel(self, ns3_channel):
1201 return self.channels[id(ns3_channel)]
1203 channel =
Channel(ns3_channel)
1204 self.channels[id(ns3_channel)] = channel
1205 self.channels_group.add_child(channel.canvas_item, -1)
1208 def create_link(self, node, node_or_channel):
1210 self.links_group.add_child(link.canvas_item, -1)
1211 link.canvas_item.lower(
None)
1213 def update_view(self):
1216 self.time_label.set_text(
"Time: %f s" % ns.core.Simulator.Now().GetSeconds())
1218 self._update_node_positions()
1221 for info_win
in self.information_windows:
1224 self._update_transmissions_view()
1225 self._update_drops_view()
1227 self.emit(
"update-view")
1229 def _update_node_positions(self):
1230 for node
in self.nodes.values():
1231 if node.has_mobility:
1232 ns3_node = ns.network.NodeList.GetNode(node.node_index)
1233 mobility = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1234 if mobility
is not None:
1235 pos = mobility.GetPosition()
1237 node.set_position(x, y)
1238 if node
is self.follow_node:
1239 hadj = self._scrolled_window.get_hadjustment()
1240 vadj = self._scrolled_window.get_vadjustment()
1241 px, py = self.canvas.convert_to_pixels(x, y)
1242 hadj.set_value(px - hadj.get_page_size() / 2)
1243 vadj.set_value(py - vadj.get_page_size() / 2)
1245 def center_on_node(self, node):
1246 if isinstance(node, ns.network.Node):
1247 node = self.nodes[node.GetId()]
1248 elif isinstance(node, (int, long)):
1249 node = self.nodes[node]
1250 elif isinstance(node, Node):
1253 raise TypeError(
"expected int, viz.Node or ns.network.Node, not %r" % node)
1255 x, y = node.get_position()
1256 hadj = self._scrolled_window.get_hadjustment()
1257 vadj = self._scrolled_window.get_vadjustment()
1258 px, py = self.canvas.convert_to_pixels(x, y)
1259 hadj.set_value(px - hadj.get_page_size() / 2)
1260 vadj.set_value(py - vadj.get_page_size() / 2)
1262 def update_model(self):
1263 self.simulation.lock.acquire()
1265 self.emit(
"simulation-periodic-update")
1267 self.simulation.lock.release()
1269 def do_simulation_periodic_update(self):
1270 smooth_factor = int(self.transmissions_smoothing_adjustment.get_value()*10)
1272 transmissions = self.simulation.sim_helper.GetTransmissionSamples()
1273 self._last_transmissions.append(transmissions)
1274 while len(self._last_transmissions) > smooth_factor:
1275 self._last_transmissions.pop(0)
1277 drops = self.simulation.sim_helper.GetPacketDropSamples()
1278 self._last_drops.append(drops)
1279 while len(self._last_drops) > smooth_factor:
1280 self._last_drops.pop(0)
1282 def _get_label_over_line_position(self, pos1_x, pos1_y, pos2_x, pos2_y):
1283 hadj = self._scrolled_window.get_hadjustment()
1284 vadj = self._scrolled_window.get_vadjustment()
1285 bounds_x1, bounds_y1 = self.canvas.convert_from_pixels(hadj.get_value(), vadj.get_value())
1286 bounds_x2, bounds_y2 = self.canvas.convert_from_pixels(hadj.get_value() + hadj.get_page_size(),
1287 vadj.get_value() + vadj.get_page_size())
1288 pos1_x, pos1_y, pos2_x, pos2_y = ns.visualizer.PyViz.LineClipping(bounds_x1, bounds_y1,
1289 bounds_x2, bounds_y2,
1292 return (pos1_x + pos2_x)/2, (pos1_y + pos2_y)/2
1294 def _update_transmissions_view(self):
1295 transmissions_average = {}
1296 for transmission_set
in self._last_transmissions:
1297 for transmission
in transmission_set:
1298 key = (transmission.transmitter.GetId(), transmission.receiver.GetId())
1299 rx_bytes, count = transmissions_average.get(key, (0, 0))
1300 rx_bytes += transmission.bytes
1302 transmissions_average[key] = rx_bytes, count
1304 old_arrows = self._transmission_arrows
1305 for arrow, label
in old_arrows:
1306 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1307 label.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1310 k = self.node_size_adjustment.get_value()/5
1312 for (transmitter_id, receiver_id), (rx_bytes, rx_count)
in transmissions_average.items():
1313 transmitter = self.get_node(transmitter_id)
1314 receiver = self.get_node(receiver_id)
1316 arrow, label = old_arrows.pop()
1318 arrow = GooCanvas.CanvasPolyline(line_width=2.0, stroke_color_rgba=0x00C000C0, close_path=
False, end_arrow=
True, pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1319 arrow.set_property(
"parent", self.canvas.get_root_item())
1322 label = GooCanvas.CanvasText(parent=self.canvas.get_root_item(), pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1325 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1326 line_width =
max(0.1, math.log(float(rx_bytes)/rx_count/self.sample_period)*k)
1327 arrow.set_property(
"line-width", line_width)
1329 pos1_x, pos1_y = transmitter.get_position()
1330 pos2_x, pos2_y = receiver.get_position()
1331 points = GooCanvas.CanvasPoints.new(2)
1332 points.set_point(0, pos1_x, pos1_y)
1333 points.set_point(1, pos2_x, pos2_y)
1334 arrow.set_property(
"points", points)
1336 kbps = float(rx_bytes*8)/1e3/rx_count/self.sample_period
1337 label.set_properties(visibility=GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD,
1338 visibility_threshold=0.5,
1339 font=(
"Sans Serif %f" % int(1+BITRATE_FONT_SIZE*k)))
1340 angle = math.atan2((pos2_y - pos1_y), (pos2_x - pos1_x))
1341 if -PI_OVER_2 <= angle <= PI_OVER_2:
1342 label.set_properties(text=(
"%.2f kbit/s →" % (kbps,)),
1343 alignment=Pango.Alignment.CENTER,
1344 anchor=GooCanvas.CanvasAnchorType.S,
1345 x=0, y=-line_width/2)
1347 label.set_properties(text=(
"← %.2f kbit/s" % (kbps,)),
1348 alignment=Pango.Alignment.CENTER,
1349 anchor=GooCanvas.CanvasAnchorType.N,
1350 x=0, y=line_width/2)
1352 lx, ly = self._get_label_over_line_position(pos1_x, pos1_y,
1357 label.set_transform(M)
1360 warnings.warn(
"PyGobject bug causing label position error; "
1361 "should be fixed in PyGObject >= 3.29.1")
1362 label.set_properties(x=(lx + label.props.x),
1363 y=(ly + label.props.y))
1365 new_arrows.append((arrow, label))
1367 self._transmission_arrows = new_arrows + old_arrows
1370 def _update_drops_view(self):
1372 for drop_set
in self._last_drops:
1373 for drop
in drop_set:
1374 key = drop.transmitter.GetId()
1375 drop_bytes, count = drops_average.get(key, (0, 0))
1376 drop_bytes += drop.bytes
1378 drops_average[key] = drop_bytes, count
1380 old_arrows = self._drop_arrows
1381 for arrow, label
in old_arrows:
1382 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1383 label.set_property(
"visibility", GooCanvas.CanvasItemVisibility.HIDDEN)
1387 vadjustment = self._scrolled_window.get_vadjustment()
1388 bottom_y = vadjustment.get_value() + vadjustment.get_page_size()
1389 dummy, edge_y = self.canvas.convert_from_pixels(0, bottom_y)
1391 k = self.node_size_adjustment.get_value()/5
1393 for transmitter_id, (drop_bytes, drop_count)
in drops_average.items():
1394 transmitter = self.get_node(transmitter_id)
1396 arrow, label = old_arrows.pop()
1398 arrow = GooCanvas.CanvasPolyline(line_width=2.0, stroke_color_rgba=0xC00000C0, close_path=
False, end_arrow=
True, pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1399 arrow.set_property(
"parent", self.canvas.get_root_item())
1402 label = GooCanvas.CanvasText(pointer_events=GooCanvas.CanvasPointerEvents.NONE)
1403 label.set_property(
"parent", self.canvas.get_root_item())
1406 arrow.set_property(
"visibility", GooCanvas.CanvasItemVisibility.VISIBLE)
1407 arrow.set_property(
"line-width",
max(0.1, math.log(float(drop_bytes)/drop_count/self.sample_period)*k))
1408 pos1_x, pos1_y = transmitter.get_position()
1409 pos2_x, pos2_y = pos1_x, edge_y
1410 points = GooCanvas.CanvasPoints.new(2)
1411 points.set_point(0, pos1_x, pos1_y)
1412 points.set_point(1, pos2_x, pos2_y)
1413 arrow.set_property(
"points", points)
1415 label.set_properties(visibility=GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD,
1416 visibility_threshold=0.5,
1417 font=(
"Sans Serif %i" % int(1+BITRATE_FONT_SIZE*k)),
1418 text=(
"%.2f kbit/s" % (float(drop_bytes*8)/1e3/drop_count/self.sample_period,)),
1419 alignment=Pango.Alignment.CENTER,
1420 x=(pos1_x + pos2_x)/2,
1421 y=(pos1_y + pos2_y)/2)
1423 new_arrows.append((arrow, label))
1425 self._drop_arrows = new_arrows + old_arrows
1428 def update_view_timeout(self):
1432 while not self.simulation.lock.acquire(
False):
1433 while Gtk.events_pending():
1434 Gtk.main_iteration()
1435 pause_messages = self.simulation.pause_messages
1436 self.simulation.pause_messages = []
1439 self.simulation.target_time = ns.core.Simulator.Now ().GetSeconds () + self.sample_period
1442 self.simulation.lock.release()
1446 dialog = Gtk.MessageDialog(parent=self.window, flags=0, type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK,
1447 message_format=
'\n'.join(pause_messages))
1448 dialog.connect(
"response",
lambda d, r: d.destroy())
1450 self.play_button.set_active(
False)
1453 if not self.play_button.get_active():
1454 self._update_timeout_id =
None
1458 self.simulation.go.set()
1462 def _start_update_timer(self):
1463 if self._update_timeout_id
is not None:
1464 GLib.source_remove(self._update_timeout_id)
1466 self._update_timeout_id = GLib.timeout_add(int(SAMPLE_PERIOD/
min(self.speed, 1)*1e3),
1467 self.update_view_timeout,
1468 priority=PRIORITY_UPDATE_VIEW)
1470 def _on_play_button_toggled(self, button):
1471 if button.get_active():
1472 self._start_update_timer()
1474 if self._update_timeout_id
is not None:
1475 GLib.source_remove(self._update_timeout_id)
1477 def _quit(self, *dummy_args):
1478 if self._update_timeout_id
is not None:
1479 GLib.source_remove(self._update_timeout_id)
1480 self._update_timeout_id =
None
1481 self.simulation.quit =
True
1482 self.simulation.go.set()
1483 self.simulation.join()
1486 def _monkey_patch_ipython(self):
1493 original_runcode = self.ipython.runcode
1494 def runcode(ip, *args):
1496 self.simulation.lock.acquire()
1498 return original_runcode(*args)
1501 self.simulation.lock.release()
1503 self.ipython.runcode = types.MethodType(runcode, self.ipython)
1505 def autoscale_view(self):
1508 self._update_node_positions()
1509 positions = [node.get_position()
for node
in self.nodes.values()]
1510 min_x, min_y =
min(x
for (x,y)
in positions),
min(y
for (x,y)
in positions)
1511 max_x, max_y =
max(x
for (x,y)
in positions),
max(y
for (x,y)
in positions)
1512 min_x_px, min_y_px = self.canvas.convert_to_pixels(min_x, min_y)
1513 max_x_px, max_y_px = self.canvas.convert_to_pixels(max_x, max_y)
1516 dx_px = max_x_px - min_x_px
1517 dy_px = max_y_px - min_y_px
1518 hadj = self._scrolled_window.get_hadjustment()
1519 vadj = self._scrolled_window.get_vadjustment()
1520 new_dx, new_dy = 1.5*dx_px, 1.5*dy_px
1522 if new_dx == 0
or new_dy == 0:
1525 self.zoom.set_value(
min(hadj.get_page_size()/new_dx, vadj.get_page_size()/new_dy))
1527 x1, y1 = self.canvas.convert_from_pixels(hadj.get_value(), vadj.get_value())
1528 x2, y2 = self.canvas.convert_from_pixels((hadj.get_value() +
1529 hadj.get_page_size()),
1531 vadj.get_page_size()))
1534 center_x = (min_x + max_x) / 2
1535 center_y = (min_y + max_y) / 2
1537 self.canvas.scroll_to(center_x - width/2, center_y - height/2)
1542 self.scan_topology()
1543 self.window.connect(
"delete-event", self._quit)
1545 GLib.timeout_add(200, self.autoscale_view)
1546 self.simulation.
start()
1553 self._monkey_patch_ipython()
1558 def on_root_button_press_event(self, view, target, event):
1559 if event.button == 1:
1560 self.select_node(
None)
1563 def on_node_button_press_event(self, view, target, event, node):
1564 button = event.button
1566 self.select_node(node)
1569 self.popup_node_menu(node, event)
1572 self.begin_node_drag(node, event)
1576 def on_node_button_release_event(self, view, target, event, node):
1577 if event.button == 2:
1578 self.end_node_drag(node)
1582 class NodeDragState(
object):
1583 def __init__(self, canvas_x0, canvas_y0, sim_x0, sim_y0):
1584 self.canvas_x0 = canvas_x0
1585 self.canvas_y0 = canvas_y0
1586 self.sim_x0 = sim_x0
1587 self.sim_y0 = sim_y0
1588 self.motion_signal =
None
1590 def begin_node_drag(self, node, event):
1591 self.simulation.lock.acquire()
1593 ns3_node = ns.network.NodeList.GetNode(node.node_index)
1594 mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1597 if self.node_drag_state
is not None:
1599 pos = mob.GetPosition()
1601 self.simulation.lock.release()
1602 devpos = self.canvas.get_window().get_device_position(event.device)
1603 x0, y0 = self.canvas.convert_from_pixels(devpos.x, devpos.y)
1604 self.node_drag_state = self.NodeDragState(x0, y0, pos.x, pos.y)
1605 self.node_drag_state.motion_signal = node.canvas_item.connect(
"motion-notify-event", self.node_drag_motion, node)
1607 def node_drag_motion(self, item, targe_item, event, node):
1608 self.simulation.lock.acquire()
1610 ns3_node = ns.network.NodeList.GetNode(node.node_index)
1611 mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
1614 if self.node_drag_state
is None:
1616 devpos = self.canvas.get_window().get_device_position(event.device)
1617 canvas_x, canvas_y = self.canvas.convert_from_pixels(devpos.x, devpos.y)
1618 dx = (canvas_x - self.node_drag_state.canvas_x0)
1619 dy = (canvas_y - self.node_drag_state.canvas_y0)
1620 pos = mob.GetPosition()
1624 mob.SetPosition(pos)
1627 self.simulation.lock.release()
1630 def end_node_drag(self, node):
1631 if self.node_drag_state
is None:
1633 node.canvas_item.disconnect(self.node_drag_state.motion_signal)
1634 self.node_drag_state =
None
1636 def popup_node_menu(self, node, event):
1638 self.emit(
"populate-node-menu", node, menu)
1639 menu.popup(
None,
None,
None,
None, event.button, event.time)
1641 def _update_ipython_selected_node(self):
1650 if self.selected_node
is None:
1653 self.simulation.lock.acquire()
1655 ns3_node = ns.network.NodeList.GetNode(self.selected_node.node_index)
1657 self.simulation.lock.release()
1658 self.ipython.updateNamespace({
'selected_node': ns3_node})
1661 def select_node(self, node):
1662 if isinstance(node, ns.network.Node):
1663 node = self.nodes[node.GetId()]
1664 elif isinstance(node, (int, long)):
1665 node = self.nodes[node]
1666 elif isinstance(node, Node):
1671 raise TypeError(
"expected None, int, viz.Node or ns.network.Node, not %r" % node)
1673 if node
is self.selected_node:
1676 if self.selected_node
is not None:
1677 self.selected_node.selected =
False
1678 self.selected_node = node
1679 if self.selected_node
is not None:
1680 self.selected_node.selected =
True
1682 if self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
1683 if self.selected_node
is None:
1684 self.simulation.set_nodes_of_interest([])
1686 self.simulation.set_nodes_of_interest([self.selected_node.node_index])
1688 self._update_ipython_selected_node()
1691 def add_information_window(self, info_win):
1692 self.information_windows.append(info_win)
1693 self.simulation.lock.acquire()
1697 self.simulation.lock.release()
1699 def remove_information_window(self, info_win):
1700 self.information_windows.remove(info_win)
1702 def _canvas_tooltip_cb(self, canvas, x, y, keyboard_mode, tooltip):
1704 hadj = self._scrolled_window.get_hadjustment()
1705 vadj = self._scrolled_window.get_vadjustment()
1706 x, y = self.canvas.convert_from_pixels(hadj.get_value() + x, vadj.get_value() + y)
1707 item = self.canvas.get_item_at(x, y,
True)
1711 while item
is not None:
1712 obj = getattr(item,
"pyviz_object",
None)
1714 obj.tooltip_query(tooltip)
1716 item = item.props.parent
1719 def _get_export_file_name(self):
1720 sel = Gtk.FileChooserDialog(
"Save...", self.canvas.get_toplevel(),
1721 Gtk.FileChooserAction.SAVE,
1722 (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
1723 Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
1724 sel.set_default_response(Gtk.ResponseType.OK)
1725 sel.set_local_only(
True)
1726 sel.set_do_overwrite_confirmation(
True)
1727 sel.set_current_name(
"Unnamed.pdf")
1729 filter = Gtk.FileFilter()
1730 filter.set_name(
"Embedded PostScript")
1731 filter.add_mime_type(
"image/x-eps")
1732 sel.add_filter(filter)
1734 filter = Gtk.FileFilter()
1735 filter.set_name(
"Portable Document Graphics")
1736 filter.add_mime_type(
"application/pdf")
1737 sel.add_filter(filter)
1739 filter = Gtk.FileFilter()
1740 filter.set_name(
"Scalable Vector Graphics")
1741 filter.add_mime_type(
"image/svg+xml")
1742 sel.add_filter(filter)
1745 if resp != Gtk.ResponseType.OK:
1749 file_name = sel.get_filename()
1753 def _take_screenshot(self, dummy_button):
1755 file_name = self._get_export_file_name()
1756 if file_name
is None:
1760 x1 = self._scrolled_window.get_hadjustment().get_value()
1761 y1 = self._scrolled_window.get_vadjustment().get_value()
1762 x2 = x1 + self._scrolled_window.get_hadjustment().get_page_size()
1763 y2 = y1 + self._scrolled_window.get_vadjustment().get_page_size()
1764 bounds = GooCanvas.CanvasBounds()
1765 bounds.x1, bounds.y1 = self.canvas.convert_from_pixels(x1, y1)
1766 bounds.x2, bounds.y2 = self.canvas.convert_from_pixels(x2, y2)
1767 dest_width = bounds.x2 - bounds.x1
1768 dest_height = bounds.y2 - bounds.y1
1771 dummy, extension = os.path.splitext(file_name)
1772 extension = extension.lower()
1773 if extension ==
'.eps':
1774 surface = cairo.PSSurface(file_name, dest_width, dest_height)
1775 elif extension ==
'.pdf':
1776 surface = cairo.PDFSurface(file_name, dest_width, dest_height)
1777 elif extension ==
'.svg':
1778 surface = cairo.SVGSurface(file_name, dest_width, dest_height)
1780 dialog = Gtk.MessageDialog(parent = self.canvas.get_toplevel(),
1781 flags = Gtk.DialogFlags.DESTROY_WITH_PARENT,
1782 type = Gtk.MessageType.ERROR,
1783 buttons = Gtk.ButtonsType.OK,
1784 message_format =
"Unknown extension '%s' (valid extensions are '.eps', '.svg', and '.pdf')"
1791 cr = cairo.Context(surface)
1792 cr.translate(-bounds.x1, -bounds.y1)
1793 self.canvas.render(cr, bounds, self.zoom.get_value())
1797 def set_follow_node(self, node):
1798 if isinstance(node, ns.network.Node):
1799 node = self.nodes[node.GetId()]
1800 self.follow_node = node
1802 def _start_shell(self, dummy_button):
1803 if self.shell_window
is not None:
1804 self.shell_window.present()
1807 self.shell_window = Gtk.Window()
1808 self.shell_window.set_size_request(750,550)
1809 self.shell_window.set_resizable(
True)
1810 scrolled_window = Gtk.ScrolledWindow()
1811 scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC,
1812 Gtk.PolicyType.AUTOMATIC)
1814 self.ipython.modify_font(Pango.FontDescription(SHELL_FONT))
1815 self.ipython.set_wrap_mode(Gtk.WrapMode.CHAR)
1817 scrolled_window.add(self.ipython)
1818 scrolled_window.show()
1819 self.shell_window.add(scrolled_window)
1820 self.shell_window.show()
1821 self.shell_window.connect(
'destroy', self._on_shell_window_destroy)
1823 self._update_ipython_selected_node()
1824 self.ipython.updateNamespace({
'viz': self})
1827 def _on_shell_window_destroy(self, window):
1828 self.shell_window =
None
1831initialization_hooks = []
1835 Adds a callback to be called after
1836 the visualizer is initialized, like this::
1837 initialization_hook(visualizer, *args)
1839 global initialization_hooks
1840 initialization_hooks.append((hook, args))
1849 viz.canvas.set_bounds(cx1, cy1, cx2, cy2)
1854 assert Visualizer.INSTANCE
is None
1855 if _import_error
is not None:
1857 print(
"No visualization support (%s)." % (str(_import_error),),
1859 ns.core.Simulator.Run()
1863 for hook, args
in initialization_hooks:
1864 GLib.idle_add(hook, viz, *args)
1865 ns.network.Packet.EnablePrinting()
def set_position(self, x, y)
Initializer function.
def __init__(self, channel)
Initializer function.
def get_position(self)
Initializer function.
def on_enter_notify_event(self, view, target, event)
On Enter event handle.
visualizer
visualier object
def set_label(self, label)
Set a label for the node.
def add_link(self, link)
Add link 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 get_position(self)
Get position function.
_highlighted
is highlighted
def _set_selected(self, value)
Set selected function.
_label_canvas_item
label canvas
highlighted
highlighted property
def on_leave_notify_event(self, view, target, event)
On Leave event handle.
def remove_link(self, link)
Remove link function.
def _update_svg_position(self, x, y)
Update svg position.
def __init__(self, visualizer, node_index)
Initialize function.
_has_mobility
has mobility model
def _get_selected(self)
Get selected function.
def set_color(self, color)
Set color function.
def _get_highlighted(self)
Get highlighted function.
def _update_position(self)
Update position function.
def has_mobility(self)
Has mobility function.
def set_position(self, x, y)
Set position function.
def tooltip_query(self, tooltip)
Query tooltip.
def set_size(self, size)
Set size function.
def _update_appearance(self)
Update the node aspect to reflect the selected/highlighted state.
def _set_highlighted(self, value)
Set highlighted function.
pause_messages
pause messages
def run(self)
Initializer function.
def set_nodes_of_interest(self, nodes)
Set nodes of interest function.
def __init__(self, viz)
Initializer function.
sim_helper
helper function
def __init__(self, node1, node2)
Initializer function.
def update_points(self)
Update points function.
def transform_distance_simulation_to_canvas(d)
def transform_distance_canvas_to_simulation(d)
def lookup_netdevice_traits(class_type)
def transform_point_simulation_to_canvas(x, y)
def add_initialization_hook(hook, *args)
def set_bounds(x1, y1, x2, y2)