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