2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.structure;
23 import jalview.analysis.AlignSeq;
24 import jalview.api.AlignmentViewPanel;
25 import jalview.api.StructureSelectionManagerProvider;
26 import jalview.commands.CommandI;
27 import jalview.commands.EditCommand;
28 import jalview.commands.OrderCommand;
29 import jalview.datamodel.AlignedCodonFrame;
30 import jalview.datamodel.AlignmentAnnotation;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.Annotation;
33 import jalview.datamodel.PDBEntry;
34 import jalview.datamodel.SearchResults;
35 import jalview.datamodel.SequenceI;
36 import jalview.gui.AlignFrame;
37 import jalview.gui.Desktop;
38 import jalview.io.AppletFormatAdapter;
39 import jalview.util.MappingUtils;
40 import jalview.util.MessageManager;
42 import java.io.PrintStream;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collections;
46 import java.util.Enumeration;
47 import java.util.HashMap;
48 import java.util.IdentityHashMap;
49 import java.util.LinkedHashSet;
50 import java.util.List;
53 import java.util.Vector;
56 import MCview.PDBChain;
57 import MCview.PDBfile;
59 public class StructureSelectionManager
61 public final static String NEWLINE = System.lineSeparator();
63 static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
65 private List<StructureMapping> mappings = new ArrayList<StructureMapping>();
67 private boolean processSecondaryStructure = false;
69 private boolean secStructServices = false;
71 private boolean addTempFacAnnot = false;
74 * Set of any registered mappings between (dataset) sequences.
76 Set<AlignedCodonFrame> seqmappings = new LinkedHashSet<AlignedCodonFrame>();
78 private List<CommandListener> commandListeners = new ArrayList<CommandListener>();
80 private List<SelectionListener> sel_listeners = new ArrayList<SelectionListener>();
83 * @return true if will try to use external services for processing secondary
86 public boolean isSecStructServices()
88 return secStructServices;
92 * control use of external services for processing secondary structure
94 * @param secStructServices
96 public void setSecStructServices(boolean secStructServices)
98 this.secStructServices = secStructServices;
102 * flag controlling addition of any kind of structural annotation
104 * @return true if temperature factor annotation will be added
106 public boolean isAddTempFacAnnot()
108 return addTempFacAnnot;
112 * set flag controlling addition of structural annotation
114 * @param addTempFacAnnot
116 public void setAddTempFacAnnot(boolean addTempFacAnnot)
118 this.addTempFacAnnot = addTempFacAnnot;
123 * @return if true, the structure manager will attempt to add secondary
124 * structure lines for unannotated sequences
127 public boolean isProcessSecondaryStructure()
129 return processSecondaryStructure;
133 * Control whether structure manager will try to annotate mapped sequences
134 * with secondary structure from PDB data.
138 public void setProcessSecondaryStructure(boolean enable)
140 processSecondaryStructure = enable;
144 * debug function - write all mappings to stdout
146 public void reportMapping()
148 if (mappings.isEmpty())
150 System.err.println("reportMapping: No PDB/Sequence mappings.");
154 System.err.println("reportMapping: There are " + mappings.size()
157 for (StructureMapping sm : mappings)
159 System.err.println("mapping " + i++ + " : " + sm.pdbfile);
165 * map between the PDB IDs (or structure identifiers) used by Jalview and the
166 * absolute filenames for PDB data that corresponds to it
168 Map<String, String> pdbIdFileName = new HashMap<String, String>();
170 Map<String, String> pdbFileNameId = new HashMap<String, String>();
172 public void registerPDBFile(String idForFile, String absoluteFile)
174 pdbIdFileName.put(idForFile, absoluteFile);
175 pdbFileNameId.put(absoluteFile, idForFile);
178 public String findIdForPDBFile(String idOrFile)
180 String id = pdbFileNameId.get(idOrFile);
184 public String findFileForPDBId(String idOrFile)
186 String id = pdbIdFileName.get(idOrFile);
190 public boolean isPDBFileRegistered(String idOrFile)
192 return pdbFileNameId.containsKey(idOrFile)
193 || pdbIdFileName.containsKey(idOrFile);
196 private static StructureSelectionManager nullProvider = null;
198 public static StructureSelectionManager getStructureSelectionManager(
199 StructureSelectionManagerProvider context)
203 if (nullProvider == null)
205 if (instances != null)
209 .getString("error.implementation_error_structure_selection_manager_null"),
210 new NullPointerException(MessageManager
211 .getString("exception.ssm_context_is_null")));
215 nullProvider = new StructureSelectionManager();
220 if (instances == null)
222 instances = new java.util.IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager>();
224 StructureSelectionManager instance = instances.get(context);
225 if (instance == null)
227 if (nullProvider != null)
229 instance = nullProvider;
233 instance = new StructureSelectionManager();
235 instances.put(context, instance);
241 * flag controlling whether SeqMappings are relayed from received sequence
242 * mouse over events to other sequences
244 boolean relaySeqMappings = true;
247 * Enable or disable relay of seqMapping events to other sequences. You might
248 * want to do this if there are many sequence mappings and the host computer
253 public void setRelaySeqMappings(boolean relay)
255 relaySeqMappings = relay;
259 * get the state of the relay seqMappings flag.
261 * @return true if sequence mouse overs are being relayed to other mapped
264 public boolean isRelaySeqMappingsEnabled()
266 return relaySeqMappings;
269 Vector listeners = new Vector();
272 * register a listener for alignment sequence mouseover events
276 public void addStructureViewerListener(Object svl)
278 if (!listeners.contains(svl))
280 listeners.addElement(svl);
285 * Returns the file name for a mapped PDB id (or null if not mapped).
290 public String alreadyMappedToFile(String pdbid)
292 for (StructureMapping sm : mappings)
294 if (sm.getPdbId().equals(pdbid))
303 * Import structure data and register a structure mapping for broadcasting
304 * colouring, mouseovers and selection events (convenience wrapper).
307 * - one or more sequences to be mapped to pdbFile
308 * @param targetChains
309 * - optional chain specification for mapping each sequence to pdb
310 * (may be nill, individual elements may be nill)
312 * - structure data resource
314 * - how to resolve data from resource
315 * @return null or the structure data parsed as a pdb file
317 synchronized public PDBfile setMapping(SequenceI[] sequence,
318 String[] targetChains, String pdbFile, String protocol)
320 return setMapping(true, sequence, targetChains, pdbFile, protocol);
324 * create sequence structure mappings between each sequence and the given
325 * pdbFile (retrieved via the given protocol).
327 * @param forStructureView
328 * when true, record the mapping for use in mouseOvers
331 * - one or more sequences to be mapped to pdbFile
332 * @param targetChains
333 * - optional chain specification for mapping each sequence to pdb
334 * (may be nill, individual elements may be nill)
336 * - structure data resource
338 * - how to resolve data from resource
339 * @return null or the structure data parsed as a pdb file
341 synchronized public PDBfile setMapping(boolean forStructureView,
342 SequenceI[] sequence, String[] targetChains, String pdbFile,
346 * There will be better ways of doing this in the future, for now we'll use
347 * the tried and tested MCview pdb mapping
349 boolean parseSecStr = processSecondaryStructure;
350 if (isPDBFileRegistered(pdbFile))
352 for (SequenceI sq : sequence)
355 while (ds.getDatasetSequence() != null)
357 ds = ds.getDatasetSequence();
360 if (ds.getAnnotation() != null)
362 for (AlignmentAnnotation ala : ds.getAnnotation())
364 // false if any annotation present from this structure
365 // JBPNote this fails for jmol/chimera view because the *file* is
366 // passed, not the structure data ID -
367 if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile)))
378 pdb = new PDBfile(addTempFacAnnot, parseSecStr, secStructServices,
380 if (pdb.id != null && pdb.id.trim().length() > 0
381 && AppletFormatAdapter.FILE.equals(protocol))
383 registerPDBFile(pdb.id.trim(), pdbFile);
385 } catch (Exception ex)
387 ex.printStackTrace();
392 for (int s = 0; s < sequence.length; s++)
394 boolean infChain = true;
395 final SequenceI seq = sequence[s];
396 if (targetChains != null && targetChains[s] != null)
399 targetChain = targetChains[s];
401 else if (seq.getName().indexOf("|") > -1)
403 targetChain = seq.getName().substring(
404 seq.getName().lastIndexOf("|") + 1);
405 if (targetChain.length() > 1)
407 if (targetChain.trim().length() == 0)
413 // not a valid chain identifier
424 * Attempt pairwise alignment of the sequence with each chain in the PDB,
425 * and remember the highest scoring chain
428 AlignSeq maxAlignseq = null;
429 String maxChainId = " ";
430 PDBChain maxChain = null;
431 boolean first = true;
432 for (PDBChain chain : pdb.chains)
434 if (targetChain.length() > 0 && !targetChain.equals(chain.id)
437 continue; // don't try to map chains don't match.
439 // TODO: correctly determine sequence type for mixed na/peptide
441 final String type = chain.isNa ? AlignSeq.DNA : AlignSeq.PEP;
442 AlignSeq as = AlignSeq.doGlobalNWAlignment(seq, chain.sequence,
445 // AlignSeq as = new AlignSeq(sequence[s], chain.sequence, type);
446 // as.calcScoreMatrix();
447 // as.traceAlignment();
449 if (first || as.maxscore > max
450 || (as.maxscore == max && chain.id.equals(targetChain)))
456 maxChainId = chain.id;
459 if (maxChain == null)
463 final StringBuilder mappingDetails = new StringBuilder(128);
464 mappingDetails.append(NEWLINE).append("PDB Sequence is :")
465 .append(NEWLINE).append("Sequence = ")
466 .append(maxChain.sequence.getSequenceAsString());
467 mappingDetails.append(NEWLINE).append("No of residues = ")
468 .append(maxChain.residues.size()).append(NEWLINE)
470 PrintStream ps = new PrintStream(System.out)
473 public void print(String x)
475 mappingDetails.append(x);
479 public void println()
481 mappingDetails.append(NEWLINE);
485 maxAlignseq.printAlignment(ps);
487 mappingDetails.append(NEWLINE).append("PDB start/end ");
488 mappingDetails.append(String.valueOf(maxAlignseq.seq2start)).append(
490 mappingDetails.append(String.valueOf(maxAlignseq.seq2end));
492 mappingDetails.append(NEWLINE).append("SEQ start/end ");
493 mappingDetails.append(
494 String.valueOf(maxAlignseq.seq1start + seq.getStart() - 1))
496 mappingDetails.append(String.valueOf(maxAlignseq.seq1end
497 + seq.getEnd() - 1));
499 maxChain.makeExactMapping(maxAlignseq, seq);
500 jalview.datamodel.Mapping sqmpping = maxAlignseq
501 .getMappingFromS1(false);
502 jalview.datamodel.Mapping omap = new jalview.datamodel.Mapping(
503 sqmpping.getMap().getInverse());
504 maxChain.transferRESNUMFeatures(seq, null);
506 // allocate enough slots to store the mapping from positions in
507 // sequence[s] to the associated chain
508 int[][] mapping = new int[seq.findPosition(seq.getLength()) + 2][2];
514 Atom tmp = maxChain.atoms.elementAt(index);
515 if (resNum != tmp.resNumber && tmp.alignmentMapping != -1)
517 resNum = tmp.resNumber;
518 if (tmp.alignmentMapping >= -1)
520 // TODO (JAL-1836) address root cause: negative residue no in PDB file
521 mapping[tmp.alignmentMapping + 1][0] = tmp.resNumber;
522 mapping[tmp.alignmentMapping + 1][1] = tmp.atomIndex;
527 } while (index < maxChain.atoms.size());
529 if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
531 pdbFile = "INLINE" + pdb.id;
533 StructureMapping newMapping = new StructureMapping(seq, pdbFile,
534 pdb.id, maxChainId, mapping, mappingDetails.toString());
535 if (forStructureView)
537 mappings.add(newMapping);
539 maxChain.transferResidueAnnotation(newMapping, sqmpping);
546 public void removeStructureViewerListener(Object svl, String[] pdbfiles)
548 listeners.removeElement(svl);
549 if (svl instanceof SequenceListener)
551 for (int i = 0; i < listeners.size(); i++)
553 if (listeners.elementAt(i) instanceof StructureListener)
555 ((StructureListener) listeners.elementAt(i))
556 .releaseReferences(svl);
561 if (pdbfiles == null)
567 * Remove mappings to the closed listener's PDB files, but first check if
568 * another listener is still interested
570 List<String> pdbs = new ArrayList<String>(Arrays.asList(pdbfiles));
572 StructureListener sl;
573 for (int i = 0; i < listeners.size(); i++)
575 if (listeners.elementAt(i) instanceof StructureListener)
577 sl = (StructureListener) listeners.elementAt(i);
578 for (String pdbfile : sl.getPdbFile())
580 pdbs.remove(pdbfile);
586 * Rebuild the mappings set, retaining only those which are for 'other' PDB
591 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
592 for (StructureMapping sm : mappings)
594 if (!pdbs.contains(sm.pdbfile))
605 * Propagate mouseover of a single position in a structure
611 public void mouseOverStructure(int pdbResNum, String chain, String pdbfile)
613 AtomSpec atomSpec = new AtomSpec(pdbfile, chain, pdbResNum, 0);
614 List<AtomSpec> atoms = Collections.singletonList(atomSpec);
615 mouseOverStructure(atoms);
619 * Propagate mouseover or selection of multiple positions in a structure
623 public void mouseOverStructure(List<AtomSpec> atoms)
625 if (listeners == null)
627 // old or prematurely sent event
630 boolean hasSequenceListener = false;
631 for (int i = 0; i < listeners.size(); i++)
633 if (listeners.elementAt(i) instanceof SequenceListener)
635 hasSequenceListener = true;
638 if (!hasSequenceListener)
643 SearchResults results = new SearchResults();
644 for (AtomSpec atom : atoms)
646 SequenceI lastseq = null;
648 for (StructureMapping sm : mappings)
650 if (sm.pdbfile.equals(atom.getPdbFile())
651 && sm.pdbchain.equals(atom.getChain()))
653 int indexpos = sm.getSeqPos(atom.getPdbResNum());
654 if (lastipos != indexpos && lastseq != sm.sequence)
656 results.addResult(sm.sequence, indexpos, indexpos);
658 lastseq = sm.sequence;
659 // construct highlighted sequence list
660 for (AlignedCodonFrame acf : seqmappings)
662 acf.markMappedRegion(sm.sequence, indexpos, results);
668 for (Object li : listeners)
670 if (li instanceof SequenceListener)
672 ((SequenceListener) li).highlightSequence(results);
678 * highlight regions associated with a position (indexpos) in seq
681 * the sequence that the mouse over occurred on
683 * the absolute position being mouseovered in seq (0 to seq.length())
685 * the sequence position (if -1, seq.findPosition is called to
686 * resolve the residue number)
688 public void mouseOverSequence(SequenceI seq, int indexpos, int index,
691 boolean hasSequenceListeners = handlingVamsasMo
692 || !seqmappings.isEmpty();
693 SearchResults results = null;
696 index = seq.findPosition(indexpos);
698 for (int i = 0; i < listeners.size(); i++)
700 Object listener = listeners.elementAt(i);
701 if (listener == source)
703 // TODO listener (e.g. SeqPanel) is never == source (AlignViewport)
704 // Temporary fudge with SequenceListener.getVamsasSource()
707 if (listener instanceof StructureListener)
709 highlightStructure((StructureListener) listener, seq, index);
713 if (listener instanceof SequenceListener)
715 final SequenceListener seqListener = (SequenceListener) listener;
716 if (hasSequenceListeners
717 && seqListener.getVamsasSource() != source)
719 if (relaySeqMappings)
723 results = MappingUtils.buildSearchResults(seq, index,
726 if (handlingVamsasMo)
728 results.addResult(seq, index, index);
731 if (!results.isEmpty())
733 seqListener.highlightSequence(results);
738 else if (listener instanceof VamsasListener && !handlingVamsasMo)
740 ((VamsasListener) listener).mouseOverSequence(seq, indexpos,
743 else if (listener instanceof SecondaryStructureListener)
745 ((SecondaryStructureListener) listener).mouseOverSequence(seq,
753 * Send suitable messages to a StructureListener to highlight atoms
754 * corresponding to the given sequence position.
760 protected void highlightStructure(StructureListener sl, SequenceI seq,
763 if (!sl.isListeningFor(seq))
768 List<AtomSpec> atoms = new ArrayList<AtomSpec>();
769 for (StructureMapping sm : mappings)
771 if (sm.sequence == seq || sm.sequence == seq.getDatasetSequence())
773 atomNo = sm.getAtomNum(index);
777 atoms.add(new AtomSpec(sm.pdbfile, sm.pdbchain, sm
778 .getPDBResNum(index), atomNo));
782 sl.highlightAtoms(atoms);
786 * true if a mouse over event from an external (ie Vamsas) source is being
789 boolean handlingVamsasMo = false;
794 * as mouseOverSequence but only route event to SequenceListeners
798 * in an alignment sequence
800 public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
803 handlingVamsasMo = true;
804 long msg = sequenceI.hashCode() * (1 + position);
808 mouseOverSequence(sequenceI, position, -1, source);
810 handlingVamsasMo = false;
813 public Annotation[] colourSequenceFromStructure(SequenceI seq,
817 // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
818 // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
820 * Annotation [] annotations = new Annotation[seq.getLength()];
822 * StructureListener sl; int atomNo = 0; for (int i = 0; i <
823 * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
824 * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
826 * for (int j = 0; j < mappings.length; j++) {
828 * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
829 * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
830 * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
831 * "+mappings[j].pdbfile);
833 * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
834 * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
836 * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
837 * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
838 * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
839 * mappings[j].pdbfile); }
841 * annotations[index] = new Annotation("X",null,' ',0,col); } return
842 * annotations; } } } }
844 * return annotations;
848 public void structureSelectionChanged()
852 public void sequenceSelectionChanged()
856 public void sequenceColoursChanged(Object source)
858 StructureListener sl;
859 for (int i = 0; i < listeners.size(); i++)
861 if (listeners.elementAt(i) instanceof StructureListener)
863 sl = (StructureListener) listeners.elementAt(i);
864 sl.updateColours(source);
869 public StructureMapping[] getMapping(String pdbfile)
871 List<StructureMapping> tmp = new ArrayList<StructureMapping>();
872 for (StructureMapping sm : mappings)
874 if (sm.pdbfile.equals(pdbfile))
879 return tmp.toArray(new StructureMapping[tmp.size()]);
883 * Returns a readable description of all mappings for the given pdbfile to any
884 * of the given sequences
890 public String printMappings(String pdbfile, List<SequenceI> seqs)
892 if (pdbfile == null || seqs == null || seqs.isEmpty())
897 StringBuilder sb = new StringBuilder(64);
898 for (StructureMapping sm : mappings)
900 if (sm.pdbfile.equals(pdbfile) && seqs.contains(sm.sequence))
902 sb.append(sm.mappingDetails);
904 // separator makes it easier to read multiple mappings
905 sb.append("=====================");
911 return sb.toString();
915 * Deregister each mapping in the set, unless there is still an alignment that
916 * holds a reference to it. Note we do not update the set itself, as it may be
917 * shared with an alignment view which is still open.
921 public void deregisterMappings(Set<AlignedCodonFrame> set)
925 for (AlignedCodonFrame acf : set)
927 deregisterMapping(acf);
933 * Remove the given mapping provided no alignment holds a reference to it
937 public void deregisterMapping(AlignedCodonFrame acf)
939 if (noReferencesTo(acf))
941 boolean removed = seqmappings.remove(acf);
942 if (removed && seqmappings.isEmpty())
944 System.out.println("All mappings removed");
950 * Answers true if no alignment holds a reference to the given mapping
955 protected boolean noReferencesTo(AlignedCodonFrame acf)
957 AlignFrame[] frames = Desktop.getAlignFrames();
962 for (AlignFrame af : frames)
964 for (AlignmentViewPanel ap : af.getAlignPanels())
966 AlignmentI al = ap.getAlignment();
967 if (al != null && al.getCodonFrames().contains(acf))
977 * Add each of the given codonFrames to the stored set, if not aready present.
981 public void registerMappings(Set<AlignedCodonFrame> set)
985 for (AlignedCodonFrame acf : set)
987 registerMapping(acf);
993 * Add the given mapping to the stored set, unless already stored.
995 public void registerMapping(AlignedCodonFrame acf)
999 if (!seqmappings.contains(acf))
1001 seqmappings.add(acf);
1007 * Resets this object to its initial state by removing all registered
1008 * listeners, codon mappings, PDB file mappings
1010 public void resetAll()
1012 if (mappings != null)
1016 if (seqmappings != null)
1018 seqmappings.clear();
1020 if (sel_listeners != null)
1022 sel_listeners.clear();
1024 if (listeners != null)
1028 if (commandListeners != null)
1030 commandListeners.clear();
1032 if (view_listeners != null)
1034 view_listeners.clear();
1036 if (pdbFileNameId != null)
1038 pdbFileNameId.clear();
1040 if (pdbIdFileName != null)
1042 pdbIdFileName.clear();
1046 public void addSelectionListener(SelectionListener selecter)
1048 if (!sel_listeners.contains(selecter))
1050 sel_listeners.add(selecter);
1054 public void removeSelectionListener(SelectionListener toremove)
1056 if (sel_listeners.contains(toremove))
1058 sel_listeners.remove(toremove);
1062 public synchronized void sendSelection(
1063 jalview.datamodel.SequenceGroup selection,
1064 jalview.datamodel.ColumnSelection colsel, SelectionSource source)
1066 for (SelectionListener slis : sel_listeners)
1070 slis.selection(selection, colsel, source);
1075 Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
1077 public synchronized void sendViewPosition(
1078 jalview.api.AlignmentViewPanel source, int startRes, int endRes,
1079 int startSeq, int endSeq)
1082 if (view_listeners != null && view_listeners.size() > 0)
1084 Enumeration<AlignmentViewPanelListener> listeners = view_listeners
1086 while (listeners.hasMoreElements())
1088 AlignmentViewPanelListener slis = listeners.nextElement();
1091 slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
1099 * release all references associated with this manager provider
1101 * @param jalviewLite
1103 public static void release(StructureSelectionManagerProvider jalviewLite)
1105 // synchronized (instances)
1107 if (instances == null)
1111 StructureSelectionManager mnger = (instances.get(jalviewLite));
1114 instances.remove(jalviewLite);
1118 } catch (Throwable x)
1125 public void registerPDBEntry(PDBEntry pdbentry)
1127 if (pdbentry.getFile() != null
1128 && pdbentry.getFile().trim().length() > 0)
1130 registerPDBFile(pdbentry.getId(), pdbentry.getFile());
1134 public void addCommandListener(CommandListener cl)
1136 if (!commandListeners.contains(cl))
1138 commandListeners.add(cl);
1142 public boolean hasCommandListener(CommandListener cl)
1144 return this.commandListeners.contains(cl);
1147 public boolean removeCommandListener(CommandListener l)
1149 return commandListeners.remove(l);
1153 * Forward a command to any command listeners (except for the command's
1157 * the command to be broadcast (in its form after being performed)
1159 * if true, the command was being 'undone'
1162 public void commandPerformed(CommandI command, boolean undo,
1163 VamsasSource source)
1165 for (CommandListener listener : commandListeners)
1167 listener.mirrorCommand(command, undo, this, source);
1172 * Returns a new CommandI representing the given command as mapped to the
1173 * given sequences. If no mapping could be made, or the command is not of a
1174 * mappable kind, returns null.
1182 public CommandI mapCommand(CommandI command, boolean undo,
1183 final AlignmentI mapTo, char gapChar)
1185 if (command instanceof EditCommand)
1187 return MappingUtils.mapEditCommand((EditCommand) command, undo,
1188 mapTo, gapChar, seqmappings);
1190 else if (command instanceof OrderCommand)
1192 return MappingUtils.mapOrderCommand((OrderCommand) command, undo,
1193 mapTo, seqmappings);