Merge develop to Release_2_8_3_Branch
[jalview.git] / src / jalview / appletgui / IdPanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ 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.appletgui;
22
23 import jalview.datamodel.Sequence;
24 import jalview.datamodel.SequenceFeature;
25 import jalview.datamodel.SequenceGroup;
26 import jalview.datamodel.SequenceI;
27 import jalview.util.UrlLink;
28
29 import java.awt.BorderLayout;
30 import java.awt.Panel;
31 import java.awt.event.InputEvent;
32 import java.awt.event.MouseEvent;
33 import java.awt.event.MouseListener;
34 import java.awt.event.MouseMotionListener;
35 import java.util.List;
36 import java.util.Vector;
37
38 public class IdPanel extends Panel implements MouseListener,
39         MouseMotionListener
40 {
41
42   protected IdCanvas idCanvas;
43
44   protected AlignViewport av;
45
46   protected AlignmentPanel alignPanel;
47
48   ScrollThread scrollThread = null;
49
50   int offy;
51
52   int width;
53
54   int lastid = -1;
55
56   boolean mouseDragging = false;
57
58   java.util.Vector links = new java.util.Vector();
59
60   public IdPanel(AlignViewport av, AlignmentPanel parent)
61   {
62     this.av = av;
63     alignPanel = parent;
64     idCanvas = new IdCanvas(av);
65     setLayout(new BorderLayout());
66     add(idCanvas, BorderLayout.CENTER);
67     idCanvas.addMouseListener(this);
68     idCanvas.addMouseMotionListener(this);
69
70     String label, url;
71     // TODO: add in group link parameter
72     if (av.applet != null)
73     {
74       for (int i = 1; i < 10; i++)
75       {
76         label = av.applet.getParameter("linkLabel_" + i);
77         url = av.applet.getParameter("linkURL_" + i);
78
79         if (label != null && url != null)
80         {
81           links.addElement(label + "|" + url);
82         }
83
84       }
85     }
86     {
87       // upgrade old SRS link
88       int srsPos = links
89               .indexOf("SRS|http://srs.ebi.ac.uk/srsbin/cgi-bin/wgetz?-newId+(([uniprot-all:$SEQUENCE_ID$]))+-view+SwissEntry");
90       if (srsPos > -1)
91       {
92         links.setElementAt(
93                 "EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$",
94                 srsPos);
95       }
96     }
97     if (links.size() < 1)
98     {
99       links = new java.util.Vector();
100       links.addElement("EMBL-EBI Search|http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$");
101     }
102   }
103
104   Tooltip tooltip;
105
106   public void mouseMoved(MouseEvent e)
107   {
108     int seq = alignPanel.seqPanel.findSeq(e);
109
110     SequenceI sequence = av.getAlignment().getSequenceAt(seq);
111
112     // look for non-pos features
113     StringBuffer tooltiptext = new StringBuffer();
114     if (sequence != null)
115     {
116       if (sequence.getDescription() != null)
117       {
118         tooltiptext.append(sequence.getDescription());
119         tooltiptext.append("\n");
120       }
121
122       SequenceFeature sf[] = sequence.getSequenceFeatures();
123       for (int sl = 0; sf != null && sl < sf.length; sl++)
124       {
125         if (sf[sl].begin == sf[sl].end && sf[sl].begin == 0)
126         {
127           boolean nl = false;
128           if (sf[sl].getFeatureGroup() != null)
129           {
130             tooltiptext.append(sf[sl].getFeatureGroup());
131             nl = true;
132           }
133           ;
134           if (sf[sl].getType() != null)
135           {
136             tooltiptext.append(" ");
137             tooltiptext.append(sf[sl].getType());
138             nl = true;
139           }
140           ;
141           if (sf[sl].getDescription() != null)
142           {
143             tooltiptext.append(" ");
144             tooltiptext.append(sf[sl].getDescription());
145             nl = true;
146           }
147           ;
148           if (sf[sl].getScore() != Float.NaN && sf[sl].getScore() != 0f)
149           {
150             tooltiptext.append(" Score = ");
151             tooltiptext.append(sf[sl].getScore());
152             nl = true;
153           }
154           ;
155           if (sf[sl].getStatus() != null && sf[sl].getStatus().length() > 0)
156           {
157             tooltiptext.append(" (");
158             tooltiptext.append(sf[sl].getStatus());
159             tooltiptext.append(")");
160             nl = true;
161           }
162           ;
163           if (nl)
164           {
165             tooltiptext.append("\n");
166           }
167         }
168       }
169     }
170     if (tooltiptext.length() == 0)
171     {
172       // nothing to display - so clear tooltip if one is visible
173       if (tooltip != null)
174       {
175         tooltip.setVisible(false);
176       }
177       tooltip = null;
178       tooltiptext = null;
179       return;
180     }
181     if (tooltip == null)
182     {
183       tooltip = new Tooltip(sequence.getDisplayId(true) + "\n"
184               + tooltiptext.toString(), idCanvas);
185     }
186     else
187     {
188       tooltip.setTip(sequence.getDisplayId(true) + "\n"
189               + tooltiptext.toString());
190     }
191     tooltiptext = null;
192   }
193
194   public void mouseDragged(MouseEvent e)
195   {
196     mouseDragging = true;
197
198     int seq = Math.max(0, alignPanel.seqPanel.findSeq(e));
199
200     if (seq < lastid)
201     {
202       selectSeqs(lastid - 1, seq);
203     }
204     else if (seq > lastid)
205     {
206       selectSeqs(lastid + 1, seq);
207     }
208
209     lastid = seq;
210     alignPanel.paintAlignment(false);
211   }
212
213   public void mouseClicked(MouseEvent e)
214   {
215     if (e.getClickCount() < 2)
216     {
217       return;
218     }
219
220     // DEFAULT LINK IS FIRST IN THE LINK LIST
221     int seq = alignPanel.seqPanel.findSeq(e);
222     SequenceI sq = av.getAlignment().getSequenceAt(seq);
223     if (sq == null)
224     {
225       return;
226     }
227     String id = sq.getName();
228
229     String target = null;
230     String url = null;
231     int i = 0;
232     while (url == null && i < links.size())
233     {
234       // DEFAULT LINK IS FIRST IN THE LINK LIST
235       // BUT IF ITS A REGEX AND DOES NOT MATCH THE NEXT ONE WILL BE TRIED
236       url = links.elementAt(i++).toString();
237       jalview.util.UrlLink urlLink = null;
238       try
239       {
240         urlLink = new UrlLink(url);
241         target = urlLink.getTarget();
242       } catch (Exception foo)
243       {
244         System.err.println("Exception for URLLink '" + url + "'");
245         foo.printStackTrace();
246         url = null;
247         continue;
248       }
249       ;
250       if (!urlLink.isValid())
251       {
252         System.err.println(urlLink.getInvalidMessage());
253         url = null;
254         continue;
255       }
256
257       String urls[] = urlLink.makeUrls(id, true);
258       if (urls == null || urls[0] == null || urls[0].length() < 1)
259       {
260         url = null;
261         continue;
262       }
263       // just take first URL made from regex
264       url = urls[1];
265     }
266     try
267     {
268
269       alignPanel.alignFrame.showURL(url, target);
270     } catch (Exception ex)
271     {
272       ex.printStackTrace();
273     }
274   }
275
276   public void mouseEntered(MouseEvent e)
277   {
278     if (scrollThread != null)
279     {
280       scrollThread.running = false;
281     }
282   }
283
284   public void mouseExited(MouseEvent e)
285   {
286     if (av.getWrapAlignment())
287     {
288       return;
289     }
290
291     if (mouseDragging && e.getY() < 0 && av.getStartSeq() > 0)
292     {
293       scrollThread = new ScrollThread(true);
294     }
295
296     if (mouseDragging && e.getY() >= getSize().height
297             && av.getAlignment().getHeight() > av.getEndSeq())
298     {
299       scrollThread = new ScrollThread(false);
300     }
301   }
302
303   public void mousePressed(MouseEvent e)
304   {
305     if (e.getClickCount() > 1)
306     {
307       return;
308     }
309
310     int y = e.getY();
311     if (av.getWrapAlignment())
312     {
313       y -= 2 * av.getCharHeight();
314     }
315
316     int seq = alignPanel.seqPanel.findSeq(e);
317
318     if ((e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
319     {
320       Sequence sq = (Sequence) av.getAlignment().getSequenceAt(seq);
321
322       // build a new links menu based on the current links + any non-positional
323       // features
324       Vector nlinks = new Vector();
325       for (int l = 0, lSize = links.size(); l < lSize; l++)
326       {
327         nlinks.addElement(links.elementAt(l));
328       }
329       SequenceFeature sf[] = sq == null ? null : sq.getSequenceFeatures();
330       for (int sl = 0; sf != null && sl < sf.length; sl++)
331       {
332         if (sf[sl].begin == sf[sl].end && sf[sl].begin == 0)
333         {
334           if (sf[sl].links != null && sf[sl].links.size() > 0)
335           {
336             for (int l = 0, lSize = sf[sl].links.size(); l < lSize; l++)
337             {
338               nlinks.addElement(sf[sl].links.elementAt(l));
339             }
340           }
341         }
342       }
343
344       APopupMenu popup = new APopupMenu(alignPanel, sq, nlinks);
345       this.add(popup);
346       popup.show(this, e.getX(), e.getY());
347       return;
348     }
349
350     if ((av.getSelectionGroup() == null)
351             || ((!e.isControlDown() && !e.isShiftDown()) && av
352                     .getSelectionGroup() != null))
353     {
354       av.setSelectionGroup(new SequenceGroup());
355       av.getSelectionGroup().setStartRes(0);
356       av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
357     }
358
359     if (e.isShiftDown() && lastid != -1)
360     {
361       selectSeqs(lastid, seq);
362     }
363     else
364     {
365       selectSeq(seq);
366     }
367
368     alignPanel.paintAlignment(false);
369   }
370
371   void selectSeq(int seq)
372   {
373     lastid = seq;
374     SequenceI pickedSeq = av.getAlignment().getSequenceAt(seq);
375     av.getSelectionGroup().addOrRemove(pickedSeq, true);
376   }
377
378   void selectSeqs(int start, int end)
379   {
380
381     lastid = start;
382
383     if (end >= av.getAlignment().getHeight())
384     {
385       end = av.getAlignment().getHeight() - 1;
386     }
387
388     if (end < start)
389     {
390       int tmp = start;
391       start = end;
392       end = tmp;
393       lastid = end;
394     }
395     if (av.getSelectionGroup() == null)
396     {
397       av.setSelectionGroup(new SequenceGroup());
398     }
399     for (int i = start; i <= end; i++)
400     {
401       av.getSelectionGroup().addSequence(
402               av.getAlignment().getSequenceAt(i), i == end);
403     }
404
405   }
406
407   public void mouseReleased(MouseEvent e)
408   {
409     if (scrollThread != null)
410     {
411       scrollThread.running = false;
412     }
413
414     if (av.getSelectionGroup() != null)
415     {
416       av.getSelectionGroup().recalcConservation();
417     }
418
419     mouseDragging = false;
420     PaintRefresher.Refresh(this, av.getSequenceSetId());
421     // always send selection message when mouse is released
422     av.sendSelection();
423   }
424
425   public void highlightSearchResults(List<SequenceI> list)
426   {
427     idCanvas.setHighlighted(list);
428
429     if (list == null)
430     {
431       return;
432     }
433
434     int index = av.getAlignment().findIndex(list.get(0));
435
436     // do we need to scroll the panel?
437     if (av.getStartSeq() > index || av.getEndSeq() < index)
438     {
439       alignPanel.setScrollValues(av.getStartRes(), index);
440     }
441   }
442
443   // this class allows scrolling off the bottom of the visible alignment
444   class ScrollThread extends Thread
445   {
446     boolean running = false;
447
448     boolean up = true;
449
450     public ScrollThread(boolean up)
451     {
452       this.up = up;
453       start();
454     }
455
456     public void stopScrolling()
457     {
458       running = false;
459     }
460
461     public void run()
462     {
463       running = true;
464       while (running)
465       {
466         if (alignPanel.scrollUp(up))
467         {
468           // scroll was ok, so add new sequence to selection
469           int seq = av.getStartSeq();
470           if (!up)
471           {
472             seq = av.getEndSeq();
473           }
474
475           if (seq < lastid)
476           {
477             selectSeqs(lastid - 1, seq);
478           }
479           else if (seq > lastid && seq < av.getAlignment().getHeight())
480           {
481             selectSeqs(lastid + 1, seq);
482           }
483
484           lastid = seq;
485         }
486         else
487         {
488           running = false;
489         }
490
491         alignPanel.paintAlignment(true);
492         try
493         {
494           Thread.sleep(100);
495         } catch (Exception ex)
496         {
497         }
498       }
499     }
500   }
501
502 }