Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.gui

File IdPanel.java

 

Coverage histogram

../../img/srcFileCovDistChart1.png
53% of files have more coverage

Code metrics

66
141
23
2
597
364
69
0.49
6.13
11.5
3

Classes

Class Line # Actions
IdPanel 56 122 60 183
0.080402018%
IdPanel.ScrollThread 527 19 9 31
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

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.gui;
22   
23    import jalview.bin.Jalview;
24    import jalview.datamodel.Sequence;
25    import jalview.datamodel.SequenceFeature;
26    import jalview.datamodel.SequenceGroup;
27    import jalview.datamodel.SequenceI;
28    import jalview.io.SequenceAnnotationReport;
29    import jalview.util.MessageManager;
30    import jalview.util.Platform;
31    import jalview.viewmodel.AlignmentViewport;
32    import jalview.viewmodel.ViewportRanges;
33   
34    import java.awt.BorderLayout;
35    import java.awt.event.ActionEvent;
36    import java.awt.event.ActionListener;
37    import java.awt.event.MouseEvent;
38    import java.awt.event.MouseListener;
39    import java.awt.event.MouseMotionListener;
40    import java.awt.event.MouseWheelEvent;
41    import java.awt.event.MouseWheelListener;
42    import java.util.List;
43   
44    import javax.swing.JPanel;
45    import javax.swing.SwingUtilities;
46    import javax.swing.Timer;
47    import javax.swing.ToolTipManager;
48   
49    /**
50    * This panel hosts alignment sequence ids and responds to mouse clicks on them,
51    * as well as highlighting ids matched by a search from the Find menu.
52    *
53    * @author $author$
54    * @version $Revision$
55    */
 
56    public class IdPanel extends JPanel
57    implements MouseListener, MouseMotionListener, MouseWheelListener
58    {
59    private IdCanvas idCanvas;
60   
61    protected AlignmentViewport av;
62   
63    protected AlignmentPanel alignPanel;
64   
65    ScrollThread scrollThread = null;
66   
67    String linkImageURL;
68   
69    int offy;
70   
71    // int width;
72    int lastid = -1;
73   
74    boolean mouseDragging = false;
75   
76    private final SequenceAnnotationReport seqAnnotReport;
77   
78    /**
79    * Creates a new IdPanel object.
80    *
81    * @param av
82    * @param parent
83    */
 
84  217 toggle public IdPanel(AlignViewport av, AlignmentPanel parent)
85    {
86  217 this.av = av;
87  217 alignPanel = parent;
88  217 setIdCanvas(new IdCanvas(av));
89  217 linkImageURL = getClass().getResource("/images/link.gif").toString();
90  217 seqAnnotReport = new SequenceAnnotationReport(linkImageURL);
91  217 setLayout(new BorderLayout());
92  217 add(getIdCanvas(), BorderLayout.CENTER);
93  217 addMouseListener(this);
94  217 addMouseMotionListener(this);
95  217 addMouseWheelListener(this);
96  217 ToolTipManager.sharedInstance().registerComponent(this);
97    }
98   
99    /**
100    * Respond to mouse movement by constructing tooltip text for the sequence id
101    * under the mouse.
102    *
103    * @param e
104    * DOCUMENT ME!
105    */
 
106  0 toggle @Override
107    public void mouseMoved(MouseEvent e)
108    {
109  0 SeqPanel sp = alignPanel.getSeqPanel();
110  0 int seq = Math.max(0, sp.findSeq(e));
111  0 if (seq > -1 && seq < av.getAlignment().getHeight())
112    {
113  0 SequenceI sequence = av.getAlignment().getSequenceAt(seq);
114  0 StringBuilder tip = new StringBuilder(64);
115  0 seqAnnotReport.createTooltipAnnotationReport(tip, sequence,
116    av.isShowDBRefs(), av.isShowNPFeats(), sp.seqCanvas.fr);
117  0 setToolTipText(JvSwingUtils.wrapTooltip(true,
118    sequence.getDisplayId(true) + " " + tip.toString()));
119    }
120    }
121   
122    /**
123    * Responds to a mouse drag by selecting the sequences under the dragged
124    * region.
125    *
126    * @param e
127    */
 
128  0 toggle @Override
129    public void mouseDragged(MouseEvent e)
130    {
131  0 mouseDragging = true;
132   
133  0 int seq = Math.max(0, alignPanel.getSeqPanel().findSeq(e));
134   
135  0 if (seq < lastid)
136    {
137  0 selectSeqs(lastid - 1, seq);
138    }
139  0 else if (seq > lastid)
140    {
141  0 selectSeqs(lastid + 1, seq);
142    }
143   
144  0 lastid = seq;
145  0 alignPanel.paintAlignment(false, false);
146    }
147   
148    /**
149    * Response to the mouse wheel by scrolling the alignment panel.
150    */
 
151  0 toggle @Override
152    public void mouseWheelMoved(MouseWheelEvent e)
153    {
154  0 e.consume();
155  0 double wheelRotation = e.getPreciseWheelRotation();
156  0 if (wheelRotation > 0)
157    {
158  0 if (e.isShiftDown())
159    {
160  0 av.getRanges().scrollRight(true);
161    }
162    else
163    {
164  0 av.getRanges().scrollUp(false);
165    }
166    }
167  0 else if (wheelRotation < 0)
168    {
169  0 if (e.isShiftDown())
170    {
171  0 av.getRanges().scrollRight(false);
172    }
173    else
174    {
175  0 av.getRanges().scrollUp(true);
176    }
177    }
178    }
179   
180    /**
181    * Handle a mouse click event. Currently only responds to a double-click. The
182    * action is to try to open a browser window at a URL that searches for the
183    * selected sequence id. The search URL is configured in Preferences |
184    * Connections | URL link from Sequence ID. For example:
185    *
186    * http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$
187    *
188    * @param e
189    */
 
190  0 toggle @Override
191    public void mouseClicked(MouseEvent e)
192    {
193    /*
194    * Ignore single click. Ignore 'left' click followed by 'right' click (user
195    * selects a row then its pop-up menu).
196    */
197  0 if (e.getClickCount() < 2 || SwingUtilities.isRightMouseButton(e))
198    {
199    // reinstate isRightMouseButton check to ignore mouse-related popup events
200    // note - this does nothing on default MacBookPro force-trackpad config!
201  0 return;
202    }
203   
204  0 int seq = alignPanel.getSeqPanel().findSeq(e);
205  0 String id = av.getAlignment().getSequenceAt(seq).getName();
206  0 String url = Preferences.sequenceUrlLinks.getPrimaryUrl(id);
207   
208  0 try
209    {
210  0 jalview.util.BrowserLauncher.openURL(url);
211    } catch (Exception ex)
212    {
213  0 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
214    MessageManager.getString("label.web_browser_not_found_unix"),
215    MessageManager.getString("label.web_browser_not_found"),
216    JvOptionPane.WARNING_MESSAGE);
217  0 ex.printStackTrace();
218    }
219    }
220   
221    /**
222    * On (re-)entering the panel, stop any scrolling
223    *
224    * @param e
225    */
 
226  0 toggle @Override
227    public void mouseEntered(MouseEvent e)
228    {
229  0 stopScrolling();
230    }
231   
232    /**
233    * Interrupts the scroll thread if one is running
234    */
 
235  0 toggle void stopScrolling()
236    {
237  0 if (scrollThread != null)
238    {
239  0 scrollThread.stopScrolling();
240    }
241    }
242   
243    /**
244    * DOCUMENT ME!
245    *
246    * @param e
247    * DOCUMENT ME!
248    */
 
249  0 toggle @Override
250    public void mouseExited(MouseEvent e)
251    {
252  0 if (av.getWrapAlignment())
253    {
254  0 return;
255    }
256   
257  0 if (mouseDragging)
258    {
259    /*
260    * on mouse drag above or below the panel, start
261    * scrolling if there are more sequences to show
262    */
263  0 ViewportRanges ranges = av.getRanges();
264  0 if (e.getY() < 0 && ranges.getStartSeq() > 0)
265    {
266  0 startScrolling(true);
267    }
268  0 else if (e.getY() >= getHeight()
269    && ranges.getEndSeq() <= av.getAlignment().getHeight())
270    {
271  0 startScrolling(false);
272    }
273    }
274    }
275   
276    /**
277    * Starts scrolling either up or down
278    *
279    * @param up
280    */
 
281  0 toggle void startScrolling(boolean up)
282    {
283  0 scrollThread = new ScrollThread(up);
284  0 if (!Jalview.isJS())
285    {
286    /*
287    * Java - run in a new thread
288    */
289  0 scrollThread.start();
290    }
291    else
292    {
293    /*
294    * for JalviewJS using Swing Timer
295    */
296  0 Timer t = new Timer(20, new ActionListener()
297    {
 
298  0 toggle @Override
299    public void actionPerformed(ActionEvent e)
300    {
301  0 if (scrollThread != null)
302    {
303    // if (!scrollOnce() {t.stop();}) gives compiler error :-(
304  0 scrollThread.scrollOnce();
305    }
306    }
307    });
308  0 t.addActionListener(new ActionListener()
309    {
 
310  0 toggle @Override
311    public void actionPerformed(ActionEvent e)
312    {
313  0 if (scrollThread == null)
314    {
315    // finished and nulled itself
316  0 t.stop();
317    }
318    }
319    });
320  0 t.start();
321    }
322    }
323   
324    /**
325    * Respond to a mouse press. Does nothing for (left) double-click as this is
326    * handled by mouseClicked().
327    *
328    * Right mouse down - construct and show context menu.
329    *
330    * Ctrl-down or Shift-down - add to or expand current selection group if there
331    * is one.
332    *
333    * Mouse down - select this sequence.
334    *
335    * @param e
336    */
 
337  0 toggle @Override
338    public void mousePressed(MouseEvent e)
339    {
340  0 if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e))
341    {
342  0 return;
343    }
344   
345  0 if (e.isPopupTrigger()) // Mac reports this in mousePressed
346    {
347  0 showPopupMenu(e);
348  0 return;
349    }
350   
351    /*
352    * defer right-mouse click handling to mouseReleased on Windows
353    * (where isPopupTrigger() will answer true)
354    * NB isRightMouseButton is also true for Cmd-click on Mac
355    */
356  0 if (SwingUtilities.isRightMouseButton(e) && !Platform.isAMac())
357    {
358  0 return;
359    }
360   
361  0 if ((av.getSelectionGroup() == null)
362    || (!jalview.util.Platform.isControlDown(e) && !e.isShiftDown()
363    && av.getSelectionGroup() != null))
364    {
365  0 av.setSelectionGroup(new SequenceGroup());
366  0 av.getSelectionGroup().setStartRes(0);
367  0 av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
368    }
369   
370  0 int seq = alignPanel.getSeqPanel().findSeq(e);
371  0 if (e.isShiftDown() && (lastid != -1))
372    {
373  0 selectSeqs(lastid, seq);
374    }
375    else
376    {
377  0 selectSeq(seq);
378    }
379   
380  0 av.isSelectionGroupChanged(true);
381   
382  0 alignPanel.paintAlignment(false, false);
383    }
384   
385    /**
386    * Build and show the popup-menu at the right-click mouse position
387    *
388    * @param e
389    */
 
390  0 toggle void showPopupMenu(MouseEvent e)
391    {
392  0 int seq2 = alignPanel.getSeqPanel().findSeq(e);
393  0 Sequence sq = (Sequence) av.getAlignment().getSequenceAt(seq2);
394   
395    /*
396    * build a new links menu based on the current links
397    * and any non-positional features
398    */
399  0 List<String> nlinks = Preferences.sequenceUrlLinks.getLinksForMenu();
400  0 List<SequenceFeature> features = sq.getFeatures().getNonPositionalFeatures();
401  0 for (SequenceFeature sf : features)
402    {
403  0 if (sf.links != null)
404    {
405  0 for (String link : sf.links)
406    {
407  0 nlinks.add(link);
408    }
409    }
410    }
411   
412  0 PopupMenu pop = new PopupMenu(alignPanel, sq, features,
413    Preferences.getGroupURLLinks());
414  0 pop.show(this, e.getX(), e.getY());
415    }
416   
417    /**
418    * Toggle whether the sequence is part of the current selection group.
419    *
420    * @param seq
421    */
 
422  0 toggle void selectSeq(int seq)
423    {
424  0 lastid = seq;
425   
426  0 SequenceI pickedSeq = av.getAlignment().getSequenceAt(seq);
427  0 av.getSelectionGroup().addOrRemove(pickedSeq, true);
428    }
429   
430    /**
431    * Add contiguous rows of the alignment to the current selection group. Does
432    * nothing if there is no selection group.
433    *
434    * @param start
435    * @param end
436    */
 
437  0 toggle void selectSeqs(int start, int end)
438    {
439  0 if (av.getSelectionGroup() == null)
440    {
441  0 return;
442    }
443   
444  0 if (end >= av.getAlignment().getHeight())
445    {
446  0 end = av.getAlignment().getHeight() - 1;
447    }
448   
449  0 lastid = start;
450   
451  0 if (end < start)
452    {
453  0 int tmp = start;
454  0 start = end;
455  0 end = tmp;
456  0 lastid = end;
457    }
458   
459  0 for (int i = start; i <= end; i++)
460    {
461  0 av.getSelectionGroup().addSequence(av.getAlignment().getSequenceAt(i),
462    i == end);
463    }
464    }
465   
466    /**
467    * Respond to mouse released. Refreshes the display and triggers broadcast of
468    * the new selection group to any listeners.
469    *
470    * @param e
471    */
 
472  0 toggle @Override
473    public void mouseReleased(MouseEvent e)
474    {
475  0 stopScrolling();
476   
477  0 mouseDragging = false;
478  0 PaintRefresher.Refresh(this, av.getSequenceSetId());
479    // always send selection message when mouse is released
480  0 av.sendSelection();
481   
482  0 if (e.isPopupTrigger()) // Windows reports this in mouseReleased
483    {
484  0 showPopupMenu(e);
485    }
486    }
487   
488    /**
489    * Highlight sequence ids that match the given list, and if necessary scroll
490    * to the start sequence of the list.
491    *
492    * @param list
493    */
 
494  0 toggle public void highlightSearchResults(List<SequenceI> list)
495    {
496  0 getIdCanvas().setHighlighted(list);
497   
498  0 if (list == null)
499    {
500  0 return;
501    }
502   
503  0 int index = av.getAlignment().findIndex(list.get(0));
504   
505    // do we need to scroll the panel?
506  0 if ((av.getRanges().getStartSeq() > index)
507    || (av.getRanges().getEndSeq() < index))
508    {
509  0 av.getRanges().setStartSeq(index);
510    }
511    }
512   
 
513  2234 toggle public IdCanvas getIdCanvas()
514    {
515  2234 return idCanvas;
516    }
517   
 
518  217 toggle public void setIdCanvas(IdCanvas idCanvas)
519    {
520  217 this.idCanvas = idCanvas;
521    }
522   
523    /**
524    * Performs scrolling of the visible alignment up or down, adding newly
525    * visible sequences to the current selection
526    */
 
527    class ScrollThread extends Thread
528    {
529    private boolean running = false;
530   
531    private boolean up;
532   
533    /**
534    * Constructor for a thread that scrolls either up or down
535    *
536    * @param up
537    */
 
538  0 toggle public ScrollThread(boolean up)
539    {
540  0 this.up = up;
541  0 setName("IdPanel$ScrollThread$" + String.valueOf(up));
542  0 start();
543    }
544   
545    /**
546    * Sets a flag to stop the scrolling
547    */
 
548  0 toggle public void stopScrolling()
549    {
550  0 running = false;
551    }
552   
553    /**
554    * Scrolls the alignment either up or down, one row at a time, adding newly
555    * visible sequences to the current selection. Speed is limited to a maximum
556    * of ten rows per second. The thread exits when the end of the alignment is
557    * reached or a flag is set to stop it by a call to stopScrolling.
558    */
 
559  0 toggle @Override
560    public void run()
561    {
562  0 running = true;
563   
564  0 while (running)
565    {
566  0 running = scrollOnce();
567  0 try
568    {
569  0 Thread.sleep(100);
570    } catch (Exception ex)
571    {
572    }
573    }
574  0 IdPanel.this.scrollThread = null;
575    }
576   
577    /**
578    * Scrolls one row up or down. Answers true if a scroll could be done, false
579    * if not (top or bottom of alignment reached).
580    */
 
581  0 toggle boolean scrollOnce()
582    {
583  0 ViewportRanges ranges = IdPanel.this.av.getRanges();
584  0 if (ranges.scrollUp(up))
585    {
586  0 int toSeq = up ? ranges.getStartSeq() : ranges.getEndSeq();
587  0 int fromSeq = toSeq < lastid ? lastid - 1 : lastid + 1;
588  0 IdPanel.this.selectSeqs(fromSeq, toSeq);
589  0 lastid = toSeq;
590  0 alignPanel.paintAlignment(false, false);
591  0 return true;
592    }
593   
594  0 return false;
595    }
596    }
597    }