Add support RNAML format
[jalview.git] / src / jalview / gui / AppVarna.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.gui;
19
20 import java.util.*;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23 import java.awt.*;
24
25 import javax.swing.*;
26 import javax.swing.event.*;
27
28 import java.awt.event.*;
29 import java.io.*;
30
31 import jalview.api.AlignViewportI;
32 import jalview.api.AlignmentViewPanel;
33 import jalview.api.SequenceStructureBinding;
34 import jalview.bin.Cache;
35 import jalview.datamodel.*;
36 import jalview.gui.ViewSelectionMenu.ViewSetProvider;
37 import jalview.structure.*;
38 import jalview.io.*;
39 import jalview.schemes.*;
40 import jalview.util.ShiftList;
41 import fr.orsay.lri.varna.VARNAPanel;
42 import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax;
43 import fr.orsay.lri.varna.exceptions.ExceptionNonEqualLength;
44 import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses;
45 import fr.orsay.lri.varna.interfaces.InterfaceVARNAListener;
46 import fr.orsay.lri.varna.interfaces.InterfaceVARNASelectionListener;
47 import fr.orsay.lri.varna.models.BaseList;
48 import fr.orsay.lri.varna.models.VARNAConfig;
49 import fr.orsay.lri.varna.models.annotations.HighlightRegionAnnotation;
50 import fr.orsay.lri.varna.models.rna.ModeleBase;
51 import fr.orsay.lri.varna.models.rna.ModeleBaseNucleotide;
52 import fr.orsay.lri.varna.models.rna.RNA;
53
54 public class AppVarna extends JInternalFrame implements
55         InterfaceVARNAListener, SelectionListener,
56         SecondaryStructureListener// implements
57                                   // Runnable,SequenceStructureBinding,
58                                   // ViewSetProvider
59         , InterfaceVARNASelectionListener, VamsasSource
60
61 {
62   AppVarnaBinding vab;
63
64   VARNAPanel varnaPanel;
65
66   public String name;
67
68   public StructureSelectionManager ssm;
69
70   /*
71    * public AppVarna(){ vab = new AppVarnaBinding(); initVarna(); }
72    */
73
74   AlignmentPanel ap;
75
76   public AppVarna(String sname, SequenceI seq, String strucseq, String struc,
77           String name, AlignmentPanel ap)
78   {
79           System.out.println("je suis là (AppVarna!!");
80           System.out.println("1:"+sname);
81           System.out.println("2:"+seq);
82           System.out.println("3:"+strucseq);
83           System.out.println("4:"+struc);
84           System.out.println("5:"+name);
85           System.out.println("6:"+ap);
86     this.ap = ap;
87     ArrayList<RNA> rnaList = new ArrayList<RNA>();
88     RNA rna1 = new RNA(name);
89     try
90     {
91     System.out.println("ou ici ?");
92       rna1.setRNA(strucseq, replaceOddGaps(struc));
93       System.out.println("La séquence est :"+rna1.getSeq());
94       System.out.println("La séquence est :"+struc);
95       System.out.println("La séquence est :"+replaceOddGaps(struc).toString());
96     } catch (ExceptionUnmatchedClosingParentheses e2)
97     {
98       e2.printStackTrace();
99     } catch (ExceptionFileFormatOrSyntax e3)
100     {
101       e3.printStackTrace();
102     }
103     
104     RNA trim = trimRNA(rna1, "trimmed "+sname);
105     rnaList.add(trim);
106     rnaList.add(rna1);
107     
108     rnas.put(seq, rna1);
109     rnas.put(seq, trim);
110    
111     rna1.setName(sname+" (with gaps)");
112
113     {
114       seqs.put(trim, seq);
115       seqs.put(rna1, seq);
116       
117       /**
118        * if (false || seq.getStart()!=1) { for (RNA rshift:rnaList) { ShiftList
119        * shift=offsets.get(rshift); if (shift==null) { offsets.put(rshift,
120        * shift=new ShiftList());} shift.addShift(1, seq.getStart()-1);
121        * offsetsInv.put(rshift, shift.getInverse()); } }
122        **/
123     }
124     vab = new AppVarnaBinding(rnaList);
125     // vab = new AppVarnaBinding(seq,struc);
126     // System.out.println("Hallo: "+name);
127     this.name = sname+" trimmed to "+name;
128     initVarna();
129    
130     ssm = ap.getStructureSelectionManager();
131     System.out.println(ssm.toString());
132     ssm.addStructureViewerListener(this);
133     ssm.addSelectionListener(this);
134   }
135
136   public void initVarna()
137   {
138           System.out.println("initialisation VANRA");
139     // vab.setFinishedInit(false);
140     varnaPanel = vab.get_varnaPanel();
141     setBackground(Color.white);
142     JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true,
143             vab.getListPanel(), varnaPanel);
144     getContentPane().setLayout(new BorderLayout());
145     getContentPane().add(split, BorderLayout.CENTER);
146     // getContentPane().add(vab.getTools(), BorderLayout.NORTH);
147     varnaPanel.addVARNAListener(this);
148     varnaPanel.addSelectionListener(this);
149     jalview.gui.Desktop.addInternalFrame(this, "VARNA -" + name,
150             getBounds().width, getBounds().height);
151     this.pack();
152     showPanel(true);
153     System.out.println("Sortie initialisation VANRA");
154   }
155
156   public String replaceOddGaps(String oldStr)
157   {
158     String patternStr = "[^([{<>}])]";
159     String replacementStr = ".";
160     Pattern pattern = Pattern.compile(patternStr);
161     Matcher matcher = pattern.matcher(oldStr);
162     String newStr = matcher.replaceAll(replacementStr);
163     return newStr;
164   }
165
166   public RNA trimRNA(RNA rna, String name)
167   {
168     ShiftList offset = new ShiftList();
169     
170     RNA rnaTrim = new RNA(name);
171     try
172     {
173       rnaTrim.setRNA(rna.getSeq(), replaceOddGaps(rna.getStructDBN()));
174     } catch (ExceptionUnmatchedClosingParentheses e2)
175     {
176       e2.printStackTrace();
177     } catch (ExceptionFileFormatOrSyntax e3)
178     {
179       e3.printStackTrace();
180     }
181
182     StringBuffer seq = new StringBuffer(rnaTrim.getSeq());
183     StringBuffer struc = new StringBuffer(rnaTrim.getStructDBN());
184     int ofstart = -1, sleng = rnaTrim.getSeq().length();
185     for (int i = 0; i < sleng; i++)
186     {
187       // TODO: Jalview utility for gap detection java.utils.isGap()
188       // TODO: Switch to jalview rna datamodel
189       if (jalview.util.Comparison.isGap(seq.charAt(i)))
190       {
191         if (ofstart == -1)
192         {
193           ofstart = i;
194         }
195         if (!rnaTrim.findPair(i).isEmpty())
196         {
197           int m = rnaTrim.findPair(i).get(1);
198           int l = rnaTrim.findPair(i).get(0);
199
200           struc.replace(m, m + 1, "*");
201           struc.replace(l, l + 1, "*");
202         }
203         else
204         {
205           struc.replace(i, i + 1, "*");
206         }
207       }
208       else
209       {
210         if (ofstart > -1)
211         {
212           offset.addShift(offset.shift(ofstart), ofstart - i);
213           ofstart = -1;
214         }
215       }
216     }
217     // final gap
218     if (ofstart > -1)
219     {
220       offset.addShift(offset.shift(ofstart), ofstart - sleng);
221       ofstart = -1;
222     }
223     String newSeq = rnaTrim.getSeq().replace("-", "");
224     rnaTrim.getSeq().replace(".", "");
225     String newStruc = struc.toString().replace("*", "");
226
227     try
228     {
229       rnaTrim.setRNA(newSeq, newStruc);
230       registerOffset(rnaTrim, offset);
231     } catch (ExceptionUnmatchedClosingParentheses e)
232     {
233       // TODO Auto-generated catch block
234       e.printStackTrace();
235     } catch (ExceptionFileFormatOrSyntax e)
236     {
237       // TODO Auto-generated catch block
238       e.printStackTrace();
239     }
240     return rnaTrim;
241   }
242
243   // needs to be many-many
244   Map<RNA, SequenceI> seqs = new Hashtable<RNA, SequenceI>();
245
246   Map<SequenceI, RNA> rnas = new Hashtable<SequenceI, RNA>();
247
248   Map<RNA, ShiftList> offsets = new Hashtable<RNA, ShiftList>();
249
250   Map<RNA, ShiftList> offsetsInv = new Hashtable<RNA, ShiftList>();
251
252   private void registerOffset(RNA rnaTrim, ShiftList offset)
253   {
254     offsets.put(rnaTrim, offset);
255     offsetsInv.put(rnaTrim, offset.getInverse());
256   }
257
258   public void showPanel(boolean show)
259   {
260     this.setVisible(show);
261   }
262
263   private boolean _started = false;
264
265   public void run()
266   {
267     _started = true;
268
269     try
270     {
271       initVarna();
272     } catch (OutOfMemoryError oomerror)
273     {
274       new OOMWarning("When trying to open the Varna viewer!", oomerror);
275     } catch (Exception ex)
276     {
277       Cache.log.error("Couldn't open Varna viewer!", ex);
278     }
279   }
280
281   @Override
282   public void onUINewStructure(VARNAConfig v, RNA r)
283   {
284
285   }
286
287   @Override
288   public void onWarningEmitted(String s)
289   {
290     // TODO Auto-generated method stub
291
292   }
293
294   private class VarnaHighlighter
295   {
296     private HighlightRegionAnnotation _lastHighlight;
297
298     private RNA _lastRNAhighlighted = null;
299
300     public void highlightRegion(RNA rna, int start, int end)
301     {
302       clearSelection(null);
303       HighlightRegionAnnotation highlight = new HighlightRegionAnnotation(
304               rna.getBasesBetween(start, end));
305       rna.addHighlightRegion(highlight);
306       _lastHighlight = highlight;
307       _lastRNAhighlighted = rna;
308
309     }
310
311     public HighlightRegionAnnotation getLastHighlight()
312     {
313       return _lastHighlight;
314     }
315
316     public RNA getLastRNA()
317     {
318       return _lastRNAhighlighted;
319     }
320
321     public void clearSelection(AppVarnaBinding vab)
322     {
323       if (_lastRNAhighlighted != null)
324       {
325         _lastRNAhighlighted.removeHighlightRegion(_lastHighlight);
326         if (vab != null)
327         {
328           vab.updateSelectedRNA(_lastRNAhighlighted);
329         }
330         _lastRNAhighlighted = null;
331         _lastHighlight = null;
332
333       }
334     }
335   }
336
337   VarnaHighlighter mouseOverHighlighter = new VarnaHighlighter(),
338           selectionHighlighter = new VarnaHighlighter();
339
340   /**
341    * If a mouseOver event from the AlignmentPanel is noticed the currently
342    * selected RNA in the VARNA window is highlighted at the specific position.
343    * To be able to remove it before the next highlight it is saved in
344    * _lastHighlight
345    */
346   @Override
347   public void mouseOverSequence(SequenceI sequence, int index)
348   {
349     RNA rna = vab.getSelectedRNA();
350     if (seqs.get(rna) == sequence)
351     {
352       ShiftList shift = offsets.get(rna);
353       if (shift != null)
354       {
355    //      System.err.print("Orig pos:"+index);
356          index = shift.shift(index);
357    //      System.err.println("\nFinal pos:"+index);
358       }
359       mouseOverHighlighter.highlightRegion(rna, index, index);
360       vab.updateSelectedRNA(rna);
361     }
362   }
363
364   @Override
365   public void onStructureRedrawn()
366   {
367     // TODO Auto-generated method stub
368
369   }
370
371   @Override
372   public void selection(SequenceGroup seqsel, ColumnSelection colsel,
373           SelectionSource source)
374   {
375     if (source != ap.av)
376     {
377       // ignore events from anything but our parent alignpanel
378       // TODO - reuse many-one panel-view system in jmol viewer
379       return;
380     }
381     if (seqsel != null && seqsel.getSize() > 0)
382     {
383       int start = seqsel.getStartRes(), end = seqsel.getEndRes();
384       RNA rna = vab.getSelectedRNA();
385       ShiftList shift = offsets.get(rna);
386       if (shift != null)
387       {
388         start = shift.shift(start);
389         end = shift.shift(end);
390       }
391       selectionHighlighter.highlightRegion(rna, start, end);
392       selectionHighlighter.getLastHighlight().setOutlineColor(
393               seqsel.getOutlineColour());
394       // TODO - translate column markings to positions on structure if present.
395       vab.updateSelectedRNA(rna);
396     }
397     else
398     {
399       selectionHighlighter.clearSelection(vab);
400     }
401   }
402
403   @Override
404   public void onHoverChanged(ModeleBase arg0, ModeleBase arg1)
405   {
406     RNA rna = vab.getSelectedRNA();
407     ShiftList shift = offsetsInv.get(rna);
408     SequenceI seq = seqs.get(rna);
409     if (arg1 != null && seq != null)
410     {
411       if (shift != null)
412       {
413         int i = shift.shift(arg1.getIndex());
414  //       System.err.println("shifted "+(arg1.getIndex())+" to "+i);
415         ssm.mouseOverVamsasSequence(seq, i, this);
416       }
417       else
418       {
419         ssm.mouseOverVamsasSequence(seq, arg1.getIndex(), this);
420       }
421     }
422   }
423
424   @Override
425   public void onSelectionChanged(BaseList arg0, BaseList arg1, BaseList arg2)
426   {
427     // TODO translate selected regions in VARNA to a selection on the
428     // alignpanel.
429
430   }
431
432 }