/* * 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; import org.eurocarbdb.application.glycoworkbench.plugin.reporting.*; import org.eurocarbdb.application.glycoworkbench.plugin.*; import org.eurocarbdb.application.glycanbuilder.*; import java.awt.print.*; import java.util.*; import java.io.*; import org.w3c.dom.*; import org.xml.sax.SAXException; import javax.xml.transform.sax.TransformerHandler; import org.xml.sax.helpers.AttributesImpl; public class GlycanWorkspace extends BuilderWorkspace implements SAXUtils.SAXWriter { public static class Event extends java.util.EventObject { protected Scan parent; protected Scan child; protected Scan current; protected int index; public Event(GlycanWorkspace _source, Scan _parent, Scan _child, int _index, Scan _current) { super(_source); parent = _parent; child = _child; index = _index; current = _current; } public Scan getParentScan() { return parent; } public Scan getChildScan() { return child; } public int getIndex() { return index; } public Scan getCurrentScan() { return current; } } public interface Listener { public void currentScanChanged(Event e); public void scanAdded(Event e); public void scanRemoved(Event e); public void internalDocumentChanged(Event e); } // configuration protected FragmentOptions theFragmentOptions; protected AnnotationOptions theAnnotationOptions; // documents protected Plugin theSearchGenerator; protected AnnotatedPeakList theSearchResults; protected Vector<Scan> theScanList; protected Scan currentScan; protected Double recent_mz_value = null; // listeners protected Vector<Listener> gw_listeners = new Vector<Listener>(); //---- public GlycanWorkspace() { super(); } public GlycanWorkspace(String config_file, boolean create) { super(config_file,create); } // base document public Collection<javax.swing.filechooser.FileFilter> getFileFormats() { Vector<javax.swing.filechooser.FileFilter> filters = new Vector<javax.swing.filechooser.FileFilter>(); filters.add(new ExtensionFileFilter("gwp", "GlycoWorkbench workspace file")); return filters; } public javax.swing.filechooser.FileFilter getAllFileFormats() { return new ExtensionFileFilter("gwp", "Workspace files"); } // protected void createConfiguration() { super.createConfiguration(); theFragmentOptions = new FragmentOptions(); theAnnotationOptions = new AnnotationOptions(); } public void init(String config_file, boolean create, boolean keep_configuration ) { super.init(config_file,create,keep_configuration); // initialize documents theSearchResults = new AnnotatedPeakList(); theScanList = new Vector<Scan>(); theScanList.add(currentScan = new Scan(this)); registerListeners(currentScan); } protected void retrieveFromConfiguration() { super.retrieveFromConfiguration(); theFragmentOptions.retrieve(theConfiguration); theAnnotationOptions.retrieve(theConfiguration); } protected void storeToConfiguration(boolean save_options) { super.storeToConfiguration(save_options); if( save_options ) { theFragmentOptions.store(theConfiguration); theAnnotationOptions.store(theConfiguration); } } public Double getRecentMZValue() { return recent_mz_value; } public void setRecentMZValue(Double v) { recent_mz_value = v; } public FragmentOptions getFragmentOptions() { return theFragmentOptions; } public void storeFragmentOptions() { theFragmentOptions.store(theConfiguration); } public AnnotationOptions getAnnotationOptions() { return theAnnotationOptions; } public void storeAnnotationOptions() { theAnnotationOptions.store(theConfiguration); } public Scan scanAt(int ind) { return theScanList.elementAt(ind); } public int indexOf(Scan s) { return theScanList.indexOf(s); } public int getNoScans() { return theScanList.size(); } public Collection<Scan> getScanList() { return theScanList; } public Scan getFirstScan() { return theScanList.firstElement(); } public Scan getNextScan(Scan s) { if( s==null ) return null; int index = theScanList.indexOf(s); if( index==-1 ) return null; if( index==theScanList.size()-1 ) { if( index>0 ) return theScanList.elementAt(index-1); return null; } return theScanList.elementAt(index+1); } public Scan getCurrentScan() { return currentScan; } public boolean setCurrentScan(Scan s) { if( s!=null ) { if( s!=currentScan ) { Scan old = currentScan; Scan parent = old.getParent(); int index = (parent!=null) ?parent.indexOf(old) :-1; currentScan = s; fireCurrentScanChanged(new Event(this,parent,old,index,s)); } return true; } return false; } public boolean addScan(Scan parent, Scan toadd) { if( toadd==null ) return false; int index = -1; if( parent==null ) { theScanList.add(toadd); index = theScanList.indexOf(toadd); } else { parent.add(toadd); index = parent.indexOf(toadd); } registerListeners(toadd); fireScanAdded(new Event(this,parent,toadd,index,currentScan)); fireDocumentChanged(this); return true; } public boolean removeScan(Scan parent, Scan toremove) { if( toremove==null ) return false; int index = -1; if( parent==null ) { index = theScanList.indexOf(toremove); if( index==-1 ) return false; if( theScanList.size()==1 ) addScan(null,new Scan(this)); if( toremove.containsSubTree(currentScan) ) setCurrentScan(getNextScan(currentScan)); theScanList.remove(toremove); } else { index = parent.indexOf(toremove); if( index==-1 ) return false; if( toremove.containsSubTree(currentScan) ) setCurrentScan(parent); parent.remove(toremove); } deregisterListeners(toremove); fireScanRemoved(new Event(this,parent,toremove,index,currentScan)); fireDocumentChanged(this); return true; } public boolean syncScan(Scan scan){ boolean matchFound=false; Scan parentScan=scan.getParent(); if(parentScan!=null){ AnnotatedPeakList annotatedPeakList=parentScan.getAnnotatedPeakList(); PeakAnnotationMultiple peakAnnotations=annotatedPeakList.getAnnotations(new Peak(scan.getPrecursorMZ(),.0)); if(peakAnnotations!=null){ for(Vector<Annotation> structureToAnnotations:peakAnnotations.getAnnotations()){ for(Annotation annotation:structureToAnnotations){ scan.getStructures().addStructure(annotation.getFragmentEntry().fragment); } if(structureToAnnotations.size() > 0){ matchFound=true; } } } }else{ } fireDocumentChanged(this); return matchFound; } public Vector<Scan> getAllScans() { Vector<Scan> ret = new Vector<Scan>(); for( Scan s : theScanList ) getAllScans(s,ret); return ret; } public Vector<Scan> getAllParentScans(){ Vector<Scan> ret = new Vector<Scan>(); ret.addAll(theScanList); return ret; } private void getAllScans(Scan s, Vector<Scan> dst) { dst.add(s); for( Scan c : s.getChildren() ) getAllScans(c,dst); } public Scan findInternalDocument(BaseDocument doc) { if( doc!=null ) { for( Scan s : theScanList ) { Scan ret = s.findInternalDocument(doc); if( ret!=null ) return ret; } } return null; } public boolean addAnnotationReport(AnnotationReportDocument ard) { if( ard==null || currentScan==null ) return false; currentScan.getAnnotationReports().add(ard); ard.addDocumentChangeListener(this); fireDocumentChanged(); return true; } public boolean removeAnnotationReport(AnnotationReportDocument ard) { if( ard==null || currentScan==null ) return false; if( !currentScan.getAnnotationReports().contains(ard) ) return false; currentScan.getAnnotationReports().remove(ard); ard.addDocumentChangeListener(this); fireDocumentChanged(); return true; } private void registerListeners(Scan s) { if( s!=null ) { s.getStructures().addDocumentChangeListener(this); s.getFragments().addDocumentChangeListener(this); s.getSpectra().addDocumentChangeListener(this); s.getPeakList().addDocumentChangeListener(this); s.getAnnotatedPeakList().addDocumentChangeListener(this); s.getNotes().addDocumentChangeListener(this); for( AnnotationReportDocument ard : s.getAnnotationReports() ) ard.addDocumentChangeListener(this); } } private void deregisterListeners(Scan s) { if( s!=null ) { s.getStructures().removeDocumentChangeListener(this); s.getFragments().removeDocumentChangeListener(this); s.getSpectra().removeDocumentChangeListener(this); s.getPeakList().removeDocumentChangeListener(this); s.getAnnotatedPeakList().removeDocumentChangeListener(this); s.getNotes().removeDocumentChangeListener(this); for( AnnotationReportDocument ard : s.getAnnotationReports() ) ard.removeDocumentChangeListener(this); } } private void addListeners(Scan node) { if( node==null ) return; registerListeners(node); for( Scan s : node.getChildren()) addListeners(s); } private void removeListeners(Scan node) { if( node==null ) return; deregisterListeners(node); for( Scan s : node.getChildren()) removeListeners(s); } public void setPrecursorMZ(Scan s, Double mz) { if( s!=null ) { s.setPrecursorMZ(mz); //fireCurrentScanChanged(new Event(this,s.getParent(),s,-1,s)); setChanged(true); fireInternalDocumentChanged(s); } } public void setMsMs(Scan s, boolean f) { if( s!=null ) { s.setMsMs(f); setChanged(true); fireInternalDocumentChanged(s); } } public boolean isCurrent(Scan s) { return currentScan==s; } public Plugin getSearchGenerator() { return theSearchGenerator; } public void setSearchGenerator(Plugin p) { theSearchGenerator = p; } public AnnotatedPeakList getSearchResults() { return theSearchResults; } public GlycanDocument getStructures() { return currentScan.getStructures(); } public FragmentDocument getFragments() { return currentScan.getFragments(); } public SpectraDocument getSpectra() { return currentScan.getSpectra(); } public PeakList getPeakList() { return currentScan.getPeakList(); } public AnnotatedPeakList getAnnotatedPeakList() { return currentScan.getAnnotatedPeakList(); } public NotesDocument getNotes() { return currentScan.getNotes(); } public Collection<AnnotationReportDocument> getAnnotationReports() { return currentScan.getAnnotationReports(); } public Collection<BaseDocument> getAllDocuments() { Vector<BaseDocument> ret = new Vector<BaseDocument>(); ret.add(this); ret.add(new AnnotationReportDocument()); ret.add(currentScan.getNotes()); ret.add(currentScan.getSpectra()); ret.add(currentScan.getAnnotatedPeakList()); ret.add(currentScan.getPeakList()); ret.add(currentScan.getFragments()); ret.add(currentScan.getStructures()); return ret; } public Collection<BaseDocument> getUnsavedDocuments() { Vector<BaseDocument> ret = new Vector<BaseDocument>(); for(Scan s : theScanList) getUnsavedDocuments(ret,s); return ret; } private void getUnsavedDocuments(Vector<BaseDocument> buffer, Scan scan) { if( scan.getStructures().hasChanged() ) buffer.add(scan.getStructures()); if( scan.getFragments().hasChanged() ) buffer.add(scan.getFragments()); if( scan.getSpectra().hasChanged() ) buffer.add(scan.getSpectra()); if( scan.getPeakList().hasChanged() ) buffer.add(scan.getPeakList()); if( scan.getAnnotatedPeakList().hasChanged() ) buffer.add(scan.getAnnotatedPeakList()); if( scan.getNotes().hasChanged() ) buffer.add(scan.getNotes()); for( AnnotationReportDocument ard : scan.getAnnotationReports() ) if( ard.hasChanged() ) buffer.add(ard); for( Scan c : scan.getChildren() ) getUnsavedDocuments(buffer,c); } public void resetChanges() { this.resetStatus(); for(Scan s : theScanList) resetChanges(s); fireDocumentInit(); } private void resetChanges(Scan s) { s.getStructures().resetStatus(); s.getFragments().resetStatus(); s.getSpectra().resetStatus(); s.getPeakList().resetStatus(); s.getAnnotatedPeakList().resetStatus(); s.getNotes().resetStatus(); for( AnnotationReportDocument ard : s.getAnnotationReports() ) ard.resetStatus(); for( Scan c : s.getChildren() ) resetChanges(c); } // listeners public void addWorkspaceListener(Listener l) { if( l!=null ) gw_listeners.add(l); } public void removeWorkspaceListener(Listener l) { gw_listeners.remove(l); } public void fireCurrentScanChanged(Event e) { for( Listener l : gw_listeners ) l.currentScanChanged(e); } public void fireScanAdded(Event e) { for( Listener l : gw_listeners ) l.scanAdded(e); } public void fireScanRemoved(Event e) { for( Listener l : gw_listeners ) l.scanRemoved(e); } public void fireInternalDocumentChanged(BaseDocument doc) { Scan s = findInternalDocument(doc); fireInternalDocumentChanged(s); } public void fireInternalDocumentChanged(Scan s) { if( s==null || gw_listeners==null ) return; Event e = new Event(this,s,null,-1,currentScan); for( Listener l : gw_listeners ) l.internalDocumentChanged(e); } public void fireDocumentInit() { for(Scan s : theScanList) fireDocumentInit(s); super.fireDocumentInit(); } private void fireDocumentInit(Scan s) { s.getStructures().fireDocumentInit(); s.getFragments().fireDocumentInit(); s.getSpectra().fireDocumentInit(); s.getPeakList().fireDocumentInit(); s.getAnnotatedPeakList().fireDocumentInit(); s.getNotes().fireDocumentInit(); for( AnnotationReportDocument ard : s.getAnnotationReports() ) ard.fireDocumentInit(); for( Scan c : s.getChildren() ) fireDocumentInit(c); } public void documentInit(BaseDocument.DocumentChangeEvent e) { // there's a change in some internal document setChanged(true); fireInternalDocumentChanged((BaseDocument)e.getSource()); } public void documentChanged(BaseDocument.DocumentChangeEvent e) { // there's a change in some internal document setChanged(true); fireInternalDocumentChanged((BaseDocument)e.getSource()); } // serialization protected void read(InputStream is, boolean merge) throws Exception { /*Document document = XMLUtils.read(is); if( document==null ) throw new Exception("Cannot read from string"); fromXML(XMLUtils.assertChild(document,"GlycanWorkspace"),merge);*/ SAXUtils.read(is,new SAXHandler(this,merge)); } public void write(OutputStream os) throws Exception { /* Document document = XMLUtils.newDocument(); document.appendChild(toXML(document)); XMLUtils.write(fos,document); */ SAXUtils.write(os,this); } public String toString() { try{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); write(bos); return bos.toString(); } catch(Exception e) { LogUtils.report(e); return ""; } } public void fromString(String str, boolean merge) throws Exception { ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes()); read(bis,merge); } public void fromXML(Node w_node, boolean merge) throws Exception { resetStatus(); // set configuration //Node c_node = XMLUtils.assertChild(w_node,"Configuration"); //theConfiguration = Configuration.fromXML(c_node); //retrieveFromConfiguration(); if( !merge ) theScanList = new Vector<Scan>(); // set scan list Vector<Node> s_nodes = XMLUtils.findAllChildren(w_node, "Scan"); for( Node s_node : s_nodes) { Scan read = Scan.fromXML(this,s_node); theScanList.add(read); addListeners(read); } currentScan = getFirstScan(); // set glycan document Node gd_node = XMLUtils.findChild(w_node,"Structures"); if( gd_node!=null ) currentScan.getStructures().fromXML(gd_node,merge); } public Element toXML(Document document) { if( document==null ) return null; // create root node Element w_node = document.createElement("GlycanWorkspace"); // create configuration node storeToConfiguration(true); w_node.appendChild(theConfiguration.toXML(document)); // create scan node for(Scan s : theScanList) w_node.appendChild(s.toXML(document)); return w_node; } public static class SAXHandler extends SAXUtils.ObjectTreeHandler { private GlycanWorkspace theDocument; private boolean merge; public SAXHandler(GlycanWorkspace _doc, boolean _merge) { theDocument = _doc; merge = _merge; } public boolean isElement(String namespaceURI, String localName, String qName) { return qName.equals(getNodeElementName()); } public static String getNodeElementName() { return "GlycanWorkspace"; } protected SAXUtils.ObjectTreeHandler getHandler(String namespaceURI, String localName, String qName) { if( qName.equals(GlycanDocument.SAXHandler.getNodeElementName()) ) return new GlycanDocument.SAXHandler(new GlycanDocument(theDocument),merge); if( qName.equals(Scan.SAXHandler.getNodeElementName()) ) return new Scan.SAXHandler(theDocument); return null; } protected Object finalizeContent(String namespaceURI, String localName, String qName) throws SAXException{ // clear if( !merge ) { // clear changed status theDocument.resetStatus(); // remove listeners for( Scan s : theDocument.theScanList ) theDocument.removeListeners(s); // init scans theDocument.theScanList = new Vector<Scan>(); } else { // set changed status theDocument.setChanged(true); } // set scan list for( Object o : getSubObjects(Scan.SAXHandler.getNodeElementName()) ) { theDocument.theScanList.add((Scan)o); theDocument.addListeners((Scan)o); } theDocument.currentScan = theDocument.getFirstScan(); // set glycan document GlycanDocument gd = (GlycanDocument)getSubObject(GlycanDocument.SAXHandler.getNodeElementName(),false); if( gd!=null ) theDocument.currentScan.getStructures().setStructures(gd.getStructures()); return (object = theDocument); } } public void write(TransformerHandler th) throws SAXException { th.startElement("","","GlycanWorkspace",new AttributesImpl()); // add configuration storeToConfiguration(true); theConfiguration.write(th); // add scans for(Scan s : theScanList) s.write(th); th.endElement("","","GlycanWorkspace"); } }