From 4e9de862a30e169a04f1c002556918577391fc80 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Thu, 12 Dec 2019 11:06:52 -0800 Subject: [PATCH] updated nodes to store actual positions, instead of scaled ones, updated shapes to return actual positions for metadata, added some logic for resetting the canvas and drawn nodes when resizing, convert node update coords into scaled coords for moving nodes --- coretk/coretk/appconfig.py | 25 +- coretk/coretk/coreclient.py | 12 +- coretk/coretk/data/mobility/sample1.scen | 28 + coretk/coretk/data/xmls/sample1.xml | 786 ++++++++++---------- coretk/coretk/dialogs/canvassizeandscale.py | 8 +- coretk/coretk/graph/graph.py | 88 ++- coretk/coretk/graph/node.py | 17 +- coretk/coretk/graph/shape.py | 10 + coretk/coretk/menuaction.py | 6 +- coretk/coretk/menubar.py | 15 +- 10 files changed, 535 insertions(+), 460 deletions(-) create mode 100644 coretk/coretk/data/mobility/sample1.scen diff --git a/coretk/coretk/appconfig.py b/coretk/coretk/appconfig.py index b2606994..33b08793 100644 --- a/coretk/coretk/appconfig.py +++ b/coretk/coretk/appconfig.py @@ -14,7 +14,7 @@ CUSTOM_EMANE_PATH = HOME_PATH.joinpath("custom_emane") CUSTOM_SERVICE_PATH = HOME_PATH.joinpath("custom_services") ICONS_PATH = HOME_PATH.joinpath("icons") MOBILITY_PATH = HOME_PATH.joinpath("mobility") -XML_PATH = HOME_PATH.joinpath("xml") +XMLS_PATH = HOME_PATH.joinpath("xmls") CONFIG_PATH = HOME_PATH.joinpath("gui.yaml") # local paths @@ -22,6 +22,7 @@ DATA_PATH = Path(__file__).parent.joinpath("data") LOCAL_ICONS_PATH = DATA_PATH.joinpath("icons").absolute() LOCAL_BACKGROUND_PATH = DATA_PATH.joinpath("backgrounds").absolute() LOCAL_XMLS_PATH = DATA_PATH.joinpath("xmls").absolute() +LOCAL_MOBILITY_PATH = DATA_PATH.joinpath("mobility").absolute() # configuration data TERMINALS = [ @@ -43,6 +44,12 @@ class IndentDumper(yaml.Dumper): return super().increase_indent(flow, False) +def copy_files(current_path, new_path): + for current_file in current_path.glob("*"): + new_file = new_path.joinpath(current_file.name) + shutil.copy(current_file, new_file) + + def check_directory(): if HOME_PATH.exists(): logging.info("~/.coretk exists") @@ -54,16 +61,12 @@ def check_directory(): CUSTOM_SERVICE_PATH.mkdir() ICONS_PATH.mkdir() MOBILITY_PATH.mkdir() - XML_PATH.mkdir() - for image in LOCAL_ICONS_PATH.glob("*"): - new_image = ICONS_PATH.joinpath(image.name) - shutil.copy(image, new_image) - for background in LOCAL_BACKGROUND_PATH.glob("*"): - new_background = BACKGROUNDS_PATH.joinpath(background.name) - shutil.copy(background, new_background) - for xml_file in LOCAL_XMLS_PATH.glob("*"): - new_xml = XML_PATH.joinpath(xml_file.name) - shutil.copy(xml_file, new_xml) + XMLS_PATH.mkdir() + + copy_files(LOCAL_ICONS_PATH, ICONS_PATH) + copy_files(LOCAL_BACKGROUND_PATH, BACKGROUNDS_PATH) + copy_files(LOCAL_XMLS_PATH, XMLS_PATH) + copy_files(LOCAL_MOBILITY_PATH, MOBILITY_PATH) if "TERM" in os.environ: terminal = TERMINALS[0] diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index 36562cce..57224a93 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -300,14 +300,16 @@ class CoreClient: width = self.app.guiconfig["preferences"]["width"] height = self.app.guiconfig["preferences"]["height"] - width, height = canvas_config.get("dimensions", [width, height]) - self.app.canvas.redraw_canvas(width, height) + dimensions = canvas_config.get("dimensions", [width, height]) + self.app.canvas.redraw_canvas(dimensions) wallpaper = canvas_config.get("wallpaper") if wallpaper: wallpaper = str(appconfig.BACKGROUNDS_PATH.joinpath(wallpaper)) - self.app.canvas.set_wallpaper(wallpaper) - self.app.canvas.update_grid() + self.app.canvas.set_wallpaper(wallpaper) + else: + self.app.canvas.redraw_canvas() + self.app.canvas.set_wallpaper(None) # load saved shapes shapes_config = config.get("shapes") @@ -482,7 +484,7 @@ class CoreClient: "wallpaper-style": self.app.canvas.scale_option.get(), "gridlines": self.app.canvas.show_grid.get(), "fit_image": self.app.canvas.adjust_to_dim.get(), - "dimensions": self.app.canvas.width_and_height(), + "dimensions": self.app.canvas.current_dimensions, } canvas_config = json.dumps(canvas_config) diff --git a/coretk/coretk/data/mobility/sample1.scen b/coretk/coretk/data/mobility/sample1.scen new file mode 100644 index 00000000..c2fc5a44 --- /dev/null +++ b/coretk/coretk/data/mobility/sample1.scen @@ -0,0 +1,28 @@ +# +# nodes: 4, max time: 27.000000, max x: 600.00, max y: 600.00 +# nominal range: 300.00 link bw: 54000000.00 +# pause: 30.00, min speed 1.50 max speed: 4.50 + +$node_(6) set X_ 780.0 +$node_(6) set Y_ 228.0 +$node_(6) set Z_ 0.00 +$node_(7) set X_ 816.0 +$node_(7) set Y_ 348.0 +$node_(7) set Z_ 0.00 +$node_(8) set X_ 672.0 +$node_(8) set Y_ 420.0 +$node_(8) set Z_ 0.00 +$node_(9) set X_ 672.0 +$node_(9) set Y_ 96.0 +$node_(9) set Z_ 0.00 +$ns_ at 1.00 "$node_(6) setdest 500.0 178.0 25.0" +$ns_ at 2.00 "$node_(7) setdest 400.0 288.0 15.0" +$ns_ at 1.00 "$node_(8) setdest 590.0 520.0 17.0" +$ns_ at 3.00 "$node_(9) setdest 720.0 300.0 20.0" +$ns_ at 8.00 "$node_(7) setdest 600.0 350.0 10.0" +$ns_ at 9.00 "$node_(8) setdest 730.0 300.0 15.0" +$ns_ at 10.00 "$node_(6) setdest 600.0 108.0 10.0" +$ns_ at 16.00 "$node_(9) setdest 672.0 96.0 20.0" +$ns_ at 17.00 "$node_(7) setdest 816.0 348.0 20.0" +$ns_ at 18.00 "$node_(6) setdest 780.0 228.0 25.0" +$ns_ at 22.00 "$node_(8) setdest 672.0 420.0 20.0" diff --git a/coretk/coretk/data/xmls/sample1.xml b/coretk/coretk/data/xmls/sample1.xml index 8c61b7de..afec8874 100644 --- a/coretk/coretk/data/xmls/sample1.xml +++ b/coretk/coretk/data/xmls/sample1.xml @@ -1,5 +1,5 @@ - + @@ -18,15 +18,6 @@ - - - - - - - - - @@ -36,6 +27,23 @@ + + + + + + + + + + + + + + + + + @@ -44,6 +52,14 @@ + + + + + + + + @@ -61,28 +77,12 @@ - - - - - - - - - - - - - - - - @@ -117,62 +117,62 @@ - - + + - - + + - - + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + @@ -188,7 +188,7 @@ - + @@ -367,6 +367,177 @@ bootquagga /sbin/sysctl -w net.ipv4.conf.eth1.forwarding=1 /sbin/sysctl -w net.ipv4.conf.eth1.send_redirects=0 /sbin/sysctl -w net.ipv4.conf.eth1.rp_filter=0 + + + + + + /usr/local/etc/quagga + /var/run/quagga + + + sh quaggaboot.sh zebra + + + pidof zebra + + + killall zebra + + + interface eth0 + ip address 10.0.1.1/24 + ipv6 address a:1::1/64 +! +interface eth1 + ip address 10.0.2.1/24 + ipv6 address a:2::1/64 +! +router ospf + router-id 10.0.1.1 + network 10.0.1.0/24 area 0 + network 10.0.2.0/24 area 0 +! +router ospf6 + router-id 10.0.1.1 + interface eth0 area 0.0.0.0 + interface eth1 area 0.0.0.0 +! + + #!/bin/sh +# auto-generated by zebra service (quagga.py) +QUAGGA_CONF=/usr/local/etc/quagga/Quagga.conf +QUAGGA_SBIN_SEARCH="/usr/local/sbin /usr/sbin /usr/lib/quagga" +QUAGGA_BIN_SEARCH="/usr/local/bin /usr/bin /usr/lib/quagga" +QUAGGA_STATE_DIR=/var/run/quagga + +searchforprog() +{ + prog=$1 + searchpath=$@ + ret= + for p in $searchpath; do + if [ -x $p/$prog ]; then + ret=$p + break + fi + done + echo $ret +} + +confcheck() +{ + CONF_DIR=`dirname $QUAGGA_CONF` + # if /etc/quagga exists, point /etc/quagga/Quagga.conf -> CONF_DIR + if [ "$CONF_DIR" != "/etc/quagga" ] && [ -d /etc/quagga ] && [ ! -e /etc/quagga/Quagga.conf ]; then + ln -s $CONF_DIR/Quagga.conf /etc/quagga/Quagga.conf + fi + # if /etc/quagga exists, point /etc/quagga/vtysh.conf -> CONF_DIR + if [ "$CONF_DIR" != "/etc/quagga" ] && [ -d /etc/quagga ] && [ ! -e /etc/quagga/vtysh.conf ]; then + ln -s $CONF_DIR/vtysh.conf /etc/quagga/vtysh.conf + fi +} + +bootdaemon() +{ + QUAGGA_SBIN_DIR=$(searchforprog $1 $QUAGGA_SBIN_SEARCH) + if [ "z$QUAGGA_SBIN_DIR" = "z" ]; then + echo "ERROR: Quagga's '$1' daemon not found in search path:" + echo " $QUAGGA_SBIN_SEARCH" + return 1 + fi + + flags="" + + if [ "$1" = "xpimd" ] && \ + grep -E -q '^[[:space:]]*router[[:space:]]+pim6[[:space:]]*$' $QUAGGA_CONF; then + flags="$flags -6" + fi + + $QUAGGA_SBIN_DIR/$1 $flags -d + if [ "$?" != "0" ]; then + echo "ERROR: Quagga's '$1' daemon failed to start!:" + return 1 + fi +} + +bootquagga() +{ + QUAGGA_BIN_DIR=$(searchforprog 'vtysh' $QUAGGA_BIN_SEARCH) + if [ "z$QUAGGA_BIN_DIR" = "z" ]; then + echo "ERROR: Quagga's 'vtysh' program not found in search path:" + echo " $QUAGGA_BIN_SEARCH" + return 1 + fi + + # fix /var/run/quagga permissions + id -u quagga 2>/dev/null >/dev/null + if [ "$?" = "0" ]; then + chown quagga $QUAGGA_STATE_DIR + fi + + bootdaemon "zebra" + for r in rip ripng ospf6 ospf bgp babel; do + if grep -q "^router \<${r}\>" $QUAGGA_CONF; then + bootdaemon "${r}d" + fi + done + + if grep -E -q '^[[:space:]]*router[[:space:]]+pim6?[[:space:]]*$' $QUAGGA_CONF; then + bootdaemon "xpimd" + fi + + $QUAGGA_BIN_DIR/vtysh -b +} + +if [ "$1" != "zebra" ]; then + echo "WARNING: '$1': all Quagga daemons are launched by the 'zebra' service!" + exit 1 +fi +confcheck +bootquagga + + service integrated-vtysh-config + + + + + + pidof ospfd + + + killall ospfd + + + + + pidof ospf6d + + + killall ospf6d + + + + + sh ipforward.sh + + + #!/bin/sh +# auto-generated by IPForward service (utility.py) +/sbin/sysctl -w net.ipv4.conf.all.forwarding=1 +/sbin/sysctl -w net.ipv4.conf.default.forwarding=1 +/sbin/sysctl -w net.ipv6.conf.all.forwarding=1 +/sbin/sysctl -w net.ipv6.conf.default.forwarding=1 +/sbin/sysctl -w net.ipv4.conf.all.send_redirects=0 +/sbin/sysctl -w net.ipv4.conf.default.send_redirects=0 +/sbin/sysctl -w net.ipv4.conf.all.rp_filter=0 +/sbin/sysctl -w net.ipv4.conf.default.rp_filter=0 +/sbin/sysctl -w net.ipv4.conf.eth0.forwarding=1 +/sbin/sysctl -w net.ipv4.conf.eth0.send_redirects=0 +/sbin/sysctl -w net.ipv4.conf.eth0.rp_filter=0 +/sbin/sysctl -w net.ipv4.conf.eth1.forwarding=1 +/sbin/sysctl -w net.ipv4.conf.eth1.send_redirects=0 +/sbin/sysctl -w net.ipv4.conf.eth1.rp_filter=0 @@ -550,7 +721,7 @@ bootquagga - + /usr/local/etc/quagga /var/run/quagga @@ -566,22 +737,20 @@ bootquagga interface eth0 - ip address 10.0.1.1/24 - ipv6 address a:1::1/64 -! -interface eth1 - ip address 10.0.2.1/24 - ipv6 address a:2::1/64 -! -router ospf - router-id 10.0.1.1 - network 10.0.1.0/24 area 0 - network 10.0.2.0/24 area 0 + ip address 10.0.0.9/32 + ipv6 address a::9/128 + ipv6 ospf6 instance-id 65 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 6 + ipv6 ospf6 retransmit-interval 5 + ipv6 ospf6 network manet-designated-router + ipv6 ospf6 diffhellos + ipv6 ospf6 adjacencyconnectivity uniconnected + ipv6 ospf6 lsafullness mincostlsa ! router ospf6 - router-id 10.0.1.1 + router-id 10.0.0.9 interface eth0 area 0.0.0.0 - interface eth1 area 0.0.0.0 ! #!/bin/sh @@ -681,15 +850,7 @@ bootquagga - - - pidof ospfd - - - killall ospfd - - - + pidof ospf6d @@ -697,7 +858,7 @@ bootquagga killall ospf6d - + sh ipforward.sh @@ -715,9 +876,6 @@ bootquagga /sbin/sysctl -w net.ipv4.conf.eth0.forwarding=1 /sbin/sysctl -w net.ipv4.conf.eth0.send_redirects=0 /sbin/sysctl -w net.ipv4.conf.eth0.rp_filter=0 -/sbin/sysctl -w net.ipv4.conf.eth1.forwarding=1 -/sbin/sysctl -w net.ipv4.conf.eth1.send_redirects=0 -/sbin/sysctl -w net.ipv4.conf.eth1.rp_filter=0 @@ -876,6 +1034,164 @@ bootquagga /sbin/sysctl -w net.ipv4.conf.eth0.forwarding=1 /sbin/sysctl -w net.ipv4.conf.eth0.send_redirects=0 /sbin/sysctl -w net.ipv4.conf.eth0.rp_filter=0 + + + + + + /usr/local/etc/quagga + /var/run/quagga + + + sh quaggaboot.sh zebra + + + pidof zebra + + + killall zebra + + + interface eth0 + ip address 10.0.0.7/32 + ipv6 address a::7/128 + ipv6 ospf6 instance-id 65 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 6 + ipv6 ospf6 retransmit-interval 5 + ipv6 ospf6 network manet-designated-router + ipv6 ospf6 diffhellos + ipv6 ospf6 adjacencyconnectivity uniconnected + ipv6 ospf6 lsafullness mincostlsa +! +router ospf6 + router-id 10.0.0.7 + interface eth0 area 0.0.0.0 +! + + #!/bin/sh +# auto-generated by zebra service (quagga.py) +QUAGGA_CONF=/usr/local/etc/quagga/Quagga.conf +QUAGGA_SBIN_SEARCH="/usr/local/sbin /usr/sbin /usr/lib/quagga" +QUAGGA_BIN_SEARCH="/usr/local/bin /usr/bin /usr/lib/quagga" +QUAGGA_STATE_DIR=/var/run/quagga + +searchforprog() +{ + prog=$1 + searchpath=$@ + ret= + for p in $searchpath; do + if [ -x $p/$prog ]; then + ret=$p + break + fi + done + echo $ret +} + +confcheck() +{ + CONF_DIR=`dirname $QUAGGA_CONF` + # if /etc/quagga exists, point /etc/quagga/Quagga.conf -> CONF_DIR + if [ "$CONF_DIR" != "/etc/quagga" ] && [ -d /etc/quagga ] && [ ! -e /etc/quagga/Quagga.conf ]; then + ln -s $CONF_DIR/Quagga.conf /etc/quagga/Quagga.conf + fi + # if /etc/quagga exists, point /etc/quagga/vtysh.conf -> CONF_DIR + if [ "$CONF_DIR" != "/etc/quagga" ] && [ -d /etc/quagga ] && [ ! -e /etc/quagga/vtysh.conf ]; then + ln -s $CONF_DIR/vtysh.conf /etc/quagga/vtysh.conf + fi +} + +bootdaemon() +{ + QUAGGA_SBIN_DIR=$(searchforprog $1 $QUAGGA_SBIN_SEARCH) + if [ "z$QUAGGA_SBIN_DIR" = "z" ]; then + echo "ERROR: Quagga's '$1' daemon not found in search path:" + echo " $QUAGGA_SBIN_SEARCH" + return 1 + fi + + flags="" + + if [ "$1" = "xpimd" ] && \ + grep -E -q '^[[:space:]]*router[[:space:]]+pim6[[:space:]]*$' $QUAGGA_CONF; then + flags="$flags -6" + fi + + $QUAGGA_SBIN_DIR/$1 $flags -d + if [ "$?" != "0" ]; then + echo "ERROR: Quagga's '$1' daemon failed to start!:" + return 1 + fi +} + +bootquagga() +{ + QUAGGA_BIN_DIR=$(searchforprog 'vtysh' $QUAGGA_BIN_SEARCH) + if [ "z$QUAGGA_BIN_DIR" = "z" ]; then + echo "ERROR: Quagga's 'vtysh' program not found in search path:" + echo " $QUAGGA_BIN_SEARCH" + return 1 + fi + + # fix /var/run/quagga permissions + id -u quagga 2>/dev/null >/dev/null + if [ "$?" = "0" ]; then + chown quagga $QUAGGA_STATE_DIR + fi + + bootdaemon "zebra" + for r in rip ripng ospf6 ospf bgp babel; do + if grep -q "^router \<${r}\>" $QUAGGA_CONF; then + bootdaemon "${r}d" + fi + done + + if grep -E -q '^[[:space:]]*router[[:space:]]+pim6?[[:space:]]*$' $QUAGGA_CONF; then + bootdaemon "xpimd" + fi + + $QUAGGA_BIN_DIR/vtysh -b +} + +if [ "$1" != "zebra" ]; then + echo "WARNING: '$1': all Quagga daemons are launched by the 'zebra' service!" + exit 1 +fi +confcheck +bootquagga + + service integrated-vtysh-config + + + + + + pidof ospf6d + + + killall ospf6d + + + + + sh ipforward.sh + + + #!/bin/sh +# auto-generated by IPForward service (utility.py) +/sbin/sysctl -w net.ipv4.conf.all.forwarding=1 +/sbin/sysctl -w net.ipv4.conf.default.forwarding=1 +/sbin/sysctl -w net.ipv6.conf.all.forwarding=1 +/sbin/sysctl -w net.ipv6.conf.default.forwarding=1 +/sbin/sysctl -w net.ipv4.conf.all.send_redirects=0 +/sbin/sysctl -w net.ipv4.conf.default.send_redirects=0 +/sbin/sysctl -w net.ipv4.conf.all.rp_filter=0 +/sbin/sysctl -w net.ipv4.conf.default.rp_filter=0 +/sbin/sysctl -w net.ipv4.conf.eth0.forwarding=1 +/sbin/sysctl -w net.ipv4.conf.eth0.send_redirects=0 +/sbin/sysctl -w net.ipv4.conf.eth0.rp_filter=0 @@ -1221,164 +1537,6 @@ bootquagga /sbin/sysctl -w net.ipv4.conf.eth0.forwarding=1 /sbin/sysctl -w net.ipv4.conf.eth0.send_redirects=0 /sbin/sysctl -w net.ipv4.conf.eth0.rp_filter=0 - - - - - - /usr/local/etc/quagga - /var/run/quagga - - - sh quaggaboot.sh zebra - - - pidof zebra - - - killall zebra - - - interface eth0 - ip address 10.0.0.7/32 - ipv6 address a::7/128 - ipv6 ospf6 instance-id 65 - ipv6 ospf6 hello-interval 2 - ipv6 ospf6 dead-interval 6 - ipv6 ospf6 retransmit-interval 5 - ipv6 ospf6 network manet-designated-router - ipv6 ospf6 diffhellos - ipv6 ospf6 adjacencyconnectivity uniconnected - ipv6 ospf6 lsafullness mincostlsa -! -router ospf6 - router-id 10.0.0.7 - interface eth0 area 0.0.0.0 -! - - #!/bin/sh -# auto-generated by zebra service (quagga.py) -QUAGGA_CONF=/usr/local/etc/quagga/Quagga.conf -QUAGGA_SBIN_SEARCH="/usr/local/sbin /usr/sbin /usr/lib/quagga" -QUAGGA_BIN_SEARCH="/usr/local/bin /usr/bin /usr/lib/quagga" -QUAGGA_STATE_DIR=/var/run/quagga - -searchforprog() -{ - prog=$1 - searchpath=$@ - ret= - for p in $searchpath; do - if [ -x $p/$prog ]; then - ret=$p - break - fi - done - echo $ret -} - -confcheck() -{ - CONF_DIR=`dirname $QUAGGA_CONF` - # if /etc/quagga exists, point /etc/quagga/Quagga.conf -> CONF_DIR - if [ "$CONF_DIR" != "/etc/quagga" ] && [ -d /etc/quagga ] && [ ! -e /etc/quagga/Quagga.conf ]; then - ln -s $CONF_DIR/Quagga.conf /etc/quagga/Quagga.conf - fi - # if /etc/quagga exists, point /etc/quagga/vtysh.conf -> CONF_DIR - if [ "$CONF_DIR" != "/etc/quagga" ] && [ -d /etc/quagga ] && [ ! -e /etc/quagga/vtysh.conf ]; then - ln -s $CONF_DIR/vtysh.conf /etc/quagga/vtysh.conf - fi -} - -bootdaemon() -{ - QUAGGA_SBIN_DIR=$(searchforprog $1 $QUAGGA_SBIN_SEARCH) - if [ "z$QUAGGA_SBIN_DIR" = "z" ]; then - echo "ERROR: Quagga's '$1' daemon not found in search path:" - echo " $QUAGGA_SBIN_SEARCH" - return 1 - fi - - flags="" - - if [ "$1" = "xpimd" ] && \ - grep -E -q '^[[:space:]]*router[[:space:]]+pim6[[:space:]]*$' $QUAGGA_CONF; then - flags="$flags -6" - fi - - $QUAGGA_SBIN_DIR/$1 $flags -d - if [ "$?" != "0" ]; then - echo "ERROR: Quagga's '$1' daemon failed to start!:" - return 1 - fi -} - -bootquagga() -{ - QUAGGA_BIN_DIR=$(searchforprog 'vtysh' $QUAGGA_BIN_SEARCH) - if [ "z$QUAGGA_BIN_DIR" = "z" ]; then - echo "ERROR: Quagga's 'vtysh' program not found in search path:" - echo " $QUAGGA_BIN_SEARCH" - return 1 - fi - - # fix /var/run/quagga permissions - id -u quagga 2>/dev/null >/dev/null - if [ "$?" = "0" ]; then - chown quagga $QUAGGA_STATE_DIR - fi - - bootdaemon "zebra" - for r in rip ripng ospf6 ospf bgp babel; do - if grep -q "^router \<${r}\>" $QUAGGA_CONF; then - bootdaemon "${r}d" - fi - done - - if grep -E -q '^[[:space:]]*router[[:space:]]+pim6?[[:space:]]*$' $QUAGGA_CONF; then - bootdaemon "xpimd" - fi - - $QUAGGA_BIN_DIR/vtysh -b -} - -if [ "$1" != "zebra" ]; then - echo "WARNING: '$1': all Quagga daemons are launched by the 'zebra' service!" - exit 1 -fi -confcheck -bootquagga - - service integrated-vtysh-config - - - - - - pidof ospf6d - - - killall ospf6d - - - - - sh ipforward.sh - - - #!/bin/sh -# auto-generated by IPForward service (utility.py) -/sbin/sysctl -w net.ipv4.conf.all.forwarding=1 -/sbin/sysctl -w net.ipv4.conf.default.forwarding=1 -/sbin/sysctl -w net.ipv6.conf.all.forwarding=1 -/sbin/sysctl -w net.ipv6.conf.default.forwarding=1 -/sbin/sysctl -w net.ipv4.conf.all.send_redirects=0 -/sbin/sysctl -w net.ipv4.conf.default.send_redirects=0 -/sbin/sysctl -w net.ipv4.conf.all.rp_filter=0 -/sbin/sysctl -w net.ipv4.conf.default.rp_filter=0 -/sbin/sysctl -w net.ipv4.conf.eth0.forwarding=1 -/sbin/sysctl -w net.ipv4.conf.eth0.send_redirects=0 -/sbin/sysctl -w net.ipv4.conf.eth0.rp_filter=0 @@ -1391,164 +1549,6 @@ bootquagga # auto-generated by DefaultRoute service (utility.py) ip route add default via 10.0.1.1 ip route add default via a:1::1 - - - - - - /usr/local/etc/quagga - /var/run/quagga - - - sh quaggaboot.sh zebra - - - pidof zebra - - - killall zebra - - - interface eth0 - ip address 10.0.0.9/32 - ipv6 address a::9/128 - ipv6 ospf6 instance-id 65 - ipv6 ospf6 hello-interval 2 - ipv6 ospf6 dead-interval 6 - ipv6 ospf6 retransmit-interval 5 - ipv6 ospf6 network manet-designated-router - ipv6 ospf6 diffhellos - ipv6 ospf6 adjacencyconnectivity uniconnected - ipv6 ospf6 lsafullness mincostlsa -! -router ospf6 - router-id 10.0.0.9 - interface eth0 area 0.0.0.0 -! - - #!/bin/sh -# auto-generated by zebra service (quagga.py) -QUAGGA_CONF=/usr/local/etc/quagga/Quagga.conf -QUAGGA_SBIN_SEARCH="/usr/local/sbin /usr/sbin /usr/lib/quagga" -QUAGGA_BIN_SEARCH="/usr/local/bin /usr/bin /usr/lib/quagga" -QUAGGA_STATE_DIR=/var/run/quagga - -searchforprog() -{ - prog=$1 - searchpath=$@ - ret= - for p in $searchpath; do - if [ -x $p/$prog ]; then - ret=$p - break - fi - done - echo $ret -} - -confcheck() -{ - CONF_DIR=`dirname $QUAGGA_CONF` - # if /etc/quagga exists, point /etc/quagga/Quagga.conf -> CONF_DIR - if [ "$CONF_DIR" != "/etc/quagga" ] && [ -d /etc/quagga ] && [ ! -e /etc/quagga/Quagga.conf ]; then - ln -s $CONF_DIR/Quagga.conf /etc/quagga/Quagga.conf - fi - # if /etc/quagga exists, point /etc/quagga/vtysh.conf -> CONF_DIR - if [ "$CONF_DIR" != "/etc/quagga" ] && [ -d /etc/quagga ] && [ ! -e /etc/quagga/vtysh.conf ]; then - ln -s $CONF_DIR/vtysh.conf /etc/quagga/vtysh.conf - fi -} - -bootdaemon() -{ - QUAGGA_SBIN_DIR=$(searchforprog $1 $QUAGGA_SBIN_SEARCH) - if [ "z$QUAGGA_SBIN_DIR" = "z" ]; then - echo "ERROR: Quagga's '$1' daemon not found in search path:" - echo " $QUAGGA_SBIN_SEARCH" - return 1 - fi - - flags="" - - if [ "$1" = "xpimd" ] && \ - grep -E -q '^[[:space:]]*router[[:space:]]+pim6[[:space:]]*$' $QUAGGA_CONF; then - flags="$flags -6" - fi - - $QUAGGA_SBIN_DIR/$1 $flags -d - if [ "$?" != "0" ]; then - echo "ERROR: Quagga's '$1' daemon failed to start!:" - return 1 - fi -} - -bootquagga() -{ - QUAGGA_BIN_DIR=$(searchforprog 'vtysh' $QUAGGA_BIN_SEARCH) - if [ "z$QUAGGA_BIN_DIR" = "z" ]; then - echo "ERROR: Quagga's 'vtysh' program not found in search path:" - echo " $QUAGGA_BIN_SEARCH" - return 1 - fi - - # fix /var/run/quagga permissions - id -u quagga 2>/dev/null >/dev/null - if [ "$?" = "0" ]; then - chown quagga $QUAGGA_STATE_DIR - fi - - bootdaemon "zebra" - for r in rip ripng ospf6 ospf bgp babel; do - if grep -q "^router \<${r}\>" $QUAGGA_CONF; then - bootdaemon "${r}d" - fi - done - - if grep -E -q '^[[:space:]]*router[[:space:]]+pim6?[[:space:]]*$' $QUAGGA_CONF; then - bootdaemon "xpimd" - fi - - $QUAGGA_BIN_DIR/vtysh -b -} - -if [ "$1" != "zebra" ]; then - echo "WARNING: '$1': all Quagga daemons are launched by the 'zebra' service!" - exit 1 -fi -confcheck -bootquagga - - service integrated-vtysh-config - - - - - - pidof ospf6d - - - killall ospf6d - - - - - sh ipforward.sh - - - #!/bin/sh -# auto-generated by IPForward service (utility.py) -/sbin/sysctl -w net.ipv4.conf.all.forwarding=1 -/sbin/sysctl -w net.ipv4.conf.default.forwarding=1 -/sbin/sysctl -w net.ipv6.conf.all.forwarding=1 -/sbin/sysctl -w net.ipv6.conf.default.forwarding=1 -/sbin/sysctl -w net.ipv4.conf.all.send_redirects=0 -/sbin/sysctl -w net.ipv4.conf.default.send_redirects=0 -/sbin/sysctl -w net.ipv4.conf.all.rp_filter=0 -/sbin/sysctl -w net.ipv4.conf.default.rp_filter=0 -/sbin/sysctl -w net.ipv4.conf.eth0.forwarding=1 -/sbin/sysctl -w net.ipv4.conf.eth0.send_redirects=0 -/sbin/sysctl -w net.ipv4.conf.eth0.rp_filter=0 @@ -1842,8 +1842,8 @@ bootquagga - - + + diff --git a/coretk/coretk/dialogs/canvassizeandscale.py b/coretk/coretk/dialogs/canvassizeandscale.py index 5a472104..0a113936 100644 --- a/coretk/coretk/dialogs/canvassizeandscale.py +++ b/coretk/coretk/dialogs/canvassizeandscale.py @@ -21,11 +21,7 @@ class SizeAndScaleDialog(Dialog): self.canvas = self.app.canvas self.validation = app.validation self.section_font = font.Font(weight="bold") - # get current canvas dimensions - plot = self.canvas.find_withtag("rectangle") - x0, y0, x1, y1 = self.canvas.bbox(plot[0]) - width = abs(x0 - x1) - 2 - height = abs(y0 - y1) - 2 + width, height = self.canvas.current_dimensions self.pixel_width = tk.IntVar(value=width) self.pixel_height = tk.IntVar(value=height) location = self.app.core.location @@ -232,7 +228,7 @@ class SizeAndScaleDialog(Dialog): def click_apply(self): width, height = self.pixel_width.get(), self.pixel_height.get() - self.canvas.redraw_canvas(width, height) + self.canvas.redraw_canvas((width, height)) if self.canvas.wallpaper: self.canvas.redraw_wallpaper() location = self.app.core.location diff --git a/coretk/coretk/graph/graph.py b/coretk/coretk/graph/graph.py index e79e0f9c..42d2c4de 100644 --- a/coretk/coretk/graph/graph.py +++ b/coretk/coretk/graph/graph.py @@ -14,19 +14,13 @@ from coretk.graph.shape import Shape from coretk.graph.shapeutils import ShapeType, is_draw_shape from coretk.nodeutils import NodeUtils -SCROLL_BUFFER = 25 ZOOM_IN = 1.1 ZOOM_OUT = 0.9 class CanvasGraph(tk.Canvas): def __init__(self, master, core, width, height): - super().__init__( - master, - highlightthickness=0, - background="#cccccc", - scrollregion=(0, 0, width + SCROLL_BUFFER, height + SCROLL_BUFFER), - ) + super().__init__(master, highlightthickness=0, background="#cccccc") self.app = master self.core = core self.mode = GraphMode.SELECT @@ -44,8 +38,8 @@ class CanvasGraph(tk.Canvas): self.grid = None self.throughput_draw = Throughput(self, core) self.shape_drawing = False - self.default_width = width - self.default_height = height + self.default_dimensions = (width, height) + self.current_dimensions = self.default_dimensions self.ratio = 1.0 self.offset = (0, 0) self.cursor = (0, 0) @@ -66,17 +60,22 @@ class CanvasGraph(tk.Canvas): self.draw_canvas() self.draw_grid() - def draw_canvas(self): + def draw_canvas(self, dimensions=None): + if self.grid is not None: + self.delete(self.grid) + if not dimensions: + dimensions = self.default_dimensions + self.current_dimensions = dimensions self.grid = self.create_rectangle( 0, 0, - self.default_width, - self.default_height, + *dimensions, outline="#000000", fill="#ffffff", width=1, tags="rectangle", ) + self.configure(scrollregion=self.bbox(tk.ALL)) def reset_and_redraw(self, session): """ @@ -121,6 +120,16 @@ class CanvasGraph(tk.Canvas): self.bind("", lambda e: self.scan_mark(e.x, e.y)) self.bind("", lambda e: self.scan_dragto(e.x, e.y, gain=1)) + def get_actual_coords(self, x, y): + actual_x = (x - self.offset[0]) / self.ratio + actual_y = (y - self.offset[1]) / self.ratio + return actual_x, actual_y + + def get_scaled_coords(self, x, y): + scaled_x = (x * self.ratio) + self.offset[0] + scaled_y = (y * self.ratio) + self.offset[1] + return scaled_x, scaled_y + def draw_grid(self): """ Create grid. @@ -177,7 +186,9 @@ class CanvasGraph(tk.Canvas): # draw nodes on the canvas image = NodeUtils.node_icon(core_node.type, core_node.model) - node = CanvasNode(self.master, core_node, image) + x = core_node.position.x + y = core_node.position.y + node = CanvasNode(self.master, x, y, core_node, image) self.nodes[node.id] = node self.core.canvas_nodes[core_node.id] = node @@ -422,8 +433,8 @@ class CanvasGraph(tk.Canvas): if not factor: factor = ZOOM_IN if event.delta > 0 else ZOOM_OUT event.x, event.y = self.canvasx(event.x), self.canvasy(event.y) - self.scale("all", event.x, event.y, factor, factor) - self.configure(scrollregion=self.bbox("all")) + self.scale(tk.ALL, event.x, event.y, factor, factor) + self.configure(scrollregion=self.bbox(tk.ALL)) self.ratio *= float(factor) self.offset = ( self.offset[0] * factor + event.x * (1 - factor), @@ -444,7 +455,10 @@ class CanvasGraph(tk.Canvas): x, y = self.canvas_xy(event) self.cursor = x, y selected = self.get_selected(event) - logging.debug("click press: %s", selected) + logging.debug("click press(%s): %s", self.cursor, selected) + x_check = self.cursor[0] - self.offset[0] + y_check = self.cursor[1] - self.offset[1] + logging.debug("clock press ofset(%s, %s)", x_check, y_check) is_node = selected in self.nodes if self.mode == GraphMode.EDGE and is_node: x, y = self.coords(selected) @@ -466,6 +480,11 @@ class CanvasGraph(tk.Canvas): node = self.nodes[selected] self.select_object(node.id) self.selected = selected + logging.info( + "selected coords: (%s, %s)", + node.core_node.position.x, + node.core_node.position.y, + ) else: logging.debug("create selection box") if self.mode == GraphMode.SELECT: @@ -557,10 +576,14 @@ class CanvasGraph(tk.Canvas): def add_node(self, x, y): if self.selected is None or self.selected in self.shapes: + actual_x, actual_y = self.get_actual_coords(x, y) core_node = self.core.create_node( - int(x), int(y), self.node_draw.node_type, self.node_draw.model + int(actual_x), + int(actual_y), + self.node_draw.node_type, + self.node_draw.model, ) - node = CanvasNode(self.master, core_node, self.node_draw.image) + node = CanvasNode(self.master, x, y, core_node, self.node_draw.image) self.core.canvas_nodes[core_node.id] = node self.nodes[node.id] = node return node @@ -652,18 +675,24 @@ class CanvasGraph(tk.Canvas): def resize_to_wallpaper(self): self.delete(self.wallpaper_id) image = ImageTk.PhotoImage(self.wallpaper) - self.redraw_canvas(image.width(), image.height()) + self.redraw_canvas((image.width(), image.height())) self.draw_wallpaper(image) - def redraw_canvas(self, width, height): - """ - redraw grid with new dimension + def redraw_canvas(self, dimensions=None): + logging.info("redrawing canvas to dimensions: %s", dimensions) - :return: nothing - """ - # resize canvas and scrollregion - self.config(scrollregion=(0, 0, width + SCROLL_BUFFER, height + SCROLL_BUFFER)) - self.coords(self.grid, 0, 0, width, height) + # reset scale and move back to original position + logging.info("resetting scaling: %s %s", self.ratio, self.offset) + factor = 1 / self.ratio + self.scale(tk.ALL, self.offset[0], self.offset[1], factor, factor) + self.move(tk.ALL, -self.offset[0], -self.offset[1]) + + # reset ratio and offset + self.ratio = 1.0 + self.offset = (0, 0) + + # redraw canvas rectangle + self.draw_canvas(dimensions) # redraw gridlines to new canvas size self.delete(tags.GRIDLINE) @@ -672,10 +701,11 @@ class CanvasGraph(tk.Canvas): def redraw_wallpaper(self): if self.adjust_to_dim.get(): + logging.info("drawing wallpaper to canvas dimensions") self.resize_to_wallpaper() else: option = ScaleOption(self.scale_option.get()) - logging.info("canvas scale option: %s", option) + logging.info("drawing canvas using scaling option: %s", option) if option == ScaleOption.UPPER_LEFT: self.wallpaper_upper_left() elif option == ScaleOption.CENTERED: @@ -698,7 +728,7 @@ class CanvasGraph(tk.Canvas): def set_wallpaper(self, filename): logging.info("setting wallpaper: %s", filename) - if filename is not None: + if filename: img = Image.open(filename) self.wallpaper = img self.wallpaper_file = filename diff --git a/coretk/coretk/graph/node.py b/coretk/coretk/graph/node.py index eadcd0df..a0f406f7 100644 --- a/coretk/coretk/graph/node.py +++ b/coretk/coretk/graph/node.py @@ -20,13 +20,11 @@ NODE_TEXT_OFFSET = 5 class CanvasNode: - def __init__(self, app, core_node, image): + def __init__(self, app, x, y, core_node, image): self.app = app self.canvas = app.canvas self.image = image self.core_node = core_node - x = self.core_node.position.x - y = self.core_node.position.y self.id = self.canvas.create_image( x, y, anchor=tk.CENTER, image=self.image, tags=tags.NODE ) @@ -98,8 +96,10 @@ class CanvasNode: return image_box[3] + NODE_TEXT_OFFSET def move(self, x, y): - x_offset = x - self.core_node.position.x - y_offset = y - self.core_node.position.y + x, y = self.canvas.get_scaled_coords(x, y) + current_x, current_y = self.canvas.coords(self.id) + x_offset = x - current_x + y_offset = y - current_y self.motion(x_offset, y_offset, update=False) def motion(self, x_offset, y_offset, update=True): @@ -107,8 +107,6 @@ class CanvasNode: self.canvas.move(self.text_id, x_offset, y_offset) self.canvas.move_selection(self.id, x_offset, y_offset) x, y = self.canvas.coords(self.id) - self.core_node.position.x = int(x) - self.core_node.position.y = int(y) # move antennae for antenna_id in self.antennae: @@ -131,7 +129,10 @@ class CanvasNode: else: self.canvas.coords(edge.id, x1, y1, x, y) - # update core with new location + # set actual coords for node and update core is running + real_x, real_y = self.canvas.get_actual_coords(x, y) + self.core_node.position.x = int(real_x) + self.core_node.position.y = int(real_y) if self.app.core.is_runtime() and update: self.app.core.edit_node(self.core_node) diff --git a/coretk/coretk/graph/shape.py b/coretk/coretk/graph/shape.py index 80621107..99a18a9f 100644 --- a/coretk/coretk/graph/shape.py +++ b/coretk/coretk/graph/shape.py @@ -147,6 +147,16 @@ class Shape: def metadata(self): coords = self.canvas.coords(self.id) + # update coords to actual positions + if len(coords) == 4: + x1, y1, x2, y2 = coords + x1, y1 = self.canvas.get_actual_coords(x1, y1) + x2, y2 = self.canvas.get_actual_coords(x2, y2) + coords = (x1, y1, x2, y2) + else: + x1, y1 = coords + x1, y1 = self.canvas.get_actual_coords(x1, y1) + coords = (x1, y1) return { "type": self.shape_type.value, "iconcoords": coords, diff --git a/coretk/coretk/menuaction.py b/coretk/coretk/menuaction.py index 3115cd58..616e9bc1 100644 --- a/coretk/coretk/menuaction.py +++ b/coretk/coretk/menuaction.py @@ -10,7 +10,7 @@ from tkinter import filedialog, messagebox import grpc -from coretk.appconfig import XML_PATH +from coretk.appconfig import XMLS_PATH from coretk.dialogs.about import AboutDialog from coretk.dialogs.canvassizeandscale import SizeAndScaleDialog from coretk.dialogs.canvaswallpaper import CanvasBackgroundDialog @@ -82,7 +82,7 @@ class MenuAction: def file_save_as_xml(self, event=None): logging.info("menuaction.py file_save_as_xml()") file_path = filedialog.asksaveasfilename( - initialdir=str(XML_PATH), + initialdir=str(XMLS_PATH), title="Save As", filetypes=(("EmulationScript XML files", "*.xml"), ("All files", "*")), defaultextension=".xml", @@ -93,7 +93,7 @@ class MenuAction: def file_open_xml(self, event=None): logging.info("menuaction.py file_open_xml()") file_path = filedialog.askopenfilename( - initialdir=str(XML_PATH), + initialdir=str(XMLS_PATH), title="Open", filetypes=(("XML Files", "*.xml"), ("All Files", "*")), ) diff --git a/coretk/coretk/menubar.py b/coretk/coretk/menubar.py index 2521bd97..460ce2bf 100644 --- a/coretk/coretk/menubar.py +++ b/coretk/coretk/menubar.py @@ -46,7 +46,12 @@ class Menubar(tk.Menu): :return: nothing """ menu = tk.Menu(self) - menu.add_command(label="New Session", accelerator="Ctrl+N", state=tk.DISABLED) + menu.add_command( + label="New Session", + accelerator="Ctrl+N", + command=self.app.core.create_new_session, + ) + self.app.bind_all("", lambda e: self.app.core.create_new_session()) menu.add_command( label="Open...", command=self.menuaction.file_open_xml, accelerator="Ctrl+O" ) @@ -104,10 +109,6 @@ class Menubar(tk.Menu): :return: nothing """ menu = tk.Menu(self) - menu.add_command(label="New", state=tk.DISABLED) - menu.add_command(label="Manage...", state=tk.DISABLED) - menu.add_command(label="Delete", state=tk.DISABLED) - menu.add_separator() menu.add_command( label="Size/scale...", command=self.menuaction.canvas_size_and_scale ) @@ -115,6 +116,10 @@ class Menubar(tk.Menu): label="Wallpaper...", command=self.menuaction.canvas_set_wallpaper ) menu.add_separator() + menu.add_command(label="New", state=tk.DISABLED) + menu.add_command(label="Manage...", state=tk.DISABLED) + menu.add_command(label="Delete", state=tk.DISABLED) + menu.add_separator() menu.add_command(label="Previous", accelerator="PgUp", state=tk.DISABLED) menu.add_command(label="Next", accelerator="PgDown", state=tk.DISABLED) menu.add_command(label="First", accelerator="Home", state=tk.DISABLED)