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