Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 16:11:35 GMT
  2. Package jalview.gui

File OverviewPanel.java

 

Coverage histogram

../../img/srcFileCovDistChart6.png
37% of files have more coverage

Code metrics

36
109
25
1
501
327
47
0.43
4.36
25
1.88

Classes

Class Line # Actions
OverviewPanel 61 109 47
0.6058823560.6%
 

Contributing tests

This file is covered by 10 tests. .

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.api.AlignViewportI;
24    import jalview.bin.Cache;
25    import jalview.renderer.OverviewRenderer;
26    import jalview.util.MessageManager;
27    import jalview.util.Platform;
28    import jalview.viewmodel.OverviewDimensions;
29    import jalview.viewmodel.OverviewDimensionsHideHidden;
30    import jalview.viewmodel.OverviewDimensionsShowHidden;
31    import jalview.viewmodel.ViewportListenerI;
32   
33    import java.awt.BorderLayout;
34    import java.awt.Cursor;
35    import java.awt.Dimension;
36    import java.awt.Rectangle;
37    import java.awt.event.ActionEvent;
38    import java.awt.event.ActionListener;
39    import java.awt.event.ComponentAdapter;
40    import java.awt.event.ComponentEvent;
41    import java.awt.event.MouseAdapter;
42    import java.awt.event.MouseEvent;
43    import java.awt.event.MouseMotionAdapter;
44    import java.beans.PropertyChangeEvent;
45    import java.beans.PropertyVetoException;
46   
47    import javax.swing.JCheckBoxMenuItem;
48    import javax.swing.JInternalFrame;
49    import javax.swing.JPanel;
50    import javax.swing.JPopupMenu;
51    import javax.swing.SwingUtilities;
52   
53    /**
54    * Panel displaying an overview of the full alignment, with an interactive box
55    * representing the viewport onto the alignment.
56    *
57    * @author $author$
58    * @version $Revision$
59    */
60    @SuppressWarnings("serial")
 
61    public class OverviewPanel extends JPanel
62    implements Runnable, ViewportListenerI
63    {
64    protected OverviewDimensions od;
65   
66    private OverviewCanvas oviewCanvas;
67   
68    private AlignViewportI av;
69   
70    private AlignmentPanel ap;
71   
72    private JInternalFrame internalFrame;
73   
74    protected JCheckBoxMenuItem displayToggle;
75   
76    protected boolean showHidden = true;
77   
78    protected boolean draggingBox = false;
79   
80    private Dimension dim;
81   
82    private boolean showProgress = !Platform.isJS();
83    protected ProgressPanel progressPanel;
84   
85    /**
86    * Creates the appropriate type of OverviewDimensions, with the desired size
87    */
 
88  43 toggle private void createOverviewDimensions()
89    {
90  43 boolean showAnnotation = (av.isShowAnnotation()
91    && av.getAlignmentConservationAnnotation() != null);
92  43 if (showHidden)
93    {
94  6 od = new OverviewDimensionsShowHidden(av.getRanges(), showAnnotation,
95    dim);
96    }
97    else
98    {
99  37 od = new OverviewDimensionsHideHidden(av.getRanges(), showAnnotation,
100    dim);
101    }
102    }
103   
104    /**
105    * * Creates a new OverviewPanel object.
106    *
107    * @param alPanel
108    * The alignment panel which is shown in the overview panel
109    * @param frame
110    * @param isShowHidden
111    * TODO
112    */
 
113  43 toggle public OverviewPanel(AlignmentPanel alPanel, Dimension dim,
114    boolean isShowHidden)
115    {
116  43 this.av = alPanel.av;
117  43 this.ap = alPanel;
118  43 this.dim = dim;
119   
120  43 showHidden = isShowHidden;
121  43 createOverviewDimensions();
122  43 setLayout(new BorderLayout());
123  43 progressPanel = new ProgressPanel(OverviewRenderer.UPDATE,
124    MessageManager.getString("label.oview_calc"), getWidth());
125  43 this.add(progressPanel, BorderLayout.SOUTH);
126  43 oviewCanvas = new OverviewCanvas(od, av, progressPanel);
127   
128  43 add(oviewCanvas, BorderLayout.CENTER);
129   
130  43 av.getRanges().addPropertyChangeListener(this);
131   
132    // without this the overview window does not size to fit the overview canvas
133  43 setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
134   
135  43 addComponentListener(new ComponentAdapter()
136    {
 
137  76 toggle @Override
138    public void componentResized(ComponentEvent evt)
139    {
140    // Resize is called on the initial display of the overview.
141    // This code adjusts sizes to account for the progress bar if it has not
142    // already been accounted for, which triggers another resize call for
143    // the correct sizing, at which point the overview image is updated.
144    // (This avoids a double recalculation of the image.)
145  76 if (getWidth() == od.getWidth() && getHeight() == od.getHeight()
146    + progressPanel.getHeight())
147    {
148  73 updateOverviewImage();
149    }
150    else
151    {
152  3 if ((getWidth() > 0) && (getHeight() > 0))
153    {
154  3 od.setWidth(getWidth());
155  3 od.setHeight(getHeight() - progressPanel.getHeight());
156    }
157   
158  3 setPreferredSize(new Dimension(od.getWidth(),
159    od.getHeight() + progressPanel.getHeight()));
160    }
161    }
162   
163    });
164   
165  43 addMouseMotionListener(new MouseMotionAdapter()
166    {
 
167  0 toggle @Override
168    public void mouseDragged(MouseEvent evt)
169    {
170  0 if (!SwingUtilities.isRightMouseButton(evt))
171    {
172  0 if (draggingBox)
173    {
174    // set the mouse position as a fixed point in the box
175    // and drag relative to that position
176  0 od.adjustViewportFromMouse(evt.getX(), evt.getY(),
177    av.getAlignment().getHiddenSequences(),
178    av.getAlignment().getHiddenColumns());
179    }
180    else
181    {
182  0 od.updateViewportFromMouse(evt.getX(), evt.getY(),
183    av.getAlignment().getHiddenSequences(),
184    av.getAlignment().getHiddenColumns());
185    }
186    }
187    }
188   
 
189  0 toggle @Override
190    public void mouseMoved(MouseEvent evt)
191    {
192  0 if (od.isPositionInBox(evt.getX(), evt.getY()))
193    {
194    /*
195    * using HAND_CURSOR rather than DRAG_CURSOR
196    * as the latter is not supported on Mac
197    */
198  0 getParent().setCursor(
199    Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
200    }
201    else
202    {
203    // reset cursor
204  0 getParent().setCursor(
205    Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
206    }
207    }
208   
209    });
210   
211  43 addMouseListener(new MouseAdapter()
212    {
 
213  0 toggle @Override
214    public void mousePressed(MouseEvent evt)
215    {
216   
217  0 if (Platform.isWinRightButton(evt)) {
218  0 showPopupMenu(evt);
219  0 return;
220    }
221  0 if (SwingUtilities.isRightMouseButton(evt)) {
222  0 return;
223    }
224    // don't do anything if the mouse press is in the overview's box
225    // (wait to see if it's a drag instead)
226    // otherwise update the viewport
227  0 if (!od.isPositionInBox(evt.getX(), evt.getY()))
228    {
229  0 draggingBox = false;
230   
231    // display drag cursor at mouse position
232  0 setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
233   
234  0 od.updateViewportFromMouse(evt.getX(), evt.getY(),
235    av.getAlignment().getHiddenSequences(),
236    av.getAlignment().getHiddenColumns());
237  0 getParent().setCursor(
238    Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
239    }
240    else
241    {
242  0 draggingBox = true;
243  0 od.setDragPoint(evt.getX(), evt.getY(),
244    av.getAlignment().getHiddenSequences(),
245    av.getAlignment().getHiddenColumns());
246    }
247    }
248   
 
249  0 toggle @Override
250    public void mouseClicked(MouseEvent evt)
251    {
252  0 if (SwingUtilities.isRightMouseButton(evt))
253    {
254  0 showPopupMenu(evt);
255    }
256    }
257   
 
258  0 toggle @Override
259    public void mouseReleased(MouseEvent evt)
260    {
261  0 draggingBox = false;
262    }
263   
264    });
265   
266    /*
267    * Javascript does not call componentResized on initial display,
268    * so do the update here
269    */
270  43 if (Platform.isJS())
271    {
272  0 updateOverviewImage();
273    }
274    }
275   
276    /*
277    * Displays the popup menu and acts on user input
278    */
 
279  0 toggle protected void showPopupMenu(MouseEvent e)
280    {
281  0 JPopupMenu popup = new JPopupMenu();
282  0 ActionListener menuListener = new ActionListener()
283    {
 
284  0 toggle @Override
285    public void actionPerformed(ActionEvent event)
286    {
287    // switch on/off the hidden columns view
288  0 toggleHiddenColumns();
289  0 displayToggle.setSelected(showHidden);
290    }
291    };
292  0 displayToggle = new JCheckBoxMenuItem(
293    MessageManager.getString("label.togglehidden"));
294  0 displayToggle.setEnabled(true);
295  0 displayToggle.setSelected(showHidden);
296  0 popup.add(displayToggle);
297  0 displayToggle.addActionListener(menuListener);
298  0 popup.show(this, e.getX(), e.getY());
299    }
300   
301    /*
302    * Toggle overview display between showing hidden columns and hiding hidden columns
303    */
 
304  0 toggle protected void toggleHiddenColumns()
305    {
306  0 showHidden = !showHidden;
307  0 createOverviewDimensions();
308  0 oviewCanvas.resetOviewDims(od);
309  0 updateOverviewImage();
310  0 setBoxPosition();
311    }
312   
313    /**
314    * Updates the overview image when the related alignment panel is updated
315    */
 
316  679 toggle public void updateOverviewImage()
317    {
318  679 if (oviewCanvas == null)
319    {
320    /*
321    * panel has been disposed
322    */
323  0 return;
324    }
325   
326  679 if ((getWidth() > 0) && (getHeight() > 0))
327    {
328  676 od.setWidth(getWidth());
329  676 od.setHeight(getHeight() - progressPanel.getHeight());
330    }
331   
332  679 setPreferredSize(new Dimension(od.getWidth(),
333    od.getHeight() + progressPanel.getHeight()));
334   
335  679 if (oviewCanvas.restartDraw())
336    {
337  531 return;
338    }
339   
340  148 Thread thread = new Thread(this);
341  148 thread.start();
342  148 repaint();
343   
344   
345    }
346   
 
347  148 toggle @Override
348    public void run()
349    {
350  148 if (oviewCanvas != null)
351    {
352  137 oviewCanvas.draw(av.isShowSequenceFeatures(),
353    (av.isShowAnnotation()
354    && av.getAlignmentConservationAnnotation() != null),
355    ap.getSeqPanel().seqCanvas.getFeatureRenderer());
356  124 setBoxPosition();
357    }
358    }
359   
360    /**
361    * Update the overview panel box when the associated alignment panel is
362    * changed
363    *
364    */
 
365  82 toggle private void setBoxPositionOnly()
366    {
367  82 if (od != null)
368    {
369  82 int oldX = od.getBoxX();
370  82 int oldY = od.getBoxY();
371  82 int oldWidth = od.getBoxWidth();
372  82 int oldHeight = od.getBoxHeight();
373  82 od.setBoxPosition(av.getAlignment().getHiddenSequences(),
374    av.getAlignment().getHiddenColumns());
375  82 repaint(oldX - 1, oldY - 1, oldWidth + 2, oldHeight + 2);
376  82 repaint(od.getBoxX(), od.getBoxY(), od.getBoxWidth(),
377    od.getBoxHeight());
378    }
379    }
380   
 
381  124 toggle private void setBoxPosition()
382    {
383  124 if (od != null)
384    {
385  124 od.setBoxPosition(av.getAlignment().getHiddenSequences(),
386    av.getAlignment().getHiddenColumns());
387  124 repaint();
388    }
389    }
390   
 
391  82 toggle @Override
392    public void propertyChange(PropertyChangeEvent evt)
393    {
394  82 setBoxPositionOnly();
395    }
396   
397    /**
398    * Removes this object as a property change listener, and nulls references
399    */
 
400  44 toggle protected void dispose()
401    {
402  44 try
403    {
404  44 if (av != null)
405    {
406  44 av.getRanges().removePropertyChangeListener(this);
407    }
408   
409  44 oviewCanvas.dispose();
410   
411    /*
412    * close the parent frame (which also removes it from the
413    * Desktop Windows menu)
414    */
415  44 ((JInternalFrame) SwingUtilities.getAncestorOfClass(
416    JInternalFrame.class, (this))).setClosed(true);
417    } catch (PropertyVetoException e)
418    {
419    // ignore
420    } finally
421    {
422  44 progressPanel = null;
423  44 av = null;
424  44 oviewCanvas = null;
425  44 ap = null;
426  44 od = null;
427  44 internalFrame = null;
428    }
429    }
430   
 
431  17 toggle public boolean isShowHiddenRegions()
432    {
433  17 return showHidden;
434    }
435   
 
436  59 toggle public OverviewCanvas getCanvas()
437    {
438  59 return oviewCanvas;
439    }
440   
441    /**
442    * Sets the title of the enclosing frame
443    *
444    * @param title
445    */
 
446  113 toggle public void setTitle(String title)
447    {
448  113 internalFrame.setTitle(title);
449    }
450   
451    /**
452    * Returns the title of the enclosing frame
453    *
454    * @return title
455    */
 
456  68 toggle public String getTitle()
457    {
458  68 return internalFrame.getTitle();
459    }
460   
461    /**
462    * Sets the bounds of the frame holding the Overview panel
463    *
464    * @param xpos
465    * @param ypos
466    * @param width
467    * @param height
468    */
 
469  13 toggle public void setFrameBounds(int xpos, int ypos, int width, int height)
470    {
471  13 internalFrame.setBounds(xpos, ypos, width, height);
472    }
473   
474    /**
475    * Returns the bounds of the enclosing frame
476    *
477    * @return
478    */
 
479  16 toggle public Rectangle getFrameBounds()
480    {
481  16 return internalFrame.getBounds();
482    }
483   
484    /**
485    * Closes the frame containing the overview panel
486    */
 
487  12 toggle public void close()
488    {
489  12 internalFrame.dispose();
490    }
491   
492    /**
493    * set the containing frame - used to hold the title
494    * NB JAL-4107 overview title needs to be shown in an embedded jlabel in 2.12
495    * @param frame
496    */
 
497  43 toggle public void setInternalFrame(JInternalFrame frame)
498    {
499  43 internalFrame = frame;
500    }
501    }