//=====================================================================
// File: CutoffDialog.java
// Class: CutoffDialog
// Package: AFLPgui
//
// Author: James J. Benham
// Date: August 11, 1998
// Contact: james_benham@hmc.edu
//
// Genographer v1.0 - Computer assisted scoring of gels.
// 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.Dialog;
import java.awt.Frame;
import java.awt.Label;
import java.awt.List;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import AFLPcore.Cutoff;
import AFLPcore.CutoffFunction;
import AFLPcore.DataList;
import AFLPcore.FeatureList;
import AFLPcore.Lane;
import AFLPcore.Option;
import AFLPcore.ProgOptions;
/**
* This dialog box will display a cutoff. All of the levels of the cutoff
* are displayed in a list. Any element of the list can be selected, and
* the height of that element can be modified. Additionally, new elements,
* cutoff functions, can be added to the list as well as deleted. The
* dialog box will save the cutoff to a list of lanes when the "Ok" button
* is clicked.
*
* @see Cutoff
* @see CutoffFunction
*
* @author James J. Benham
* @version 1.0.0
* @date August 11, 1998
*/
public class CutoffDialog extends Dialog implements ActionListener,
ItemListener,
KeyListener,
WindowListener
{
private static final String HELP_FILE = "cutoffhelp.html";
private static int WIDTH = 444;
private static int HEIGHT = 240;
// List box parameters
private static int LIST_H_INSET = 10;
private static int LIST_V_INSET = 30;
private static int LIST_WIDTH = 90;
private static int LIST_HEIGHT = 200;
// Field parameters
private static int V_SPACE = 10;
private static int H_SPACE = 4;
private static int COMP_HEIGHT = 25;
private static int COMP_H_INSET = 110;
private static int LABEL_WIDTH = 80;
private static int FIELD_WIDTH = 80;
// Button parameters
private static int BUTTON_WIDTH = 80;
private static int ENTER_WIDTH = 120;
private static int SCORE_WIDTH = 110;
private static int BUTTON_H_INSET = 354;
private Button okButton;
private Button cancelButton;
private Button newButton;
private Button deleteButton;
private Button defaultButton;
private Button helpButton;
private Button enterButton;
private List cutoffList;
private TextField heightField;
private Cutoff currentCutoff;
private DataList lanes;
private int index;
private double size;
private Frame parent;
/**
* Create a new CutoffDialog with the specified parameters.
*
* @param parent the owner of this dialog box
* @param title the title of the dialog box
* @param modal if true, dialog blocks input to the parent window
* when shown
*/
public CutoffDialog(Frame parent, String title, boolean modal)
{
super(parent, title, modal);
this.parent = parent;
index = -1;
addWindowListener(this);
componentLayout();
loadSelection(index);
}
/**
* Initializes the CutoffDialog with important information. This
* should be called before displaying the dialog box.
*
* @param ct the cutoff to display. The levels of the cutoff will
* appear in the list.
* @param lanes the lanes to add the cutoff to when the "Ok" button
* is clicked.
* @param startPos the size in bp where the cutoff should first be
* defined. The cutoff will apply to the lane from
* the start position to the beginning of the next
* cutoff or until the end of the lane.
*/
public void init(Cutoff ct, DataList lanes, double startPos)
{
currentCutoff = (Cutoff) ct.clone();
this.lanes = lanes;
size = startPos;
// refresh the display
CutoffFunction ctfn;
cutoffList.setVisible(false);
cutoffList.removeAll();
for(int i=0; i < currentCutoff.getNumLevels(); i++)
{
ctfn = currentCutoff.getCutoffFunction(i);
cutoffList.add("" + ctfn.getCutoff(size));
}
cutoffList.setVisible(true);
}
/**
* Loads the selected function when something in the list is changed.
*/
public void itemStateChanged(ItemEvent e)
{
if(e.getSource() == cutoffList)
{
// get the selected item
index = cutoffList.getSelectedIndex();
loadSelection(index);
}
}
/**
* Handles the events generated by the buttons.
*/
public void actionPerformed(ActionEvent e)
{
try{
if(e.getSource() == okButton)
{
saveToLanes(); // save the info;
dispose();
setVisible(false);
}
else if(e.getSource() == enterButton)
{
storeInfo(index);
}
else if(e.getSource() == cancelButton)
{
dispose();
setVisible(false);
}
else if(e.getSource() == newButton)
{
index = -1;
cutoffList.select(index);
loadSelection(index);
}
else if(e.getSource() == deleteButton)
{
if(index != -1)
{
cutoffList.remove(index);
currentCutoff.deleteFunction(index);
index = -1;
loadSelection(index);
}
}
else if(e.getSource() == defaultButton)
{
cutoffList.removeAll();
currentCutoff = new Cutoff(size, 1);
CutoffFunction ctfn;
ctfn = (CutoffFunction) FeatureList.getCutoffMgr().getDefault();
ctfn = (CutoffFunction) ctfn.clone();
Option opts[] = ctfn.getOptions();
opts[0].setValue(1000);
ctfn.setOptions(opts);
currentCutoff.setCutoffFunction(ctfn, 0);
cutoffList.add("1000.0");
index = -1;
loadSelection(index);
}
else if(e.getSource() == helpButton)
{
ProgOptions.showHelp(HELP_FILE);
}
}
catch(Throwable error)
{
ErrorDialog eD = new ErrorDialog((Frame) getParent());
eD.showError(error);
}
}
/**
* Used to store the info when enter is pressed in the text field.
*/
public void keyReleased(KeyEvent e)
{
// Assume that a release of the enter key constitutes the typing
// of the enter key. It is very unlikely that it got pushed down
// somewhere else and released here.
// Only one text field is sending events
if (e.getKeyCode() == KeyEvent.VK_ENTER)
storeInfo(index);
}
/**
* Closes the dialog box. This has the same affect as pressing the cancel
* button.
*/
public void windowClosing(WindowEvent e)
{
dispose();
setVisible(false);
}
/**
* Loads the specified cutoff function into the display. In other words,
* it loads the value into the height text field. If the index
* is -1, then a blank display is loaded.
*
* @param index the level of the desired cutoff to load.
*/
private void loadSelection(int index)
{
if(index != -1)
{
CutoffFunction ctFn = currentCutoff.getCutoffFunction(index);
// update the displays
heightField.setText("" + ctFn.getCutoff(size));
}
else
{
heightField.setText("");
}
}
/**
* Reads in the height from the text field and stores it into the
* cutoff. If the index
is -1, then a new level will
* be created and added to the cutoff.
*
* @param index the level of the current cutoff function, -1 for a
* new function
*
* @exception NumberFormatException occurs if the method cannot read
* a number from the text field.
*/
public void storeInfo(int index) throws NumberFormatException
{
double height = 0;
try{
height = (new Double(heightField.getText())).doubleValue();
}
catch(NumberFormatException e)
{
throw new NumberFormatException("Height must be a number.");
}
CutoffFunction ctfn;
Option opts[];
if(index != -1)
{
// simply modifiy the current function and update the name in the list
ctfn = currentCutoff.getCutoffFunction(index);
// get the options and use that to set the height
opts = ctfn.getOptions();
// set the first one, which should be the height and store it back
opts[0].setValue(height);
ctfn.setOptions(opts);
cutoffList.replaceItem("" + ctfn.getCutoff(size), index);
}
else
{
// We have a new function, so it must be created and then added to the
// list. Find the location of the function and insert it there in the
// screen list
ctfn = (CutoffFunction) FeatureList.getCutoffMgr().getDefault();
ctfn = (CutoffFunction) ctfn.clone();
// get the options and use that to set the height
opts = ctfn.getOptions();
// set the first one, which should be the height and store it back
opts[0].setValue(height);
ctfn.setOptions(opts);
// add the function
currentCutoff.addFunction(ctfn);
// refresh the display
cutoffList.setVisible(false);
cutoffList.removeAll();
for(int i=0; i < currentCutoff.getNumLevels(); i++)
{
ctfn = currentCutoff.getCutoffFunction(i);
cutoffList.add("" + ctfn.getCutoff(size));
}
cutoffList.setVisible(true);
}
}
/**
* Shows or hides this dialog box. When it is shown, it will load
* a blank selection.
*
* @param b true
to show the component.
*/
public void setVisible(boolean b)
{
super.setVisible(b);
if(b)
{
// show blank fields and no selection
index = -1;
loadSelection(index);
}
}
/**
* Takes the cutoff currently defined by this class and adds it to
* all of the lanes specified in init
. The cutoff is
* added at the point specified in init
. If a cutoff
* already exists at that location, it is replaced. If not, then
* the cutoff is simply inserted there.
*
* @see CutoffDialog#init
*/
private void saveToLanes()
{
Lane ln;
Cutoff ctff = null;
for(int i = 0; i < lanes.size(); i++)
{
ln = (Lane) lanes.dataAt(i);
ctff = ln.cutoffUnder(size);
// see if we need to create a new cutoff function for this region.
if(ctff.getStartPos() < size)
{
ln.addCutoff((Cutoff) currentCutoff.clone());
}
else
{
// we have to replace the one there, it's easiest.
DataList ctList = ln.getCutoffs();
int location = ctList.find(ctff.getStartPos()).location;
ctList.removeElementAt(location);
ln.addCutoff((Cutoff) currentCutoff.clone());
}
}
}
/**
* Adds all of the components to the dialog box and adds the
* appropriate listeners.
*/
private void componentLayout()
{
int startY = 0;
setLayout(null);
setSize(WIDTH, HEIGHT);
setResizable(false);
//====================Add the list==================
cutoffList = new List();
add(cutoffList);
cutoffList.setBounds(LIST_H_INSET, LIST_V_INSET, LIST_WIDTH, LIST_HEIGHT);
cutoffList.addItemListener(this);
startY += LIST_V_INSET;
//===================Add height stuff==================
Label heightL = new Label("Height:", Label.LEFT);
heightField = new TextField();
add(heightL);
add(heightField);
heightL.setBounds(COMP_H_INSET, startY, LABEL_WIDTH, COMP_HEIGHT);
heightField.setBounds(COMP_H_INSET + H_SPACE + LABEL_WIDTH, startY,
FIELD_WIDTH, COMP_HEIGHT);
heightField.addKeyListener(this);
startY += V_SPACE + COMP_HEIGHT;
//====================Add buttons======================
enterButton = new Button("Enter Changes");
add(enterButton);
enterButton.setBounds(COMP_H_INSET, startY, ENTER_WIDTH, COMP_HEIGHT);
enterButton.addActionListener(this);
startY = LIST_V_INSET;
okButton = new Button("Ok");
add(okButton);
okButton.setBounds(BUTTON_H_INSET, startY, BUTTON_WIDTH, COMP_HEIGHT);
okButton.addActionListener(this);
startY += V_SPACE + COMP_HEIGHT;
cancelButton = new Button("Cancel");
add(cancelButton);
cancelButton.setBounds(BUTTON_H_INSET, startY, BUTTON_WIDTH, COMP_HEIGHT);
cancelButton.addActionListener(this);
startY += V_SPACE + COMP_HEIGHT;
newButton = new Button("New");
add(newButton);
newButton.setBounds(BUTTON_H_INSET, startY, BUTTON_WIDTH, COMP_HEIGHT);
newButton.addActionListener(this);
startY += V_SPACE + COMP_HEIGHT;
deleteButton = new Button("Delete");
add(deleteButton);
deleteButton.setBounds(BUTTON_H_INSET, startY, BUTTON_WIDTH, COMP_HEIGHT);
deleteButton.addActionListener(this);
startY += V_SPACE + COMP_HEIGHT;
defaultButton = new Button("Default");
add(defaultButton);
defaultButton.setBounds(BUTTON_H_INSET, startY, BUTTON_WIDTH, COMP_HEIGHT);
defaultButton.addActionListener(this);
startY += V_SPACE + COMP_HEIGHT;
helpButton = new Button("Help");
add(helpButton);
helpButton.setBounds(BUTTON_H_INSET, startY, BUTTON_WIDTH, COMP_HEIGHT);
helpButton.addActionListener(this);
startY += V_SPACE + COMP_HEIGHT;
}
// ==================Unused methods required by interfaces=================
/**Unused*/public void keyPressed(KeyEvent e) {}
/**Unused*/public void keyTyped(KeyEvent e) {}
/**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) {}
}