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