home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Late Night VRML 2.0 with Java CD-ROM
/
code.zip
/
Ch18
/
MultiUserClient.java
< prev
next >
Wrap
Text File
|
1997-02-21
|
34KB
|
796 lines
// The Multi-User Client applet
// Written by Bernie Roehl, January 1997
import java.applet.*;
import java.util.*;
import java.awt.*;
import java.io.*;
import netscape.javascript.JSObject;
import vrml.external.Browser;
import vrml.external.Node;
import vrml.external.field.*;
import vrml.external.exception.*;
import multi.*;
public class MultiUserClient
extends Applet
implements Runnable, EventOutObserver {
Thread myThread;
boolean running = true;
public static final String version = "0.1";
World world = null; // the world we're connected to
LocalEntity myEntity; // our avatar
String username = "";
String password = "";
String hostname;
int port;
String banner = "none";
String[] info = new String[10]; // our public info
Panel cardPanel; // multi-page panel
// Various controls
Button disconnectButton, hideButton, muteButton, queryButton, selectButton;
Checkbox infoCheckbox, peopleCheckbox, filterCheckbox;
Checkbox avatarCheckbox, networkCheckbox, profileCheckbox;
Checkbox suspendCheckbox;
List avatarList;
List peopleList;
static final int SCROLLMAX = 50;
Scrollbar visualAcuitySlider, visualHorizonSlider;
// Scrollbar textAcuitySlider, textHorizonSlider;
TextField nicknameField, nameField, emailField, webpageField;
TextField geographyField, phoneField, faxField;
TextField packetsField, connectedField, bannerField, statusField;
Vector avatars = new Vector(); // URLs of avatars
Vector people = new Vector(); // entities in the world
public String getAppletInfo() {
return "Multi-User Client" + version + ", written by Bernie Roehl";
}
public String[][] getParameterInfo() {
String[][] info = {
{ "host", "string", "name or IP address of filtering hsot" },
{ "port", "integer", "IP port of filtering host" }
};
return info;
}
// methods called by other applets:
public World getWorld() { return world; }
public LocalEntity getAvatar() { return myEntity; }
// initializer
public void init() {
// get the applet parameters
hostname = new String(getParameter("host"));
port = Integer.parseInt(getParameter("port"));
if (hostname == null) // default to the site this applet came from
hostname = getDocumentBase().getHost();
// create the controls
connectedField = new TextField(6); // used to display connect time
connectedField.setEditable(false); // display-only
packetsField = new TextField(6); // displays # of packets received
packetsField.setEditable(false); // display-only
bannerField = new TextField(12); // used to display host's banner
bannerField.setEditable(false); // display-only
statusField = new TextField(34); // used to display current status
statusField.setEditable(false); // display-only
disconnectButton = new Button("Disconnect"); // disconnect from the world
muteButton = new Button("Mute/Unmute"); // mute a user
hideButton = new Button("Hide/Unhide"); // hide a user
queryButton = new Button("Query"); // query public info for a user
selectButton = new Button("Select"); // select an avatar
// public info fields
nicknameField = new TextField(8);
nameField = new TextField(8);
emailField = new TextField(8);
webpageField = new TextField(8);
geographyField = new TextField(8);
phoneField = new TextField(8);
faxField = new TextField(8);
// radio buttons to select pages
CheckboxGroup selector = new CheckboxGroup();
infoCheckbox = new Checkbox("Info", selector, true);
peopleCheckbox = new Checkbox("People", selector, false);
filterCheckbox = new Checkbox("Filter", selector, false);
avatarCheckbox = new Checkbox("Avatar", selector, false);
networkCheckbox = new Checkbox("Network", selector, false);
profileCheckbox = new Checkbox("Profile", selector, false);
// sliders for filtering info
visualAcuitySlider = new Scrollbar(Scrollbar.HORIZONTAL, 0, 0, 0, SCROLLMAX);
visualHorizonSlider = new Scrollbar(Scrollbar.HORIZONTAL, 0, 0, 0, SCROLLMAX);
// textAcuitySlider = new Scrollbar(Scrollbar.HORIZONTAL, 0, 0, 0, SCROLLMAX);
// textHorizonSlider = new Scrollbar(Scrollbar.HORIZONTAL, 0, 0, 0, SCROLLMAX);
suspendCheckbox = new Checkbox(); // suspend updates from filter host
peopleList = new List(10, false); // list of users
peopleList.setFont(new Font("Courier", Font.PLAIN, 12));
avatarList = new List(10, false); // list of avatars
avatarList.setFont(new Font("Courier", Font.PLAIN, 12));
// populate the avatar list
for (int i = 0; getParameter("avatarDesc" + i) != null; ++i) {
String desc = getParameter("avatarDesc" + i);
String url = getParameter("avatarUrl" + i);
if (url != null) {
avatarList.addItem(new String(desc));
avatars.addElement(new String(url));
}
}
avatarList.select(0);
avatarList.makeVisible(0);
// and now, the panels
GridBagLayout gbl;
GridBagConstraints gbc = new GridBagConstraints();
Label label; // used for layout purposes
Panel mainControls = new Panel();
mainControls.setLayout(new FlowLayout());
mainControls.setBackground(Color.lightGray);
mainControls.add(disconnectButton);
Panel statusPanel = new Panel();
statusPanel.setLayout(new FlowLayout());
statusPanel.setBackground(Color.lightGray);
statusPanel.setForeground(Color.blue);
statusPanel.add(new Label("Status:"));
statusField.setForeground(Color.white);
statusPanel.add(statusField);
// panel of radio buttons to select pages
Panel selectorPanel = new Panel();
selectorPanel.setLayout(new GridLayout(6, 1));
selectorPanel.setBackground(Color.cyan);
selectorPanel.add(infoCheckbox);
selectorPanel.add(peopleCheckbox);
selectorPanel.add(filterCheckbox);
selectorPanel.add(avatarCheckbox);
selectorPanel.add(networkCheckbox);
selectorPanel.add(profileCheckbox);
// program information panel
Panel infoPanel = new Panel();
infoPanel.setLayout(new GridLayout(4, 1));
Label line1 = new Label("Multi-User Client", Label.CENTER);
line1.setFont(new Font("Helvetica", Font.BOLD, 24));
infoPanel.add(line1);
Label line2 = new Label("Version " + version, Label.CENTER);
line2.setFont(new Font("Helvetica", Font.PLAIN, 20));
infoPanel.add(line2);
Label line3 = new Label("Written by Bernie Roehl", Label.CENTER);
line3.setFont(new Font("Helvetica", Font.ITALIC, 16));
infoPanel.add(line3);
Label line4 = new Label("January 1997", Label.CENTER);
line4.setFont(new Font("Helvetica", Font.ITALIC, 16));
infoPanel.add(line4);
// list of users
Panel peoplePanel = new Panel();
gbl = new GridBagLayout();
peoplePanel.setLayout(gbl);
gbc.fill = GridBagConstraints.NONE; gbc.anchor = GridBagConstraints.CENTER;
gbc.weightx = 100; gbc.weighty = 100;
gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 1; gbc.gridheight = 3;
gbl.setConstraints(peopleList, gbc); peoplePanel.add(peopleList);
gbc.anchor = GridBagConstraints.SOUTH;
gbc.gridy = 0; gbc.gridx = 1; gbc.gridheight = 1;
gbl.setConstraints(hideButton, gbc); peoplePanel.add(hideButton);
gbc.gridy = 1; gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints(muteButton, gbc); peoplePanel.add(muteButton);
gbc.gridy = 2; gbc.anchor = GridBagConstraints.NORTH;
gbl.setConstraints(queryButton, gbc); peoplePanel.add(queryButton);
// filtering options
Panel filterPanel = new Panel();
gbl = new GridBagLayout();
filterPanel.setLayout(gbl);
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 100; gbc.weighty = 100; gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.gridx = 0; gbc.gridy = 0; gbc.anchor = GridBagConstraints.EAST;
gbc.gridy = 0; label = new Label("Visual acuity:"); gbl.setConstraints(label, gbc); filterPanel.add(label);
gbc.gridy = 1; label = new Label("Visual horizon:"); gbl.setConstraints(label, gbc); filterPanel.add(label);
// gbc.gridy = 2; label = new Label("Text distance:"); gbl.setConstraints(label, gbc); filterPanel.add(label);
// gbc.gridy = 3; label = new Label("Text horizon:"); gbl.setConstraints(label, gbc); filterPanel.add(label);
gbc.gridy = 4; label = new Label("Suspend:"); gbl.setConstraints(label, gbc); filterPanel.add(label);
gbc.gridx = 1; gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(0, 0, 0, 20);
gbc.gridy = 0; gbl.setConstraints(visualAcuitySlider, gbc); filterPanel.add(visualAcuitySlider);
gbc.gridy = 1; gbl.setConstraints(visualHorizonSlider, gbc); filterPanel.add(visualHorizonSlider);
// gbc.gridy = 2; gbl.setConstraints(textAcuitySlider, gbc); filterPanel.add(textAcuitySlider);
// gbc.gridy = 3; gbl.setConstraints(textHorizonSlider, gbc); filterPanel.add(textHorizonSlider);
gbc.gridy = 4; gbl.setConstraints(suspendCheckbox, gbc); filterPanel.add(suspendCheckbox);
// avatar selection
Panel avatarPanel = new Panel();
gbl = new GridBagLayout();
avatarPanel.setLayout(gbl);
gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.CENTER;
gbc.weightx = 100; gbc.weighty = 100; gbc.insets = new Insets(10, 10, 10, 10);
gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 1; gbc.gridheight = 1;
gbl.setConstraints(avatarList, gbc); avatarPanel.add(avatarList);
gbc.gridy = 1; gbc.fill = GridBagConstraints.NONE;
gbl.setConstraints(selectButton, gbc); avatarPanel.add(selectButton);
// network information
Panel networkPanel = new Panel();
gbl = new GridBagLayout();
networkPanel.setLayout(gbl);
gbc.fill = GridBagConstraints.NONE; gbc.insets = new Insets(0, 0, 0, 0);
gbc.weightx = 0; gbc.weighty = 0; gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.gridx = 0; gbc.gridy = 0; gbc.anchor = GridBagConstraints.EAST;
gbc.gridy = 0; label = new Label("Host:"); gbl.setConstraints(label, gbc); networkPanel.add(label);
gbc.gridy = 1; label = new Label("Port:"); gbl.setConstraints(label, gbc); networkPanel.add(label);
gbc.gridy = 2; label = new Label("Server:"); gbl.setConstraints(label, gbc); networkPanel.add(label);
gbc.gridy = 3; label = new Label("Packets rcvd:"); gbl.setConstraints(label, gbc); networkPanel.add(label);
gbc.gridy = 4; label = new Label("Connect time:"); gbl.setConstraints(label, gbc); networkPanel.add(label);
gbc.gridx = 1; gbc.anchor = GridBagConstraints.WEST;
gbc.gridy = 0; label = new Label(hostname); gbl.setConstraints(label, gbc); networkPanel.add(label);
gbc.gridy = 1; label = new Label(String.valueOf(port)); gbl.setConstraints(label, gbc); networkPanel.add(label);
gbc.gridy = 2; gbl.setConstraints(bannerField, gbc); networkPanel.add(bannerField);
gbc.gridy = 3; gbl.setConstraints(packetsField, gbc); networkPanel.add(packetsField);
gbc.gridy = 4; gbl.setConstraints(connectedField, gbc); networkPanel.add(connectedField);
// user's public information (profile)
Panel profilePanel = new Panel();
gbl = new GridBagLayout();
profilePanel.setLayout(gbl);
gbc.fill = GridBagConstraints.NONE;
gbc.insets = new Insets(10, 10, 10, 10);
gbc.weightx = 100; gbc.weighty = 100;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.gridx = 0; gbc.gridy = 0; gbc.anchor = GridBagConstraints.EAST;
gbc.gridy = 0; label = new Label("Nickname:"); gbl.setConstraints(label, gbc); profilePanel.add(label);
gbc.gridy = 1; label = new Label("First/Last name:"); gbl.setConstraints(label, gbc); profilePanel.add(label);
gbc.gridy = 2; label = new Label("email address:"); gbl.setConstraints(label, gbc); profilePanel.add(label);
gbc.gridy = 3; label = new Label("Web page:"); gbl.setConstraints(label, gbc); profilePanel.add(label);
gbc.gridy = 4; label = new Label("Geographic location:"); gbl.setConstraints(label, gbc); profilePanel.add(label);
gbc.gridy = 5; label = new Label("Phone number:"); gbl.setConstraints(label, gbc); profilePanel.add(label);
gbc.gridy = 6; label = new Label("Fax number:"); gbl.setConstraints(label, gbc); profilePanel.add(label);
gbc.gridx = 1; gbc.anchor = GridBagConstraints.WEST;
gbc.gridy = 0; gbl.setConstraints(nicknameField, gbc); profilePanel.add(nicknameField);
gbc.gridy = 1; gbl.setConstraints(nameField, gbc); profilePanel.add(nameField);
gbc.gridy = 2; gbl.setConstraints(emailField, gbc); profilePanel.add(emailField);
gbc.gridy = 3; gbl.setConstraints(webpageField, gbc); profilePanel.add(webpageField);
gbc.gridy = 4; gbl.setConstraints(geographyField, gbc); profilePanel.add(geographyField);
gbc.gridy = 5; gbl.setConstraints(phoneField, gbc); profilePanel.add(phoneField);
gbc.gridy = 6; gbl.setConstraints(faxField, gbc); profilePanel.add(faxField);
// multi-panel panel
cardPanel = new Panel();
cardPanel.setLayout(new CardLayout());
cardPanel.add("Info", infoPanel);
cardPanel.add("People", peoplePanel);
cardPanel.add("Filter", filterPanel);
cardPanel.add("Avatar", avatarPanel);
cardPanel.add("Network", networkPanel);
cardPanel.add("Profile", profilePanel);
// and finally, the overall layout of the main panel
setLayout(new BorderLayout());
// add("North", mainControls); No disconnect button yet
add("South", statusPanel);
add("East", selectorPanel);
add("Center", cardPanel);
}
public void start() {
if (myThread == null)
myThread = new Thread(this);
myThread.start();
if (world != null)
world.suspend(suspendCheckbox.getState());
}
public void stop() {
if (world != null)
world.suspend(true);
if (myThread != null)
myThread.stop();
}
public void run() {
new LoginDialog(this);
browserSetup(); // connect to the VRML browser
worldSetup(); // connect to the world
new TimeUpdater(this); // keeps the time up-to-date
new PeopleReader(this); // keeps list of users up-to-date
while (running) {
if (world != null) {
Enumeration en = world.getEntities();
// go through entities
while (en.hasMoreElements())
updateEntity((Entity) en.nextElement());
}
Thread.yield();
}
}
private void updateEntity(Entity e) {
int state = e.getState();
if (state == Entity.STALE || state == Entity.GONE) {
// entity has left or expired
e.setState(Entity.DEAD);
e.setRepresentation(null);
return; // done with this entity
}
// make sure the object has a representation
Thing rep = (Thing) e.getRepresentation();
if (rep == null || e.hasNewURL()) {
// need to create a representation
String url = e.getURL();
if (url == null)
return;
try { rep = new Thing(browser, addAvatars, removeAvatars, url); }
catch (InvalidVrmlException ex) {
System.out.println("couldn't add object: " + ex);
return;
}
catch (InvalidEventInException ex) {
System.out.println("couldn't add object: " + ex);
return;
}
e.setRepresentation(rep);
e.unmarkNewURL();
}
if (e.hasChanged()) {
// update rep with location and orientation
rep.setLocation(e.getLocation());
rep.setOrientation(e.getOrientation());
rep.setVisibility(!e.isHidden());
e.markUnchanged();
}
}
public boolean handleEvent(Event evt) {
CardLayout layout = (CardLayout) cardPanel.getLayout();
if (evt.id == Event.ACTION_EVENT) {
if (evt.target instanceof Checkbox) {
if (evt.target == infoCheckbox)
layout.show(cardPanel, "Info");
else if (evt.target == peopleCheckbox)
layout.show(cardPanel, "People");
else if (evt.target == filterCheckbox)
layout.show(cardPanel, "Filter");
else if (evt.target == avatarCheckbox)
layout.show(cardPanel, "Avatar");
else if (evt.target == networkCheckbox)
layout.show(cardPanel, "Network");
else if (evt.target == profileCheckbox)
layout.show(cardPanel, "Profile");
else if (evt.target == suspendCheckbox && world != null)
world.suspend(((Boolean) evt.arg).booleanValue());
return true;
}
else if (evt.target instanceof TextField) {
if (evt.target == nicknameField && myEntity != null)
myEntity.setNickName((String) evt.arg);
else if (evt.target == nameField)
info[0] = (String) evt.arg;
else if (evt.target == emailField)
info[1] = (String) evt.arg;
else if (evt.target == webpageField)
info[2] = (String) evt.arg;
else if (evt.target == geographyField)
info[3] = (String) evt.arg;
else if (evt.target == phoneField)
info[4] = (String) evt.arg;
else if (evt.target == faxField)
info[5] = (String) evt.arg;
if (myEntity != null) {
myEntity.setInfo(info);
try { myEntity.updateRegistry(); }
catch (IOException ex) { }
catch (PermissionDeniedException ex) { }
}
return true;
}
else if (evt.target instanceof Button) {
if (evt.target == disconnectButton)
running = false;
else if (evt.target == selectButton && myEntity != null) {
myEntity.setURL((String) avatars.elementAt(avatarList.getSelectedIndex()));
try { myEntity.updateRegistry(); }
catch (IOException ex) { }
catch (PermissionDeniedException ex) { }
}
else if (evt.target == hideButton) {
int n = peopleList.getSelectedIndex();
Entity e = (Entity) people.elementAt(n);
e.Hide(!e.isHidden());
peopleList.replaceItem(peopleFormat(e), n);
peopleList.select(n);
}
else if (evt.target == muteButton) {
int n = peopleList.getSelectedIndex();
Entity e = (Entity) people.elementAt(n);
e.Mute(!e.isMuted());
peopleList.replaceItem(peopleFormat(e), n);
peopleList.select(n);
}
else if (evt.target == queryButton)
new QueryDialog((Entity) people.elementAt(peopleList.getSelectedIndex()));
return true;
}
else if (evt.target instanceof Scrollbar && world != null) {
switch (evt.id) {
case Event.SCROLL_LINE_UP: case Event.SCROLL_LINE_DOWN:
case Event.SCROLL_PAGE_UP: case Event.SCROLL_PAGE_DOWN:
case Event.SCROLL_ABSOLUTE:
if (evt.target == visualAcuitySlider)
world.setVisualAcuity(visualAcuitySlider.getValue() / (float) SCROLLMAX);
else if (evt.target == visualHorizonSlider)
world.setVisualHorizonCount(visualHorizonSlider.getValue());
return true;
default: return false;
}
}
}
return false;
}
public static String peopleFormat(Entity e) { // format an entry in the user list
String name = e.getNickName();
if (name == null)
name = "Guest";
return (e.isHidden() ? "H" : " ") + (e.isMuted() ? "M" : " ") + " " + name;
}
private Browser getBrowser() {
Browser browser = Browser.getBrowser();
if (browser == null) {
JSObject win = JSObject.getWindow(this);
if (win != null) {
JSObject doc = (JSObject) win.getMember("document");
JSObject embeds = (JSObject) doc.getMember("embeds");
JSObject applets = (JSObject) doc.getMember("applets");
JSObject frames = (JSObject) doc.getMember("frames");
for (int i = 0; i < 10; ++i) {
browser = (Browser) embeds.getSlot(0);
if (browser != null)
break;
try { Thread.sleep(500); }
catch (InterruptedException e) { }
}
}
}
return browser;
}
Browser browser; // the VRML browser
Node root; // root node of the loaded world
Node proxSensor; // first one's a ProximitySensor
Node entityGroup; // second one's a group for holding avatars
EventOutSFVec3f position_changed; // eventOuts of ProximitySensor
EventOutSFRotation orientation_changed;
EventInMFNode addAvatars = null; // eventIns of ObjGroup
EventInMFNode removeAvatars = null;
private void browserSetup() {
// find the VRML browser
browser = getBrowser();
if (browser == null)
System.out.println("Could not find VRML browser!");
// find the root node of the loaded world
root = null;
try {
while (root == null)
root = browser.getNode("Root");
}
catch (InvalidNodeException e) {
System.out.println("Could not find node named \"Root\"");
}
EventInMFNode addChildren = null;
try { addChildren = (EventInMFNode) root.getEventIn("addChildren"); }
catch (InvalidEventInException e) {
System.out.println("Could not access addChildren eventIn on root node: " + e);
}
Node[] ournodes = browser.createVrmlFromString(
"ProximitySensor { size 1e30 1e30 1e30 }\n" +
"Group { }\n"
);
addChildren.setValue(ournodes);
proxSensor = ournodes[0];
entityGroup = ournodes[1];
// find the entityGroup's node's addChildren and
// removeChildren eventIns
try {
addAvatars = (EventInMFNode) entityGroup.getEventIn("addChildren");
removeAvatars = (EventInMFNode) entityGroup.getEventIn("removeChildren");
}
catch (InvalidEventInException e) {
System.out.println("Could not access eventIn on ObjGroup node: " + e);
}
// capture the proxSensor's position_changed and
// orientation_changed eventIns
position_changed =
(EventOutSFVec3f) proxSensor.getEventOut("position_changed");
position_changed.advise(this, null);
orientation_changed =
(EventOutSFRotation) proxSensor.getEventOut("orientation_changed");
orientation_changed.advise(this, null);
}
private int n = 0; // used to count callbacks
public void callback(EventOut event, double time, Object userData) {
System.out.println("callback!");
if (event.getType() == FieldTypes.SFVEC3F) {
EventOutSFVec3f pos = (EventOutSFVec3f) event;
float[] values = pos.getValue();
Vec3 loc = new Vec3(values[0], values[1], values[2]);
System.out.println("location = " + loc);
if (world != null)
world.setViewpoint(loc);
if (myEntity != null) {
myEntity.setLocation(loc);
try { myEntity.sendUpdate(); }
catch (IOException e) { }
}
}
else if (event.getType() == FieldTypes.SFROTATION) {
if (myEntity != null) {
EventOutSFRotation rot = (EventOutSFRotation) event;
float[] values = rot.getValue();
if (myEntity != null) {
myEntity.setOrientation(
new Rotation(
values[0], values[1], values[2], values[3]));
try { myEntity.sendUpdate(); }
catch (IOException e) { }
}
}
}
}
private void worldSetup() {
// connect to the world
try {
world = new World(hostname, port);
statusField.setText("Connected");
statusField.setForeground(Color.yellow);
}
catch (Exception ex) {
statusField.setText(ex.toString());
statusField.setForeground(Color.red);
}
if (world != null) {
// set the banner
banner = world.getBanner();
if (banner == null)
banner = "";
bannerField.setText(banner);
// create our avatar
try { world.identity(username, password); }
catch (IOException ex) {
System.out.println("couldn't IDENT: " + ex);
}
catch (BadIdentityException ex) {
System.out.println("couldn't IDENT: " + ex);
}
try {
// we use the username as the cname
// for the user's avatar:
myEntity = new LocalEntity(world, username);
// we also use it as our initial nickname:
myEntity.setNickName(username);
// use a default avatar:
myEntity.setURL((String) avatars.elementAt(0));
myEntity.updateRegistry();
}
catch (PermissionDeniedException ex) {
System.out.println("couldn't create avatar: " + ex);
}
catch (IOException ex) {
System.out.println("couldn't create avatar: " + ex);
}
}
}
}
class QueryDialog extends Dialog {
protected Button dismissButton = new Button("Dismiss");
public QueryDialog(Entity entity) {
super(new Frame(), "Query User", true); // modal dialog box
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
setLayout(gbl);
Label label;
gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 100; gbc.weighty = 100; gbc.insets = new Insets(10, 0, 10, 20);
gbc.anchor = GridBagConstraints.EAST; gbc.fill = GridBagConstraints.NONE;
gbc.gridy = 0; label = new Label("First/Last name:"); gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 1; label = new Label("email address:"); gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 2; label = new Label("Web page:"); gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 3; label = new Label("Geographic location:"); gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 4; label = new Label("Phone number:"); gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 5; label = new Label("Fax number:"); gbl.setConstraints(label, gbc); add(label);
gbc.gridx = 1; gbc.anchor = GridBagConstraints.WEST;
String[] info = entity.getInfo();
gbc.gridy = 0; label = new Label(info[0] == null ? "<unknown>" : info[0]); gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 1; label = new Label(info[1] == null ? "<unknown>" : info[1]); gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 2; label = new Label(info[2] == null ? "<unknown>" : info[2]); gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 3; label = new Label(info[3] == null ? "<unknown>" : info[3]); gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 4; label = new Label(info[4] == null ? "<unknown>" : info[4]); gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 5; label = new Label(info[5] == null ? "<unknown>" : info[5]); gbl.setConstraints(label, gbc); add(label);
gbc.gridx = 0; gbc.gridy = 6; gbc.gridwidth = 2;
gbc.anchor = GridBagConstraints.CENTER; gbc.insets = new Insets(10, 10, 10, 10);
gbc.gridy = 6; gbl.setConstraints(dismissButton, gbc); add(dismissButton);
pack();
show();
}
public boolean action(Event evt, Object whichAction) {
if (evt.target == dismissButton)
hide();
return true;
}
}
class LoginDialog extends Dialog {
protected Button connectButton = new Button("Connect");
protected TextField usernameField, passwordField;
public LoginDialog(MultiUserClient muclient) {
super(new Frame(), "Login", true); // modal dialog box
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
setLayout(gbl);
Label label;
gbc.gridx = 0; gbc.gridy = 0;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 100; gbc.weighty = 100;
gbc.insets = new Insets(10, 0, 10, 20);
gbc.anchor = GridBagConstraints.EAST;
gbc.fill = GridBagConstraints.NONE;
label = new Label("Userid:");
gbl.setConstraints(label, gbc); add(label);
gbc.gridy = 1;
label = new Label("Password:");
gbl.setConstraints(label, gbc); add(label);
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx = 1; gbc.gridy = 0;
usernameField = new TextField(16);
gbl.setConstraints(usernameField, gbc); add(usernameField);
gbc.gridy = 1;
passwordField = new TextField(16);
passwordField.setEchoCharacter('*');
gbl.setConstraints(passwordField, gbc); add(passwordField);
gbc.gridy = 2;
gbl.setConstraints(connectButton, gbc); add(connectButton);
pack();
show();
muclient.username = usernameField.getText();
muclient.password = passwordField.getText();
}
public boolean action(Event evt, Object whichAction) {
if (evt.target == connectButton)
hide();
return true;
}
}
class TimeUpdater extends Thread {
MultiUserClient client;
public TimeUpdater(MultiUserClient cli) {
client = cli;
setPriority(NORM_PRIORITY-1);
start();
}
public void run() {
while (true) {
long secondsConnected =
(System.currentTimeMillis()
- client.world.getConnectedTime())/1000;
long minutesConnected = secondsConnected/60;
long hours = minutesConnected / 60;
long minutes = minutesConnected % 60;
client.connectedField.setText(
hours + ":" + ((minutes < 10) ? "0" : "")
+ minutes);
client.packetsField.setText(
String.valueOf(client.world.getPacketCount()));
try sleep(1000); catch (InterruptedException ex) { }
}
}
}
class PeopleReader extends Thread {
MultiUserClient client;
public PeopleReader(MultiUserClient cli) {
client = cli;
setPriority(NORM_PRIORITY-1);
start();
}
public void run() {
while (true) {
// clear the list so we can re-fill it:
client.peopleList.delItems(0,
client.peopleList.countItems()-1);
client.people = new Vector();
Enumeration en = client.world.getEntities();
while (en.hasMoreElements()) {
Entity e = (Entity) en.nextElement();
if (e.isAvatar() == false) // ignore non-avatars
continue;
if (e.needsInfo()) // not all there yet
continue;
client.people.addElement(e);
client.peopleList.addItem(client.peopleFormat(e));
}
client.peopleList.select(0);
try Thread.sleep(10000); // update every ten seconds
catch (InterruptedException ex) { }
}
}
}