- /*
 - * @(#)FormView.java 1.14 00/02/02
 - *
 - * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
 - *
 - * This software is the proprietary information of Sun Microsystems, Inc.
 - * Use is subject to license terms.
 - *
 - */
 - package javax.swing.text.html;
 - import java.net.*;
 - import java.io.*;
 - import java.awt.*;
 - import java.awt.event.*;
 - import javax.swing.*;
 - import javax.swing.event.*;
 - import javax.swing.text.*;
 - /**
 - * Component decorator that implements the view interface
 - * for form elements, <input>, <textarea>,
 - * and <select>. The model for the component is stored
 - * as an attribute of the the element (using StyleConstants.ModelAttribute),
 - * and is used to build the component of the view. The type
 - * of the model is assumed to of the type that would be set by
 - * <code>HTMLDocument.HTMLReader.FormAction</code>. If there are
 - * multiple views mapped over the document, they will share the
 - * embedded component models.
 - * <p>
 - * The following table shows what components get built
 - * by this view.
 - * <table>
 - * <tr>
 - * <th>Element Type
 - * <th>Component built
 - * <tr>
 - * <td>input, type button
 - * <td>JButton
 - * <tr>
 - * <td>input, type checkbox
 - * <td>JCheckBox
 - * <tr>
 - * <td>input, type image
 - * <td>JButton
 - * <tr>
 - * <td>input, type password
 - * <td>JPasswordField
 - * <tr>
 - * <td>input, type radio
 - * <td>JRadioButton
 - * <tr>
 - * <td>input, type reset
 - * <td>JButton
 - * <tr>
 - * <td>input, type submit
 - * <td>JButton
 - * <tr>
 - * <td>input, type text
 - * <td>JTextField
 - * <tr>
 - * <td>select, size > 1 or multiple attribute defined
 - * <td>JList in a JScrollPane
 - * <tr>
 - * <td>select, size unspecified or 1
 - * <td>JComboBox
 - * <tr>
 - * <td>textarea
 - * <td>JTextArea in a JScrollPane
 - * </table>
 - *
 - * @author Timothy Prinzing
 - * @author Sunita Mani
 - * @version 1.14 02/02/00
 - */
 - public class FormView extends ComponentView implements ActionListener {
 - /**
 - * If a value attribute is not specified for a FORM input element
 - * of type "submit", then this default string is used.
 - *
 - * @deprecated As of 1.3, value now comes from UIManager property
 - * FormView.submitButtonText
 - */
 - public static final String SUBMIT = new String("Submit Query");
 - /**
 - * If a value attribute is not specified for a FORM input element
 - * of type "reset", then this default string is used.
 - *
 - * @deprecated As of 1.3, value comes from UIManager UIManager property
 - * FormView.resetButtonText
 - */
 - public static final String RESET = new String("Reset");
 - /**
 - * Creates a new FormView object.
 - *
 - * @param elem the element to decorate
 - */
 - public FormView(Element elem) {
 - super(elem);
 - }
 - /**
 - * Create the component. This is basically a
 - * big switch statement based upon the tag type
 - * and html attributes of the associated element.
 - */
 - protected Component createComponent() {
 - AttributeSet attr = getElement().getAttributes();
 - HTML.Tag t = (HTML.Tag)
 - attr.getAttribute(StyleConstants.NameAttribute);
 - JComponent c = null;
 - Object model = attr.getAttribute(StyleConstants.ModelAttribute);
 - if (t == HTML.Tag.INPUT) {
 - c = createInputComponent(attr, model);
 - } else if (t == HTML.Tag.SELECT) {
 - if (model instanceof OptionListModel) {
 - JList list = new JList((ListModel) model);
 - int size = HTML.getIntegerAttributeValue(attr,
 - HTML.Attribute.SIZE,
 - 1);
 - list.setVisibleRowCount(size);
 - list.setSelectionModel((ListSelectionModel)model);
 - c = new JScrollPane(list);
 - } else {
 - c = new JComboBox((ComboBoxModel) model);
 - }
 - } else if (t == HTML.Tag.TEXTAREA) {
 - JTextArea area = new JTextArea((Document) model);
 - int rows = HTML.getIntegerAttributeValue(attr,
 - HTML.Attribute.ROWS,
 - 0);
 - area.setRows(rows);
 - int cols = HTML.getIntegerAttributeValue(attr,
 - HTML.Attribute.COLS,
 - 0);
 - area.setColumns(cols);
 - c = new JScrollPane(area,
 - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
 - JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
 - }
 - if (c != null) {
 - c.setAlignmentY(1.0f);
 - }
 - return c;
 - }
 - /**
 - * Creates a component for an <INPUT> element based on the
 - * value of the "type" attribute.
 - *
 - * @param set of attributes associated with the <INPUT> element.
 - * @param model the value of the StyleConstants.ModelAttribute
 - * @return the component.
 - */
 - private JComponent createInputComponent(AttributeSet attr, Object model) {
 - JComponent c = null;
 - String type = (String) attr.getAttribute(HTML.Attribute.TYPE);
 - if (type.equals("submit") || type.equals("reset")) {
 - String value = (String)
 - attr.getAttribute(HTML.Attribute.VALUE);
 - if (value == null) {
 - if (type.equals("submit")) {
 - value = UIManager.getString("FormView.submitButtonText");
 - } else {
 - value = UIManager.getString("FormView.resetButtonText");
 - }
 - }
 - JButton button = new JButton(value);
 - if (model != null) {
 - button.setModel((ButtonModel)model);
 - button.addActionListener(this);
 - }
 - c = button;
 - } else if (type.equals("image")) {
 - String srcAtt = (String) attr.getAttribute(HTML.Attribute.SRC);
 - JButton button;
 - try {
 - URL base = ((HTMLDocument)getElement().getDocument()).getBase();
 - URL srcURL = new URL(base, srcAtt);
 - Icon icon = new ImageIcon(srcURL);
 - button = new JButton(icon);
 - } catch (MalformedURLException e) {
 - button = new JButton(srcAtt);
 - }
 - if (model != null) {
 - button.setModel((ButtonModel)model);
 - button.addMouseListener(new MouseEventListener());
 - }
 - c = button;
 - } else if (type.equals("checkbox")) {
 - c = new JCheckBox();
 - if (model != null) {
 - boolean checked = (attr.getAttribute(HTML.Attribute.CHECKED) != null);
 - ((JToggleButton.ToggleButtonModel) model).setSelected(checked);
 - ((JCheckBox)c).setModel((JToggleButton.ToggleButtonModel)model);
 - }
 - } else if (type.equals("radio")) {
 - c = new JRadioButton();
 - if (model != null) {
 - boolean checked = (attr.getAttribute(HTML.Attribute.CHECKED) != null);
 - ((JToggleButton.ToggleButtonModel)model).setSelected(checked);
 - ((JRadioButton)c).setModel((JToggleButton.ToggleButtonModel)model);
 - }
 - } else if (type.equals("text")) {
 - int size = HTML.getIntegerAttributeValue(attr,
 - HTML.Attribute.SIZE,
 - -1);
 - JTextField field;
 - if (size > 0) {
 - // If the size is specified, we don't want to allow the
 - // text field to be bigger than the preferred size.
 - field = new JTextField() {
 - public Dimension getMaximumSize() {
 - return getPreferredSize();
 - }
 - };
 - field.setColumns(size);
 - }
 - else {
 - field = new JTextField();
 - }
 - c = field;
 - if (model != null) {
 - field.setDocument((Document) model);
 - }
 - String value = (String)
 - attr.getAttribute(HTML.Attribute.VALUE);
 - if (value != null) {
 - field.setText(value);
 - }
 - field.addActionListener(this);
 - } else if (type.equals("password")) {
 - JPasswordField field = new JPasswordField();
 - c = field;
 - if (model != null) {
 - field.setDocument((Document) model);
 - }
 - int size = HTML.getIntegerAttributeValue(attr,
 - HTML.Attribute.SIZE,
 - -1);
 - if (size > 0) {
 - field.setColumns(size);
 - }
 - String value = (String)
 - attr.getAttribute(HTML.Attribute.VALUE);
 - if (value != null) {
 - field.setText(value);
 - }
 - field.addActionListener(this);
 - }
 - return c;
 - }
 - /**
 - * Responsible for processeing the ActionEvent.
 - * If the element associated with the FormView,
 - * has a type of "submit", "reset", "text" or "password"
 - * then the action is processed. In the case of a "submit"
 - * the form is submitted. In the case of a "reset"
 - * the form is reset to its original state.
 - * In the case of "text" or "password", if the
 - * element is the last one of type "text" or "password",
 - * the form is submitted. Otherwise, focus is transferred
 - * to the next component in the form.
 - *
 - * @param evt the ActionEvent.
 - */
 - public void actionPerformed(ActionEvent evt) {
 - Element element = getElement();
 - StringBuffer dataBuffer = new StringBuffer();
 - HTMLDocument doc = (HTMLDocument)getDocument();
 - AttributeSet attr = element.getAttributes();
 - String type = (String) attr.getAttribute(HTML.Attribute.TYPE);
 - if (type.equals("submit")) {
 - doc.getFormData(dataBuffer, element);
 - submitData(dataBuffer.toString());
 - } else if (type.equals("reset")) {
 - doc.resetForm(element);
 - } else if (type.equals("text") || type.equals("password")) {
 - if (doc.isLastTextOrPasswordField(element)) {
 - doc.getFormData(dataBuffer, element);
 - submitData(dataBuffer.toString());
 - } else {
 - getComponent().transferFocus();
 - }
 - }
 - }
 - /**
 - * This method is responsible for submitting the form data.
 - * A thread is forked to undertake the submission.
 - */
 - protected void submitData(String data) {
 - //System.err.println("data ->"+data+"<-");
 - SubmitThread dataThread = new SubmitThread(getElement(), data);
 - dataThread.start();
 - }
 - /**
 - * The SubmitThread is responsible for submitting the form.
 - * It performs a POST or GET based on the value of method
 - * attribute associated with HTML.Tag.FORM. In addition to
 - * submitting, it is also responsible for display the
 - * results of the form submission.
 - */
 - class SubmitThread extends Thread {
 - String data;
 - HTMLDocument hdoc;
 - HTMLDocument newDoc;
 - AttributeSet formAttr;
 - InputStream in;
 - public SubmitThread(Element elem, String data) {
 - this.data = data;
 - hdoc = (HTMLDocument)elem.getDocument();
 - formAttr = hdoc.getFormAttributes(elem.getAttributes());
 - }
 - /**
 - * This method is responsible for extracting the
 - * method and action attributes associated with the
 - * <FORM> and using those to determine how (POST or GET)
 - * and where (URL) to submit the form. If action is
 - * not specified, the base url of the existing document is
 - * used. Also, if method is not specified, the default is
 - * GET. Once form submission is done, run uses the
 - * SwingUtilities.invokeLater() method, to load the results
 - * of the form submission into the current JEditorPane.
 - */
 - public void run() {
 - if (data.length() > 0) {
 - String method = getMethod();
 - String action = getAction();
 - URL url;
 - try {
 - URL actionURL;
 - /* if action is null use the base url and ensure that
 - the file name excludes any parameters that may be attached */
 - URL baseURL = hdoc.getBase();
 - if (action == null) {
 - String file = baseURL.getFile();
 - actionURL = new URL(baseURL.getProtocol(),
 - baseURL.getHost(),
 - baseURL.getPort(),
 - file);
 - } else {
 - actionURL = new URL(baseURL, action);
 - }
 - URLConnection connection;
 - if ("post".equals(method)) {
 - url = actionURL;
 - connection = url.openConnection();
 - postData(connection, data);
 - } else {
 - /* the default, GET */
 - url = new URL(actionURL+"?"+data);
 - connection = url.openConnection();
 - }
 - in = connection.getInputStream();
 - // safe assumption since we are in an html document
 - JEditorPane c = (JEditorPane)getContainer();
 - HTMLEditorKit kit = (HTMLEditorKit)c.getEditorKit();
 - newDoc = (HTMLDocument)kit.createDefaultDocument();
 - newDoc.putProperty(Document.StreamDescriptionProperty, url);
 - Runnable callLoadDocument = new Runnable() {
 - public void run() {
 - loadDocument();
 - }
 - };
 - SwingUtilities.invokeLater(callLoadDocument);
 - } catch (MalformedURLException m) {
 - // REMIND how do we deal with exceptions ??
 - } catch (IOException e) {
 - // REMIND how do we deal with exceptions ??
 - }
 - }
 - }
 - /**
 - * This method is responsible for loading the
 - * document into the FormView's container,
 - * which is a JEditorPane.
 - */
 - public void loadDocument() {
 - JEditorPane c = (JEditorPane)getContainer();
 - try {
 - c.read(in, newDoc);
 - } catch (IOException e) {
 - // REMIND failed to load document
 - }
 - }
 - /**
 - * Get the value of the action attribute.
 - */
 - public String getAction() {
 - if (formAttr == null) {
 - return null;
 - }
 - return (String)formAttr.getAttribute(HTML.Attribute.ACTION);
 - }
 - /**
 - * Get the form's method parameter.
 - */
 - String getMethod() {
 - if (formAttr != null) {
 - String method = (String)formAttr.getAttribute(HTML.Attribute.METHOD);
 - if (method != null) {
 - return method.toLowerCase();
 - }
 - }
 - return null;
 - }
 - /**
 - * This method is responsible for writing out the form submission
 - * data when the method is POST.
 - *
 - * @param connection to use.
 - * @param data to write.
 - */
 - public void postData(URLConnection connection, String data) {
 - connection.setDoOutput(true);
 - PrintWriter out = null;
 - try {
 - out = new PrintWriter(new OutputStreamWriter(connection.getOutputStream()));
 - out.print(data);
 - out.flush();
 - } catch (IOException e) {
 - // REMIND: should do something reasonable!
 - } finally {
 - if (out != null) {
 - out.close();
 - }
 - }
 - }
 - }
 - /**
 - * MouseEventListener class to handle form submissions when
 - * an input with type equal to image is clicked on.
 - * A MouseListener is necessary since along with the image
 - * data the coordinates associated with the mouse click
 - * need to be submitted.
 - */
 - protected class MouseEventListener extends MouseAdapter {
 - public void mouseReleased(MouseEvent evt) {
 - String imageData = getImageData(evt.getPoint());
 - imageSubmit(imageData);
 - }
 - }
 - /**
 - * This method is called to submit a form in response
 - * to a click on an image -- an <INPUT> form
 - * element of type "image".
 - *
 - * @param the mouse click coordinates.
 - */
 - protected void imageSubmit(String imageData) {
 - StringBuffer dataBuffer = new StringBuffer();
 - Element elem = getElement();
 - HTMLDocument hdoc = (HTMLDocument)elem.getDocument();
 - hdoc.getFormData(dataBuffer, getElement());
 - if (dataBuffer.length() > 0) {
 - dataBuffer.append('&');
 - }
 - dataBuffer.append(imageData);
 - submitData(dataBuffer.toString());
 - return;
 - }
 - /**
 - * Extracts the value of the name attribute
 - * associated with the input element of type
 - * image. If name is defined it is encoded using
 - * the URLEncoder.encode() method and the
 - * image data is returned in the following format:
 - * name + ".x" +"="+ x +"&"+ name +".y"+"="+ y
 - * otherwise,
 - * "x="+ x +"&y="+ y
 - *
 - * @param point associated with the mouse click.
 - * @return the image data.
 - */
 - private String getImageData(Point point) {
 - String mouseCoords = point.x + ":" + point.y;
 - int sep = mouseCoords.indexOf(':');
 - String x = mouseCoords.substring(0, sep);
 - String y = mouseCoords.substring(++sep);
 - String name = (String) getElement().getAttributes().getAttribute(HTML.Attribute.NAME);
 - String data;
 - if (name == null || name.equals("")) {
 - data = "x="+ x +"&y="+ y;
 - } else {
 - name = URLEncoder.encode(name);
 - data = name + ".x" +"="+ x +"&"+ name +".y"+"="+ y;
 - }
 - return data;
 - }
 - }