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