//
// VisADApplet.java
//

/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

package visad.browser;

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.MemoryImageSource;
import java.io.*;
import java.net.*;
import java.util.*;

/**
 * An applet for connecting to a VisAD display available through a
 * SocketSlaveDisplay server. The applet functions completely independently
 * of VisAD, using only JDK 1.1 code, so that it can be imbedded
 * within a web page for use in a web browser.
 */
public class VisADApplet extends Applet
  implements ActionListener, MouseListener, MouseMotionListener, WidgetListener
{

  /**
   * Debugging flag.
   */
  private static final boolean DEBUG = false;

  /**
   * The default host name for the SocketSlaveDisplay server.
   */
  private static final String DEFAULT_HOST = "localhost";

  /**
   * The default port at which to connect.
   */
  private static final int DEFAULT_PORT = 4567;

  /**
   * Code for refresh action.
   */
  public static final int REFRESH = 0;

  /**
   * Code for mouse event action.
   */
  public static final int MOUSE_EVENT = 1;

  /**
   * Code for message action.
   */
  public static final int MESSAGE = 2;

  /**
   * Whether the applet client is connected to a server.
   */
  private boolean connected = false;

  /**
   * IP address of the server.
   */
  private String address = "";

  /**
   * Port of the server.
   */
  private int port = DEFAULT_PORT;

  /**
   * Currently connected socket.
   */
  private Socket socket = null;

  /**
   * Output stream of currently connected socket.
   */
  private DataOutputStream out = null;

  /**
   * ID number.
   */
  private int id;

  /**
   * Latest image from the server's display.
   */
  private Image image = null;

  /**
   * Text field for typing in IP address of server.
   */
  private TextField addressField;

  /**
   * Text field for typing in port of server.
   */
  private TextField portField;

  /**
   * Button for connecting to the specified IP address and port.
   */
  private Button connectButton;

  /**
   * Canvas for painting remote display image from the server.
   */
  private Component canvas;

  /**
   * Frame for display widgets.
   */
  private Frame frame;

  /**
   * Layout manager for widget frame.
   */
  private GridBagLayout widgetLayout;

  /**
   * GridBagConstraints object for use in widget layout.
   */
  private GridBagConstraints constraints;

  /**
   * Thread for communicating with server.
   */
  private Thread commThread = null;

  /**
   * Hashtable for storing widgets.
   */
  private Hashtable hashtable = new Hashtable();

  private Applet myself;
  /**
   * Adds a component to the applet with the specified constraints.
   */
  private void addComponent(Component c, GridBagLayout layout,
    int x, int y, int w, int h, double wx, double wy)
  {
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = x;
    gbc.gridy = y;
    gbc.gridwidth = w;
    gbc.gridheight = h;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.weightx = wx;
    gbc.weighty = wy;
    layout.setConstraints(c, gbc);
    add(c);
  }

  /**
   * Adds a widget to the control panel.
   */
  private void addWidget(Widget widget, String hash) {
    // add widget to hashtable
    hashtable.put(hash, widget);

    // add widget to control panel
    if (constraints.gridy > 0) {
      Divider divider = new Divider();
      widgetLayout.setConstraints(divider, constraints);
      constraints.gridy++;
      frame.add(divider);
    }
    widgetLayout.setConstraints(widget, constraints);
    constraints.gridy++;
    frame.add(widget);
    frame.pack();
    frame.setVisible(true);
  }

  /**
   * Removes all widgets from the control panel.
   */
  private synchronized void removeAllWidgets() {
    // clear hashtable
    hashtable = new Hashtable();

    // clear control panel
    constraints.gridy = 0;
    frame.setVisible(false);
    frame.removeAll();
  }

  /**
   * Initializes the applet and lays out its GUI.
   */
  public void init() {
    // set background to white
    setBackground(Color.white);

    // lay out components with GridBagLayout
    GridBagLayout gridbag = new GridBagLayout();
    setLayout(gridbag);
    myself = (Applet)this;

    // construct GUI components
    addressField = new TextField(DEFAULT_HOST);
    portField = new TextField("" + DEFAULT_PORT, 4);
    connectButton = new Button("Connect");
    canvas = new Component() {
      public void update(Graphics g) { paint(g); }
      public void paint(Graphics g) {
        if (connected) {
          // connected; paint the remote display's image
          if (image != null) {
            g.drawImage(image, 0, 0, this);
          }
        }
        else {
          // not connected; paint directions on how to connect
          g.setColor(Color.black);
          g.drawString("VisADApplet", 80, 20);
          g.drawString("To connect to a VisAD display available", 10, 50);
          g.drawString("through a SocketSlaveDisplay server, type", 10, 70);
          g.drawString("the IP address of the server into the IP", 10, 90);
          g.drawString("address field and type the port of the", 10, 110);
          g.drawString("server into the port field, then press", 10, 130);
          g.drawString("the Connect button.", 10, 150);
        }
      }
    };

    // respond to GUI component events
    addressField.addActionListener(this);
    portField.addActionListener(this);
    connectButton.addActionListener(this);
    canvas.addMouseListener(this);
    canvas.addMouseMotionListener(this);

    // lay out GUI components
    addComponent(new Label("IP address"), gridbag, 0, 0, 1, 1, 0.0, 0.0);
    addComponent(addressField, gridbag, 1, 0, 1, 1, 1.0, 0.0);
    addComponent(new Label("Port"), gridbag, 2, 0, 1, 1, 0.0, 0.0);
    addComponent(portField, gridbag, 3, 0, 1, 1, 0.0, 0.0);
    addComponent(connectButton, gridbag, 4, 0, 1, 1, 0.0, 0.0);
    addComponent(canvas, gridbag, 0, 1, 5, 1, 1.0, 1.0);

    // construct widget frame
    frame = new Frame("Controls");
    widgetLayout = new GridBagLayout();
    frame.setLayout(widgetLayout);
    constraints = new GridBagConstraints();
    constraints.gridx = 0;
    constraints.gridy = 0;
    constraints.fill = GridBagConstraints.BOTH;
    frame.setBackground(Widget.PALE_GRAY);
  }

  /**
   * Close the current server connection
   */
  public void disconnect() {
    if (connected) {
      connected = false;
      // remove all widget listeners
      for (int i=0; i 

Ads help maintain this website.