All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit a0faebc8 authored by Leigh B. Stoller's avatar Leigh B. Stoller

Make the new node selector applet live, since no more feedback was

forthcoming ...
parent 12eeadb1
...@@ -14,8 +14,7 @@ include $(OBJDIR)/Makeconf ...@@ -14,8 +14,7 @@ include $(OBJDIR)/Makeconf
ifeq ($(JAVAC),) ifeq ($(JAVAC),)
JARS = JARS =
else else
JARS = $(TESTBED_SRCDIR)/www/robotrack/tracker.jar \ JARS = $(TESTBED_SRCDIR)/www/robotrack/tracker.jar
$(TESTBED_SRCDIR)/www/robotrack/selector.jar
endif endif
all: all:
......
...@@ -30,9 +30,11 @@ public class NodeSelect extends JApplet { ...@@ -30,9 +30,11 @@ public class NodeSelect extends JApplet {
private Selector selector; private Selector selector;
int myHeight, myWidth; int myHeight, myWidth;
String uid, auth, pid, eid; String uid, auth, pid, eid;
double pixels_per_meter = 1.0; double pixels_per_meter = 100.0;
URL urlServer; URL urlServer;
static final DecimalFormat FORMATTER = new DecimalFormat("0.00"); static final DecimalFormat FORMATTER = new DecimalFormat("0.00");
static final int INCH =
Toolkit.getDefaultToolkit().getScreenResolution();
/* From the floormap generation code. */ /* From the floormap generation code. */
int X_ADJUST = 60; int X_ADJUST = 60;
...@@ -43,6 +45,7 @@ public class NodeSelect extends JApplet { ...@@ -43,6 +45,7 @@ public class NodeSelect extends JApplet {
int FONT_WIDTH = 10; int FONT_WIDTH = 10;
Font OurFont = null; Font OurFont = null;
Font BoldFont = null; Font BoldFont = null;
Font RulerFont = null;
// The width of the list boxes. // The width of the list boxes.
int LISTBOX_WIDTH = 150; int LISTBOX_WIDTH = 150;
...@@ -50,6 +53,10 @@ public class NodeSelect extends JApplet { ...@@ -50,6 +53,10 @@ public class NodeSelect extends JApplet {
// For zooming ... // For zooming ...
double scale = 1.0; double scale = 1.0;
// rulers
int HORIZONTAL = 0;
int VERTICAL = 1;
/* /*
* A little class to hold info we need to get data from the server * A little class to hold info we need to get data from the server
* about buildings, floors, nodes. * about buildings, floors, nodes.
...@@ -150,8 +157,9 @@ public class NodeSelect extends JApplet { ...@@ -150,8 +157,9 @@ public class NodeSelect extends JApplet {
myHeight = appletSize.height; myHeight = appletSize.height;
myWidth = appletSize.width; myWidth = appletSize.width;
} }
OurFont = new Font("Helvetica", Font.BOLD, 16); OurFont = new Font("Helvetica", Font.BOLD, 12);
BoldFont = new Font("Helvetica", Font.BOLD, 20); BoldFont = new Font("Helvetica", Font.BOLD, 20);
RulerFont = new Font("SansSerif", Font.PLAIN, 10);
/* /*
* Now add my one object to the contentpane. * Now add my one object to the contentpane.
...@@ -559,26 +567,28 @@ public class NodeSelect extends JApplet { ...@@ -559,26 +567,28 @@ public class NodeSelect extends JApplet {
this.revalidate(); this.revalidate();
} }
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
int button = e.getButton(); int button = e.getButton();
int modifier = e.getModifiersEx(); int modifier = e.getModifiersEx();
int x = e.getX() + xoff; int x = e.getX() + xoff;
int y = e.getY() - yoff; int y = e.getY() - yoff;
Node node = null; PhysNode pnode = null;
System.out.println("Clicked on " + e.getX() + "," + e.getY()); System.out.println("Clicked on " + e.getX() + "," + e.getY());
System.out.println("Clicked on " + x + "," + y); System.out.println("Clicked on " + x + "," + y);
if (x > 0 && y > 0 && x <= width && y <= height) if (x > 0 && y > 0 && x <= width && y <= height)
node = FindNode(this, (int)(x / scale), (int)(y / scale)); pnode = (PhysNode)
FindNode(this, (int)(x / scale), (int)(y / scale));
if (!e.isPopupTrigger()) { if (!e.isPopupTrigger()) {
if (node != null) { if (pnode != null) {
SelectNode(node, modifier); if (!pnode.allocated)
SelectNode(pnode, modifier);
return; return;
} }
} }
// Forward to outer event handler, including the node // Forward to outer event handler, including the node
selector.doPopupMenu(e, node); selector.doPopupMenu(e, pnode);
} }
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
PhysMapPanel.mouseReleased(e); PhysMapPanel.mouseReleased(e);
...@@ -688,7 +698,7 @@ public class NodeSelect extends JApplet { ...@@ -688,7 +698,7 @@ public class NodeSelect extends JApplet {
ListPanel.add(ToplistScroller); ListPanel.add(ToplistScroller);
// add a label for the lower list box // add a label for the lower list box
ListPanel.add(new JLabel("Selected Nodes")); ListPanel.add(new JLabel("Assigned Nodes"));
// And add the lower listbox. // And add the lower listbox.
ListPanel.add(BotlistScroller); ListPanel.add(BotlistScroller);
...@@ -790,6 +800,9 @@ public class NodeSelect extends JApplet { ...@@ -790,6 +800,9 @@ public class NodeSelect extends JApplet {
DefaultListModel model; DefaultListModel model;
PhysNode pnode = (PhysNode) a.nextElement(); PhysNode pnode = (PhysNode) a.nextElement();
if (pnode.allocated)
continue;
if (pnode.selected) if (pnode.selected)
model = (DefaultListModel) SelectList.getModel(); model = (DefaultListModel) SelectList.getModel();
else else
...@@ -801,11 +814,33 @@ public class NodeSelect extends JApplet { ...@@ -801,11 +814,33 @@ public class NodeSelect extends JApplet {
} }
/* /*
* Create a surrounding scroll pane. * We need to force the physmappanel to layout now, so we
* figure out how big the ruler bars need to be. If we do not
* do that, the rulers will be 0 sized, and really hard to see!
*/
PhysMapPanel.getLayout().layoutContainer(PhysMapPanel);
Dimension physmapdim =
PhysMapPanel.getLayout().minimumLayoutSize(PhysMapPanel);
/*
* Create a surrounding scroll pane.
*/ */
PhysMapScrollPane = new JScrollPane(PhysMapPanel); PhysMapScrollPane = new JScrollPane(PhysMapPanel);
PhysMapScrollPane.setPreferredSize(new Dimension(mapwidth, PhysMapScrollPane.setPreferredSize(new Dimension(mapwidth,
mapheight)); mapheight));
// Create the row and column headers (rulers, sortof).
Ruler columnView = new Ruler(HORIZONTAL);
Ruler rowView = new Ruler(VERTICAL);
// Make sure the rulers know how big they need to be.
columnView.setPreferredWidth(physmapdim.width);
rowView.setPreferredHeight(physmapdim.height);
PhysMapScrollPane.setColumnHeaderView(columnView);
PhysMapScrollPane.setRowHeaderView(rowView);
// Now we can add the scrollpane.
MapPanel.add(PhysMapScrollPane); MapPanel.add(PhysMapScrollPane);
// Add add our two inner panels to the outer panel // Add add our two inner panels to the outer panel
...@@ -1487,11 +1522,23 @@ public class NodeSelect extends JApplet { ...@@ -1487,11 +1522,23 @@ public class NodeSelect extends JApplet {
map.rescale(); map.rescale();
} }
// Force everything to layout again before getSize(). // Force everything to layout again.
revalidate(); revalidate();
validate(); validate();
repaint();
// Tell rulers to recompute their size.
Ruler ruler =
(Ruler) PhysMapScrollPane.getColumnHeader().getView();
ruler.reset();
ruler =
(Ruler) PhysMapScrollPane.getRowHeader().getView();
ruler.reset();
// Force everything to layout again.
revalidate();
validate();
/* /*
* Okay scale P so that it moves (thereby keeping the * Okay scale P so that it moves (thereby keeping the
* original position more or less centered). * original position more or less centered).
...@@ -1543,6 +1590,118 @@ public class NodeSelect extends JApplet { ...@@ -1543,6 +1590,118 @@ public class NodeSelect extends JApplet {
repaint(); repaint();
} }
} }
/*
* This class and code comes from one of the examples on the Sun
* Java site.
*/
public class Ruler extends JComponent {
private int SIZE = 30;
private int orientation;
private int increment;
private int units;
public Ruler(int or) {
orientation = or;
// Tick every meter at any scale.
increment = (int) (pixels_per_meter * scale);
units = increment * 5;
}
public void reset () {
setsizes();
// Tick every meter at any scale.
increment = (int) (pixels_per_meter * scale);
units = increment * 5;
}
private void setsizes() {
int width;
int height;
if (orientation == HORIZONTAL) {
width = PhysMapPanel.getWidth();
height = SIZE;
}
else {
width = SIZE;
height = PhysMapPanel.getHeight();
}
System.out.println(orientation + ": " + width + "," + height);
setPreferredSize(new Dimension(width, height));
}
public int getIncrement() {
return increment;
}
public void setPreferredHeight(int ph) {
setPreferredSize(new Dimension(SIZE, ph));
}
public void setPreferredWidth(int pw) {
setPreferredSize(new Dimension(pw, SIZE));
}
protected void paintComponent(Graphics g) {
Rectangle drawHere = g.getClipBounds();
//System.out.println(drawHere);
// Fill clipping area with dirty brown/orange.
g.setColor(new Color(230, 163, 4));
g.fillRect(drawHere.x, drawHere.y,
drawHere.width, drawHere.height);
// Do the ruler labels in a small font that's black.
g.setFont(RulerFont);
g.setColor(Color.black);
// Some vars we need.
int end = 0;
int start = 0;
int tickLength = 0;
String label = null;
// Use clipping bounds to calculate first and last locations.
if (orientation == HORIZONTAL) {
start = (drawHere.x / increment) * increment;
end = (((drawHere.x + drawHere.width) / increment) + 1)
* increment;
}
else {
start = (drawHere.y / increment) * increment;
end = (((drawHere.y + drawHere.height) / increment) + 1)
* increment;
}
//System.out.println("Rulers Painting(" + orientation + "): " +
// start + "," + end);
// Draw ticks
for (int i = start; i < end; i += increment) {
if (i != 0 && i % units == 0) {
tickLength = 10;
label = Integer.toString(i/increment);
}
else {
tickLength = 7;
label = null;
}
if (tickLength != 0) {
if (orientation == HORIZONTAL) {
g.drawLine(i, SIZE-1, i, SIZE-tickLength-1);
if (label != null)
g.drawString(label, i-4, 15);
}
else {
g.drawLine(SIZE-1, i, SIZE-tickLength-1, i);
if (label != null)
g.drawString(label, 2, i+5);
}
}
}
}
}
} }
/* /*
......
...@@ -334,13 +334,13 @@ elsif (@ARGV == 1) { ...@@ -334,13 +334,13 @@ elsif (@ARGV == 1) {
my $path_col = ($scale_arg == 0 ? "thumb_path" : "image_path"); my $path_col = ($scale_arg == 0 ? "thumb_path" : "image_path");
my $db_scale = max($scale_arg, 1); my $db_scale = max($scale_arg, 1);
# Nozoom signals a call by robotmap. Don't use robots "building" otherwise. # Nozoom signals a call by robotmap. Don't use robots "building" otherwise.
my $robo_bldg = "b.building ". ($nozoom ? "" : "not "). "like '%ROBOTS%'"; my $robo_bldg = ($nozoom ? "" : "b.building not like '%ROBOTS%' and ");
my $query_result = my $query_result =
DBQueryFatal("select b.building,b.title,f.floor,f.$path_col,". DBQueryFatal("select b.building,b.title,f.floor,f.$path_col,".
"f.pixels_per_meter ". "f.pixels_per_meter ".
" from buildings as b ". " from buildings as b ".
"left join floorimages as f on f.building=b.building ". "left join floorimages as f on f.building=b.building ".
"where $robo_bldg and f.scale=$db_scale"); "where $robo_bldg f.scale=$db_scale");
if (!$query_result->numrows) { if (!$query_result->numrows) {
die("*** $0:\n". die("*** $0:\n".
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# #
# EMULAB-COPYRIGHT # EMULAB-COPYRIGHT
# Copyright (c) 2000-2004 University of Utah and the Flux Group. # Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved. # All rights reserved.
# #
...@@ -126,13 +126,13 @@ if (!(defined $min_x)) { ...@@ -126,13 +126,13 @@ if (!(defined $min_x)) {
# adjust each node's position so topleftmost node is at (60,60) * $zoom. # adjust each node's position so topleftmost node is at (60,60) * $zoom.
foreach $i (keys %nodes) { foreach $i (keys %nodes) {
$nodes{$i}{"x"} = ($nodes{$i}{"x"} - $min_x + 60) * $zoom; $nodes{$i}{"x"} = (($nodes{$i}{"x"} - $min_x) * $zoom) + 60;
$nodes{$i}{"y"} = ($nodes{$i}{"y"} - $min_y + 60) * $zoom; $nodes{$i}{"y"} = (($nodes{$i}{"y"} - $min_y) * $zoom) + 60;
} }
# adjust max x,y appropriately. # adjust max x,y appropriately.
$max_x = ($max_x - $min_x + 120) * $zoom; $max_x = (($max_x - $min_x) * $zoom) + 120;
$max_y = ($max_y - $min_y + 120) * $zoom; $max_y = (($max_y - $min_y) * $zoom) + 120;
} }
# get vlan list. # get vlan list.
......
<?php <?php
# #
# EMULAB-COPYRIGHT # EMULAB-COPYRIGHT
# Copyright (c) 2004 University of Utah and the Flux Group. # Copyright (c) 2004, 2005 University of Utah and the Flux Group.
# All rights reserved. # All rights reserved.
# #
include("defs.php3"); include("defs.php3");
...@@ -440,6 +440,9 @@ echo " Click on the dots below to see information about the node.\n"; ...@@ -440,6 +440,9 @@ echo " Click on the dots below to see information about the node.\n";
echo " <br>\n"; echo " <br>\n";
echo " Click elsewhere on the map to set the center point for a zoomed-in view.\n"; echo " Click elsewhere on the map to set the center point for a zoomed-in view.\n";
echo " <br>\n"; echo " <br>\n";
echo " Check out the nifty new <a href=robotrack/selector.php3?building=MEB>";
echo "Java Applet</a> for selecting wireless nodes\n";
echo " <br>\n";
# Couldn't get JavaScript submit on checkbox to be portable to IE with map in form. # Couldn't get JavaScript submit on checkbox to be portable to IE with map in form.
# Just use image buttons to show and invert the checkbox state. That works. # Just use image buttons to show and invert the checkbox state. That works.
if ($ghost) { if ($ghost) {
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved.
#
chdir("..");
include("defs.php3");
#
# Only known and logged in users.
#
$uid = GETLOGIN();
LOGGEDINORDIE($uid);
#
# Verify page arguments. Allow user to optionally specify building/floor.
#
if (isset($building) && $building != "") {
# Sanitize for the shell.
if (!preg_match("/^[-\w]+$/", $building)) {
PAGEARGERROR("Invalid building argument.");
}
}
else {
PAGEARGERROR("Must supply a building.");
}
if (isset($floor) && $floor != "") {
if (!preg_match("/^[-\w]+$/", $floor)) {
PAGEARGERROR("Invalid floor argument.");
}
}
else {
PAGEARGERROR("Must supply a floor.");
}
#
# Make sure it exists in the DB.
#
$query_result =
DBQueryFatal("select pixels_per_meter from floorimages ".
"where building='$building' and floor='$floor'");
if (!mysql_num_rows($query_result)) {
PAGEARGERROR("No such building/floor $building/$floor");
}
#
# Need cleanup "handler" to make sure temp files get deleted!
#
function CLEANUP()
{
global $prefix, $uid;
#
# The backend script (vis/floormap.in) removes all the temp files
# with the -c option. Yucky, but file perms and owners make this
# the easiest way to do it.
#
if (isset($prefix)) {
SUEXEC($uid, "nobody", "webfloormap -o $prefix -k ");
# This file does belong to the web server.
unlink($prefix);
}
exit();
}
register_shutdown_function("CLEANUP");
#
# Create a tempfile to use as a unique prefix; it is not actually used but
# serves the same purpose (The script uses ${prefix}.jpg and ${prefix}.map .)
#
$prefix = tempnam("/tmp", "floormap");
#
# Build the image.
#
$perl_args = "-o $prefix -t -z -n -x -v -y -f $floor $building";
$retval = SUEXEC($uid, "nobody", "webfloormap $perl_args",
SUEXEC_ACTION_IGNORE);
if ($retval) {
SUEXECERROR(SUEXEC_ACTION_USERERROR);
# Never returns.
die("");
}
#
# Now spit it back.
#
if (($fp = fopen("${prefix}.jpg", "r"))) {
header("Content-type: image/jpg");
fpassthru($fp);
}
else {
# No Data. Spit back a stub image.
header("Content-type: image/gif");
readfile("coming-soon-thumb.gif");
}
?>
...@@ -72,8 +72,18 @@ while ($row = mysql_fetch_array($query_result)) { ...@@ -72,8 +72,18 @@ while ($row = mysql_fetch_array($query_result)) {
$or = $row["orientation"]; $or = $row["orientation"];
$mobile = ($class == "robot" ? 1 : 0); $mobile = ($class == "robot" ? 1 : 0);
# In meters. # In meters.
$size = ($class == "robot" ? 0.27 : 0.07); if ($class == "robot") {
$radius = ($class == "robot" ? 0.18 : 0.04); $size = 0.27;
$radius = 0.18;
}
elseif ($class == "pc" || $class == "pcwireless") {
$size = 1.0;
$radius = 0.5;
}
else {
$size = 0.07;
$radius = 0.04;
}
$alloc = (isset($pid) ? 1 : 0); $alloc = (isset($pid) ? 1 : 0);
if (!isset($vname)) if (!isset($vname))
......
...@@ -21,52 +21,59 @@ if (isset($building) && $building != "") { ...@@ -21,52 +21,59 @@ if (isset($building) && $building != "") {
PAGEARGERROR("Invalid building argument."); PAGEARGERROR("Invalid building argument.");
} }
# Optional floor argument. Sanitize for the shell. # Optional floor argument. Sanitize for the shell.
if (isset($floor) && !preg_match("/^[-\w]+$/", $floor)) { if (isset($floor) && $floor != "") {
PAGEARGERROR("Invalid floor argument."); if (!preg_match("/^[-\w]+$/", $floor)) {
PAGEARGERROR("Invalid floor argument.");
}
} }
else
unset($floor);
} }
else { else {
$building = "MEB-ROBOTS"; $building = "MEB-ROBOTS";
$floor = 4; $floor = 4;
} }
if (!isset($pid) || if (isset($pid) && $pid != "" && isset($eid) && $eid != "") {
strcmp($pid, "") == 0) { if (!preg_match("/^[-\w]+$/", $pid)) {
PAGEARGERROR("You must provide a Project ID."); PAGEARGERROR("Invalid pid argument.");
} }
if (!preg_match("/^[-\w]+$/", $eid)) {
if (!isset($eid) || PAGEARGERROR("Invalid eid argument.");
strcmp($eid, "") == 0) { }
PAGEARGERROR("You must provide an Experiment ID."); #
} # Check to make sure this is a valid PID/EID tuple.
#
if (!preg_match("/^[-\w]+$/", $pid)) { if (! TBValidExperiment($pid, $eid)) {
PAGEARGERROR("Invalid pid argument."); USERERROR("Experiment $pid/$eid is not a valid experiment.", 1);
} }
if (!preg_match("/^[-\w]+$/", $eid)) {
PAGEARGERROR("Invalid eid argument.");
} }
else {
# unset($pid);
# Check to make sure this is a valid PID/EID tuple. unset($eid);
#
if (! TBValidExperiment($pid, $eid)) {
USERERROR("Experiment $pid/$eid is not a valid experiment.", 1);
} }