X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fstructure%2FStructureSelectionManager.java;h=5a9e382369288c89e3bb84a89a615deb9a139162;hb=865a855a4ca87eadb3e5ff284ed32ed307d9c34b;hp=483f1a4f8858e1a950fa0de7455adad3c7016982;hpb=429079d152295a6418732fdccc369597c5216c9b;p=jalview.git diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index 483f1a4..5a9e382 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -1,19 +1,20 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5) - * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1) + * Copyright (C) 2014 The Jalview Authors * * This file is part of Jalview. * * Jalview 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, either version 3 of the License, or (at your option) any later version. - * + * * Jalview 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 Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.structure; @@ -22,23 +23,54 @@ import java.util.*; import MCview.*; import jalview.analysis.*; +import jalview.api.AlignmentViewPanel; +import jalview.api.StructureSelectionManagerProvider; import jalview.datamodel.*; public class StructureSelectionManager { - static StructureSelectionManager instance; + static IdentityHashMap instances; StructureMapping[] mappings; + /** + * debug function - write all mappings to stdout + */ + public void reportMapping() + { + if (mappings == null) + { + System.err.println("reportMapping: No PDB/Sequence mappings."); + } + else + { + System.err.println("reportMapping: There are " + mappings.length + + " mappings."); + for (int m = 0; m < mappings.length; m++) + { + System.err.println("mapping " + m + " : " + mappings[m].pdbfile); + } + } + } + Hashtable mappingData = new Hashtable(); - public static StructureSelectionManager getStructureSelectionManager() + public static StructureSelectionManager getStructureSelectionManager( + StructureSelectionManagerProvider context) { + if (context==null) + { + throw new Error("Implementation error. Structure selection manager's context is 'null'", new NullPointerException("SSM context is null")); + } + if (instances == null) + { + instances = new java.util.IdentityHashMap(); + } + StructureSelectionManager instance = instances.get(context); if (instance == null) { - instance = new StructureSelectionManager(); + instances.put(context, instance = new StructureSelectionManager()); } - return instance; } @@ -73,6 +105,11 @@ public class StructureSelectionManager Vector listeners = new Vector(); + /** + * register a listener for alignment sequence mouseover events + * + * @param svl + */ public void addStructureViewerListener(Object svl) { if (!listeners.contains(svl)) @@ -96,13 +133,28 @@ public class StructureSelectionManager return null; } - /* - * There will be better ways of doing this in the future, for now we'll use - * the tried and tested MCview pdb mapping + /** + * create sequence structure mappings between each sequence and the given + * pdbFile (retrieved via the given protocol). + * + * @param sequence + * - one or more sequences to be mapped to pdbFile + * @param targetChains + * - optional chain specification for mapping each sequence to pdb + * (may be nill, individual elements may be nill) + * @param pdbFile + * - structure data resource + * @param protocol + * - how to resolve data from resource + * @return null or the structure data parsed as a pdb file */ synchronized public MCview.PDBfile setMapping(SequenceI[] sequence, String[] targetChains, String pdbFile, String protocol) { + /* + * There will be better ways of doing this in the future, for now we'll use + * the tried and tested MCview pdb mapping + */ MCview.PDBfile pdb = null; try { @@ -116,12 +168,28 @@ public class StructureSelectionManager String targetChain; for (int s = 0; s < sequence.length; s++) { + boolean infChain = true; if (targetChains != null && targetChains[s] != null) + { + infChain = false; targetChain = targetChains[s]; + } else if (sequence[s].getName().indexOf("|") > -1) { targetChain = sequence[s].getName().substring( sequence[s].getName().lastIndexOf("|") + 1); + if (targetChain.length() > 1) + { + if (targetChain.trim().length() == 0) + { + targetChain = " "; + } + else + { + // not a valid chain identifier + targetChain = ""; + } + } } else targetChain = ""; @@ -130,27 +198,38 @@ public class StructureSelectionManager AlignSeq maxAlignseq = null; String maxChainId = " "; PDBChain maxChain = null; - + boolean first = true; for (int i = 0; i < pdb.chains.size(); i++) { - - // TODO: correctly determine sequence type for mixed na/peptide structures - AlignSeq as = new AlignSeq(sequence[s], ((PDBChain) pdb.chains - .elementAt(i)).sequence, ((PDBChain)pdb.chains.elementAt(i)).isNa ? AlignSeq.DNA : AlignSeq.PEP); + PDBChain chain = ((PDBChain) pdb.chains.elementAt(i)); + if (targetChain.length() > 0 && !targetChain.equals(chain.id) + && !infChain) + { + continue; // don't try to map chains don't match. + } + // TODO: correctly determine sequence type for mixed na/peptide + // structures + AlignSeq as = new AlignSeq(sequence[s], + ((PDBChain) pdb.chains.elementAt(i)).sequence, + ((PDBChain) pdb.chains.elementAt(i)).isNa ? AlignSeq.DNA + : AlignSeq.PEP); as.calcScoreMatrix(); as.traceAlignment(); - PDBChain chain = ((PDBChain) pdb.chains.elementAt(i)); - if (as.maxscore > max + if (first || as.maxscore > max || (as.maxscore == max && chain.id.equals(targetChain))) { + first = false; maxChain = chain; max = as.maxscore; maxAlignseq = as; maxChainId = chain.id; } } - + if (maxChain == null) + { + continue; + } final StringBuffer mappingDetails = new StringBuffer(); mappingDetails.append("\n\nPDB Sequence is :\nSequence = " + maxChain.sequence.getSequenceAsString()); @@ -181,7 +260,10 @@ public class StructureSelectionManager maxChain.transferRESNUMFeatures(sequence[s], null); - int[][] mapping = new int[sequence[s].getEnd() + 2][2]; + // allocate enough slots to store the mapping from positions in + // sequence[s] to the associated chain + int[][] mapping = new int[sequence[s].findPosition(sequence[s] + .getLength()) + 2][2]; int resNum = -10000; int index = 0; @@ -213,8 +295,8 @@ public class StructureSelectionManager pdbFile = "INLINE" + pdb.id; mappings[mappings.length - 1] = new StructureMapping(sequence[s], - pdbFile, pdb.id, maxChainId, mapping, mappingDetails - .toString()); + pdbFile, pdb.id, maxChainId, mapping, + mappingDetails.toString()); maxChain.transferResidueAnnotation(mappings[mappings.length - 1]); } // /////// @@ -222,32 +304,54 @@ public class StructureSelectionManager return pdb; } - public void removeStructureViewerListener(Object svl, String pdbfile) + public void removeStructureViewerListener(Object svl, String[] pdbfiles) { listeners.removeElement(svl); + if (svl instanceof SequenceListener) + { + for (int i = 0; i < listeners.size(); i++) + { + if (listeners.elementAt(i) instanceof StructureListener) + { + ((StructureListener) listeners.elementAt(i)) + .releaseReferences(svl); + } + } + } + if (pdbfiles == null) + { + return; + } boolean removeMapping = true; - + String[] handlepdbs; + Vector pdbs = new Vector(); + for (int i = 0; i < pdbfiles.length; pdbs.addElement(pdbfiles[i++])) + ; StructureListener sl; for (int i = 0; i < listeners.size(); i++) { if (listeners.elementAt(i) instanceof StructureListener) { sl = (StructureListener) listeners.elementAt(i); - if (sl.getPdbFile().equals(pdbfile)) + handlepdbs = sl.getPdbFile(); + for (int j = 0; j < handlepdbs.length; j++) { - removeMapping = false; - break; + if (pdbs.contains(handlepdbs[j])) + { + pdbs.removeElement(handlepdbs[j]); + } } + } } - if (removeMapping && mappings != null) + if (pdbs.size() > 0 && mappings != null) { Vector tmp = new Vector(); for (int i = 0; i < mappings.length; i++) { - if (!mappings[i].pdbfile.equals(pdbfile)) + if (!pdbs.contains(mappings[i].pdbfile)) { tmp.addElement(mappings[i]); } @@ -260,8 +364,15 @@ public class StructureSelectionManager public void mouseOverStructure(int pdbResNum, String chain, String pdbfile) { + if (listeners == null) + { + // old or prematurely sent event + return; + } boolean hasSequenceListeners = handlingVamsasMo || seqmappings != null; SearchResults results = null; + SequenceI lastseq = null; + int lastipos = -1, indexpos; for (int i = 0; i < listeners.size(); i++) { if (listeners.elementAt(i) instanceof SequenceListener) @@ -270,31 +381,39 @@ public class StructureSelectionManager { results = new SearchResults(); } - int indexpos; - for (int j = 0; j < mappings.length; j++) + if (mappings != null) { - if (mappings[j].pdbfile.equals(pdbfile) - && mappings[j].pdbchain.equals(chain)) + for (int j = 0; j < mappings.length; j++) { - indexpos = mappings[j].getSeqPos(pdbResNum); - results.addResult(mappings[j].sequence, indexpos, indexpos); - // construct highlighted sequence list - if (seqmappings != null) + if (mappings[j].pdbfile.equals(pdbfile) + && mappings[j].pdbchain.equals(chain)) { + indexpos = mappings[j].getSeqPos(pdbResNum); + if (lastipos != indexpos && lastseq != mappings[j].sequence) + { + results.addResult(mappings[j].sequence, indexpos, indexpos); + lastipos = indexpos; + lastseq = mappings[j].sequence; + // construct highlighted sequence list + if (seqmappings != null) + { - Enumeration e = seqmappings.elements(); - while (e.hasMoreElements()) + Enumeration e = seqmappings.elements(); + while (e.hasMoreElements()) - { - ((AlignedCodonFrame) e.nextElement()).markMappedRegion( - mappings[j].sequence, indexpos, results); + { + ((AlignedCodonFrame) e.nextElement()).markMappedRegion( + mappings[j].sequence, indexpos, results); + } + } } + } } } } } - if (results.getSize() > 0) + if (results != null) { for (int i = 0; i < listeners.size(); i++) { @@ -318,7 +437,8 @@ public class StructureSelectionManager * the sequence position (if -1, seq.findPosition is called to * resolve the residue number) */ - public void mouseOverSequence(SequenceI seq, int indexpos, int index) + public void mouseOverSequence(SequenceI seq, int indexpos, int index, + VamsasSource source) { boolean hasSequenceListeners = handlingVamsasMo || seqmappings != null; SearchResults results = null; @@ -328,10 +448,18 @@ public class StructureSelectionManager int atomNo = 0; for (int i = 0; i < listeners.size(); i++) { - if (listeners.elementAt(i) instanceof StructureListener) + Object listener = listeners.elementAt(i); + if (listener == source) { - sl = (StructureListener) listeners.elementAt(i); - + continue; + } + if (listener instanceof StructureListener) + { + sl = (StructureListener) listener; + if (mappings == null) + { + continue; + } for (int j = 0; j < mappings.length; j++) { if (mappings[j].sequence == seq @@ -350,7 +478,7 @@ public class StructureSelectionManager else { if (relaySeqMappings && hasSequenceListeners - && listeners.elementAt(i) instanceof SequenceListener) + && listener instanceof SequenceListener) { // DEBUG // System.err.println("relay Seq " + seq.getDisplayId(false) + " " + @@ -385,12 +513,10 @@ public class StructureSelectionManager } if (hasSequenceListeners) { - ((SequenceListener) listeners.elementAt(i)) - .highlightSequence(results); + ((SequenceListener) listener).highlightSequence(results); } } - else if (listeners.elementAt(i) instanceof VamsasListener - && !handlingVamsasMo) + else if (listener instanceof VamsasListener && !handlingVamsasMo) { // DEBUG // System.err.println("Vamsas from Seq " + seq.getDisplayId(false) + " @@ -398,8 +524,12 @@ public class StructureSelectionManager // index); // pass the mouse over and absolute position onto the // VamsasListener(s) - ((VamsasListener) listeners.elementAt(i)) - .mouseOver(seq, indexpos); + ((VamsasListener) listener).mouseOver(seq, indexpos, source); + } + else if (listener instanceof SecondaryStructureListener) + { + ((SecondaryStructureListener) listener).mouseOverSequence(seq, + indexpos); } } } @@ -420,14 +550,15 @@ public class StructureSelectionManager * @param position * in an alignment sequence */ - public void mouseOverVamsasSequence(SequenceI sequenceI, int position) + public void mouseOverVamsasSequence(SequenceI sequenceI, int position, + VamsasSource source) { handlingVamsasMo = true; long msg = sequenceI.hashCode() * (1 + position); if (lastmsg != msg) { lastmsg = msg; - mouseOverSequence(sequenceI, position, -1); + mouseOverSequence(sequenceI, position, -1, source); } handlingVamsasMo = false; } @@ -491,14 +622,16 @@ public class StructureSelectionManager public StructureMapping[] getMapping(String pdbfile) { Vector tmp = new Vector(); - for (int i = 0; i < mappings.length; i++) + if (mappings != null) { - if (mappings[i].pdbfile.equals(pdbfile)) + for (int i = 0; i < mappings.length; i++) { - tmp.addElement(mappings[i]); + if (mappings[i].pdbfile.equals(pdbfile)) + { + tmp.addElement(mappings[i]); + } } } - StructureMapping[] ret = new StructureMapping[tmp.size()]; for (int i = 0; i < tmp.size(); i++) { @@ -588,7 +721,7 @@ public class StructureSelectionManager modifySeqMappingList(true, codonFrames); } - Vector sel_listeners = new Vector(); + Vector sel_listeners = new Vector(); public void addSelectionListener(SelectionListener selecter) { @@ -625,4 +758,82 @@ public class StructureSelectionManager } } } + + Vector view_listeners = new Vector(); + + public synchronized void sendViewPosition( + jalview.api.AlignmentViewPanel source, int startRes, int endRes, + int startSeq, int endSeq) + { + + if (view_listeners != null && view_listeners.size() > 0) + { + Enumeration listeners = view_listeners + .elements(); + while (listeners.hasMoreElements()) + { + AlignmentViewPanelListener slis = listeners.nextElement(); + if (slis != source) + { + slis.viewPosition(startRes, endRes, startSeq, endSeq, source); + } + ; + } + } + } + + public void finalize() throws Throwable + { + if (listeners != null) + { + listeners.clear(); + listeners = null; + } + if (mappingData != null) + { + mappingData.clear(); + mappingData = null; + } + if (sel_listeners != null) + { + sel_listeners.clear(); + sel_listeners = null; + } + if (view_listeners != null) + { + view_listeners.clear(); + view_listeners = null; + } + mappings = null; + seqmappingrefs = null; + } + + /** + * release all references associated with this manager provider + * + * @param jalviewLite + */ + public static void release(StructureSelectionManagerProvider jalviewLite) + { + // synchronized (instances) + { + if (instances == null) + { + return; + } + StructureSelectionManager mnger = (instances.get(jalviewLite)); + if (mnger != null) + { + instances.remove(jalviewLite); + try + { + mnger.finalize(); + } catch (Throwable x) + { + } + ; + } + } + } + }