/* * EuroCarbDB, a framework for carbohydrate bioinformatics * * Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * A copy of this license accompanies this distribution in the file LICENSE.txt. * * 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 Lesser General Public License * for more details. * * Last commit: $Rev: 1930 $ by $Author: david@nixbioinf.org $ on $Date:: 2010-07-29 #$ */ /** @author Alessio Ceroni (a.ceroni@imperial.ac.uk) */ package org.eurocarbdb.application.glycoworkbench.plugin; import org.eurocarbdb.application.glycanbuilder.*; import org.eurocarbdb.application.glycoworkbench.*; import java.awt.*; import java.awt.geom.*; import java.awt.event.*; import java.awt.print.PrinterJob; import javax.swing.*; import javax.swing.border.BevelBorder; import org.jfree.chart.JFreeChart; import org.jfree.chart.ChartPanel; import org.jfree.data.xy.DefaultXYDataset; import org.jfree.data.Range; import org.jfree.chart.plot.XYPlot; public class PeakAnnotationCalibrationPanel extends DocumentPanel<AnnotatedPeakList> implements ActionListener, ComponentListener, GlycanWorkspace.Listener, BaseDocument.DocumentChangeListener { private static final int MOD_MASK = MouseEvent.CTRL_MASK | MouseEvent.SHIFT_MASK | MouseEvent.ALT_MASK | MouseEvent.META_MASK | MouseEvent.ALT_GRAPH_MASK; // components protected JLabel theStructure; protected DefaultXYDataset theDataset; protected XYPlot thePlot; protected JFreeChart theChart; protected ChartPanel theChartPanel; protected JToolBar theToolBarDocument; protected JToolBar theToolBarEdit; // data protected int current_ind = 0; protected String accuracy_unit; // actions protected JButton accunit_button = null; protected boolean was_moving = false; protected boolean is_moving = false; protected Point2D mouse_start_point = null; protected Cursor hand_cursor = null; // public PeakAnnotationCalibrationPanel() { super(); } protected void initSingletons() { super.initSingletons(); accuracy_unit = "da"; } protected void initComponents() { setLayout(new BorderLayout()); // create structure viewer theStructure = new JLabel(); theStructure.setBorder(new BevelBorder(BevelBorder.RAISED)); add(theStructure,BorderLayout.NORTH); // create chart theDataset = new DefaultXYDataset(); theChart = org.jfree.chart.ChartFactory.createScatterPlot("Calibration", "m/z ratio", "accuracy (Da)", theDataset, org.jfree.chart.plot.PlotOrientation.VERTICAL, true, false, false); thePlot = (XYPlot)theChart.getPlot(); theChartPanel = new ChartPanel(theChart); theChartPanel.setDomainZoomable(true); theChartPanel.setRangeZoomable(true); theChartPanel.setPopupMenu(null); add(theChartPanel,BorderLayout.CENTER); // create toolbar JPanel theToolBarPanel = new JPanel(new BorderLayout()); theToolBarDocument = createToolBarDocument(); theToolBarEdit = createToolBarEdit(); theToolBarPanel.add(theToolBarDocument, BorderLayout.NORTH); theToolBarPanel.add(theToolBarEdit, BorderLayout.CENTER); add(theToolBarPanel,BorderLayout.SOUTH); // load cursors hand_cursor = FileUtils.createCursor("hand"); } protected void finalSettings() { super.finalSettings(); theChartPanel.addMouseMotionListener( new MouseMotionAdapter() { public void mouseDragged(MouseEvent e) { onMouseDragged(e); } }); theChartPanel.addMouseListener( new MouseAdapter() { public void mousePressed(MouseEvent e) { onMousePressed(e); } public void mouseReleased(MouseEvent e) { onMouseReleased(e); } public void mouseClicked(MouseEvent e) { onMouseClicked(e); } }); } public AnnotatedPeakList getDocumentFromWorkspace(GlycanWorkspace workspace) { return ( workspace!=null ) ?workspace.getAnnotatedPeakList() :null; } public void setDocumentFromWorkspace(GlycanWorkspace workspace) { if( theDocument!=null ) theDocument.removeDocumentChangeListener(this); theDocument = getDocumentFromWorkspace(workspace); if( theDocument==null ) theDocument = new AnnotatedPeakList(); theDocument.addDocumentChangeListener(this); current_ind = 0; updateView(); updateActions(); } protected void createActions() { theActionManager.add("accunit=da",FileUtils.defaultThemeManager.getImageIcon("da"),"Show accuracy in Da",-1, "",this); theActionManager.add("accunit=ppm",FileUtils.defaultThemeManager.getImageIcon("ppm"),"Show accuracy in PPM",-1, "",this); theActionManager.add("new",FileUtils.defaultThemeManager.getImageIcon("new"),"Clear",KeyEvent.VK_N, "",this); theActionManager.add("close",FileUtils.defaultThemeManager.getImageIcon("close"),"Close structure",KeyEvent.VK_S, "",this); theActionManager.add("last",FileUtils.defaultThemeManager.getImageIcon("last"),"Last structure",KeyEvent.VK_L, "",this); theActionManager.add("next",FileUtils.defaultThemeManager.getImageIcon("next"),"Next structure",KeyEvent.VK_N, "",this); theActionManager.add("print",FileUtils.defaultThemeManager.getImageIcon("print"),"Print...",KeyEvent.VK_P, "",this); //theActionManager.add("undo",FileUtils.defaultThemeManager.getImageIcon("undo"),"Undo",KeyEvent.VK_U, "",this); //theActionManager.add("redo",FileUtils.defaultThemeManager.getImageIcon("redo"),"Redo", KeyEvent.VK_R, "",this); theActionManager.add("arrow",FileUtils.defaultThemeManager.getImageIcon("arrow"),"Activate zoom",-1, "",this); theActionManager.add("hand",FileUtils.defaultThemeManager.getImageIcon("hand"),"Activate moving",-1, "",this); theActionManager.add("zoomnone",FileUtils.defaultThemeManager.getImageIcon("zoomnone"),"Reset zoom",-1, "",this); theActionManager.add("zoomin",FileUtils.defaultThemeManager.getImageIcon("zoomin"),"Zoom in",-1, "",this); theActionManager.add("zoomout",FileUtils.defaultThemeManager.getImageIcon("zoomout"),"Zoom out",-1, "",this); } protected void updateActions() { theActionManager.get("close").setEnabled(theDocument.getNoStructures()!=0); theActionManager.get("last").setEnabled(current_ind>0); theActionManager.get("next").setEnabled(current_ind<(theDocument.getNoStructures()-1)); //theActionManager.get("undo").setEnabled(theDocument.getUndoManager().canUndo()); //theActionManager.get("redo").setEnabled(theDocument.getUndoManager().canRedo()); theActionManager.get("arrow").setEnabled(is_moving); theActionManager.get("hand").setEnabled(!is_moving); theActionManager.get("zoomnone").setEnabled(true); theActionManager.get("zoomin").setEnabled(true); theActionManager.get("zoomout").setEnabled(true); } private JToolBar createToolBarDocument() { JToolBar toolbar = new JToolBar(); toolbar.setFloatable(false); toolbar.add(theActionManager.get("last")); toolbar.add(theActionManager.get("close")); toolbar.add(theActionManager.get("next")); toolbar.addSeparator(); toolbar.add(accunit_button = new JButton(theActionManager.get("accunit=ppm")) ); accunit_button.setText(null); toolbar.add(theActionManager.get("new")); toolbar.addSeparator(); toolbar.add(theActionManager.get("print")); //toolbar.addSeparator(); //toolbar.add(theActionManager.get("undo")); //toolbar.add(theActionManager.get("redo")); return toolbar; } private JToolBar createToolBarEdit() { JToolBar toolbar = new JToolBar(); toolbar.setFloatable(false); toolbar.addSeparator(); toolbar.add(theActionManager.get("arrow")); toolbar.add(theActionManager.get("hand")); toolbar.addSeparator(); toolbar.add(theActionManager.get("zoomnone")); toolbar.add(theActionManager.get("zoomin")); toolbar.add(theActionManager.get("zoomout")); return toolbar; } protected JPopupMenu createPopupMenu() { JPopupMenu menu = new JPopupMenu(); menu.add(theActionManager.get("zoomnone")); menu.add(theActionManager.get("zoomin")); menu.add(theActionManager.get("zoomout")); return menu; } //----------------- // data public boolean isChartEmpty() { return (theDocument.getNoStructures()==0 || theDocument.getNoAnnotatedPeaks(current_ind)==0); } public double screenToDataX(double length) { Rectangle2D data_area = theChartPanel.getScreenDataArea(); double mz_unit = thePlot.getDomainAxis().lengthToJava2D(1.,data_area,thePlot.getDomainAxisEdge()); return length/mz_unit; } public double screenToDataY(double length) { Rectangle2D data_area = theChartPanel.getScreenDataArea(); double int_unit = thePlot.getRangeAxis().lengthToJava2D(1.,data_area,thePlot.getRangeAxisEdge()); return length/int_unit; } public Point2D screenToDataCoords(Point2D p) { Rectangle2D data_area = theChartPanel.getScreenDataArea(); double x = thePlot.getDomainAxis().java2DToValue(p.getX(),data_area,thePlot.getDomainAxisEdge()); double y = thePlot.getRangeAxis().java2DToValue(p.getY(),data_area,thePlot.getRangeAxisEdge()); return new Point2D.Double(x,y); } public double screenToDataCoordX(double x) { Rectangle2D data_area = theChartPanel.getScreenDataArea(); return thePlot.getDomainAxis().java2DToValue(x,data_area,thePlot.getDomainAxisEdge()); } public double screenToDataCoordY(double y) { Rectangle2D data_area = theChartPanel.getScreenDataArea(); return thePlot.getRangeAxis().java2DToValue(y,data_area,thePlot.getRangeAxisEdge()); } public void clear() { current_ind = 0; theDocument.clear(); } //----------- // Visualization protected void updateData() { current_ind = Math.min(current_ind,theDocument.getNoStructures()-1); current_ind = Math.max(current_ind,0); } protected void updateView() { if( theStructure!=null ) { if( theDocument.getNoStructures()>0 ) theStructure.setIcon(new ImageIcon(theWorkspace.getGlycanRenderer().getImage(theDocument.getStructure(current_ind),false,true,true,0.667))); else theStructure.setIcon(null); } // update data if( theDocument.getNoStructures()>0 ) { theDataset.removeSeries("best"); theDataset.removeSeries("all"); if( accuracy_unit.equals("ppm") ) { theDataset.addSeries("best", theDocument.getBestCalibrationDataPPM(current_ind)); theDataset.addSeries("all", theDocument.getCalibrationDataPPM(current_ind)); } else { theDataset.addSeries("best", theDocument.getBestCalibrationData(current_ind)); theDataset.addSeries("all", theDocument.getCalibrationData(current_ind)); } } // update axis if( accuracy_unit.equals("ppm") ) thePlot.getRangeAxis().setLabel("accuracy (PPM)"); else thePlot.getRangeAxis().setLabel("accuracy (Da)"); theChartPanel.setDomainZoomable(!is_moving); theChartPanel.setRangeZoomable(!is_moving); onZoomNone(); } //----------------- // actions public void closeCurrent() { if( theDocument.getNoStructures()>0 ) { int old_ind = current_ind; current_ind = Math.min(current_ind,theDocument.getNoStructures()-2); current_ind = Math.max(current_ind,0); // long action theApplication.haltInteractions(); theDocument.removePeakAnnotationsAt(old_ind); theApplication.restoreInteractions(); } } public void showLast() { if( theDocument.getNoStructures()>0 && current_ind>0 ) { current_ind--; updateView(); } } public void showNext() { if( theDocument.getNoStructures()>0 && current_ind<(theDocument.getNoStructures()-1) ) { current_ind++; updateView(); } } public void showStructure(int s_ind) { if( s_ind>=0 && s_ind<theDocument.getNoStructures() ) { current_ind = s_ind; updateView(); } } public void onNew() { clear(); } public void onPrint() { PrinterJob pj = theWorkspace.getPrinterJob(); if( pj==null ) return; try { pj.setPrintable(theChartPanel); if( pj.printDialog() ) pj.print(); } catch(Exception e) { LogUtils.report(e); } } /*public void onUndo() { try { theDocument.getUndoManager().undo(); } catch(Exception e) { LogUtils.report(e); } } public void onRedo() { try { theDocument.getUndoManager().redo(); } catch(Exception e) { LogUtils.report(e); } } */ public void onActivateZooming() { is_moving = false; theChartPanel.setCursor(Cursor.getDefaultCursor()); theChartPanel.setDomainZoomable(true); theChartPanel.setRangeZoomable(true); } public void onActivateMoving() { is_moving = true; theChartPanel.setCursor(hand_cursor); theChartPanel.setRangeZoomable(false); theChartPanel.setDomainZoomable(false); } public void onZoomNone() { if( !isChartEmpty() ) { Range mz_range = theDocument.getMZRange(); if( mz_range.getLength()==0. ) mz_range = new Range(mz_range.getLowerBound()-10,mz_range.getLowerBound()+10); thePlot.getDomainAxis().setRange(mz_range); if( accuracy_unit.equals("da") ) { Range acc_range = theDocument.getAccuracyRange(current_ind); if( acc_range.getLength()==0. ) acc_range = new Range(acc_range.getLowerBound()-0.1,acc_range.getLowerBound()+0.1); thePlot.getRangeAxis().setRange(acc_range); } else { Range acc_range = theDocument.getAccuracyRangePPM(current_ind); if( acc_range.getLength()==0. ) acc_range = new Range(acc_range.getLowerBound()-100,acc_range.getLowerBound()+100); thePlot.getRangeAxis().setRange(acc_range); } } else { thePlot.getDomainAxis().setRange(new Range(0.,1.)); if( accuracy_unit.equals("da") ) thePlot.getRangeAxis().setRange(new Range(-1.,1.)); else thePlot.getRangeAxis().setRange(new Range(-1000.,1000.)); } } public void onZoomIn() { thePlot.getDomainAxis().resizeRange(0.5); thePlot.getRangeAxis().resizeRange(0.5); } public void onZoomOut() { thePlot.getDomainAxis().resizeRange(2.0); thePlot.getRangeAxis().resizeRange(2.0); } public void onSetAccuracyUnit(String accunit) { if( accunit.equals("da") ) { accuracy_unit = "da"; accunit_button.setAction(theActionManager.get("accunit=ppm")); accunit_button.setText(null); updateView(); } else if( accunit.equals("ppm") ) { accuracy_unit = "ppm"; accunit_button.setAction(theActionManager.get("accunit=da")); accunit_button.setText(null); updateView(); } } //----------- // listeners public void actionPerformed(ActionEvent e) { String action = GlycanAction.getAction(e); String param = GlycanAction.getParam(e); if( action.equals("last") ) showLast(); else if( action.equals("next") ) showNext(); else if( action.equals("close") ) closeCurrent(); else if( action.equals("accunit") ) onSetAccuracyUnit(param); else if( action.equals("new") ) onNew(); else if( action.equals("print") ) onPrint(); /*else if( action.equals("undo") ) onUndo(); else if( action.equals("redo") ) onRedo(); */ else if( action.equals("arrow") ) onActivateZooming(); else if( action.equals("hand") ) onActivateMoving(); else if( action.equals("zoomnone") ) onZoomNone(); else if( action.equals("zoomin") ) onZoomIn(); else if( action.equals("zoomout") ) onZoomOut(); updateActions(); } public void onMousePressed(MouseEvent e) { was_moving = is_moving; if( e.getButton()==e.BUTTON1 && theChartPanel.getScreenDataArea().contains(e.getPoint()) ) { mouse_start_point = e.getPoint(); if( (e.getModifiers() & MOD_MASK)==e.SHIFT_MASK ) onActivateMoving(); } else mouse_start_point = null; } private void onMouseDragged(MouseEvent e) { if( mouse_start_point!=null ) { if( is_moving ) { // moving double mz_delta = screenToDataX(mouse_start_point.getX() - e.getPoint().getX()); double acc_delta = screenToDataY(e.getPoint().getY() - mouse_start_point.getY()); // update mz if( mz_delta>0. ) { double old_upper_bound = thePlot.getDomainAxis().getUpperBound(); double old_lower_bound = thePlot.getDomainAxis().getLowerBound(); double new_upper_bound = old_upper_bound+mz_delta; double new_lower_bound = old_lower_bound + new_upper_bound - old_upper_bound; thePlot.getDomainAxis().setRange(new Range(new_lower_bound,new_upper_bound)); } else { double old_upper_bound = thePlot.getDomainAxis().getUpperBound(); double old_lower_bound = thePlot.getDomainAxis().getLowerBound(); double new_lower_bound = old_lower_bound+mz_delta; double new_upper_bound = old_upper_bound + new_lower_bound - old_lower_bound; thePlot.getDomainAxis().setRange(new Range(new_lower_bound,new_upper_bound)); } // update acc if( acc_delta>0. ) { double old_upper_bound = thePlot.getRangeAxis().getUpperBound(); double old_lower_bound = thePlot.getRangeAxis().getLowerBound(); double new_upper_bound = old_upper_bound+acc_delta; double new_lower_bound = old_lower_bound + new_upper_bound - old_upper_bound; thePlot.getRangeAxis().setRange(new Range(new_lower_bound,new_upper_bound)); } else { double old_upper_bound = thePlot.getRangeAxis().getUpperBound(); double old_lower_bound = thePlot.getRangeAxis().getLowerBound(); double new_lower_bound = old_lower_bound+acc_delta; double new_upper_bound = old_upper_bound + new_lower_bound - old_lower_bound; thePlot.getRangeAxis().setRange(new Range(new_lower_bound,new_upper_bound)); } mouse_start_point = e.getPoint(); } } } public void onMouseReleased(MouseEvent e) { // restore zooming if( !was_moving && is_moving ) onActivateZooming(); mouse_start_point = null; } public void onMouseClicked(MouseEvent e) { // find peak under mouse if( e.getButton()==MouseEvent.BUTTON3 && e.getClickCount()==1 && (e.getModifiers() & MOD_MASK)==e.BUTTON3_MASK ) { // open popup createPopupMenu().show(theChartPanel, e.getX(), e.getY()); } } }