X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fstructure%2FStructureSelectionManager.java;fp=src%2Fjalview%2Fstructure%2FStructureSelectionManager.java;h=ed5ee2d4cb4afb58a51d8695075c536cdc1f76f5;hb=cf491d18e6affbfacfc67eda7c6bceedd457982f;hp=af0079870b139f6d4230a701df32371c7729fc68;hpb=5dc62d509b6d0f90f3545bf40b272390410eda45;p=jalview.git diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index af00798..ed5ee2d 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -1,6 +1,6 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) - * Copyright (C) 2014 The Jalview Authors + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * @@ -22,19 +22,29 @@ package jalview.structure; import jalview.analysis.AlignSeq; import jalview.api.StructureSelectionManagerProvider; +import jalview.commands.CommandI; +import jalview.commands.EditCommand; +import jalview.commands.OrderCommand; import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; import jalview.datamodel.PDBEntry; import jalview.datamodel.SearchResults; import jalview.datamodel.SequenceI; import jalview.io.AppletFormatAdapter; +import jalview.util.MappingUtils; import jalview.util.MessageManager; import java.io.PrintStream; +import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.IdentityHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.Vector; import MCview.Atom; @@ -44,10 +54,28 @@ public class StructureSelectionManager { static IdentityHashMap instances; - StructureMapping[] mappings; + private List mappings = new ArrayList(); - private boolean processSecondaryStructure = false, - secStructServices = false, addTempFacAnnot = false; + private boolean processSecondaryStructure = false; + + private boolean secStructServices = false; + + private boolean addTempFacAnnot = false; + + /* + * Set of any registered mappings between (dataset) sequences. + */ + Set seqmappings = new LinkedHashSet(); + + /* + * Reference counters for the above mappings. Remove mappings when ref count + * goes to zero. + */ + Map seqMappingRefCounts = new HashMap(); + + private List commandListeners = new ArrayList(); + + private List sel_listeners = new ArrayList(); /** * @return true if will try to use external services for processing secondary @@ -115,17 +143,18 @@ public class StructureSelectionManager */ public void reportMapping() { - if (mappings == null) + if (mappings.isEmpty()) { System.err.println("reportMapping: No PDB/Sequence mappings."); } else { - System.err.println("reportMapping: There are " + mappings.length + System.err.println("reportMapping: There are " + mappings.size() + " mappings."); - for (int m = 0; m < mappings.length; m++) + int i = 0; + for (StructureMapping sm : mappings) { - System.err.println("mapping " + m + " : " + mappings[m].pdbfile); + System.err.println("mapping " + i++ + " : " + sm.pdbfile); } } } @@ -246,16 +275,19 @@ public class StructureSelectionManager } } + /** + * Returns the file name for a mapped PDB id (or null if not mapped). + * + * @param pdbid + * @return + */ public String alreadyMappedToFile(String pdbid) { - if (mappings != null) + for (StructureMapping sm : mappings) { - for (int i = 0; i < mappings.length; i++) + if (sm.getPdbId().equals(pdbid)) { - if (mappings[i].getPdbId().equals(pdbid)) - { - return mappings[i].pdbfile; - } + return sm.pdbfile; } } return null; @@ -482,19 +514,7 @@ public class StructureSelectionManager mappingDetails.toString()); if (forStructureView) { - - if (mappings == null) - { - mappings = new StructureMapping[1]; - } - else - { - StructureMapping[] tmp = new StructureMapping[mappings.length + 1]; - System.arraycopy(mappings, 0, tmp, 0, mappings.length); - mappings = tmp; - } - - mappings[mappings.length - 1] = newMapping; + mappings.add(newMapping); } maxChain.transferResidueAnnotation(newMapping, sqmpping); } @@ -546,19 +566,18 @@ public class StructureSelectionManager } } - if (pdbs.size() > 0 && mappings != null) + if (pdbs.size() > 0) { - Vector tmp = new Vector(); - for (int i = 0; i < mappings.length; i++) + List tmp = new ArrayList(); + for (StructureMapping sm : mappings) { - if (!pdbs.contains(mappings[i].pdbfile)) + if (!pdbs.contains(sm.pdbfile)) { - tmp.addElement(mappings[i]); + tmp.add(sm); } } - mappings = new StructureMapping[tmp.size()]; - tmp.copyInto(mappings); + mappings = tmp; } } @@ -569,7 +588,6 @@ public class StructureSelectionManager // old or prematurely sent event return; } - boolean hasSequenceListeners = handlingVamsasMo || seqmappings != null; SearchResults results = null; SequenceI lastseq = null; int lastipos = -1, indexpos; @@ -581,33 +599,21 @@ public class StructureSelectionManager { results = new SearchResults(); } - if (mappings != null) + for (StructureMapping sm : mappings) { - for (int j = 0; j < mappings.length; j++) + if (sm.pdbfile.equals(pdbfile) && sm.pdbchain.equals(chain)) { - if (mappings[j].pdbfile.equals(pdbfile) - && mappings[j].pdbchain.equals(chain)) + indexpos = sm.getSeqPos(pdbResNum); + if (lastipos != indexpos && lastseq != sm.sequence) { - indexpos = mappings[j].getSeqPos(pdbResNum); - if (lastipos != indexpos && lastseq != mappings[j].sequence) + results.addResult(sm.sequence, indexpos, indexpos); + lastipos = indexpos; + lastseq = sm.sequence; + // construct highlighted sequence list + for (AlignedCodonFrame acf : seqmappings) { - 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()) - - { - ((AlignedCodonFrame) e.nextElement()).markMappedRegion( - mappings[j].sequence, indexpos, results); - } - } + acf.markMappedRegion(sm.sequence, indexpos, results); } - } } } @@ -626,13 +632,11 @@ public class StructureSelectionManager } } - Vector seqmappings = null; // should be a simpler list of mapped seuqence - /** * highlight regions associated with a position (indexpos) in seq * * @param seq - * the sequeence that the mouse over occured on + * the sequence that the mouse over occurred on * @param indexpos * the absolute position being mouseovered in seq (0 to seq.length()) * @param index @@ -642,93 +646,54 @@ public class StructureSelectionManager public void mouseOverSequence(SequenceI seq, int indexpos, int index, VamsasSource source) { - boolean hasSequenceListeners = handlingVamsasMo || seqmappings != null; + boolean hasSequenceListeners = handlingVamsasMo + || !seqmappings.isEmpty(); SearchResults results = null; if (index == -1) { index = seq.findPosition(indexpos); } - StructureListener sl; - int atomNo = 0; for (int i = 0; i < listeners.size(); i++) { Object listener = listeners.elementAt(i); if (listener == source) { + // TODO listener (e.g. SeqPanel) is never == source (AlignViewport) + // Temporary fudge with SequenceListener.getVamsasSource() 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 - || mappings[j].sequence == seq.getDatasetSequence()) - { - atomNo = mappings[j].getAtomNum(index); - - if (atomNo > 0) - { - sl.highlightAtom(atomNo, mappings[j].getPDBResNum(index), - mappings[j].pdbchain, mappings[j].pdbfile); - } - } - } + highlightStructure((StructureListener) listener, seq, index); } else { - if (relaySeqMappings && hasSequenceListeners - && listener instanceof SequenceListener) + if (listener instanceof SequenceListener) { - // DEBUG - // System.err.println("relay Seq " + seq.getDisplayId(false) + " " + - // index); - - if (results == null) + final SequenceListener seqListener = (SequenceListener) listener; + if (hasSequenceListeners + && seqListener.getVamsasSource() != source) { - results = new SearchResults(); - if (index >= seq.getStart() && index <= seq.getEnd()) + if (relaySeqMappings) { - // construct highlighted sequence list - - if (seqmappings != null) + if (results == null) { - Enumeration e = seqmappings.elements(); - while (e.hasMoreElements()) - - { - ((AlignedCodonFrame) e.nextElement()).markMappedRegion( - seq, index, results); - } + results = MappingUtils.buildSearchResults(seq, index, + seqmappings); } - // hasSequenceListeners = results.getSize() > 0; if (handlingVamsasMo) { - // maybe have to resolve seq to a dataset seqeunce... - // add in additional direct sequence and/or dataset sequence - // highlighting results.addResult(seq, index, index); + } + seqListener.highlightSequence(results); } } - if (hasSequenceListeners) - { - ((SequenceListener) listener).highlightSequence(results); - } } else if (listener instanceof VamsasListener && !handlingVamsasMo) { - // DEBUG - // System.err.println("Vamsas from Seq " + seq.getDisplayId(false) + " - // " + - // index); - // pass the mouse over and absolute position onto the - // VamsasListener(s) - ((VamsasListener) listener).mouseOver(seq, indexpos, source); + ((VamsasListener) listener).mouseOverSequence(seq, indexpos, + source); } else if (listener instanceof SecondaryStructureListener) { @@ -740,6 +705,35 @@ public class StructureSelectionManager } /** + * Send suitable messages to a StructureListener to highlight atoms + * corresponding to the given sequence position. + * + * @param sl + * @param seq + * @param index + */ + protected void highlightStructure(StructureListener sl, SequenceI seq, + int index) + { + int atomNo; + List atoms = new ArrayList(); + for (StructureMapping sm : mappings) + { + if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence()) + { + atomNo = sm.getAtomNum(index); + + if (atomNo > 0) + { + atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain, sm + .getPDBResNum(index), atomNo)); + } + } + } + sl.highlightAtoms(atoms); + } + + /** * true if a mouse over event from an external (ie Vamsas) source is being * handled */ @@ -825,119 +819,114 @@ public class StructureSelectionManager public StructureMapping[] getMapping(String pdbfile) { - Vector tmp = new Vector(); - if (mappings != null) - { - for (int i = 0; i < mappings.length; i++) + List tmp = new ArrayList(); + for (StructureMapping sm : mappings) { - if (mappings[i].pdbfile.equals(pdbfile)) + if (sm.pdbfile.equals(pdbfile)) { - tmp.addElement(mappings[i]); + tmp.add(sm); } - } } - StructureMapping[] ret = new StructureMapping[tmp.size()]; - for (int i = 0; i < tmp.size(); i++) - { - ret[i] = (StructureMapping) tmp.elementAt(i); - } - - return ret; + return tmp.toArray(new StructureMapping[tmp.size()]); } public String printMapping(String pdbfile) { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < mappings.length; i++) + StringBuilder sb = new StringBuilder(64); + for (StructureMapping sm : mappings) { - if (mappings[i].pdbfile.equals(pdbfile)) + if (sm.pdbfile.equals(pdbfile)) { - sb.append(mappings[i].mappingDetails); + sb.append(sm.mappingDetails); } } return sb.toString(); } - private int[] seqmappingrefs = null; // refcount for seqmappings elements - - private synchronized void modifySeqMappingList(boolean add, - AlignedCodonFrame[] codonFrames) + /** + * Decrement the reference counter for each of the given mappings, and remove + * it entirely if its reference counter reduces to zero. + * + * @param set + */ + public void removeMappings(Set set) { - if (!add && (seqmappings == null || seqmappings.size() == 0)) - { - return; - } - if (seqmappings == null) + if (set != null) { - seqmappings = new Vector(); + for (AlignedCodonFrame acf : set) + { + removeMapping(acf); + } } - if (codonFrames != null && codonFrames.length > 0) + } + + /** + * Decrement the reference counter for the given mapping, and remove it + * entirely if its reference counter reduces to zero. + * + * @param acf + */ + public void removeMapping(AlignedCodonFrame acf) + { + if (acf != null && seqmappings.contains(acf)) { - for (int cf = 0; cf < codonFrames.length; cf++) + int count = seqMappingRefCounts.get(acf); + count--; + if (count > 0) { - if (seqmappings.contains(codonFrames[cf])) - { - if (add) - { - seqmappingrefs[seqmappings.indexOf(codonFrames[cf])]++; - } - else - { - if (--seqmappingrefs[seqmappings.indexOf(codonFrames[cf])] <= 0) - { - int pos = seqmappings.indexOf(codonFrames[cf]); - int[] nr = new int[seqmappingrefs.length - 1]; - if (pos > 0) - { - System.arraycopy(seqmappingrefs, 0, nr, 0, pos); - } - if (pos < seqmappingrefs.length - 1) - { - System.arraycopy(seqmappingrefs, pos + 1, nr, 0, - seqmappingrefs.length - pos - 2); - } - } - } - } - else - { - if (add) - { - seqmappings.addElement(codonFrames[cf]); - - int[] nsr = new int[(seqmappingrefs == null) ? 1 - : seqmappingrefs.length + 1]; - if (seqmappingrefs != null && seqmappingrefs.length > 0) - { - System.arraycopy(seqmappingrefs, 0, nsr, 0, - seqmappingrefs.length); - } - nsr[(seqmappingrefs == null) ? 0 : seqmappingrefs.length] = 1; - seqmappingrefs = nsr; - } - } + seqMappingRefCounts.put(acf, count); + } + else + { + seqmappings.remove(acf); + seqMappingRefCounts.remove(acf); } } } - public void removeMappings(AlignedCodonFrame[] codonFrames) + /** + * Add each of the given codonFrames to the stored set. If not aready present, + * increments its reference count instead. + * + * @param set + */ + public void addMappings(Set set) { - modifySeqMappingList(false, codonFrames); + if (set != null) + { + for (AlignedCodonFrame acf : set) + { + addMapping(acf); + } + } } - public void addMappings(AlignedCodonFrame[] codonFrames) + /** + * Add the given mapping to the stored set, or if already stored, increment + * its reference counter. + */ + public void addMapping(AlignedCodonFrame acf) { - modifySeqMappingList(true, codonFrames); + if (acf != null) + { + if (seqmappings.contains(acf)) + { + seqMappingRefCounts.put(acf, seqMappingRefCounts.get(acf) + 1); + } + else + { + seqmappings.add(acf); + seqMappingRefCounts.put(acf, 1); + } + } } - Vector sel_listeners = new Vector(); - public void addSelectionListener(SelectionListener selecter) { if (!sel_listeners.contains(selecter)) { - sel_listeners.addElement(selecter); + sel_listeners.add(selecter); } } @@ -945,7 +934,7 @@ public class StructureSelectionManager { if (sel_listeners.contains(toremove)) { - sel_listeners.removeElement(toremove); + sel_listeners.remove(toremove); } } @@ -953,18 +942,11 @@ public class StructureSelectionManager jalview.datamodel.SequenceGroup selection, jalview.datamodel.ColumnSelection colsel, SelectionSource source) { - if (sel_listeners != null && sel_listeners.size() > 0) + for (SelectionListener slis : sel_listeners) { - Enumeration listeners = sel_listeners.elements(); - while (listeners.hasMoreElements()) + if (slis != source) { - SelectionListener slis = ((SelectionListener) listeners - .nextElement()); - if (slis != source) - { - slis.selection(selection, colsel, source); - } - ; + slis.selection(selection, colsel, source); } } } @@ -992,32 +974,6 @@ public class StructureSelectionManager } } - public void finalize() throws Throwable - { - if (listeners != null) - { - listeners.clear(); - listeners = null; - } - if (pdbIdFileName != null) - { - pdbIdFileName.clear(); - pdbIdFileName = 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 * @@ -1041,7 +997,6 @@ public class StructureSelectionManager } catch (Throwable x) { } - ; } } } @@ -1055,4 +1010,67 @@ public class StructureSelectionManager } } + public void addCommandListener(CommandListener cl) + { + if (!commandListeners.contains(cl)) + { + commandListeners.add(cl); + } + } + + public boolean hasCommandListener(CommandListener cl) + { + return this.commandListeners.contains(cl); + } + + public boolean removeCommandListener(CommandListener l) + { + return commandListeners.remove(l); + } + + /** + * Forward a command to any command listeners (except for the command's + * source). + * + * @param command + * the command to be broadcast (in its form after being performed) + * @param undo + * if true, the command was being 'undone' + * @param source + */ + public void commandPerformed(CommandI command, boolean undo, + VamsasSource source) + { + for (CommandListener listener : commandListeners) + { + listener.mirrorCommand(command, undo, this, source); + } + } + + /** + * Returns a new CommandI representing the given command as mapped to the + * given sequences. If no mapping could be made, or the command is not of a + * mappable kind, returns null. + * + * @param command + * @param undo + * @param mapTo + * @param gapChar + * @return + */ + public CommandI mapCommand(CommandI command, boolean undo, + final AlignmentI mapTo, char gapChar) + { + if (command instanceof EditCommand) + { + return MappingUtils.mapEditCommand((EditCommand) command, undo, + mapTo, gapChar, seqmappings); + } + else if (command instanceof OrderCommand) + { + return MappingUtils.mapOrderCommand((OrderCommand) command, undo, + mapTo, seqmappings); + } + return null; + } }