//===================================================================== // File: FragmentMap.java // Class: FragmentMap // Package: AFLPgui // // Author: James J. Benham // Date: December 5, 2000 // Contact: james_benham@hmc.edu // // Genographer v1.4 - 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.BorderLayout; import java.awt.Button; import java.awt.Color; import java.awt.Dimension; import java.awt.FileDialog; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Label; import java.awt.Menu; import java.awt.MenuBar; import java.awt.MenuItem; import java.awt.Panel; import java.awt.PrintJob; import java.awt.ScrollPane; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import AFLPcore.Bin; import AFLPcore.BinOperation; import AFLPcore.Cutoff; import AFLPcore.CutoffFunction; import AFLPcore.DataList; import AFLPcore.FeatureList; import AFLPcore.ImportFilter; import AFLPcore.Gel; import AFLPcore.GelOperation; import AFLPcore.Lane; import AFLPcore.LaneOperation; import AFLPcore.Manager; import AFLPcore.Option; import AFLPcore.ProgOptions; /** * This is the main GenoGrapher program window. It displays all of the * data and manages the classes. It takes care of all of the menu items * and switches between different data view. It can display the data as * a standard gel image, as a set of thumbnails for the current bin, * a graph of the bin, a trace, or as text analysis. These view are * actually created in seperate classes. Each of these views has it's own * button bar and info bar, but this class picks which one to display. * *

It also handles the printing of the views as well as saving, opening, * importing, and exporting files. Most of the views do a lot of work in * their respective classes, but this one manages them all. * * @author James J. Benham * @version 1.6.0 * @date September 3, 2001 */ public class FragmentMap extends Frame implements ActionListener, WindowListener { private static final String HELP_FILE = "help.html"; private final String ICON = "geno.gif"; public static final int GEL = 0; public static final int THUMBNAIL = 1; public static final int GRAPH = 2; public static final int TRACE = 3; public static final int ANALYSIS = 4; // Constants for the printer private static final int PAGE_H_ADJUST = 36; private static final int PAGE_V_ADJUST = 33; private static final int PAGE_HEADER_SPACE = 20; protected static int BAR_HEIGHT = 22; // Menu Items protected MenuItem newItem; protected MenuItem openItem; protected MenuItem saveItem; protected MenuItem saveAsItem; protected MenuItem importItem; protected MenuItem exportItem; protected MenuItem printItem; protected MenuItem exitItem; protected MenuItem laneDeleteItem; protected MenuItem laneOpItem[]; protected MenuItem binRedrawItem; protected MenuItem binOpItem[]; protected MenuItem gelRedrawItem; protected MenuItem gelOpItem[]; protected MenuItem viewGelItem; protected MenuItem viewThumbnailItem; protected MenuItem viewGraphItem; protected MenuItem viewTraceItem; protected MenuItem viewAnalysisItem; protected MenuItem helpItem; protected MenuItem aboutItem; // Buttons on button bar protected Button newButton; protected Button openButton; protected Button saveButton; protected Button printButton; // Program variables protected Gel gel; protected GelView gelView; protected Thumbnail thumbnail; protected GraphView graph; protected TraceView trace; protected AnalysisView analysis; protected ScrollPane mainPanel; protected ButtonBar buttonBar; protected Bar infoBar; protected Bar statusBar; protected Panel bottomP; protected Label statusLabel; protected double defaultCutoff; protected int currentView; // the type of thing currently displayed. protected Bin currentBin; // The bin that is selected or viewed // Dialogs protected MultiFileDialog importDialog; protected FileDialog fileDialog; protected ErrorDialog errorDialog; // File management variables protected String currentFile; protected String currentDir; protected boolean modified; /** * Create a new FragmentMap. This is the main program window. */ public FragmentMap() { this(null); } /** * Create a new FragmentMap. This is the main program window. * * @param command line parameters. The only value accepted is * the path for the program files. It should be * the same as the startup directory. */ public FragmentMap(String argv[]) { setTitle("GenoGrapher"); gel = new Gel(); setLayout(new BorderLayout(0, 0)); setBackground(Color.white); setSize(638, 440); setIconImage(getToolkit().getImage(ICON)); File homePath; boolean goodValue = false;; if((argv != null) && (argv.length >= 1)) { homePath = new File(argv[0]); goodValue = homePath.exists(); if(!goodValue) { System.err.println("Bad command line parameter for home path."); } else { // Added by B. Master 10/25/2000 ProgOptions.homePath = homePath.getAbsolutePath(); System.out.println("Genographer path set to: " + ProgOptions.homePath); } } // Path wasn't an argument, so try looking at the current directory. // Also, path could have been bad. if(!goodValue) { // Set some of the options. homePath = new File("."); String tempSt = homePath.getAbsolutePath(); if(tempSt.endsWith(".")) tempSt = tempSt.substring(0, tempSt.length() - 1); ProgOptions.homePath = tempSt; } // Make sure we have a trailing path seperator if(! ProgOptions.homePath.endsWith(File.separator)) ProgOptions.homePath += File.separator; ProgOptions.readOptions(); // Create Components gelView = new GelView(gel, this); thumbnail = new Thumbnail(gel.getLanes(), gel.getBins(), this); graph = new GraphView(gel.getLanes(), gel.getBins(), this); trace = new TraceView(this); analysis = new AnalysisView(this); buttonBar = gelView.getButtonBar(); infoBar = gelView.getInfoBar(); statusBar = new Bar(); defaultCutoff = 0; // Make a panel for the bottom. bottomP = new Panel(); programInitialize(); currentBin = null; switchTo("Gel"); // Create the file import dialog importDialog = new MultiFileDialog(this, "Import"); fileDialog = new FileDialog(this); errorDialog = new ErrorDialog(this); // create the help file. try{ FeatureList.generateFileList(); } catch(IOException e) { errorDialog.showError(e); } currentFile = null; addWindowListener(this); } /** * Change the program display so that it displays the type specified. * Possible values are: "Gel" "Thumbnail" "Graph" "Trace" and "Analysis". * This will handle switching the button bars as well as the main window. * * @param value the view to switch the display to. */ public void switchTo(String value) { // Retrieve the currently selected bin before we switch switch(currentView) { case GEL: currentBin = gelView.getCurrentBin(); break; case THUMBNAIL: currentBin = thumbnail.getBin(); break; case GRAPH: currentBin = graph.getBin(); break; } if(value.equals("Gel")) showGelImage(); else if(value.equals("Thumbnail")) showThumbnail(); else if(value.equals("Graph")) showGraph(); else if(value.equals("Trace")) showTrace(); else if(value.equals("Analysis")) showAnalysis(); // get the buttons on the button bar that we need to handle // button bar is set appropriately by the above newButton = buttonBar.getNewButton(); openButton = buttonBar.getOpenButton(); saveButton = buttonBar.getSaveButton(); printButton = buttonBar.getPrintButton(); } /** * Display the gel image. This method will set the main display as * well as the button bar and info bar to the correct objects. */ private void showGelImage() { currentView = GEL; gelView.setCurrentBin(currentBin); mainPanel.removeAll(); mainPanel.add(gelView); remove(buttonBar); buttonBar = gelView.getButtonBar(); add(buttonBar, "North"); bottomP.remove(infoBar); infoBar = gelView.getInfoBar(); bottomP.add(infoBar, "North"); gelView.syncDisplay(); validate(); } /** * Displays the thumbnails for the currently selected bin. It also * sets the bars to the appropriate values and initializes the * thumbnail class by giveing it either the selected lanes, or if there * are no selected lanes, all of the lanes. It also sets the range * to match that of the current bin and tells the thumbnail which bin * to use. */ private void showThumbnail() { currentView = THUMBNAIL; // set the bin thumbnail.setBin(currentBin); // and a list of all the bins so it can switch if neccessary thumbnail.setBinList(gel.getBins()); if(gel.getSelectedLanes().isEmpty()) thumbnail.setLanes(gel.getLanes()); else thumbnail.setLanes(gel.getSelectedLanes()); thumbnail.init(); mainPanel.removeAll(); mainPanel.add(thumbnail); remove(buttonBar); buttonBar = thumbnail.getButtonBar(); add(buttonBar, "North"); bottomP.remove(infoBar); infoBar = thumbnail.getInfoBar(); bottomP.add(infoBar, "North"); validate(); } /** * Displays the graph of the current bin. It is initialized using * the current bin and either the selected lanes or all the lanes if * none are selected. The correct bars are selected also. */ private void showGraph() { currentView = GRAPH; // initialize it with the current bin, and all the bins and lanes if(gel.getSelectedLanes().isEmpty()) graph.init(currentBin, gel.getLanes(), gel.getBins()); else graph.init(currentBin, gel.getSelectedLanes(), gel.getBins()); mainPanel.removeAll(); mainPanel.add(graph); remove(buttonBar); buttonBar = graph.getButtonBar(); add(buttonBar, "North"); bottomP.remove(infoBar); infoBar = graph.getInfoBar(); bottomP.add(infoBar, "North"); validate(); } /** * Displays the lane trace, setting the bars to the appropriate value. * The trace displays either the first selected lane, or if there are * no selected lanes, the first lane in the gel. */ private void showTrace() { currentView = TRACE; // Pick a lane. Try the first one from the selected lanes first, // then take the first lane, null if no lanes. if(gel.getSelectedLanes().isEmpty()) { //try all lanes. if(gel.getLanes().isEmpty()) trace.init(null, gel.getLanes()); else trace.init((Lane) gel.getLanes().dataAt(0), gel.getLanes()); } else trace.init((Lane) gel.getSelectedLanes().dataAt(0), gel.getSelectedLanes()); mainPanel.removeAll(); mainPanel.add(trace); remove(buttonBar); buttonBar = trace.getButtonBar(); add(buttonBar, "North"); bottomP.remove(infoBar); infoBar = trace.getInfoBar(); bottomP.add(infoBar, "North"); validate(); } /** * Displays the analysis output, with the correct bars. The analysis * view is initialized with the current gel */ private void showAnalysis() { currentView = ANALYSIS; analysis.init(gel); mainPanel.removeAll(); mainPanel.add(analysis); mainPanel.setScrollPosition(0, 0); remove(buttonBar); buttonBar = analysis.getButtonBar(); add(buttonBar, "North"); bottomP.remove(infoBar); infoBar = analysis.getInfoBar(); bottomP.add(infoBar, "North"); validate(); } /** * Reads the specified files in to the gel. The import filter is * retrieved from the dialog used to select the files. Any options * for the filter are presented in an options dialog. * * @param files the list of files to import. */ private void importFiles(File files[]) { ImportFilter filter = importDialog.getFilter(); statusLabel.setText("Importing using " + filter.getName()); // Show the options OptionDialog optDialog = new OptionDialog(filter.getOptions(), this, filter.getName()+" Parameters"); optDialog.setVisible(true); if(!optDialog.isCanceled()) { Option[] opts = optDialog.getOptions(); filter.setOptions(opts); // Conveted from lane to lane[] by Philip DeCamp 6/25/2001 Lane [] ln = null; for(int i=0; i < files.length; i++) { try{ // read in the lane ln = filter.readLane(files[i]); // add it to the gel // Begin --Added 6/25/2001 by Philip DeCamp for(int j = 0; j < ln.length; j++) if(ln[j] != null){ gel.addLane(ln[j]); setCutoff(ln[j]); } // End --Added 6/25/2001 by Philip DeCamp statusLabel.setText(filter.getName() + ": Imported " + ln[0].getName() + " from " + files[i].getAbsolutePath() + " (" + (i+1) + " of " + files.length + " files)"); } catch(IOException ioE){ if(ioE instanceof FileNotFoundException) errorDialog.showError(ioE); else { errorDialog.showError(new IOException("Error on import. " + ioE.getMessage())); } } } // adjust the intensity gel.setIntensity(gel.getGlobalMaxIntensity()); // see if the size has been set, if not base the sizes off lane 0 if(!gelView.isSizeSet()) gelView.setGelSizeToMax(0); statusLabel.setText("Import Complete. Rebuilding gel image..."); gelView.refresh(true); } // if(!optDialog.isCanceled()) statusLabel.setText("Ready."); } /** * Reads the specified file in to the program. The file should be the * result of writing out a gel. This is the format used by the program. * This is the result of an open operation. * * @param fileName the name of a gel file written by the program. * * @see AFLPcore.Gel#read * @see FragmentMap#writeFile */ public void readFile(String fileName) { try { statusLabel.setText("Reading " + fileName); FileInputStream fs = new FileInputStream(fileName); BufferedInputStream bs = new BufferedInputStream(fs); DataInputStream inStream = new DataInputStream(bs); gel.read(inStream); inStream.close(); fs.close(); statusLabel.setText("Read completed. Building gel image..."); // rebuild the gel image gelView.refresh(true); showGelImage(); statusLabel.setText("Ready."); } catch(IOException e) { statusLabel.setText("Read failed. Ready"); errorDialog.showError(new IOException("Error while reading in file " + fileName + "." + e.getMessage())); } } /** * Writes the gel out to the specified file name. This will write all of * the information in the program session. In other words, it saves the * session. The file can be restored with the readFile * method. * * @param fileName the name of the file to write to. * * @see AFLPcore.Gel#write * @see FragmentMap#readFile */ public void writeFile(String fileName) { try { statusLabel.setText("Writing " + fileName); FileOutputStream fs = new FileOutputStream(fileName); BufferedOutputStream bs = new BufferedOutputStream(fs); DataOutputStream outStream = new DataOutputStream(bs); gel.write(outStream); outStream.close(); fs.close(); statusLabel.setText("Gel saved as " + fileName + ". Ready."); } catch (IOException e) { statusLabel.setText("Write failed! Ready."); errorDialog.showError(new IOException("Couldn't write file." + e.getMessage())); } } /** * Sets the inital cutoff level for the specified lane. The inital cutoff * is set to 50% of the max value in the lane, and has only one level. * The default cutoff function, defined by FeatureList is * used. * * @param ln the lane to set the cutoff for. */ private void setCutoff(Lane ln) { // Set some cutoffs initially: 1 level, start at beginning, 50% of max // in lane. Cutoff ct = new Cutoff(ln.getMinSize(), 1); // Retrieve the default and then clone it so this lane gets it's own // cutoff function. CutoffFunction ctfn; ctfn = (CutoffFunction) FeatureList.getCutoffMgr().getDefault(); ctfn = (CutoffFunction) ctfn.clone(); if(defaultCutoff == 0) defaultCutoff = 0.5*ln.getMaxHeight(ln.getMinSize(), ln.getMaxSize()); Option[] opts = ctfn.getOptions(); opts[0].setValue(defaultCutoff); ctfn.setOptions(opts); ct.setCutoffFunction(ctfn, 0); ln.addCutoff(ct); } /** * Prompts the user for a name for a file to be saved, by presenting * a file dialog box. */ private void saveFileAs() { String oldFile = currentFile; String oldDir = currentDir; { fileDialog.setTitle("Save file..."); fileDialog.setMode(FileDialog.SAVE); if(currentFile == null) fileDialog.setFile(""); else fileDialog.setFile(currentFile); fileDialog.show(); currentFile = fileDialog.getFile(); currentDir = fileDialog.getDirectory(); } if(currentFile != null) { writeFile(currentDir + currentFile); statusLabel.setText("Saved " + currentDir + currentFile); } else { // Canceled, so set things back to the way they were currentFile = oldFile; currentDir = oldDir; } } /** * Prints the specified data to the printer. The user selects * the printer using the system dependent print dialog, or equivalent. * If the gel is specified, then it will be printed. Or the thumbnails * could be printed. The data is specified by comparing the specified value * to constants in this class. Note: The gel does not seem to print * well at all. It seems to print in black and white, instead of grey * scale. The others seem to print fine. * * @param displayType corresponds to one of the constants declared in this * class: GEL, THUMBNAIL, * GRAPH, TRACE, or * ANALYSIS. */ private void print(int displayType) { // Get the neccessary system resources Toolkit tk = Toolkit.getDefaultToolkit(); PrintJob pJob = tk.getPrintJob(this, "AFLP print stuff", null); if(pJob != null) { Graphics g = pJob.getGraphics(); Dimension d = pJob.getPageDimension(); int width = d.width - PAGE_H_ADJUST; int height = d.height - PAGE_V_ADJUST - PAGE_HEADER_SPACE; // Set the font for the graphics g.setFont(new Font("SansSerif", Font.PLAIN, 10)); int oldWidth; int oldHeight; int gWidth; int oldBorder; int oldSpace; String name; Bin bin; switch(displayType) { case GEL: oldBorder = gel.getGelTopBorder(); oldWidth = gel.getLaneWidth(); oldSpace = gel.getLaneBorder(); // create the percent of the gel that the lane width occupies, // as compared to that occupied by the lane borders. double lanePercentage = 3.0/4.0; gel.setLaneWidth((int)(width/gel.getNumLanes()*lanePercentage)); gel.setLaneBorder((int) (width/gel.getNumLanes() * (1 - lanePercentage))); GelView pageView = new GelView(gel, this); pageView.setGelLength(height); // create a little frame for the view, just to make it work. Frame tempFrame = new Frame("Print renderer"); tempFrame.setLayout(null); tempFrame.setBounds(0, 0, 1, 1); tempFrame.add(pageView); tempFrame.setVisible(true); pageView.paint(g); tempFrame.setVisible(false); gel.setLaneWidth(oldWidth); gel.setLaneBorder(oldSpace); break; case THUMBNAIL: // figure out how many pages we need. DataList lanes = thumbnail.getLanes(); int thumbWidth = thumbnail.getThumbnailSize().width; int thumbHeight = thumbnail.getThumbnailSize().height; int numThumbnails = lanes.size(); int numPerRow = width/thumbWidth; int numPerColumn = height/thumbHeight; int numPerPage = numPerRow * numPerColumn; if(numPerPage < 1) { throw new IllegalArgumentException("Thumbnail won't fit on" + " a page!"); // return; not reached } // draw some header info bin = thumbnail.getBin(); name = bin.getName(); if(!name.equals("")) name = name + ": "; g.drawString(name + bin.getLocation() + "+/-" + bin.getRange() + " " + bin.getScoreInfo()[0], 0, height + PAGE_HEADER_SPACE); thumbnail.setViewWidth(width); if(numPerPage >= numThumbnails) { thumbnail.print(g); } else { int firstLane = 0; DataList tempLanes; while(firstLane < numThumbnails) { tempLanes = new DataList(); for(int i=firstLane; i < (firstLane + numPerPage); i++) tempLanes.addData(lanes.dataAt(i)); thumbnail.setLanes(tempLanes); thumbnail.print(g); // get the next page g.dispose(); g = pJob.getGraphics(); firstLane += numPerPage; } thumbnail.setLanes(lanes); } break; case GRAPH: bin = graph.getBin(); oldWidth = graph.getWidth(); oldHeight= graph.getHeight(); gWidth = graph.getGraphWidth(); graph.setWidth(width); graph.setHeight(height); graph.setGraphWidth(width - 20); graph.paint(g); graph.setWidth(oldWidth); graph.setHeight(oldHeight); graph.setGraphWidth(gWidth); name = bin.getName(); if(!name.equals("")) name = name + ": "; g.drawString(name + bin.getLocation() + "+/-" + bin.getRange() + " " + bin.getScoreInfo()[0], 0, height + PAGE_HEADER_SPACE); break; case TRACE: oldWidth = trace.getWidth(); oldHeight = trace.getHeight(); trace.setWidth(width); trace.setHeight(height); trace.print(g); trace.setWidth(oldWidth); trace.setHeight(oldHeight); break; case ANALYSIS: TextPrinter textP = new TextPrinter(pJob); textP.printString(analysis.getText(), g); break; } g.dispose(); pJob.end(); statusLabel.setText("Done Printing. Ready."); } } /** * This will export the specified data view out to a file. A dialog * box will be presented to allow the user to select a file name. * Only the gel and analysis currently support exporting. The gel is * exported as a PNG file, which can be read by several graphics programs. * The analysis is exported as a simple text file. * * @param view corresponds to one of the constants declared in this * class: GEL, THUMBNAIL, * GRAPH, TRACE, or * ANALYSIS. Only GEL and * ANALYSIS are currently supported. */ public void exportView(int view) { String exportFile; String exportDir; String oldDir = currentDir; { fileDialog.setTitle("Export file..."); fileDialog.setMode(FileDialog.SAVE); fileDialog.setFile(""); fileDialog.show(); exportFile = fileDialog.getFile(); exportDir = fileDialog.getDirectory(); } if(exportFile == null) { // Canceled, so set things back to the way they were currentDir = oldDir; } else { try { FileOutputStream fs; BufferedOutputStream bs; switch(view) { case GEL: // Check the file extension. int nameLength = exportFile.length(); if(nameLength < 4) { exportFile += ".png"; } else { String temp = exportFile.substring(nameLength - 4); if(!temp.equalsIgnoreCase(".png")) { exportFile += ".png"; } } fs = new FileOutputStream(exportDir + exportFile); bs = new BufferedOutputStream(fs); DataOutputStream outStream = new DataOutputStream(bs); gel.writePNG(outStream); outStream.close(); statusLabel.setText("Exported gel to " + exportDir + exportFile + ". Ready."); bs.close(); fs.close(); break; case ANALYSIS: fs = new FileOutputStream(exportDir + exportFile); bs = new BufferedOutputStream(fs); byte output[] = analysis.getText().getBytes(); bs.write(output, 0, output.length); bs.flush(); statusLabel.setText("Exported analysis to " + exportDir + exportFile + ". Ready."); bs.close(); fs.close(); break; default: statusLabel.setText("Exporting this type is not " + "supported. Ready."); } } catch (IOException except) { errorDialog.showError(new IOException("Couldn't write file." + except.getMessage())); } } } /** * Displays an about dialog box for the program. */ protected void showAbout() { AboutDialog aboutD = new AboutDialog(this, "About Genographer"); aboutD.show(); } /** * Handles the events from buttons and menu items. */ public void actionPerformed(ActionEvent e) { try{ if((e.getSource() == openItem) || (e.getSource() == openButton)) { fileDialog.setTitle("Open file..."); fileDialog.setMode(FileDialog.LOAD); fileDialog.setDirectory(currentDir); fileDialog.setFile(""); fileDialog.show(); currentFile = fileDialog.getFile(); currentDir = fileDialog.getDirectory(); if(currentFile != null) { readFile(currentDir + currentFile); } } else if((e.getSource() == saveItem) || (e.getSource() == saveButton)) { if(currentFile == null) saveFileAs(); else { writeFile(currentDir + currentFile); } } else if(e.getSource() == saveAsItem) { saveFileAs(); } else if(e.getSource() == importItem) { importDialog.setVisible(true); File files[] = importDialog.getFiles(); if(files != null) importFiles(files); } else if((e.getSource() == newItem) || (e.getSource() == newButton)) { gel = new Gel(); gelView = new GelView(gel, this); switchTo("Gel"); } else if((e.getSource() == printItem) || (e.getSource() == printButton)) { print(currentView); } else if(e.getSource() == exportItem) { exportView(currentView); } else if(e.getSource() == exitItem) { endProgram(); } else if(e.getSource() == viewGelItem) { switchTo("Gel"); } else if(e.getSource() == viewThumbnailItem) { switchTo("Thumbnail"); } else if(e.getSource() == viewGraphItem) { switchTo("Graph"); } else if(e.getSource() == viewTraceItem) { switchTo("Trace"); } else if(e.getSource() == viewAnalysisItem) { switchTo("Analysis"); } else if(e.getSource() == gelRedrawItem) { if(currentView == GEL) gelView.refresh(true); } else if(e.getSource() == binRedrawItem) { switch(currentView) { case THUMBNAIL: thumbnail.refresh(); break; case GRAPH: graph.refresh(); break; } } else if(e.getSource() == helpItem) { ProgOptions.showHelp(HELP_FILE); } else if(e.getSource() == aboutItem) { showAbout(); } else if(e.getSource() == laneDeleteItem) { DataList lanesToDelete = gel.getSelectedLanes(); // Change it into an array if(!lanesToDelete.isEmpty()) { // this will give us the list, since once we start deleting, // the list pointed to by lanesToDelete will start to change // to. Lane toDelete[] = new Lane[lanesToDelete.size()]; for(int i=0; i < toDelete.length; i++) toDelete[i] = (Lane) lanesToDelete.dataAt(i); for(int i=0; i < toDelete.length; i++) gel.removeLane(toDelete[i]); } // update the display gelView.refresh(true); } else { // Handle events from the operations String opName; opName = getName(laneOpItem, e); if(opName != null) { // lane operation LaneOperation laneOp; laneOp = (LaneOperation) FeatureList.getLaneOpMgr().get(opName); // see if we should use selected lanes or not. if(gel.getSelectedLanes().isEmpty()) laneOp.doLaneOp(gel.getLanes()); else laneOp.doLaneOp(gel.getLanes()); } opName = getName(binOpItem, e); if(opName != null) { // bin operation BinOperation binOp; binOp = (BinOperation) FeatureList.getBinOpMgr().get(opName); if(binOp.isMultiBin()) binOp.doBinOp(gel.getBins()); else { if(gelView.getCurrentBin() != null) binOp.doBinOp(gelView.getCurrentBin()); } } opName = getName(gelOpItem, e); if(opName != null) { // gel operation GelOperation gelOp; gelOp = (GelOperation) FeatureList.getGelOpMgr().get(opName); if(gel != null) gelOp.doGelOp(gel); } } // Refresh the current display. It may not be neccessary, but // it may also be, so take the conservative approach and do it. switch(currentView) { case GEL: gelView.refresh(true); case THUMBNAIL: thumbnail.refresh(); break; case GRAPH: graph.refresh(); break; } } catch(Throwable error) { // Take care of any error that might occur. All the errors come // from the event thread, which will go through here some of the // time. errorDialog.showError(error); } } /** * exits the program when the window is closed. */ public void windowClosing(WindowEvent e) { endProgram(); } /** * Clean up before the program quits. */ private void endProgram() { // What kind of clean up do we need to do System.exit(0); } /** * Gives the name associated with a given action event. The * menu items come from the FeatureList. The action * event is compared to all of the items, to see if one of them * originated it. If so, then the name of that item is returned. * * @param items menu items that the event e should be * compared to. * @param e the event for which we wish to obtain a name. * * @return either the name (label) of the item that generated the event * or null if none of the items produced the event. */ private String getName(MenuItem items[], ActionEvent e) { String name = null; for(int i=0; i < items.length; i++) if(e.getSource() == items[i]) name = items[i].getLabel(); return name; } /** * Does a lot of laying out of the window, and menu construction. */ private void programInitialize() { // Make all the other things. ControlBar controls = new ControlBar(this); //=================== Make the menu ================== MenuBar menuBar = new MenuBar(); // File menu Menu fileMenu = new Menu("File"); newItem = new MenuItem("New"); openItem = new MenuItem("Open"); saveItem = new MenuItem("Save"); saveAsItem = new MenuItem("Save As..."); importItem = new MenuItem("Import..."); exportItem = new MenuItem("Export..."); printItem = new MenuItem("Print..."); exitItem = new MenuItem("Exit"); newItem.addActionListener(this); openItem.addActionListener(this); saveAsItem.addActionListener(this); saveItem.addActionListener(this); importItem.addActionListener(this); exportItem.addActionListener(this); printItem.addActionListener(this); exitItem.addActionListener(this); fileMenu.add(newItem); fileMenu.add(openItem); fileMenu.add(saveItem); fileMenu.add(saveAsItem); fileMenu.add(new MenuItem("-")); fileMenu.add(importItem); fileMenu.add(exportItem); fileMenu.add(new MenuItem("-")); fileMenu.add(printItem); fileMenu.add(new MenuItem("-")); fileMenu.add(exitItem); menuBar.add(fileMenu); // Lane menu Menu laneMenu = new Menu("Lane"); laneDeleteItem = new MenuItem("Delete Marked Lanes."); laneDeleteItem.addActionListener(this); laneMenu.add(laneDeleteItem); menuBar.add(laneMenu); laneOpItem = addMenu(laneMenu, FeatureList.getLaneOpMgr()); // Bin menu Menu binMenu = new Menu("Bin"); binRedrawItem = new MenuItem("Redraw Bin"); binRedrawItem.addActionListener(this); binMenu.add(binRedrawItem); menuBar.add(binMenu); binOpItem = addMenu(binMenu, FeatureList.getBinOpMgr()); // Gel menu Menu gelMenu = new Menu("Gel"); gelRedrawItem = new MenuItem("Redraw Gel"); gelRedrawItem.addActionListener(this); gelMenu.add(gelRedrawItem); menuBar.add(gelMenu); gelOpItem = addMenu(gelMenu, FeatureList.getGelOpMgr()); // View menu Menu viewMenu = new Menu("View"); viewGelItem = new MenuItem("Gel"); viewThumbnailItem = new MenuItem("Thumbnail"); viewGraphItem = new MenuItem("Graph"); viewTraceItem = new MenuItem("Trace"); viewAnalysisItem = new MenuItem("Analysis"); viewGelItem.addActionListener(this); viewThumbnailItem.addActionListener(this); viewGraphItem.addActionListener(this); viewTraceItem.addActionListener(this); viewAnalysisItem.addActionListener(this); viewMenu.add(viewGelItem); viewMenu.add(viewThumbnailItem); viewMenu.add(viewGraphItem); viewMenu.add(viewTraceItem); viewMenu.add(viewAnalysisItem); menuBar.add(viewMenu); // Help menu Menu helpMenu = new Menu("Help"); helpItem = new MenuItem("Contents..."); aboutItem = new MenuItem("About"); helpItem.addActionListener(this); aboutItem.addActionListener(this); helpMenu.add(helpItem); helpMenu.add(aboutItem); menuBar.add(helpMenu); //Add labels to status/info bars statusLabel = new Label("Copyright (c) Montana" + " State University 1998. Licensed under GNU" + " General Public License. See help for details."); statusBar.setLayout(null); statusBar.add(statusLabel); statusLabel.setBounds(5, 3, 800, 18); mainPanel = new ScrollPane(); mainPanel.add(gelView); add(mainPanel, "Center"); mainPanel.setVisible(true); // Add all of the components setMenuBar(menuBar); add(controls, "West"); controls.setBounds(0, 0, 89, 200); add(buttonBar, "North"); buttonBar.setBounds(0, 0, getSize().width, 32); bottomP.setLayout(new BorderLayout()); bottomP.add(infoBar, "North"); bottomP.add(statusBar, "South"); // Different width b/c second one has bottom border infoBar.setBounds(0, 0, getSize().width, BAR_HEIGHT); statusBar.setBounds(0, BAR_HEIGHT + 1, getSize().width, BAR_HEIGHT + 1); add(bottomP, "South"); } /** * Adds Operations from the specified Manager * to the specified menu and stores the menu items. If the manager * contains anything, the mehtod will add a separator to the menu before * it adds any of the items. * * @param menu the menu to add the items to. * @param mgr the manager to retrieve the operations from * * @return an array containing all of the menu items added. * * @see AFLPcore.Manager */ public MenuItem[] addMenu(Menu menu, Manager mgr) { String names[] = mgr.getNames(); MenuItem items[] = new MenuItem[names.length]; if(names.length > 0) menu.add(new MenuItem("-")); for(int i=0; i < names.length; i++) { items[i] = new MenuItem(names[i]); menu.add(items[i]); items[i].addActionListener(this); } return items; } // ==================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) {} }