//=====================================================================
// File: OptionDialog.java
// Class: OptionDialog
// Package: AFLPgui
//
// Author: James J. Benham (plus a little defiling by Philip DeCamp)
// Date: August 12, 1998
// Contact: james_benham@hmc.edu or decamp@portalofevil.com
//
// Genographer v1.6 - Computer assisted scoring of gels.
// Changes Copyright (C) 2001 James J. Benham
// Copyright (C) 1998 Montana State University
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// The GNU General Public License is distributed in the file GPL
//=====================================================================
package AFLPgui;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Panel;
import java.awt.ScrollPane;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import AFLPcore.Option;
import AFLPcore.MissingParameterError;
/**
* This class will display options in a dialog box. The options are
* associated with a GUI component by keeping the components in a parrallel
* array. The components are displayed on the left side of the dialog, and
* if the number of options cause the display space required to exceed the
* size of the dialog, a scroll bar becomes available. The dialog will
* check to see if all of the required options have been set before
* closing.
*
* @see AFLPcore.Option
*
* @author James J. Benham
* @version 1.0.0
* @date August 12, 1998
*/
public class OptionDialog extends Dialog implements ActionListener,
WindowListener
{
// GUI Layout constants
private static final int OPTION_WIDTH = 300;
private static final int OPTION_HEIGHT = 25;
private static final int LABEL_WIDTH = 100;
private static final int FIELD_WIDTH = 150;
private static final int HEADER_INSET = 5;
private static final int HEADER_HEIGHT = 22;
private static final int OPTION_INSET = 12;
private static final int OPTION_SPACE = 5;
private static final int BUTTON_WIDTH = 70;
private static final int BUTTON_HEIGHT = 22;
private static final int BUTTON_V_SPACE = 5;
private static final int BUTTON_H_INSET = 5;
private static final int V_INSET = 25;
private static final int SCROLL_V_INSET = 20;
private static final int SCROLL_WIDTH = 16;
private static final int WIDTH = (OPTION_WIDTH + BUTTON_WIDTH +
2*BUTTON_H_INSET);
private static final int HEIGHT = 320;
private Panel optionPane;
private Button okButton;
private Button cancelButton;
private Component optUIComponent[];
private Option opts[];
private int numRequired;
private boolean canceled;
private Frame parentWin;
/**
* Creates a new option dialog with the specified parameters.
*
* @param opts the options to display
* @param parent the owner of this dialog box.
*/
public OptionDialog(Option opts[], Frame parent)
{
this(opts, parent, "");
}
/**
* Creates a new option dialog with the specified parameters
*
* @param opts the options to display
* @param parent the owner of this dialog box.
* @param title the title of the dialog box.
*/
public OptionDialog(Option opts[], Frame parent, String title)
{
// create a modal dialog box
super(parent, title, true);
parentWin = parent;
this.opts = opts;
optUIComponent = new Component[opts.length];
canceled = true;
// See how many are required
numRequired = 0;
for(int i=0; i < opts.length; i++)
{
if(opts[i].isRequired())
numRequired++;
}
layoutOptions();
addWindowListener(this);
}
/**
* Reads the options in from the various components.
*
* @return true
if all of the required options have been
* set, false
otherwise.
*
* @exception NumberFormatException occurs if one of the options which
* is suppossed to be a number is cannot be read as a number.
*/
private boolean readOptions()
{
boolean requiredSet;
String value;
TextField field;
Choice choice;
for(int i=0; i < opts.length; i++) {
switch(opts[i].getType())
{
case Option.NUMBER:
field = (TextField) optUIComponent[i];
value = field.getText();
if(!value.equals("")) {
try {
Double db = new Double(value);
opts[i].setValue(db.doubleValue());
}
catch(NumberFormatException e) {
throw new NumberFormatException(opts[i].getLabel() +
" must be a number!");
}
}
break;
case Option.STRING:
field = (TextField) optUIComponent[i];
value = field.getText();
if(!value.equals(""))
opts[i].setValue(value);
break;
case Option.CHOICE:
choice = (Choice) optUIComponent[i];
// just get the selected one.
opts[i].setValue(choice.getSelectedItem());
break;
}
}
// see if all of the required parameters have been set
requiredSet = true;
for(int i=0; i < opts.length; i++)
requiredSet = requiredSet && (!opts[i].isRequired() ||
opts[i].isSet());
return requiredSet;
}
/**
* Gives the options as they were set by the user in the dialog box.
*
* @return the options for the dialog box.
*/
public Option[] getOptions()
{
return opts;
}
/**
* Tells whether the dialog was canceled or not.
*
* @return true
if the dialog was cancelled.
*/
public boolean isCanceled()
{
return canceled;
}
/**
* Handles the buttons. If ok is clicked, then the options are read.
* if all of the options are set, then it closes the dialog. If not,
* then an error is shown. Cancel simply closes the dialog.
*/
public void actionPerformed(ActionEvent e)
{
try{
if(e.getSource() == okButton)
{
boolean allSet = readOptions();
if(allSet)
{
canceled = false;
dispose();
}
else
{
ErrorDialog eD = new ErrorDialog(parentWin);
eD.showError(new MissingParameterError("All Required optionst " +
" not set."));
}
}
if(e.getSource() == cancelButton)
{
canceled = true;
dispose();
}
} catch(Throwable error) {
ErrorDialog eD = new ErrorDialog(parentWin);
eD.showError(error);
}
}
/**
* Closes the dialog and is equivalent to pressing cancel.
*/
public void windowClosing(WindowEvent e)
{
canceled = true;
dispose();
}
/**
* Adds all of the components to the dialog box.
*/
private void layoutOptions()
{
int x;
int y;
setLayout(null);
setSize(WIDTH, HEIGHT);
setResizable(false);
// find out how long this will be
int length = ((V_INSET - SCROLL_V_INSET) +
opts.length * (OPTION_HEIGHT + OPTION_SPACE));
// add room for the required label
if(numRequired > 0)
length += OPTION_SPACE + HEADER_HEIGHT;
// add room for the optional label
if(opts.length > numRequired)
length += OPTION_SPACE + HEADER_HEIGHT;
// make the scroll pane
ScrollPane scrollArea = new ScrollPane();
add(scrollArea);
scrollArea.setBounds(0, SCROLL_V_INSET, OPTION_WIDTH,
HEIGHT - SCROLL_V_INSET);
// create a panel for the options
optionPane = new Panel();
// subtract the width of a scroll bar, can be found by
// scrollArea.getVScrollbarWidth(), but we must wait around
// for the peer to be created, which it wasn't been at this point.
// It simply returns 0. So, set it as a constant and just go
// with it. It sucks b/c it's system dependent, but it works.
optionPane.setBounds(0, 0,
OPTION_WIDTH - 4 - SCROLL_WIDTH, length);
optionPane.setLayout(null);
// Add the options panel to a scroll pane
scrollArea.add(optionPane);
// ===========add the buttons==========
okButton = new Button("Ok");
add(okButton);
okButton.addActionListener(this);
x = OPTION_WIDTH + BUTTON_H_INSET;
y = V_INSET;
okButton.setBounds(x, y, BUTTON_WIDTH, BUTTON_HEIGHT);
y += BUTTON_HEIGHT + BUTTON_V_SPACE;
cancelButton = new Button("Cancel");
add(cancelButton);
cancelButton.addActionListener(this);
cancelButton.setBounds(x, y, BUTTON_WIDTH, BUTTON_HEIGHT);
//===========draw required label=============
x = 0;
y = V_INSET - SCROLL_V_INSET;
// Optional vs Required Distiction in display removed by Philip DeCamp
// Re-inserted by jbenham Sept 3, 2001
if(numRequired > 0 && numRequired != opts.length) {
Label requiredL = new Label("Required Parameters____________________");
optionPane.add(requiredL);
requiredL.setBounds(HEADER_INSET, y, OPTION_WIDTH - HEADER_INSET,
HEADER_HEIGHT);
y += OPTION_SPACE + HEADER_HEIGHT;
}
//============ add the required options =============
for(int i=0; i < opts.length; i++) {
if(opts[i].isRequired()) {
addOption(opts[i], y, i);
y += OPTION_HEIGHT + OPTION_SPACE;
}
}
//============add the optional label===========
if(opts.length > numRequired) {
Label optionalL;
optionalL = new Label("Optional Parameters____________________");
optionPane.add(optionalL);
optionalL.setBounds(HEADER_INSET, y, OPTION_WIDTH - HEADER_INSET,
HEADER_HEIGHT);
y += OPTION_SPACE + HEADER_HEIGHT;
}
//============ add the optional options =============
for(int i=0; i < opts.length; i++) {
if(!opts[i].isRequired()) {
addOption(opts[i], y, i);
y += OPTION_HEIGHT + OPTION_SPACE;
}
}
// Remove option display code that ignores required vs optional
// jbenham Sept 3, 2001
/*
*for(int i = 0; i < opts.length; i++){
* addOption(opts[i], y, i);
* y+= OPTION_HEIGHT + OPTION_SPACE;
*}
*/
}
/**
* Creates a GUI component for the specified option and places it
* at the specified position. The component is then stored in an
* array at the specified index.
*
* @param option the option to add to the display
* @param pos the vertical position to add it at
* @param index the index into the array of GUI components. This
* is the same as the index of the option in the
* option array.
*/
public void addOption(Option option, int pos, int index)
{
// Add the label
Label label = new Label(option.getLabel() + ":");
optionPane.add(label);
if(option.getType() == Option.LABEL)
label.setBounds(OPTION_INSET, pos, WIDTH, OPTION_HEIGHT);
else
label.setBounds(OPTION_INSET, pos, LABEL_WIDTH, OPTION_HEIGHT);
// Add the component
switch(option.getType())
{
case Option.STRING: // just a text box like the number,
// difference in reading
case Option.NUMBER:
TextField tempField = new TextField();
if(option.getType() == Option.NUMBER){
Double tempInt = new Double(option.getNumValue());
tempField.setText(tempInt.toString());
}
else
tempField.setText(option.getStringValue());
optionPane.add(tempField);
tempField.setBounds(OPTION_INSET + LABEL_WIDTH, pos,
FIELD_WIDTH, OPTION_HEIGHT);
optUIComponent[index] = tempField;
break;
case Option.CHOICE:
Choice tempChoice = new Choice();
// add the choices
String choices[] = option.getChoices();
for(int i=0; i < choices.length; i++)
tempChoice.add(choices[i]);
if(option.getDefaultChoice() != null)
tempChoice.select(option.getDefaultChoice());
optionPane.add(tempChoice);
tempChoice.setBounds(OPTION_INSET + LABEL_WIDTH, pos,
FIELD_WIDTH, OPTION_HEIGHT);
optUIComponent[index] = tempChoice;
break;
}
}
// ==================Unused methods required by interfaces=================
/**Unused*/ public void windowOpened(WindowEvent e) {}
/**Unused*/ public void windowClosed(WindowEvent e) {}
/**Unused*/ public void windowIconified(WindowEvent e) {}
/**Unused*/ public void windowDeiconified(WindowEvent e) {}
/**Unused*/ public void windowActivated(WindowEvent e) {}
/**Unused*/ public void windowDeactivated(WindowEvent e) {}
}