JAL-1432 updated copyright notices
[jalview.git] / src / jalview / gui / IdPanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
3  * Copyright (C) 2014 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 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  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 package jalview.gui;
20
21 import java.awt.*;
22 import java.awt.event.*;
23 import java.util.List;
24 import java.util.Vector;
25
26 import javax.swing.*;
27
28 import jalview.datamodel.*;
29 import jalview.io.SequenceAnnotationReport;
30 import jalview.util.UrlLink;
31
32 /**
33  * DOCUMENT ME!
34  * 
35  * @author $author$
36  * @version $Revision$
37  */
38 public class IdPanel extends JPanel implements MouseListener,
39         MouseMotionListener, MouseWheelListener
40 {
41   protected IdCanvas idCanvas;
42
43   protected AlignViewport av;
44
45   protected AlignmentPanel alignPanel;
46
47   ScrollThread scrollThread = null;
48
49   String linkImageURL;
50
51   int offy;
52
53   // int width;
54   int lastid = -1;
55
56   boolean mouseDragging = false;
57
58   private final SequenceAnnotationReport seqAnnotReport;
59
60   /**
61    * Creates a new IdPanel object.
62    * 
63    * @param av
64    *          DOCUMENT ME!
65    * @param parent
66    *          DOCUMENT ME!
67    */
68   public IdPanel(AlignViewport av, AlignmentPanel parent)
69   {
70     this.av = av;
71     alignPanel = parent;
72     idCanvas = new IdCanvas(av);
73     linkImageURL = getClass().getResource("/images/link.gif").toString();
74     seqAnnotReport = new SequenceAnnotationReport(linkImageURL);
75     setLayout(new BorderLayout());
76     add(idCanvas, BorderLayout.CENTER);
77     addMouseListener(this);
78     addMouseMotionListener(this);
79     addMouseWheelListener(this);
80     ToolTipManager.sharedInstance().registerComponent(this);
81   }
82
83   /**
84    * DOCUMENT ME!
85    * 
86    * @param e
87    *          DOCUMENT ME!
88    */
89   @Override
90   public void mouseMoved(MouseEvent e)
91   {
92     SeqPanel sp = alignPanel.seqPanel;
93     int seq = Math.max(0, sp.findSeq(e));
94     if (seq > -1 && seq < av.getAlignment().getHeight())
95     {
96       SequenceI sequence = av.getAlignment().getSequenceAt(seq);
97       StringBuffer tip = new StringBuffer();
98       seqAnnotReport
99               .createSequenceAnnotationReport(tip, sequence,
100                       av.isShowDbRefs(), av.isShowNpFeats(),
101                       sp.seqCanvas.fr.minmax);
102       setToolTipText("<html>" + sequence.getDisplayId(true) + " "
103               + tip.toString() + "</html>");
104     }
105   }
106
107   /**
108    * DOCUMENT ME!
109    * 
110    * @param e
111    *          DOCUMENT ME!
112    */
113   @Override
114   public void mouseDragged(MouseEvent e)
115   {
116     mouseDragging = true;
117
118     int seq = Math.max(0, alignPanel.seqPanel.findSeq(e));
119
120     if (seq < lastid)
121     {
122       selectSeqs(lastid - 1, seq);
123     }
124     else if (seq > lastid)
125     {
126       selectSeqs(lastid + 1, seq);
127     }
128
129     lastid = seq;
130     alignPanel.paintAlignment(true);
131   }
132
133   @Override
134   public void mouseWheelMoved(MouseWheelEvent e)
135   {
136     e.consume();
137     if (e.getWheelRotation() > 0)
138     {
139       if (e.isShiftDown())
140       {
141         alignPanel.scrollRight(true);
142
143       }
144       else
145       {
146         alignPanel.scrollUp(false);
147       }
148     }
149     else
150     {
151       if (e.isShiftDown())
152       {
153         alignPanel.scrollRight(false);
154       }
155       else
156       {
157         alignPanel.scrollUp(true);
158       }
159     }
160   }
161
162   /**
163    * DOCUMENT ME!
164    * 
165    * @param e
166    *          DOCUMENT ME!
167    */
168   @Override
169   public void mouseClicked(MouseEvent e)
170   {
171     if (e.getClickCount() < 2)
172     {
173       return;
174     }
175
176     java.util.Vector links = Preferences.sequenceURLLinks;
177     if (links == null || links.size() < 1)
178     {
179       return;
180     }
181
182     int seq = alignPanel.seqPanel.findSeq(e);
183     String url = null;
184     int i = 0;
185     String id = av.getAlignment().getSequenceAt(seq).getName();
186     while (url == null && i < links.size())
187     {
188       // DEFAULT LINK IS FIRST IN THE LINK LIST
189       // BUT IF ITS A REGEX AND DOES NOT MATCH THE NEXT ONE WILL BE TRIED
190       url = links.elementAt(i++).toString();
191       jalview.util.UrlLink urlLink = null;
192       try
193       {
194         urlLink = new UrlLink(url);
195       } catch (Exception foo)
196       {
197         jalview.bin.Cache.log.error("Exception for URLLink '" + url + "'",
198                 foo);
199         url = null;
200         continue;
201       }
202       ;
203       if (!urlLink.isValid())
204       {
205         jalview.bin.Cache.log.error(urlLink.getInvalidMessage());
206         url = null;
207         continue;
208       }
209
210       String urls[] = urlLink.makeUrls(id, true);
211       if (urls == null || urls[0] == null || urls[0].length() < 4)
212       {
213         url = null;
214         continue;
215       }
216       // just take first URL made from regex
217       url = urls[1];
218     }
219     try
220     {
221       jalview.util.BrowserLauncher.openURL(url);
222     } catch (Exception ex)
223     {
224       JOptionPane
225               .showInternalMessageDialog(
226                       Desktop.desktop,
227                       "Unixers: Couldn't find default web browser."
228                               + "\nAdd the full path to your browser in Preferences.",
229                       "Web browser not found", JOptionPane.WARNING_MESSAGE);
230       ex.printStackTrace();
231     }
232
233   }
234
235   /**
236    * DOCUMENT ME!
237    * 
238    * @param e
239    *          DOCUMENT ME!
240    */
241   @Override
242   public void mouseEntered(MouseEvent e)
243   {
244     if (scrollThread != null)
245     {
246       scrollThread.running = false;
247     }
248   }
249
250   /**
251    * DOCUMENT ME!
252    * 
253    * @param e
254    *          DOCUMENT ME!
255    */
256   @Override
257   public void mouseExited(MouseEvent e)
258   {
259     if (av.getWrapAlignment())
260     {
261       return;
262     }
263
264     if (mouseDragging && (e.getY() < 0) && (av.getStartSeq() > 0))
265     {
266       scrollThread = new ScrollThread(true);
267     }
268
269     if (mouseDragging && (e.getY() >= getHeight())
270             && (av.getAlignment().getHeight() > av.getEndSeq()))
271     {
272       scrollThread = new ScrollThread(false);
273     }
274   }
275
276   /**
277    * DOCUMENT ME!
278    * 
279    * @param e
280    *          DOCUMENT ME!
281    */
282   @Override
283   public void mousePressed(MouseEvent e)
284   {
285     if (e.getClickCount() == 2)
286     {
287       return;
288     }
289
290     int seq = alignPanel.seqPanel.findSeq(e);
291
292     if (javax.swing.SwingUtilities.isRightMouseButton(e))
293     {
294       Sequence sq = (Sequence) av.getAlignment().getSequenceAt(seq);
295       // build a new links menu based on the current links + any non-positional
296       // features
297       Vector nlinks = new Vector(Preferences.sequenceURLLinks);
298       SequenceFeature sf[] = sq == null ? null : sq.getDatasetSequence()
299               .getSequenceFeatures();
300       for (int sl = 0; sf != null && sl < sf.length; sl++)
301       {
302         if (sf[sl].begin == sf[sl].end && sf[sl].begin == 0)
303         {
304           if (sf[sl].links != null && sf[sl].links.size() > 0)
305           {
306             for (int l = 0, lSize = sf[sl].links.size(); l < lSize; l++)
307             {
308               nlinks.addElement(sf[sl].links.elementAt(l));
309             }
310           }
311         }
312       }
313
314       jalview.gui.PopupMenu pop = new jalview.gui.PopupMenu(alignPanel, sq,
315               nlinks, new Vector(Preferences.getGroupURLLinks()));
316       pop.show(this, e.getX(), e.getY());
317
318       return;
319     }
320
321     if ((av.getSelectionGroup() == null)
322             || ((!e.isControlDown() && !e.isShiftDown()) && av
323                     .getSelectionGroup() != null))
324     {
325       av.setSelectionGroup(new SequenceGroup());
326       av.getSelectionGroup().setStartRes(0);
327       av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
328     }
329
330     if (e.isShiftDown() && (lastid != -1))
331     {
332       selectSeqs(lastid, seq);
333     }
334     else
335     {
336       selectSeq(seq);
337     }
338     alignPanel.paintAlignment(true);
339   }
340
341   /**
342    * DOCUMENT ME!
343    * 
344    * @param seq
345    *          DOCUMENT ME!
346    */
347   void selectSeq(int seq)
348   {
349     lastid = seq;
350
351     SequenceI pickedSeq = av.getAlignment().getSequenceAt(seq);
352     av.getSelectionGroup().addOrRemove(pickedSeq, true);
353   }
354
355   /**
356    * DOCUMENT ME!
357    * 
358    * @param start
359    *          DOCUMENT ME!
360    * @param end
361    *          DOCUMENT ME!
362    */
363   void selectSeqs(int start, int end)
364   {
365     if (av.getSelectionGroup() == null)
366     {
367       return;
368     }
369
370     if (end >= av.getAlignment().getHeight())
371     {
372       end = av.getAlignment().getHeight() - 1;
373     }
374
375     lastid = start;
376
377     if (end < start)
378     {
379       int tmp = start;
380       start = end;
381       end = tmp;
382       lastid = end;
383     }
384
385     for (int i = start; i <= end; i++)
386     {
387       av.getSelectionGroup().addSequence(
388               av.getAlignment().getSequenceAt(i), i == end);
389     }
390   }
391
392   /**
393    * DOCUMENT ME!
394    * 
395    * @param e
396    *          DOCUMENT ME!
397    */
398   @Override
399   public void mouseReleased(MouseEvent e)
400   {
401     if (scrollThread != null)
402     {
403       scrollThread.running = false;
404     }
405
406     mouseDragging = false;
407     PaintRefresher.Refresh(this, av.getSequenceSetId());
408     // always send selection message when mouse is released
409     av.sendSelection();
410   }
411
412   /**
413    * DOCUMENT ME!
414    * 
415    * @param list
416    *          DOCUMENT ME!
417    */
418   public void highlightSearchResults(List<SequenceI> list)
419   {
420     idCanvas.setHighlighted(list);
421
422     if (list == null)
423     {
424       return;
425     }
426
427     int index = av.getAlignment().findIndex(list.get(0));
428
429     // do we need to scroll the panel?
430     if ((av.getStartSeq() > index) || (av.getEndSeq() < index))
431     {
432       alignPanel.setScrollValues(av.getStartRes(), index);
433     }
434   }
435
436   // this class allows scrolling off the bottom of the visible alignment
437   class ScrollThread extends Thread
438   {
439     boolean running = false;
440
441     boolean up = true;
442
443     public ScrollThread(boolean up)
444     {
445       this.up = up;
446       start();
447     }
448
449     public void stopScrolling()
450     {
451       running = false;
452     }
453
454     @Override
455     public void run()
456     {
457       running = true;
458
459       while (running)
460       {
461         if (alignPanel.scrollUp(up))
462         {
463           // scroll was ok, so add new sequence to selection
464           int seq = av.getStartSeq();
465
466           if (!up)
467           {
468             seq = av.getEndSeq();
469           }
470
471           if (seq < lastid)
472           {
473             selectSeqs(lastid - 1, seq);
474           }
475           else if (seq > lastid)
476           {
477             selectSeqs(lastid + 1, seq);
478           }
479
480           lastid = seq;
481         }
482         else
483         {
484           running = false;
485         }
486
487         alignPanel.paintAlignment(false);
488
489         try
490         {
491           Thread.sleep(100);
492         } catch (Exception ex)
493         {
494         }
495       }
496     }
497   }
498 }