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