/*
* 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 org.pushingpixels.flamingo.api.common.icon.ResizableIcon;
import org.pushingpixels.flamingo.api.ribbon.JRibbonBand;
import org.pushingpixels.flamingo.api.ribbon.RibbonTask;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JTabbedPane;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import javax.swing.ProgressMonitor;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
public class AnnotationPlugin implements Plugin, ActionListener {
protected PluginManager theManager = null;
protected GlycoWorkbench theApplication = null;
protected GlycanWorkspace theWorkspace = null;
protected JTabbedPane theAnnotationToolsPane = null;
protected PeakAnnotationStatsPanel thePeakAnnotationStatsPanel = null;
protected PeakAnnotationDetailsPanel thePeakAnnotationDetailsPanel = null;
protected PeakAnnotationSummaryPanel thePeakAnnotationSummaryPanel = null;
protected PeakAnnotationCalibrationPanel thePeakAnnotationCalibrationPanel = null;
protected PeakAnnotationReportPanel thePeakAnnotationReportPanel = null;
protected boolean first_time_run = true;
protected boolean annotate = false;
protected boolean showTopResults = true;
protected AnnotationThread theThread = null;
protected ProgressMonitor progressDialog = null;
protected Timer activityMonitor = null;
protected ScanAnnotationCascadeThread scanThread = null;
public AnnotationPlugin(GlycoWorkbench bench) {
this.theApplication=bench;
thePeakAnnotationStatsPanel = new PeakAnnotationStatsPanel();
thePeakAnnotationDetailsPanel = new PeakAnnotationDetailsPanel();
thePeakAnnotationSummaryPanel = new PeakAnnotationSummaryPanel();
thePeakAnnotationCalibrationPanel = new PeakAnnotationCalibrationPanel();
thePeakAnnotationReportPanel = new PeakAnnotationReportPanel();
theAnnotationToolsPane = new JTabbedPane();
theAnnotationToolsPane.add("Stats", thePeakAnnotationStatsPanel);
theAnnotationToolsPane.add("Details", thePeakAnnotationDetailsPanel);
theAnnotationToolsPane.add("Summary", thePeakAnnotationSummaryPanel);
theAnnotationToolsPane.add("Calibration",
thePeakAnnotationCalibrationPanel);
}
public PeakAnnotationStatsPanel getPeakAnnotationStatsPanel() {
return thePeakAnnotationStatsPanel;
}
public PeakAnnotationDetailsPanel getPeakAnnotationDetailsPanel() {
return thePeakAnnotationDetailsPanel;
}
public PeakAnnotationSummaryPanel getPeakAnnotationSummaryPanel() {
return thePeakAnnotationSummaryPanel;
}
public PeakAnnotationCalibrationPanel getPeakAnnotationCalibrationPanel() {
return thePeakAnnotationCalibrationPanel;
}
public PeakAnnotationReportPanel getPeakAnnotationReportPanel() {
return thePeakAnnotationReportPanel;
}
public void init() {
}
public void exit() {
}
public String getName() {
return "Annotation";
}
public int getMnemonic() {
return KeyEvent.VK_A;
}
public ResizableIcon getResizableIcon(){
return FileUtils.getThemeManager().getResizableIcon("annpeaksdoc", ICON_SIZE.L3).getResizableIcon();
}
public ImageIcon getIcon() {
return ThemeManager.getEmptyIcon(ICON_SIZE.TINY);
}
public int getViewPosition(String view) {
if (view.equals("Report"))
return PluginManager.VIEW_BOTTOM;
return PluginManager.VIEW_RIGHT;
}
public java.awt.Component getLeftComponent() {
return null;
}
public java.awt.Component getRightComponent() {
return theAnnotationToolsPane;
}
public java.awt.Component getBottomComponent() {
return thePeakAnnotationReportPanel;
}
public Collection<String> getViews() {
Vector<String> views = new Vector<String>();
views.add("Stats");
views.add("Details");
views.add("Summary");
views.add("Calibration");
views.add("Report");
return views;
}
public Collection<GlycanAction> getActions() {
Vector<GlycanAction> actions = new Vector<GlycanAction>();
actions.add(new GlycanAction("options", ThemeManager.getResizableEmptyIcon(ICON_SIZE.L3),
"Set plugin options", KeyEvent.VK_O, "", this));
actions.add(null);
actions
.add(new GlycanAction(
"findFragmentsCurrent",
ThemeManager.getResizableEmptyIcon(ICON_SIZE.L3),
"Find all fragments of the current structure with a given m/z value",
KeyEvent.VK_C, "", this));
actions
.add(new GlycanAction(
"findFragmentsSelected",
this.theApplication.getThemeManager().getResizableIcon("findfragments", ICON_SIZE.L3),
"Find all fragments of the selected structures with a given m/z value",
KeyEvent.VK_S, "", this));
actions
.add(new GlycanAction(
"findFragmentsAll",
ThemeManager.getResizableEmptyIcon(ICON_SIZE.L3),
"Find all fragments of all the structures with a given m/z value",
KeyEvent.VK_A, "", this));
actions.add(null);
actions.add(new GlycanAction("matchFragmentsCurrent", ThemeManager.getResizableEmptyIcon(ICON_SIZE.L3),
"Annotate peaks with fragments from current structure",
KeyEvent.VK_U, "", this));
actions.add(new GlycanAction("matchFragmentsSelected", this.theApplication.getThemeManager().getResizableIcon("findfragments", ICON_SIZE.L3),
"Annotate peaks with fragments from selected structures",
KeyEvent.VK_E, "", this));
actions.add(new GlycanAction("matchFragmentsAll",
ThemeManager.getResizableEmptyIcon(ICON_SIZE.L3),
"Annotate peaks with fragments from all structures",
KeyEvent.VK_L, "", this));
actions.add(null);
actions
.add(new GlycanAction(
"placeAntennae",
ThemeManager.getResizableEmptyIcon(ICON_SIZE.L3),
"Place uncertain antennae in current structure using the peak list",
KeyEvent.VK_P, "", this));
actions.add(new GlycanAction("cascadeAnnotation",
ThemeManager.getResizableEmptyIcon(ICON_SIZE.L3), "Cascade scan annotation",
KeyEvent.VK_B, "", this));
return actions;
}
public Collection<GlycanAction> getToolbarActions() {
Vector<GlycanAction> actions = new Vector<GlycanAction>();
actions
.add(new GlycanAction(
"findFragmentsSelected",
this.theApplication.getThemeManager().getResizableIcon("findfragments", ICON_SIZE.L3),
"Find all fragments of the selected structures with a given m/z value",
KeyEvent.VK_S, "", this));
actions.add(new GlycanAction("matchFragmentsSelected", this.theApplication.getThemeManager().getResizableIcon("findfragments", ICON_SIZE.L3),
"Annotate peaks with fragments from selected structures",
KeyEvent.VK_E, "", this));
return actions;
}
public Collection<GlycanAction> getObjectActions(Object prototype,
ActionListener al) {
Vector<GlycanAction> actions = new Vector<GlycanAction>();
return actions;
}
public void setManager(PluginManager manager) {
theManager = manager;
if (theManager != null)
theManager
.addMsMsPeakAction(new GlycanAction(
"findFragmentsSelected",
this.theApplication.getThemeManager().getResizableIcon("findfragments", ICON_SIZE.L3),
"Find all fragments of the selected structures matching the peaks",
KeyEvent.VK_S, "", this));
}
public void setApplication(GlycoWorkbench application) {
theApplication = application;
thePeakAnnotationStatsPanel.setApplication(application);
thePeakAnnotationDetailsPanel.setApplication(application);
thePeakAnnotationSummaryPanel.setApplication(application);
thePeakAnnotationCalibrationPanel.setApplication(application);
thePeakAnnotationReportPanel.setApplication(application);
}
public void setWorkspace(GlycanWorkspace workspace) {
theWorkspace = workspace;
thePeakAnnotationStatsPanel.setWorkspace(workspace);
thePeakAnnotationDetailsPanel.setWorkspace(workspace);
thePeakAnnotationSummaryPanel.setWorkspace(workspace);
thePeakAnnotationCalibrationPanel.setWorkspace(workspace);
thePeakAnnotationReportPanel.setWorkspace(workspace);
}
public PluginManager getManager() {
return theManager;
}
public GlycoWorkbench getApplication() {
return theApplication;
}
public GlycanWorkspace getWorkspace() {
return theWorkspace;
}
public void show(String view) throws Exception {
if (view.equals("Stats"))
theAnnotationToolsPane
.setSelectedComponent(thePeakAnnotationStatsPanel);
else if (view.equals("Details"))
theAnnotationToolsPane
.setSelectedComponent(thePeakAnnotationDetailsPanel);
else if (view.equals("Summary"))
theAnnotationToolsPane
.setSelectedComponent(thePeakAnnotationSummaryPanel);
else if (view.equals("Calibration"))
theAnnotationToolsPane
.setSelectedComponent(thePeakAnnotationCalibrationPanel);
else if (view.equals("Report")) {
} else
throw new Exception("Invalid view: " + view);
}
public boolean runAction(String action) throws Exception {
if (action.startsWith("find")) {
String m_z = JOptionPane.showInputDialog(theApplication,
"Insert m/z value", theWorkspace.getRecentMZValue());
if (m_z != null) {
Double mz_value = Double.valueOf(m_z);
theWorkspace.setRecentMZValue(mz_value);
return runAction(true, action, new PeakList(mz_value));
}
return false;
} else
return runAction(true, action, theWorkspace.getPeakList());
}
public boolean runAction(String action, Object params) throws Exception {
if (runAction(first_time_run, action, params)) {
first_time_run = false;
return true;
}
return false;
}
public boolean runAction(boolean ask, String action, Object params)
throws Exception {
if (!(params instanceof PeakList))
throw new Exception("Invalid param object: PeakList needed");
PeakList peaks = (PeakList) params;
if (action.equals("options"))
return setOptions();
if (action.equals("findFragmentsCurrent")) {
annotate = false;
theApplication.getCanvas().enforceSelection();
if (matchAllFragments(ask, theApplication.getCanvas()
.getCurrentStructure(), peaks)) {
theManager.show("Search", "Details");
return true;
}
return false;
}
if (action.equals("findFragmentsSelected")) {
annotate = false;
theApplication.getCanvas().enforceSelection();
if (matchAllFragments(ask, theApplication.getCanvas()
.getSelectedStructures(), peaks)) {
theManager.show("Search", (theApplication.getCanvas()
.getSelectedStructures().size() > 1) ? "Summary"
: "Details");
return true;
}
return false;
}
if (action.equals("findFragmentsAll")) {
annotate = false;
if (matchAllFragments(ask, theWorkspace.getStructures()
.getStructures(), peaks)) {
theManager.show("Search",
(theWorkspace.getStructures().size() > 1) ? "Summary"
: "Details");
return true;
}
return false;
}
if (action.equals("matchFragmentsCurrent")) {
annotate = true;
theApplication.getCanvas().enforceSelection();
if (matchAllFragments(ask, theApplication.getCanvas()
.getCurrentStructure(), peaks)) {
theManager.show("Annotation", "Stats");
return true;
}
return false;
}
if (action.equals("matchFragmentsSelected")) {
annotate = true;
theApplication.getCanvas().enforceSelection();
if (matchAllFragments(ask, theApplication.getCanvas()
.getSelectedStructures(), peaks)) {
theManager.show("Annotation", "Stats");
return true;
}
return false;
}
if (action.equals("matchFragmentsAll")) {
annotate = true;
if (matchAllFragments(ask, theWorkspace.getStructures()
.getStructures(), peaks)) {
theManager.show("Annotation", "Stats");
return true;
}
return false;
}
if (action.equals("placeAntennae")) {
annotate = true;
theApplication.getCanvas().enforceSelection();
if (placeAntennae(ask, theApplication.getCanvas()
.getCurrentStructure(), peaks)) {
theManager.show("Annotation", "Stats");
return true;
}
return false;
}
if (action.equals("cascadeAnnotation")) {
annotate = true;
if (scanAnnotationCascade(ask, this.getWorkspace()
.getAllParentScans())) {
theManager.show("Annotation", "Stats");
this.getWorkspace().fireDocumentChanged();
return true;
}
return false;
}
throw new Exception("Invalid action: " + action);
}
public void actionPerformed(ActionEvent e) {
try {
runAction(GlycanAction.getAction(e));
} catch (Exception ex) {
LogUtils.report(ex);
}
}
public void updateViews() {
thePeakAnnotationStatsPanel.updateView();
thePeakAnnotationDetailsPanel.updateView();
thePeakAnnotationSummaryPanel.updateView();
thePeakAnnotationCalibrationPanel.updateView();
thePeakAnnotationReportPanel.updateView();
}
public void updateMasses() {
}
// ------------
// ACTIONS
public boolean setOptions() {
// show annotation options dialog
FragmentOptions frag_opt = theWorkspace.getFragmentOptions();
AnnotationOptions ann_opt = theWorkspace.getAnnotationOptions();
AnnotationOptionsDialog adlg = new AnnotationOptionsDialog(
theApplication, frag_opt, ann_opt, false, false);
adlg.setVisible(true);
if (!adlg.getReturnStatus().equals("OK"))
return false;
return true;
}
public boolean matchAllFragments(boolean ask_options, Glycan structure,
PeakList peaks) {
if (structure != null)
return matchAllFragments(ask_options, Collections
.singleton(structure), peaks);
return false;
}
public boolean scanAnnotationCascade(boolean ask, Vector<Scan> parentScans) {
if(setAnnotationOptions(ask)){
theApplication.haltInteractions();
showTopResults = false;
scanThread=new ScanAnnotationCascadeThread(parentScans,theWorkspace.getFragmentOptions(), theWorkspace.getAnnotationOptions());
scanThread.start();
progressDialog = new ProgressMonitor(theApplication,"Parent scans completed", null, 0, scanThread.getTarget());
// set up the timer action
activityMonitor = new Timer(200, new ActionListener() {
public void actionPerformed(ActionEvent event) {
int progress = scanThread.getProgress();
// show progress
progressDialog.setProgress(progress);
// check if task is completed or canceled
if (progress == scanThread.getTarget()
|| progressDialog.isCanceled()) {
System.err.println("Stopping activity monitor");
activityMonitor.stop();
progressDialog.close();
if (progress != scanThread.getTarget()) {
scanThread.interrupt();
onAnnotationAborted(scanThread);
} else {
onAnnotationCompleted(scanThread);
}
}
}
});
activityMonitor.start();
}
return true;
}
public boolean setAnnotationOptions(boolean ask_options){
if (ask_options) {
AnnotationOptionsDialog dlg = new AnnotationOptionsDialog(
theApplication,theWorkspace.getFragmentOptions(), theWorkspace.getAnnotationOptions(), true, true);
dlg.setVisible(true);
if (!dlg.getReturnStatus().equals("OK")){
return false;
}else{
return true;
}
}
return true;
}
public boolean matchAllFragments(boolean ask_options,
Collection<Glycan> structures, PeakList peaks) {
if (structures == null || structures.size() == 0)
return false;
// retrieve peak list
if (peaks.size() == 0) {
JOptionPane.showMessageDialog(theApplication,
"You must load a peak list first", "Error",
JOptionPane.ERROR_MESSAGE);
return false;
}
// show fragments dialog
FragmentOptions frag_opt = theWorkspace.getFragmentOptions();
AnnotationOptions ann_opt = theWorkspace.getAnnotationOptions();
if (ask_options) {
AnnotationOptionsDialog dlg = new AnnotationOptionsDialog(
theApplication, frag_opt, ann_opt, true, true);
dlg.setVisible(true);
if (!dlg.getReturnStatus().equals("OK"))
return false;
}
// create fragmenter
Fragmenter frag = new Fragmenter(frag_opt);
// check for linkages
if ((frag.getComputeAFragments() || frag.getComputeXFragments())
&& ask_options) {
for (Glycan s : structures) {
if (!s.checkLinkages()) {
if (JOptionPane
.showConfirmDialog(
theApplication,
"Cross ring fragments will not be computed for residues with incomplete linkage or anomeric information. Continue?",
"Warning", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION)
return false;
else
break;
}
}
}
// halt interactions
theApplication.haltInteractions();
// compute fragments and match them with peaks
showTopResults = false;
return runAnnotation(peaks, structures, frag, ann_opt);
}
public boolean placeAntennae(boolean ask_options, Glycan current,
PeakList peaks) {
if (current == null)
return false;
if (current.getNoAntennae() > 2) {
JOptionPane
.showMessageDialog(
theApplication,
"This features is still experimental and the maximum number of antennae that can be placed is set to two.",
"Warning", JOptionPane.WARNING_MESSAGE);
return false;
}
// retrieve peak list
if (peaks.size() == 0) {
JOptionPane.showMessageDialog(theApplication,
"You must load a peak list first", "Error",
JOptionPane.ERROR_MESSAGE);
return false;
}
// show fragments dialog
FragmentOptions frag_opt = theWorkspace.getFragmentOptions();
AnnotationOptions ann_opt = theWorkspace.getAnnotationOptions();
if (ask_options) {
AnnotationOptionsDialog dlg = new AnnotationOptionsDialog(
theApplication, frag_opt, ann_opt, true, true);
dlg.setVisible(true);
if (!dlg.getReturnStatus().equals("OK"))
return false;
}
// create fragmenter
Fragmenter frag = new Fragmenter(frag_opt);
// check for linkages
if ((frag.getComputeAFragments() || frag.getComputeXFragments())
&& ask_options) {
if (!current.checkLinkages()) {
if (JOptionPane
.showConfirmDialog(
theApplication,
"Cross ring fragments will not be computed for residues with incomplete linkage or anomeric information. Continue?",
"Warning", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION)
return false;
}
}
// halt interactions
theApplication.haltInteractions();
// create possible structures
Vector<Glycan> structures = new Vector<Glycan>();
current.placeAntennae(structures);
// compute fragments and match them with peaks
showTopResults = true;
return runAnnotation(peaks, structures, frag, ann_opt);
}
protected boolean runAnnotation(PeakList _peaks,
Collection<Glycan> _structures, Fragmenter _fragmenter,
AnnotationOptions _ann_opt) {
// start activity
theThread = new AnnotationThread(_peaks, _structures, _fragmenter,
_ann_opt);
theThread.start();
// launch progress dialog
progressDialog = new ProgressMonitor(theApplication,
"Matching peaks with fragments", null, 0, theThread.getTarget());
// set up the timer action
activityMonitor = new Timer(200, new ActionListener() {
public void actionPerformed(ActionEvent event) {
int progress = theThread.getProgress();
// show progress
progressDialog.setProgress(progress);
// check if task is completed or canceled
if (progress == theThread.getTarget()
|| progressDialog.isCanceled()) {
System.err.println("Stopping activity monitor");
activityMonitor.stop();
progressDialog.close();
if (progress != theThread.getTarget()) {
theThread.interrupt();
onAnnotationAborted(theThread);
} else {
onAnnotationCompleted(theThread);
}
}
}
});
System.err.println("Starting activity monitor");
activityMonitor.start();
// return control
return true;
}
protected void onAnnotationCompleted(AnnotationThread t) {
// show annotations
AnnotatedPeakList dest = null;
if (annotate)
dest = theWorkspace.getAnnotatedPeakList();
else {
dest = theWorkspace.getSearchResults();
theWorkspace.setSearchGenerator(this);
}
if (showTopResults)
dest.copy(t.getAnnotatedPeaks().getFirst(20));
else
dest.copy(t.getAnnotatedPeaks());
// restore interactions
theApplication.restoreInteractions();
// show status
if (t.getNonEmptyStructures() > 0) {
if (t.hasFuzzyStructures()) {
if (t.getNonEmptyStructures() == 1)
JOptionPane
.showMessageDialog(
theApplication,
"Cannot compute fragments for structures with uncertain terminals",
"Error", JOptionPane.ERROR_MESSAGE);
else if (t.hasNonFuzzyStructures())
JOptionPane
.showMessageDialog(
theApplication,
"Cannot compute fragments for some structures with uncertain terminals",
"Error", JOptionPane.ERROR_MESSAGE);
else
JOptionPane
.showMessageDialog(
theApplication,
"Cannot compute fragments, all structures have uncertain terminals",
"Error", JOptionPane.ERROR_MESSAGE);
}
}
}
protected void onAnnotationAborted(AnnotationThread t) {
// restore interactions
theApplication.restoreInteractions();
}
protected void onAnnotationAborted(ScanAnnotationCascadeThread scanThread) {
// restore interactions
theApplication.restoreInteractions();
}
protected void onAnnotationCompleted(ScanAnnotationCascadeThread t) {
HashMap<Scan,AnnotatedPeakList> scanToAnnotatedPeakList=t.getScanToAnnotatedPeaks();
for(Scan scan:scanToAnnotatedPeakList.keySet()){
theWorkspace.setCurrentScan(scan);
AnnotatedPeakList dest = null;
if (annotate)
dest = theWorkspace.getAnnotatedPeakList();
else {
dest = theWorkspace.getSearchResults();
theWorkspace.setSearchGenerator(this);
}
if (showTopResults)
dest.copy(scanToAnnotatedPeakList.get(scan).getFirst(20));
else
dest.copy(scanToAnnotatedPeakList.get(scan));
}
// restore interactions
theApplication.restoreInteractions();
}
@Override
public void completeSetup() {
// TODO Auto-generated method stub
}
@Override
public List<JRibbonBand> getBandsForToolBar() {
// TODO Auto-generated method stub
return null;
}
@Override
public RibbonTask getRibbonTask() {
// TODO Auto-generated method stub
return null;
}
}