Commit ec35a4d5 authored by Russ Fish's avatar Russ Fish

Minor additions: a hypview wrapper script to set up local shared lib loading;...

Minor additions: a hypview wrapper script to set up local shared lib loading; control- or shift-left-mouse for rotate as an alternative to middle-mouse; glob expression to fan-out top-level nodes in getExperiment.
parent 2861a1a6
...@@ -28,7 +28,8 @@ PYFILES = hypview.py exptToHv.py sshxmlrpc.py emulabclient.py hvFrameUI.py hv.py ...@@ -28,7 +28,8 @@ PYFILES = hypview.py exptToHv.py sshxmlrpc.py emulabclient.py hvFrameUI.py hv.py
SRCFILES = README ROADMAP GNUMakefile hvgui.wxg hvmain.cpp hv.i hv.mod _hv.cpp SRCFILES = README ROADMAP GNUMakefile hvgui.wxg hvmain.cpp hv.i hv.mod _hv.cpp
BINFILES = _hv.so BINFILES = _hv.so
DATAFILES = BigLan.hyp ts600.hyp DATAFILES = BigLan.hyp ts600.hyp
DISTFILES = ${PYFILES} ${SRCFILES} ${BINFILES} ${DATAFILES} ${HVROOT} SCRIPTFILES = hypview pangorc.local pango.modules.local
DISTFILES = ${SCRIPTFILES} ${PYFILES} ${SRCFILES} ${BINFILES} ${DATAFILES} ${HVROOT}
# Finally, make something. # Finally, make something.
default: _hv.so default: _hv.so
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
# exptToHv - Get an experiment topology via xmlrpc, and write a HyperViewer .hyp file. # exptToHv - Get an experiment topology via xmlrpc, and write a HyperViewer .hyp file.
import sets import sets
import string import string
import fnmatch
from sshxmlrpc import * from sshxmlrpc import *
from emulabclient import * from emulabclient import *
...@@ -51,7 +52,7 @@ def addConnection(graph, h1, h2): ...@@ -51,7 +52,7 @@ def addConnection(graph, h1, h2):
else: else:
graph[h2] = sets.Set([h1]) graph[h2] = sets.Set([h1])
## exptToHv - Make the request from the server. Reconstitute a topology graph ## getExperiment - Make the request from the server. Reconstitute a topology graph
## from the host interface list, and traverse it to write HyperViewer .hyp file. ## from the host interface list, and traverse it to write HyperViewer .hyp file.
# #
# Args are the project and experiment names, and optionally the root of the topology. # Args are the project and experiment names, and optionally the root of the topology.
...@@ -75,7 +76,7 @@ def getExperiment(project, experiment, root=""): ...@@ -75,7 +76,7 @@ def getExperiment(project, experiment, root=""):
if response["code"] != RESPONSE_SUCCESS: if response["code"] != RESPONSE_SUCCESS:
print "XMLRPC failure, code", response["code"] print "XMLRPC failure, code", response["code"]
pass return response["code"]
links = response["value"] links = response["value"]
# Figure out the nodes from the experiment links (interfaces) from the virt_lans table. # Figure out the nodes from the experiment links (interfaces) from the virt_lans table.
...@@ -87,7 +88,8 @@ def getExperiment(project, experiment, root=""): ...@@ -87,7 +88,8 @@ def getExperiment(project, experiment, root=""):
if not linksByName.has_key(linkName): if not linksByName.has_key(linkName):
linksByName[linkName] = sets.Set() linksByName[linkName] = sets.Set()
linksByName[linkName].add(member) # Each link/lan connects a set of interfaces. linksByName[linkName].add(member) # Each link/lan connects a set of interfaces.
pass
# Build the connection graph as a dictionary of nodes with sets of connected nodes. # Build the connection graph as a dictionary of nodes with sets of connected nodes.
hosts = sets.Set() # Collect unique node names (hosts and lans.) hosts = sets.Set() # Collect unique node names (hosts and lans.)
lans = sets.Set() lans = sets.Set()
...@@ -99,19 +101,46 @@ def getExperiment(project, experiment, root=""): ...@@ -99,19 +101,46 @@ def getExperiment(project, experiment, root=""):
hosts.add(h1) hosts.add(h1)
hosts.add(h2) hosts.add(h2)
addConnection(graph, h1, h2) addConnection(graph, h1, h2)
pass
else: else:
# Lan nodes are are links with more than two interfaces as members. # Lan nodes are are links with more than two interfaces as members.
lans.add(link) lans.add(link)
for intfc in intfcs: for intfc in intfcs:
addConnection(graph, link, intfcHost(intfc)) addConnection(graph, link, intfcHost(intfc))
pass
pass
pass
# Use the first lan or the first host as the default root node. # Use the first lan or the first host as the default root node.
if root == "": if root == "":
if len(lans) > 0: if len(lans) > 0:
root = lans.copy().pop() root = lans.copy().pop()
pass
else: else:
root = hosts.copy().pop() root = hosts.copy().pop()
pass
pass
# The root may be a glob expression, in which case we make up a root node and put
# the matching nodes under it. We could add a regexp option as well...
rootNodes = []
if '*' in root or '?' in root or '[' in root:
glob = root
rootNodes = fnmatch.filter(hosts, glob) + fnmatch.filter(lans, glob)
if len(rootNodes) > 1:
# Find a new root name that isn't already in the hosts or lans lists.
for newroot in ['root','Root','ROOT','RoOt']:
if not newroot in hosts and not newroot in lans:
root = newroot
##print "Connecting", root, "to", rootNodes
for node in rootNodes:
addConnection(graph, root, node)
pass
pass
break
pass
pass
# Walk the graph structure in depth-first order to generate the .hyp file. # Walk the graph structure in depth-first order to generate the .hyp file.
# Make a second copy of the graph as we go to avoid repeating nodes due to back-links. # Make a second copy of the graph as we go to avoid repeating nodes due to back-links.
def walkNodes(graph, graph2, node, level, outfile): def walkNodes(graph, graph2, node, level, outfile):
...@@ -120,12 +149,15 @@ def getExperiment(project, experiment, root=""): ...@@ -120,12 +149,15 @@ def getExperiment(project, experiment, root=""):
# Recursively traverse the nodes connected to this one. # Recursively traverse the nodes connected to this one.
for conn in graph[node]: for conn in graph[node]:
if not (node in graph2 and conn in graph2[node]): if (not (node in graph2 and conn in graph2[node])
# rootNodes are fanned-out from the root only.
and (level == 0 or not conn in rootNodes)):
addConnection(graph2, node, conn) addConnection(graph2, node, conn)
walkNodes(graph, graph2, conn, level+1, outfile) walkNodes(graph, graph2, conn, level+1, outfile)
pass pass
pass pass
pass pass
hypfile = "/tmp/"+experiment+'.hyp' hypfile = "/tmp/"+experiment+'.hyp'
outfile = file(hypfile,'w') outfile = file(hypfile,'w')
graph2 = {} graph2 = {}
......
...@@ -6,14 +6,14 @@ ...@@ -6,14 +6,14 @@
# All rights reserved. # All rights reserved.
# #
from wxPython.wx import * from wxPython.wx import *
from wxPython import glcanvas from wxPython.glcanvas import wxGLCanvas
class UsageDialogUI(wxDialog): class UsageDialogUI(wxDialog):
def __init__(self, *args, **kwds): def __init__(self, *args, **kwds):
# begin wxGlade: UsageDialogUI.__init__ # begin wxGlade: UsageDialogUI.__init__
kwds["style"] = wxDEFAULT_DIALOG_STYLE kwds["style"] = wxDEFAULT_DIALOG_STYLE
wxDialog.__init__(self, *args, **kwds) wxDialog.__init__(self, *args, **kwds)
self.Usage = wxStaticText(self, -1, "\n HyperViewer usage:\n -------------------------\n\n Objects close to the center of the sphere are largest. \n\n Left mouse drag: X,Y movement in hyperbolic space. \n\n Middle mouse drag: Rotate the hyperbolic space. \n\n Pickable nodes under the cursor turn green. \n Left-click to bring them to the center. \n\n") self.Usage = wxStaticText(self, -1, "\n HyperViewer mouse usage:\n -----------------------------------\n\n Objects close to the center of the sphere are largest. \n\n Left mouse drag: X,Y movement in hyperbolic space. \n\n Control- or Shift- Left mouse, or Middle mouse, drag:\n Rotate the hyperbolic space. \n\n Pickable nodes under the cursor turn bright green. \n Left-click to bring them to the center. \n\n")
self.__set_properties() self.__set_properties()
self.__do_layout() self.__do_layout()
...@@ -46,6 +46,7 @@ class OpenDialogUI(wxDialog): ...@@ -46,6 +46,7 @@ class OpenDialogUI(wxDialog):
wxDialog.__init__(self, *args, **kwds) wxDialog.__init__(self, *args, **kwds)
self.FileToOpen = wxTextCtrl(self, -1, "") self.FileToOpen = wxTextCtrl(self, -1, "")
self.OpenFile = wxButton(self, -1, "Open Data File") self.OpenFile = wxButton(self, -1, "Open Data File")
self.FileMsg = wxStaticText(self, -1, "")
self.label_2 = wxStaticText(self, -1, "Project name:", style=wxALIGN_RIGHT) self.label_2 = wxStaticText(self, -1, "Project name:", style=wxALIGN_RIGHT)
self.ProjectName = wxTextCtrl(self, -1, "") self.ProjectName = wxTextCtrl(self, -1, "")
self.label_7 = wxStaticText(self, -1, "Experiment name:") self.label_7 = wxStaticText(self, -1, "Experiment name:")
...@@ -53,6 +54,7 @@ class OpenDialogUI(wxDialog): ...@@ -53,6 +54,7 @@ class OpenDialogUI(wxDialog):
self.label_8 = wxStaticText(self, -1, "Root (optional):") self.label_8 = wxStaticText(self, -1, "Root (optional):")
self.ExperimentRoot = wxTextCtrl(self, -1, "") self.ExperimentRoot = wxTextCtrl(self, -1, "")
self.OpenExperiment = wxButton(self, -1, "Retrieve experiment") self.OpenExperiment = wxButton(self, -1, "Retrieve experiment")
self.ExperimentMsg = wxStaticText(self, -1, "")
self.__set_properties() self.__set_properties()
self.__do_layout() self.__do_layout()
...@@ -77,7 +79,7 @@ class OpenDialogUI(wxDialog): ...@@ -77,7 +79,7 @@ class OpenDialogUI(wxDialog):
FileOpening.Add(self.FileToOpen, 0, 0, 0) FileOpening.Add(self.FileToOpen, 0, 0, 0)
FileOpening.Add(20, 10, 0, 0, 0) FileOpening.Add(20, 10, 0, 0, 0)
FileOpening.Add(self.OpenFile, 0, wxALIGN_CENTER_HORIZONTAL, 0) FileOpening.Add(self.OpenFile, 0, wxALIGN_CENTER_HORIZONTAL, 0)
FileOpening.Add(20, 20, 0, 0, 0) FileOpening.Add(self.FileMsg, 0, 0, 0)
sizer_4.Add(FileOpening, 0, wxALL, 0) sizer_4.Add(FileOpening, 0, wxALL, 0)
sizer_4.Add(20, 10, 0, 0, 0) sizer_4.Add(20, 10, 0, 0, 0)
grid_sizer_1.Add(self.label_2, 0, 0, 0) grid_sizer_1.Add(self.label_2, 0, 0, 0)
...@@ -90,6 +92,7 @@ class OpenDialogUI(wxDialog): ...@@ -90,6 +92,7 @@ class OpenDialogUI(wxDialog):
grid_sizer_1.Add(20, 1, 0, 0, 0) grid_sizer_1.Add(20, 1, 0, 0, 0)
ExperimentOpening.Add(grid_sizer_1, 0, wxEXPAND, 0) ExperimentOpening.Add(grid_sizer_1, 0, wxEXPAND, 0)
ExperimentOpening.Add(self.OpenExperiment, 0, wxALIGN_CENTER_HORIZONTAL, 0) ExperimentOpening.Add(self.OpenExperiment, 0, wxALIGN_CENTER_HORIZONTAL, 0)
ExperimentOpening.Add(self.ExperimentMsg, 0, 0, 0)
ExperimentOpening.Add(20, 10, 0, 0, 0) ExperimentOpening.Add(20, 10, 0, 0, 0)
sizer_4.Add(ExperimentOpening, 1, wxALL, 0) sizer_4.Add(ExperimentOpening, 1, wxALL, 0)
self.SetAutoLayout(1) self.SetAutoLayout(1)
...@@ -120,7 +123,7 @@ class hvFrameUI(wxFrame): ...@@ -120,7 +123,7 @@ class hvFrameUI(wxFrame):
wxglade_tmp_menu.Append(3, "&Usage\tCtrl+H", "", wxITEM_NORMAL) wxglade_tmp_menu.Append(3, "&Usage\tCtrl+H", "", wxITEM_NORMAL)
self.Menu.Append(wxglade_tmp_menu, "&Help") self.Menu.Append(wxglade_tmp_menu, "&Help")
# Menu Bar end # Menu Bar end
self.hypView = glcanvas.wxGLCanvas(self.panel_1, -1) self.hypView = wxGLCanvas(self.panel_1, -1)
self.GoToTop = wxButton(self.Controls, -1, "go to top") self.GoToTop = wxButton(self.Controls, -1, "go to top")
self.LabelNodeName = wxStaticText(self.Controls, -1, " Node name ") self.LabelNodeName = wxStaticText(self.Controls, -1, " Node name ")
self.NodeName = wxTextCtrl(self.Controls, -1, "") self.NodeName = wxTextCtrl(self.Controls, -1, "")
......
This diff is collapsed.
#! /bin/sh
#
# hypview - Wrapper script for the hyperviewer application.
#
# EMULAB-COPYRIGHT
# Copyright (c) 2004 University of Utah and the Flux Group.
# All rights reserved.
#
# Optionally use shared libs under the local directory.
if [ -d libs ]; then
LD_LIBRARY_PATH=./libs; export LD_LIBRARY_PATH
fi
# Optionally use Pango loadable modules under the local directory.
if [ -d libs/pango ]; then
PANGO_RC_FILE=./pangorc.local; export PANGO_RC_FILE
fi
# If the wxPython or OpenGL directories are local, they will be used.
python hypview.py $*
...@@ -18,7 +18,7 @@ from hvFrameUI import * ...@@ -18,7 +18,7 @@ from hvFrameUI import *
from OpenGL.GL import * from OpenGL.GL import *
from wxPython.wx import * from wxPython.wx import *
from wxPython import glcanvas from wxPython.glcanvas import wxGLCanvas
# A wxPython application. # A wxPython application.
class hvApp(wxApp): class hvApp(wxApp):
...@@ -37,42 +37,58 @@ class hvApp(wxApp): ...@@ -37,42 +37,58 @@ class hvApp(wxApp):
self.SetTopWindow(self.frame) self.SetTopWindow(self.frame)
# Given command-line argument(s), attempt to read in a topology. # Given command-line argument(s), attempt to read in a topology.
if len(sys.argv) == 2 and sys.argv[1][0] == '-': # Any dash arg gives usage message. filename = project = None
# Any dash argument prints a usage message and exits.
if len(sys.argv) == 2 and sys.argv[1][0] == '-':
print '''Hyperviewer usage: print '''Hyperviewer usage:
No args - Starts up the GUI. Use the File/Open menu item to read a topology. No args - Starts up the GUI. Use the File/Open menu item to read a topology.
One arg - A .hyp file name. Read it in and start the GUI, e.g.: One arg - A .hyp file name. Read it in and start the GUI, e.g.:
./hypview.py BigLan.hyp ./hypview BigLan.hyp
Two args - Project and experiment names in the database. Two args - Project and experiment names in the database.
Get the topology from XMLRPC, make a .hyp file, start as above. Get the topology from XMLRPC, make a .hyp file, start as above.
./hypview.py testbed BigLan ./hypview testbed BigLan
Three args - Project and experiment names, plus an optional root node name. Three args - Project and experiment names, plus an optional root node name.
./hypview.py testbed BigLan clan''' ./hypview testbed BigLan clan'''
sys.exit() sys.exit()
elif len(sys.argv) == 2: # Read from a file. pass
print "Reading file:", sys.argv[1]
self.frame.ReadTopFile("wxHyperViewer", sys.argv[1]) # One command-line argument: read from a .hyp file.
elif len(sys.argv) == 2:
filename = sys.argv[1]
print "Reading file:", filename
pass pass
elif len(sys.argv) == 3: # Read from the database via XML-RPC, make a file.
print "Getting project:", sys.argv[1] + ", experiment:", sys.argv[2] # Two args: read an experiment from the DB via XML-RPC, and make a .hyp file.
filename = exptToHv.getExperiment(sys.argv[1], sys.argv[2]) elif len(sys.argv) == 3:
if filename: project = sys.argv[1]
self.frame.ReadTopFile("wxHyperViewer", filename) experiment = sys.argv[2]
pass print "Getting project:", project + ", experiment:", experiment
else: filename = exptToHv.getExperiment(project, experiment)
print "Failed to get experiment from database."
pass
pass
elif len(sys.argv) == 4: # From database, with optional graph root node.
print "Getting project:", sys.argv[1] + ", experiment:", sys.argv[2] \
+ ", root node:", sys.argv[3]
filename = exptToHv.getExperiment(sys.argv[1], sys.argv[2], sys.argv[3])
if filename:
self.frame.ReadTopFile("wxHyperViewer", filename)
pass
else:
print "Failed to get experiment from database."
pass
pass pass
# Three args: experiment from database, with optional graph root node.
elif len(sys.argv) == 4:
project = sys.argv[1]
experiment = sys.argv[2]
root = sys.argv[3]
print "Getting project:", project + ", experiment:", experiment \
+ ", root node:", root
filename = exptToHv.getExperiment(project, experiment, root)
pass
if filename:
if filename == 2:
exptError = "There is no experiment " + project + "/" + experiment
print exptError
pass
else:
self.frame.ReadTopFile("wxHyperViewer", filename)
pass
pass
elif project:
print "Failed to get experiment from database."
pass
return True return True
pass pass
...@@ -224,8 +240,11 @@ class hvFrame(hvFrameUI): ...@@ -224,8 +240,11 @@ class hvFrame(hvFrameUI):
## ##
# Mouse click events. # Mouse click events.
def OnClick(self, mouseEvent): def OnClick(self, mouseEvent):
# Encode mouse button events for HypView.
btnNum = -1 btnNum = -1
if mouseEvent.LeftDown(): # Encode mouse button events.
# Left mouse button for X-Y motion of the hyperbolic center.
if mouseEvent.LeftDown():
btnNum = 0 btnNum = 0
btnState = 0 btnState = 0
pass pass
...@@ -233,6 +252,8 @@ class hvFrame(hvFrameUI): ...@@ -233,6 +252,8 @@ class hvFrame(hvFrameUI):
btnNum = 0 btnNum = 0
btnState = 1 btnState = 1
pass pass
# Middle button for rotation of the hyperbolic space.
elif mouseEvent.MiddleDown(): elif mouseEvent.MiddleDown():
btnNum = 1 btnNum = 1
btnState = 0 btnState = 0
...@@ -242,7 +263,12 @@ class hvFrame(hvFrameUI): ...@@ -242,7 +263,12 @@ class hvFrame(hvFrameUI):
btnState = 1 btnState = 1
pass pass
# Pass mouse clicks on to HypView. # Left button with control or shift held down is also rotation.
if btnNum == 0 and ( mouseEvent.ControlDown() or mouseEvent.ShiftDown() ):
btnNum = 1
pass
# Handle mouse clicks in HypView.
if btnNum != -1: if btnNum != -1:
self.vwr.mouse(btnNum, btnState, mouseEvent.GetX(), mouseEvent.GetY(), 0, 0) self.vwr.mouse(btnNum, btnState, mouseEvent.GetX(), mouseEvent.GetY(), 0, 0)
self.vwr.redraw() self.vwr.redraw()
...@@ -315,7 +341,14 @@ class hvOpen(OpenDialogUI): ...@@ -315,7 +341,14 @@ class hvOpen(OpenDialogUI):
root = self.ExperimentRoot.GetLineText(0) root = self.ExperimentRoot.GetLineText(0)
hypfile = exptToHv.getExperiment(project, experiment, root) hypfile = exptToHv.getExperiment(project, experiment, root)
if hypfile: if hypfile:
if hypfile == 2:
exptError = "There is no experiment " + project + "/" + experiment
self.ExperimentMsg.SetLabel(exptError)
print exptError
return
self.app.frame.ReadTopFile("wxHyperViewer", hypfile) self.app.frame.ReadTopFile("wxHyperViewer", hypfile)
self.ExperimentMsg.SetLabel(" ")
self.Hide(); self.Hide();
pass pass
......
# Pango Modules file
# Automatically generated file, do not edit
#
# ModulesPath = /usr/X11R6/lib/pango/1.4.0/modules
#
libs/pango/1.4.0/modules/pango-arabic-fc.so ArabicScriptEngineFc PangoEngineShape PangoRenderFc arabic:*
libs/pango/1.4.0/modules/pango-basic-x.so BasicScriptEngineX PangoEngineShape PangoRenderX common:
libs/pango/1.4.0/modules/pango-basic-fc.so BasicScriptEngineFc PangoEngineShape PangoRenderFc armenian:* bopomofo:* cherokee:* coptic:* cyrillic:* deseret:* ethiopic:* georgian:* gothic:* greek:* han:* hiragana:* katakana:* latin:* ogham:* old-italic:* runic:* canadian-aboriginal:* yi:* braille:* cypriot:* limbu:* osmanya:* shavian:* linear-b:* ugaritic:* common:
libs/pango/1.4.0/modules/pango-hangul-fc.so HangulScriptEngineFc PangoEngineShape PangoRenderFc hangul:*
libs/pango/1.4.0/modules/pango-indic-fc.so devaScriptEngineFc PangoEngineShape PangoRenderFc devanagari:*
libs/pango/1.4.0/modules/pango-indic-fc.so bengScriptEngineFc PangoEngineShape PangoRenderFc bengali:*
libs/pango/1.4.0/modules/pango-indic-fc.so guruScriptEngineFc PangoEngineShape PangoRenderFc gurmukhi:*
libs/pango/1.4.0/modules/pango-indic-fc.so gujrScriptEngineFc PangoEngineShape PangoRenderFc gujarati:*
libs/pango/1.4.0/modules/pango-indic-fc.so oryaScriptEngineFc PangoEngineShape PangoRenderFc oriya:*
libs/pango/1.4.0/modules/pango-indic-fc.so tamlScriptEngineFc PangoEngineShape PangoRenderFc tamil:*
libs/pango/1.4.0/modules/pango-indic-fc.so teluScriptEngineFc PangoEngineShape PangoRenderFc telugu:*
libs/pango/1.4.0/modules/pango-indic-fc.so kndaScriptEngineFc PangoEngineShape PangoRenderFc kannada:*
libs/pango/1.4.0/modules/pango-indic-fc.so mlymScriptEngineFc PangoEngineShape PangoRenderFc malayalam:*
libs/pango/1.4.0/modules/pango-thai-fc.so ThaiScriptEngineFc PangoEngineShape PangoRenderFc thai:*
libs/pango/1.4.0/modules/pango-hebrew-fc.so HebrewScriptEngineFc PangoEngineShape PangoRenderFc hebrew:*
#
# pangorc file for uninstalled operation. If pango-viewer is run with
# this file in the current directory it will set it as PANGO_RC_FILE
#
[Pango]
# Use this when the pango modules are in a subdirectory.
ModuleFiles = ./pango.modules.local
[PangoX]
AliasFiles = ./pangox.aliases
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment