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