JAL-1551 formatting
[jalview.git] / src / jalview / structure / StructureSelectionManager.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
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.
11  *  
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.
16  * 
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.
20  */
21 package jalview.structure;
22
23 import jalview.analysis.AlignSeq;
24 import jalview.api.StructureSelectionManagerProvider;
25 import jalview.datamodel.AlignedCodonFrame;
26 import jalview.datamodel.AlignmentAnnotation;
27 import jalview.datamodel.Annotation;
28 import jalview.datamodel.SearchResults;
29 import jalview.datamodel.SequenceI;
30 import jalview.util.MessageManager;
31
32 import java.io.PrintStream;
33 import java.util.Enumeration;
34 import java.util.Hashtable;
35 import java.util.IdentityHashMap;
36 import java.util.Vector;
37
38 import MCview.Atom;
39 import MCview.PDBChain;
40
41 public class StructureSelectionManager
42 {
43   static IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager> instances;
44
45   StructureMapping[] mappings;
46
47   /**
48    * debug function - write all mappings to stdout
49    */
50   public void reportMapping()
51   {
52     if (mappings == null)
53     {
54       System.err.println("reportMapping: No PDB/Sequence mappings.");
55     }
56     else
57     {
58       System.err.println("reportMapping: There are " + mappings.length
59               + " mappings.");
60       for (int m = 0; m < mappings.length; m++)
61       {
62         System.err.println("mapping " + m + " : " + mappings[m].pdbfile);
63       }
64     }
65   }
66
67   Hashtable mappingData = new Hashtable();
68
69   private static StructureSelectionManager nullProvider = null;
70
71   public static StructureSelectionManager getStructureSelectionManager(
72           StructureSelectionManagerProvider context)
73   {
74     if (context == null)
75     {
76       if (nullProvider == null)
77       {
78         if (instances != null)
79         {
80           throw new Error(MessageManager.getString("error.implementation_error_structure_selection_manager_null"),
81                   new NullPointerException(MessageManager.getString("exception.ssm_context_is_null")));
82         }
83         else
84         {
85           nullProvider = new StructureSelectionManager();
86         }
87         return nullProvider;
88       }
89     }
90     if (instances == null)
91     {
92       instances = new java.util.IdentityHashMap<StructureSelectionManagerProvider, StructureSelectionManager>();
93     }
94     StructureSelectionManager instance = instances.get(context);
95     if (instance == null)
96     {
97       if (nullProvider != null)
98       {
99         instance = nullProvider;
100       }
101       else
102       {
103         instance = new StructureSelectionManager();
104       }
105       instances.put(context, instance);
106     }
107     return instance;
108   }
109
110   /**
111    * flag controlling whether SeqMappings are relayed from received sequence
112    * mouse over events to other sequences
113    */
114   boolean relaySeqMappings = true;
115
116   /**
117    * Enable or disable relay of seqMapping events to other sequences. You might
118    * want to do this if there are many sequence mappings and the host computer
119    * is slow
120    * 
121    * @param relay
122    */
123   public void setRelaySeqMappings(boolean relay)
124   {
125     relaySeqMappings = relay;
126   }
127
128   /**
129    * get the state of the relay seqMappings flag.
130    * 
131    * @return true if sequence mouse overs are being relayed to other mapped
132    *         sequences
133    */
134   public boolean isRelaySeqMappingsEnabled()
135   {
136     return relaySeqMappings;
137   }
138
139   Vector listeners = new Vector();
140
141   /**
142    * register a listener for alignment sequence mouseover events
143    * 
144    * @param svl
145    */
146   public void addStructureViewerListener(Object svl)
147   {
148     if (!listeners.contains(svl))
149     {
150       listeners.addElement(svl);
151     }
152   }
153
154   public String alreadyMappedToFile(String pdbid)
155   {
156     if (mappings != null)
157     {
158       for (int i = 0; i < mappings.length; i++)
159       {
160         if (mappings[i].getPdbId().equals(pdbid))
161         {
162           return mappings[i].pdbfile;
163         }
164       }
165     }
166     return null;
167   }
168
169   /**
170    * create sequence structure mappings between each sequence and the given
171    * pdbFile (retrieved via the given protocol).
172    * 
173    * @param sequence
174    *          - one or more sequences to be mapped to pdbFile
175    * @param targetChains
176    *          - optional chain specification for mapping each sequence to pdb
177    *          (may be nill, individual elements may be nill)
178    * @param pdbFile
179    *          - structure data resource
180    * @param protocol
181    *          - how to resolve data from resource
182    * @return null or the structure data parsed as a pdb file
183    */
184   synchronized public MCview.PDBfile setMapping(SequenceI[] sequence,
185           String[] targetChains, String pdbFile, String protocol)
186   {
187     /*
188      * There will be better ways of doing this in the future, for now we'll use
189      * the tried and tested MCview pdb mapping
190      */
191     MCview.PDBfile pdb = null;
192     try
193     {
194       pdb = new MCview.PDBfile(pdbFile, protocol);
195     } catch (Exception ex)
196     {
197       ex.printStackTrace();
198       return null;
199     }
200
201     String targetChain;
202     for (int s = 0; s < sequence.length; s++)
203     {
204       boolean infChain = true;
205       if (targetChains != null && targetChains[s] != null)
206       {
207         infChain = false;
208         targetChain = targetChains[s];
209       }
210       else if (sequence[s].getName().indexOf("|") > -1)
211       {
212         targetChain = sequence[s].getName().substring(
213                 sequence[s].getName().lastIndexOf("|") + 1);
214         if (targetChain.length() > 1)
215         {
216           if (targetChain.trim().length() == 0)
217           {
218             targetChain = " ";
219           }
220           else
221           {
222             // not a valid chain identifier
223             targetChain = "";
224           }
225         }
226       }
227       else
228       {
229         targetChain = "";
230       }
231
232       int max = -10;
233       AlignSeq maxAlignseq = null;
234       String maxChainId = " ";
235       PDBChain maxChain = null;
236       boolean first = true;
237       for (int i = 0; i < pdb.chains.size(); i++)
238       {
239         PDBChain chain = ((PDBChain) pdb.chains.elementAt(i));
240         if (targetChain.length() > 0 && !targetChain.equals(chain.id)
241                 && !infChain)
242         {
243           continue; // don't try to map chains don't match.
244         }
245         // TODO: correctly determine sequence type for mixed na/peptide
246         // structures
247         AlignSeq as = new AlignSeq(sequence[s],
248                 ((PDBChain) pdb.chains.elementAt(i)).sequence,
249                 ((PDBChain) pdb.chains.elementAt(i)).isNa ? AlignSeq.DNA
250                         : AlignSeq.PEP);
251         as.calcScoreMatrix();
252         as.traceAlignment();
253
254         if (first || as.maxscore > max
255                 || (as.maxscore == max && chain.id.equals(targetChain)))
256         {
257           first = false;
258           maxChain = chain;
259           max = as.maxscore;
260           maxAlignseq = as;
261           maxChainId = chain.id;
262         }
263       }
264       if (maxChain == null)
265       {
266         continue;
267       }
268       final StringBuffer mappingDetails = new StringBuffer();
269       mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
270               + maxChain.sequence.getSequenceAsString());
271       mappingDetails.append("\nNo of residues = "
272               + maxChain.residues.size() + "\n\n");
273       PrintStream ps = new PrintStream(System.out)
274       {
275         public void print(String x)
276         {
277           mappingDetails.append(x);
278         }
279
280         public void println()
281         {
282           mappingDetails.append("\n");
283         }
284       };
285
286       maxAlignseq.printAlignment(ps);
287
288       mappingDetails.append("\nPDB start/end " + maxAlignseq.seq2start
289               + " " + maxAlignseq.seq2end);
290       mappingDetails.append("\nSEQ start/end "
291               + (maxAlignseq.seq1start + sequence[s].getStart() - 1) + " "
292               + (maxAlignseq.seq1end + sequence[s].getEnd() - 1));
293
294       maxChain.makeExactMapping(maxAlignseq, sequence[s]);
295
296       maxChain.transferRESNUMFeatures(sequence[s], null);
297
298       // allocate enough slots to store the mapping from positions in
299       // sequence[s] to the associated chain
300       int[][] mapping = new int[sequence[s].findPosition(sequence[s]
301               .getLength()) + 2][2];
302       int resNum = -10000;
303       int index = 0;
304
305       do
306       {
307         Atom tmp = (Atom) maxChain.atoms.elementAt(index);
308         if (resNum != tmp.resNumber && tmp.alignmentMapping != -1)
309         {
310           resNum = tmp.resNumber;
311           mapping[tmp.alignmentMapping + 1][0] = tmp.resNumber;
312           mapping[tmp.alignmentMapping + 1][1] = tmp.atomIndex;
313         }
314
315         index++;
316       } while (index < maxChain.atoms.size());
317
318       if (mappings == null)
319       {
320         mappings = new StructureMapping[1];
321       }
322       else
323       {
324         StructureMapping[] tmp = new StructureMapping[mappings.length + 1];
325         System.arraycopy(mappings, 0, tmp, 0, mappings.length);
326         mappings = tmp;
327       }
328
329       if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
330       {
331         pdbFile = "INLINE" + pdb.id;
332       }
333
334       mappings[mappings.length - 1] = new StructureMapping(sequence[s],
335               pdbFile, pdb.id, maxChainId, mapping,
336               mappingDetails.toString());
337       maxChain.transferResidueAnnotation(mappings[mappings.length - 1]);
338     }
339     // ///////
340
341     return pdb;
342   }
343
344   public void removeStructureViewerListener(Object svl, String[] pdbfiles)
345   {
346     listeners.removeElement(svl);
347     if (svl instanceof SequenceListener)
348     {
349       for (int i = 0; i < listeners.size(); i++)
350       {
351         if (listeners.elementAt(i) instanceof StructureListener)
352         {
353           ((StructureListener) listeners.elementAt(i))
354                   .releaseReferences(svl);
355         }
356       }
357     }
358
359     if (pdbfiles == null)
360     {
361       return;
362     }
363     boolean removeMapping = true;
364     String[] handlepdbs;
365     Vector pdbs = new Vector();
366     for (int i = 0; i < pdbfiles.length; pdbs.addElement(pdbfiles[i++]))
367     {
368       ;
369     }
370     StructureListener sl;
371     for (int i = 0; i < listeners.size(); i++)
372     {
373       if (listeners.elementAt(i) instanceof StructureListener)
374       {
375         sl = (StructureListener) listeners.elementAt(i);
376         handlepdbs = sl.getPdbFile();
377         for (int j = 0; j < handlepdbs.length; j++)
378         {
379           if (pdbs.contains(handlepdbs[j]))
380           {
381             pdbs.removeElement(handlepdbs[j]);
382           }
383         }
384
385       }
386     }
387
388     if (pdbs.size() > 0 && mappings != null)
389     {
390       Vector tmp = new Vector();
391       for (int i = 0; i < mappings.length; i++)
392       {
393         if (!pdbs.contains(mappings[i].pdbfile))
394         {
395           tmp.addElement(mappings[i]);
396         }
397       }
398
399       mappings = new StructureMapping[tmp.size()];
400       tmp.copyInto(mappings);
401     }
402   }
403
404   public void mouseOverStructure(int pdbResNum, String chain, String pdbfile)
405   {
406     if (listeners == null)
407     {
408       // old or prematurely sent event
409       return;
410     }
411     boolean hasSequenceListeners = handlingVamsasMo || seqmappings != null;
412     SearchResults results = null;
413     SequenceI lastseq = null;
414     int lastipos = -1, indexpos;
415     for (int i = 0; i < listeners.size(); i++)
416     {
417       if (listeners.elementAt(i) instanceof SequenceListener)
418       {
419         if (results == null)
420         {
421           results = new SearchResults();
422         }
423         if (mappings != null)
424         {
425           for (int j = 0; j < mappings.length; j++)
426           {
427             if (mappings[j].pdbfile.equals(pdbfile)
428                     && mappings[j].pdbchain.equals(chain))
429             {
430               indexpos = mappings[j].getSeqPos(pdbResNum);
431               if (lastipos != indexpos && lastseq != mappings[j].sequence)
432               {
433                 results.addResult(mappings[j].sequence, indexpos, indexpos);
434                 lastipos = indexpos;
435                 lastseq = mappings[j].sequence;
436                 // construct highlighted sequence list
437                 if (seqmappings != null)
438                 {
439
440                   Enumeration e = seqmappings.elements();
441                   while (e.hasMoreElements())
442
443                   {
444                     ((AlignedCodonFrame) e.nextElement()).markMappedRegion(
445                             mappings[j].sequence, indexpos, results);
446                   }
447                 }
448               }
449
450             }
451           }
452         }
453       }
454     }
455     if (results != null)
456     {
457       for (int i = 0; i < listeners.size(); i++)
458       {
459         Object li = listeners.elementAt(i);
460         if (li instanceof SequenceListener)
461         {
462           ((SequenceListener) li).highlightSequence(results);
463         }
464       }
465     }
466   }
467
468   Vector seqmappings = null; // should be a simpler list of mapped seuqence
469
470   /**
471    * highlight regions associated with a position (indexpos) in seq
472    * 
473    * @param seq
474    *          the sequeence that the mouse over occured on
475    * @param indexpos
476    *          the absolute position being mouseovered in seq (0 to seq.length())
477    * @param index
478    *          the sequence position (if -1, seq.findPosition is called to
479    *          resolve the residue number)
480    */
481   public void mouseOverSequence(SequenceI seq, int indexpos, int index,
482           VamsasSource source)
483   {
484     boolean hasSequenceListeners = handlingVamsasMo || seqmappings != null;
485     SearchResults results = null;
486     if (index == -1)
487     {
488       index = seq.findPosition(indexpos);
489     }
490     StructureListener sl;
491     int atomNo = 0;
492     for (int i = 0; i < listeners.size(); i++)
493     {
494       Object listener = listeners.elementAt(i);
495       if (listener == source)
496       {
497         continue;
498       }
499       if (listener instanceof StructureListener)
500       {
501         sl = (StructureListener) listener;
502         if (mappings == null)
503         {
504           continue;
505         }
506         for (int j = 0; j < mappings.length; j++)
507         {
508           if (mappings[j].sequence == seq
509                   || mappings[j].sequence == seq.getDatasetSequence())
510           {
511             atomNo = mappings[j].getAtomNum(index);
512
513             if (atomNo > 0)
514             {
515               sl.highlightAtom(atomNo, mappings[j].getPDBResNum(index),
516                       mappings[j].pdbchain, mappings[j].pdbfile);
517             }
518           }
519         }
520       }
521       else
522       {
523         if (relaySeqMappings && hasSequenceListeners
524                 && listener instanceof SequenceListener)
525         {
526           // DEBUG
527           // System.err.println("relay Seq " + seq.getDisplayId(false) + " " +
528           // index);
529
530           if (results == null)
531           {
532             results = new SearchResults();
533             if (index >= seq.getStart() && index <= seq.getEnd())
534             {
535               // construct highlighted sequence list
536
537               if (seqmappings != null)
538               {
539                 Enumeration e = seqmappings.elements();
540                 while (e.hasMoreElements())
541
542                 {
543                   ((AlignedCodonFrame) e.nextElement()).markMappedRegion(
544                           seq, index, results);
545                 }
546               }
547               // hasSequenceListeners = results.getSize() > 0;
548               if (handlingVamsasMo)
549               {
550                 // maybe have to resolve seq to a dataset seqeunce...
551                 // add in additional direct sequence and/or dataset sequence
552                 // highlighting
553                 results.addResult(seq, index, index);
554               }
555             }
556           }
557           if (hasSequenceListeners)
558           {
559             ((SequenceListener) listener).highlightSequence(results);
560           }
561         }
562         else if (listener instanceof VamsasListener && !handlingVamsasMo)
563         {
564           // DEBUG
565           // System.err.println("Vamsas from Seq " + seq.getDisplayId(false) + "
566           // " +
567           // index);
568           // pass the mouse over and absolute position onto the
569           // VamsasListener(s)
570           ((VamsasListener) listener).mouseOver(seq, indexpos, source);
571         }
572         else if (listener instanceof SecondaryStructureListener)
573         {
574           ((SecondaryStructureListener) listener).mouseOverSequence(seq,
575                   indexpos);
576         }
577       }
578     }
579   }
580
581   /**
582    * true if a mouse over event from an external (ie Vamsas) source is being
583    * handled
584    */
585   boolean handlingVamsasMo = false;
586
587   long lastmsg = 0;
588
589   /**
590    * as mouseOverSequence but only route event to SequenceListeners
591    * 
592    * @param sequenceI
593    * @param position
594    *          in an alignment sequence
595    */
596   public void mouseOverVamsasSequence(SequenceI sequenceI, int position,
597           VamsasSource source)
598   {
599     handlingVamsasMo = true;
600     long msg = sequenceI.hashCode() * (1 + position);
601     if (lastmsg != msg)
602     {
603       lastmsg = msg;
604       mouseOverSequence(sequenceI, position, -1, source);
605     }
606     handlingVamsasMo = false;
607   }
608
609   public Annotation[] colourSequenceFromStructure(SequenceI seq,
610           String pdbid)
611   {
612     return null;
613     // THIS WILL NOT BE AVAILABLE IN JALVIEW 2.3,
614     // UNTIL THE COLOUR BY ANNOTATION IS REWORKED
615     /*
616      * Annotation [] annotations = new Annotation[seq.getLength()];
617      * 
618      * StructureListener sl; int atomNo = 0; for (int i = 0; i <
619      * listeners.size(); i++) { if (listeners.elementAt(i) instanceof
620      * StructureListener) { sl = (StructureListener) listeners.elementAt(i);
621      * 
622      * for (int j = 0; j < mappings.length; j++) {
623      * 
624      * if (mappings[j].sequence == seq && mappings[j].getPdbId().equals(pdbid)
625      * && mappings[j].pdbfile.equals(sl.getPdbFile())) {
626      * System.out.println(pdbid+" "+mappings[j].getPdbId() +"
627      * "+mappings[j].pdbfile);
628      * 
629      * java.awt.Color col; for(int index=0; index<seq.getLength(); index++) {
630      * if(jalview.util.Comparison.isGap(seq.getCharAt(index))) continue;
631      * 
632      * atomNo = mappings[j].getAtomNum(seq.findPosition(index)); col =
633      * java.awt.Color.white; if (atomNo > 0) { col = sl.getColour(atomNo,
634      * mappings[j].getPDBResNum(index), mappings[j].pdbchain,
635      * mappings[j].pdbfile); }
636      * 
637      * annotations[index] = new Annotation("X",null,' ',0,col); } return
638      * annotations; } } } }
639      * 
640      * return annotations;
641      */
642   }
643
644   public void structureSelectionChanged()
645   {
646   }
647
648   public void sequenceSelectionChanged()
649   {
650   }
651
652   public void sequenceColoursChanged(Object source)
653   {
654     StructureListener sl;
655     for (int i = 0; i < listeners.size(); i++)
656     {
657       if (listeners.elementAt(i) instanceof StructureListener)
658       {
659         sl = (StructureListener) listeners.elementAt(i);
660         sl.updateColours(source);
661       }
662     }
663   }
664
665   public StructureMapping[] getMapping(String pdbfile)
666   {
667     Vector tmp = new Vector();
668     if (mappings != null)
669     {
670       for (int i = 0; i < mappings.length; i++)
671       {
672         if (mappings[i].pdbfile.equals(pdbfile))
673         {
674           tmp.addElement(mappings[i]);
675         }
676       }
677     }
678     StructureMapping[] ret = new StructureMapping[tmp.size()];
679     for (int i = 0; i < tmp.size(); i++)
680     {
681       ret[i] = (StructureMapping) tmp.elementAt(i);
682     }
683
684     return ret;
685   }
686
687   public String printMapping(String pdbfile)
688   {
689     StringBuffer sb = new StringBuffer();
690     for (int i = 0; i < mappings.length; i++)
691     {
692       if (mappings[i].pdbfile.equals(pdbfile))
693       {
694         sb.append(mappings[i].mappingDetails);
695       }
696     }
697
698     return sb.toString();
699   }
700
701   private int[] seqmappingrefs = null; // refcount for seqmappings elements
702
703   private synchronized void modifySeqMappingList(boolean add,
704           AlignedCodonFrame[] codonFrames)
705   {
706     if (!add && (seqmappings == null || seqmappings.size() == 0))
707     {
708       return;
709     }
710     if (seqmappings == null)
711     {
712       seqmappings = new Vector();
713     }
714     if (codonFrames != null && codonFrames.length > 0)
715     {
716       for (int cf = 0; cf < codonFrames.length; cf++)
717       {
718         if (seqmappings.contains(codonFrames[cf]))
719         {
720           if (add)
721           {
722             seqmappingrefs[seqmappings.indexOf(codonFrames[cf])]++;
723           }
724           else
725           {
726             if (--seqmappingrefs[seqmappings.indexOf(codonFrames[cf])] <= 0)
727             {
728               int pos = seqmappings.indexOf(codonFrames[cf]);
729               int[] nr = new int[seqmappingrefs.length - 1];
730               if (pos > 0)
731               {
732                 System.arraycopy(seqmappingrefs, 0, nr, 0, pos);
733               }
734               if (pos < seqmappingrefs.length - 1)
735               {
736                 System.arraycopy(seqmappingrefs, pos + 1, nr, 0,
737                         seqmappingrefs.length - pos - 2);
738               }
739             }
740           }
741         }
742         else
743         {
744           if (add)
745           {
746             seqmappings.addElement(codonFrames[cf]);
747
748             int[] nsr = new int[(seqmappingrefs == null) ? 1
749                     : seqmappingrefs.length + 1];
750             if (seqmappingrefs != null && seqmappingrefs.length > 0)
751             {
752               System.arraycopy(seqmappingrefs, 0, nsr, 0,
753                       seqmappingrefs.length);
754             }
755             nsr[(seqmappingrefs == null) ? 0 : seqmappingrefs.length] = 1;
756             seqmappingrefs = nsr;
757           }
758         }
759       }
760     }
761   }
762
763   public void removeMappings(AlignedCodonFrame[] codonFrames)
764   {
765     modifySeqMappingList(false, codonFrames);
766   }
767
768   public void addMappings(AlignedCodonFrame[] codonFrames)
769   {
770     modifySeqMappingList(true, codonFrames);
771   }
772
773   Vector<SelectionListener> sel_listeners = new Vector<SelectionListener>();
774
775   public void addSelectionListener(SelectionListener selecter)
776   {
777     if (!sel_listeners.contains(selecter))
778     {
779       sel_listeners.addElement(selecter);
780     }
781   }
782
783   public void removeSelectionListener(SelectionListener toremove)
784   {
785     if (sel_listeners.contains(toremove))
786     {
787       sel_listeners.removeElement(toremove);
788     }
789   }
790
791   public synchronized void sendSelection(
792           jalview.datamodel.SequenceGroup selection,
793           jalview.datamodel.ColumnSelection colsel, SelectionSource source)
794   {
795     if (sel_listeners != null && sel_listeners.size() > 0)
796     {
797       Enumeration listeners = sel_listeners.elements();
798       while (listeners.hasMoreElements())
799       {
800         SelectionListener slis = ((SelectionListener) listeners
801                 .nextElement());
802         if (slis != source)
803         {
804           slis.selection(selection, colsel, source);
805         }
806         ;
807       }
808     }
809   }
810
811   Vector<AlignmentViewPanelListener> view_listeners = new Vector<AlignmentViewPanelListener>();
812
813   public synchronized void sendViewPosition(
814           jalview.api.AlignmentViewPanel source, int startRes, int endRes,
815           int startSeq, int endSeq)
816   {
817
818     if (view_listeners != null && view_listeners.size() > 0)
819     {
820       Enumeration<AlignmentViewPanelListener> listeners = view_listeners
821               .elements();
822       while (listeners.hasMoreElements())
823       {
824         AlignmentViewPanelListener slis = listeners.nextElement();
825         if (slis != source)
826         {
827           slis.viewPosition(startRes, endRes, startSeq, endSeq, source);
828         }
829         ;
830       }
831     }
832   }
833
834   public void finalize() throws Throwable
835   {
836     if (listeners != null)
837     {
838       listeners.clear();
839       listeners = null;
840     }
841     if (mappingData != null)
842     {
843       mappingData.clear();
844       mappingData = null;
845     }
846     if (sel_listeners != null)
847     {
848       sel_listeners.clear();
849       sel_listeners = null;
850     }
851     if (view_listeners != null)
852     {
853       view_listeners.clear();
854       view_listeners = null;
855     }
856     mappings = null;
857     seqmappingrefs = null;
858   }
859
860   /**
861    * release all references associated with this manager provider
862    * 
863    * @param jalviewLite
864    */
865   public static void release(StructureSelectionManagerProvider jalviewLite)
866   {
867     // synchronized (instances)
868     {
869       if (instances == null)
870       {
871         return;
872       }
873       StructureSelectionManager mnger = (instances.get(jalviewLite));
874       if (mnger != null)
875       {
876         instances.remove(jalviewLite);
877         try
878         {
879           mnger.finalize();
880         } catch (Throwable x)
881         {
882         }
883         ;
884       }
885     }
886   }
887
888 }