f9f1676aa8db3f5886bb5719cce01c42fd841ba0
[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.urls.AppletUrlProviderFactory;
28 import jalview.urls.UrlProviderFactoryI;
29 import jalview.urls.UrlProviderI;
30 import jalview.viewmodel.AlignmentViewport;
31
32 import java.awt.BorderLayout;
33 import java.awt.Panel;
34 import java.awt.event.InputEvent;
35 import java.awt.event.MouseEvent;
36 import java.awt.event.MouseListener;
37 import java.awt.event.MouseMotionListener;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Vector;
41
42 public class IdPanel extends Panel implements MouseListener,
43         MouseMotionListener
44 {
45
46   protected IdCanvas idCanvas;
47
48   protected AlignmentViewport av;
49
50   protected AlignmentPanel alignPanel;
51
52   ScrollThread scrollThread = null;
53
54   int lastid = -1;
55
56   boolean mouseDragging = false;
57
58   UrlProviderI urlProvider = null;
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
73     // make a list of label,url pairs
74     HashMap<String, String> urlList = new HashMap<String, String>();
75     if (av.applet != null)
76     {
77       for (int i = 1; i < 10; i++)
78       {
79         label = av.applet.getParameter("linkLabel_" + i);
80         url = av.applet.getParameter("linkURL_" + i);
81
82         urlList.put(label, url);
83       }
84
85       if (!urlList.isEmpty())
86       {
87         // set default as first entry in list
88         String defaultUrl = av.applet.getParameter("linkLabel_1");
89         UrlProviderFactoryI factory = new AppletUrlProviderFactory(
90                 defaultUrl, urlList);
91         urlProvider = factory.createUrlProvider();
92       }
93     }
94   }
95
96   Tooltip tooltip;
97
98   @Override
99   public void mouseMoved(MouseEvent e)
100   {
101     int seq = alignPanel.seqPanel.findSeq(e);
102
103     SequenceI sequence = av.getAlignment().getSequenceAt(seq);
104
105     // look for non-pos features
106     StringBuffer tooltiptext = new StringBuffer();
107     if (sequence != null)
108     {
109       if (sequence.getDescription() != null)
110       {
111         tooltiptext.append(sequence.getDescription());
112         tooltiptext.append("\n");
113       }
114
115       SequenceFeature sf[] = sequence.getSequenceFeatures();
116       for (int sl = 0; sf != null && sl < sf.length; sl++)
117       {
118         if (sf[sl].begin == sf[sl].end && sf[sl].begin == 0)
119         {
120           boolean nl = false;
121           if (sf[sl].getFeatureGroup() != null)
122           {
123             tooltiptext.append(sf[sl].getFeatureGroup());
124             nl = true;
125           }
126           ;
127           if (sf[sl].getType() != null)
128           {
129             tooltiptext.append(" ");
130             tooltiptext.append(sf[sl].getType());
131             nl = true;
132           }
133           ;
134           if (sf[sl].getDescription() != null)
135           {
136             tooltiptext.append(" ");
137             tooltiptext.append(sf[sl].getDescription());
138             nl = true;
139           }
140           ;
141           if (!Float.isNaN(sf[sl].getScore()) && sf[sl].getScore() != 0f)
142           {
143             tooltiptext.append(" Score = ");
144             tooltiptext.append(sf[sl].getScore());
145             nl = true;
146           }
147           ;
148           if (sf[sl].getStatus() != null && sf[sl].getStatus().length() > 0)
149           {
150             tooltiptext.append(" (");
151             tooltiptext.append(sf[sl].getStatus());
152             tooltiptext.append(")");
153             nl = true;
154           }
155           ;
156           if (nl)
157           {
158             tooltiptext.append("\n");
159           }
160         }
161       }
162     }
163     if (tooltiptext.length() == 0)
164     {
165       // nothing to display - so clear tooltip if one is visible
166       if (tooltip != null)
167       {
168         tooltip.setVisible(false);
169       }
170       tooltip = null;
171       tooltiptext = null;
172       return;
173     }
174     if (tooltip == null)
175     {
176       tooltip = new Tooltip(sequence.getDisplayId(true) + "\n"
177               + tooltiptext.toString(), idCanvas);
178     }
179     else
180     {
181       tooltip.setTip(sequence.getDisplayId(true) + "\n"
182               + tooltiptext.toString());
183     }
184     tooltiptext = null;
185   }
186
187   @Override
188   public void mouseDragged(MouseEvent e)
189   {
190     mouseDragging = true;
191
192     int seq = Math.max(0, alignPanel.seqPanel.findSeq(e));
193
194     if (seq < lastid)
195     {
196       selectSeqs(lastid - 1, seq);
197     }
198     else if (seq > lastid)
199     {
200       selectSeqs(lastid + 1, seq);
201     }
202
203     lastid = seq;
204     alignPanel.paintAlignment(false);
205   }
206
207   @Override
208   public void mouseClicked(MouseEvent e)
209   {
210     if (e.getClickCount() < 2)
211     {
212       return;
213     }
214
215     // get the sequence details
216     int seq = alignPanel.seqPanel.findSeq(e);
217     SequenceI sq = av.getAlignment().getSequenceAt(seq);
218     if (sq == null)
219     {
220       return;
221     }
222     String id = sq.getName();
223
224     // get the default url with the sequence details filled in
225     String url = urlProvider.getDefaultUrl(id);
226     String target = urlProvider.getDefaultTarget(id);
227     try
228     {
229       alignPanel.alignFrame.showURL(url, target);
230     } catch (Exception ex)
231     {
232       ex.printStackTrace();
233     }
234   }
235
236   @Override
237   public void mouseEntered(MouseEvent e)
238   {
239     if (scrollThread != null)
240     {
241       scrollThread.running = false;
242     }
243   }
244
245   @Override
246   public void mouseExited(MouseEvent e)
247   {
248     if (av.getWrapAlignment())
249     {
250       return;
251     }
252
253     if (mouseDragging && e.getY() < 0 && av.getStartSeq() > 0)
254     {
255       scrollThread = new ScrollThread(true);
256     }
257
258     if (mouseDragging && e.getY() >= getSize().height
259             && av.getAlignment().getHeight() > av.getEndSeq())
260     {
261       scrollThread = new ScrollThread(false);
262     }
263   }
264
265   @Override
266   public void mousePressed(MouseEvent e)
267   {
268     if (e.getClickCount() > 1)
269     {
270       return;
271     }
272
273     int y = e.getY();
274     if (av.getWrapAlignment())
275     {
276       y -= 2 * av.getCharHeight();
277     }
278
279     int seq = alignPanel.seqPanel.findSeq(e);
280
281     if ((e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
282     {
283       Sequence sq = (Sequence) av.getAlignment().getSequenceAt(seq);
284
285       // build a new links menu based on the current links + any non-positional
286       // features
287       Vector<String> nlinks = urlProvider.getLinksForMenu();
288
289       SequenceFeature sf[] = sq == null ? null : sq.getSequenceFeatures();
290       for (int sl = 0; sf != null && sl < sf.length; sl++)
291       {
292         if (sf[sl].begin == sf[sl].end && sf[sl].begin == 0)
293         {
294           if (sf[sl].links != null && sf[sl].links.size() > 0)
295           {
296             for (int l = 0, lSize = sf[sl].links.size(); l < lSize; l++)
297             {
298               nlinks.addElement(sf[sl].links.elementAt(l));
299             }
300           }
301         }
302       }
303
304       APopupMenu popup = new APopupMenu(alignPanel, sq, nlinks);
305       this.add(popup);
306       popup.show(this, e.getX(), e.getY());
307       return;
308     }
309
310     if ((av.getSelectionGroup() == null)
311             || ((!jalview.util.Platform.isControlDown(e) && !e
312                     .isShiftDown()) && av.getSelectionGroup() != null))
313     {
314       av.setSelectionGroup(new SequenceGroup());
315       av.getSelectionGroup().setStartRes(0);
316       av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
317     }
318
319     if (e.isShiftDown() && lastid != -1)
320     {
321       selectSeqs(lastid, seq);
322     }
323     else
324     {
325       selectSeq(seq);
326     }
327
328     alignPanel.paintAlignment(false);
329   }
330
331   void selectSeq(int seq)
332   {
333     lastid = seq;
334     SequenceI pickedSeq = av.getAlignment().getSequenceAt(seq);
335     av.getSelectionGroup().addOrRemove(pickedSeq, true);
336   }
337
338   void selectSeqs(int start, int end)
339   {
340
341     lastid = start;
342
343     if (end >= av.getAlignment().getHeight())
344     {
345       end = av.getAlignment().getHeight() - 1;
346     }
347
348     if (end < start)
349     {
350       int tmp = start;
351       start = end;
352       end = tmp;
353       lastid = end;
354     }
355     if (av.getSelectionGroup() == null)
356     {
357       av.setSelectionGroup(new SequenceGroup());
358     }
359     for (int i = start; i <= end; i++)
360     {
361       av.getSelectionGroup().addSequence(
362               av.getAlignment().getSequenceAt(i), i == end);
363     }
364
365   }
366
367   @Override
368   public void mouseReleased(MouseEvent e)
369   {
370     if (scrollThread != null)
371     {
372       scrollThread.running = false;
373     }
374
375     if (av.getSelectionGroup() != null)
376     {
377       av.getSelectionGroup().recalcConservation();
378     }
379
380     mouseDragging = false;
381     PaintRefresher.Refresh(this, av.getSequenceSetId());
382     // always send selection message when mouse is released
383     av.sendSelection();
384   }
385
386   public void highlightSearchResults(List<SequenceI> list)
387   {
388     idCanvas.setHighlighted(list);
389
390     if (list == null)
391     {
392       return;
393     }
394
395     int index = av.getAlignment().findIndex(list.get(0));
396
397     // do we need to scroll the panel?
398     if (av.getStartSeq() > index || av.getEndSeq() < index)
399     {
400       alignPanel.setScrollValues(av.getStartRes(), index);
401     }
402   }
403
404   // this class allows scrolling off the bottom of the visible alignment
405   class ScrollThread extends Thread
406   {
407     boolean running = false;
408
409     boolean up = true;
410
411     public ScrollThread(boolean up)
412     {
413       this.up = up;
414       start();
415     }
416
417     public void stopScrolling()
418     {
419       running = false;
420     }
421
422     @Override
423     public void run()
424     {
425       running = true;
426       while (running)
427       {
428         if (alignPanel.scrollUp(up))
429         {
430           // scroll was ok, so add new sequence to selection
431           int seq = av.getStartSeq();
432           if (!up)
433           {
434             seq = av.getEndSeq();
435           }
436
437           if (seq < lastid)
438           {
439             selectSeqs(lastid - 1, seq);
440           }
441           else if (seq > lastid && seq < av.getAlignment().getHeight())
442           {
443             selectSeqs(lastid + 1, seq);
444           }
445
446           lastid = seq;
447         }
448         else
449         {
450           running = false;
451         }
452
453         alignPanel.paintAlignment(true);
454         try
455         {
456           Thread.sleep(100);
457         } catch (Exception ex)
458         {
459         }
460       }
461     }
462   }
463 }