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