2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import jalview.api.AlignViewportI;
24 import jalview.api.AlignmentViewPanel;
25 import jalview.bin.Cache;
26 import jalview.renderer.OverviewRenderer;
27 import jalview.util.MessageManager;
28 import jalview.util.Platform;
29 import jalview.viewmodel.OverviewDimensions;
30 import jalview.viewmodel.OverviewDimensionsHideHidden;
31 import jalview.viewmodel.OverviewDimensionsShowHidden;
32 import jalview.viewmodel.ViewportListenerI;
34 import java.awt.BorderLayout;
35 import java.awt.Cursor;
36 import java.awt.Dimension;
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;
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;
54 * Panel displaying an overview of the full alignment, with an interactive box
55 * representing the viewport onto the alignment.
60 @SuppressWarnings("serial")
61 public class OverviewPanel extends JPanel
62 implements Runnable, ViewportListenerI
64 protected OverviewDimensions od;
66 OverviewCanvas canvas;
68 protected AlignViewportI av;
70 AlignmentViewPanel ap;
72 protected JCheckBoxMenuItem displayToggle;
74 protected boolean showHidden = true;
76 protected boolean draggingBox = false;
78 protected ProgressPanel progressPanel;
80 private Dimension dim;
82 private boolean showProgress = !Platform.isJS(); // Jalview.getInstance().getShowStatus()
85 * Creates a new OverviewPanel object.
88 * The alignment panel which is shown in the overview panel
90 public OverviewPanel(AlignmentViewPanel alPanel, Dimension dim)
92 this.av = alPanel.getAlignViewport();
96 showHidden = Cache.getDefault(Preferences.SHOW_OV_HIDDEN_AT_START,
98 createOverviewDimensions();
99 setLayout(new BorderLayout());
100 progressPanel = new ProgressPanel(OverviewRenderer.UPDATE,
101 MessageManager.getString("label.oview_calc"), getWidth());
102 if (showProgress) // BH 2019
104 add(progressPanel, BorderLayout.SOUTH);
106 canvas = new OverviewCanvas(this, od, av,
107 showProgress ? progressPanel : null);
108 canvas.setPreferredSize(canvas.getSize());
109 add(canvas, BorderLayout.CENTER);
111 av.getRanges().addPropertyChangeListener(this);
113 // without this the overview window does not size to fit the overview canvas
114 // BH - no,no! - This does not include the progressPanel!
115 // BH the problem was that OverviewCanvas.setPreferredSize() had not been set.
116 // setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
118 addComponentListener(new ComponentAdapter()
121 public void componentResized(ComponentEvent evt)
123 int ph = (progressPanel.getParent() == null ? 0
124 : progressPanel.getHeight());
125 // Resize is called on the initial display of the overview.
126 // This code adjusts sizes to account for the progress bar if it has not
127 // already been accounted for, which triggers another resize call for
128 // the correct sizing, at which point the overview image is updated.
129 // (This avoids a double recalculation of the image.)
130 if (getWidth() == od.getWidth()
131 && getHeight() == od.getHeight() + ph)
133 // BH: resizing is now exceptionally fast.
134 updateOverviewImage();
140 if ((w > 0) && (h > 0))
144 dim.setSize(w, h - ph);
147 od.setHeight(h - ph);
148 updateOverviewImage();
151 // BH 2019.07.29 this is unnecessary -- it is what layout managers are
153 // setPreferredSize(new Dimension(od.getWidth(), od.getHeight() +
160 addMouseMotionListener(new MouseMotionAdapter()
163 public void mouseDragged(MouseEvent evt)
165 if (!SwingUtilities.isRightMouseButton(evt))
169 // set the mouse position as a fixed point in the box
170 // and drag relative to that position
171 od.adjustViewportFromMouse(evt.getX(), evt.getY(),
172 av.getAlignment().getHiddenSequences(),
173 av.getAlignment().getHiddenColumns());
177 od.updateViewportFromMouse(evt.getX(), evt.getY(),
178 av.getAlignment().getHiddenSequences(),
179 av.getAlignment().getHiddenColumns());
185 public void mouseMoved(MouseEvent evt)
187 if (od.isPositionInBox(evt.getX(), evt.getY()))
190 * using HAND_CURSOR rather than DRAG_CURSOR
191 * as the latter is not supported on Mac
193 getParent().setCursor(
194 Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
199 getParent().setCursor(
200 Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
206 addMouseListener(new MouseAdapter()
209 public void mousePressed(MouseEvent evt)
212 if (Platform.isWinRightButton(evt))
217 if (SwingUtilities.isRightMouseButton(evt))
221 // don't do anything if the mouse press is in the overview's box
222 // (wait to see if it's a drag instead)
223 // otherwise update the viewport
224 if (!od.isPositionInBox(evt.getX(), evt.getY()))
228 // display drag cursor at mouse position
229 setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
231 od.updateViewportFromMouse(evt.getX(), evt.getY(),
232 av.getAlignment().getHiddenSequences(),
233 av.getAlignment().getHiddenColumns());
234 getParent().setCursor(
235 Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
240 od.setDragPoint(evt.getX(), evt.getY(),
241 av.getAlignment().getHiddenSequences(),
242 av.getAlignment().getHiddenColumns());
247 public void mouseClicked(MouseEvent evt)
249 if (SwingUtilities.isRightMouseButton(evt))
256 public void mouseReleased(MouseEvent evt)
264 // * Javascript does not call componentResized on initial display,
265 // * so do the update here
267 // if (Platform.isJS())
269 // updateOverviewImage();
274 * Create the appropriate type of OverViewDimensions, with the desired size.
276 private void createOverviewDimensions()
278 boolean showAnnotation = (av.isShowAnnotation()
279 && av.getAlignmentConservationAnnotation() != null);
282 od = new OverviewDimensionsShowHidden(av.getRanges(), showAnnotation,
287 od = new OverviewDimensionsHideHidden(av.getRanges(), showAnnotation,
294 * Displays the popup menu and acts on user input
296 protected void showPopupMenu(MouseEvent e)
298 JPopupMenu popup = new JPopupMenu();
299 ActionListener menuListener = new ActionListener()
302 public void actionPerformed(ActionEvent event)
304 // switch on/off the hidden columns view
305 toggleHiddenColumns();
306 displayToggle.setSelected(showHidden);
309 displayToggle = new JCheckBoxMenuItem(
310 MessageManager.getString("label.togglehidden"));
311 displayToggle.setEnabled(true);
312 displayToggle.setSelected(showHidden);
313 popup.add(displayToggle);
314 displayToggle.addActionListener(menuListener);
315 popup.show(this, e.getX(), e.getY());
319 * Toggle overview display between showing hidden columns and hiding hidden columns
321 protected void toggleHiddenColumns()
323 showHidden = !showHidden;
324 createOverviewDimensions();
325 canvas.resetOviewDims(od);
326 updateOverviewImage();
331 * Updates the overview image when the related alignment panel is updated.
335 * AlignFrame.setFeatureGroupState
337 * AlignmentPanel.paintAlignment(true,...) (117 references)
339 * OverviewPanel..componentResized() OverviewPanel.toggleHiddenColumns()
341 * PopupMenu for action.reveal_sequences, action.reveal_all
343 * SliderPanel.mouseReleased()
346 public void updateOverviewImage()
351 * panel has been disposed
356 int ph = (progressPanel.getParent() == null ? 0
357 : progressPanel.getHeight());
359 if ((getWidth() > 0) && (getHeight() > 0))
361 od.setWidth(getWidth());
362 od.setHeight(getHeight() - ph);
365 setPreferredSize(new Dimension(od.getWidth(), od.getHeight() + ph));
367 if (canvas.restartDraw())
372 Thread thread = new Thread(this);
382 canvas.draw(av.isShowSequenceFeatures(),
383 (av.isShowAnnotation()
384 && av.getAlignmentConservationAnnotation() != null),
385 ap.getFeatureRenderer());
390 * Update the overview panel box when the associated alignment panel is
394 private void setBoxPositionOnly()
399 int oldX = od.getBoxX();
400 int oldY = od.getBoxY();
401 int oldWidth = od.getBoxWidth();
402 int oldHeight = od.getBoxHeight();
403 od.setBoxPosition(av.getAlignment().getHiddenSequences(),
404 av.getAlignment().getHiddenColumns());
405 repaint(oldX - 1, oldY - 1, oldWidth + 2, oldHeight + 2);
406 repaint(od.getBoxX(), od.getBoxY(), od.getBoxWidth(),
411 private void setBoxPosition()
415 od.setBoxPosition(av.getAlignment().getHiddenSequences(),
416 av.getAlignment().getHiddenColumns());
422 public void propertyChange(PropertyChangeEvent evt)
424 setBoxPositionOnly();
428 * Removes this object as a property change listener, and nulls references
430 protected void dispose()
436 av.getRanges().removePropertyChangeListener(this);
442 * close the parent frame (which also removes it from the
443 * Desktop Windows menu)
445 ((JInternalFrame) SwingUtilities
446 .getAncestorOfClass(JInternalFrame.class, (this)))
448 } catch (PropertyVetoException e)
453 progressPanel = null;