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