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