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