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.bin.Cache;
24 import jalview.renderer.OverviewRenderer;
25 import jalview.util.MessageManager;
26 import jalview.util.Platform;
27 import jalview.viewmodel.OverviewDimensions;
28 import jalview.viewmodel.OverviewDimensionsHideHidden;
29 import jalview.viewmodel.OverviewDimensionsShowHidden;
30 import jalview.viewmodel.ViewportListenerI;
32 import java.awt.BorderLayout;
33 import java.awt.Cursor;
34 import java.awt.Dimension;
35 import java.awt.Image;
36 import java.awt.Point;
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.ImageIcon;
48 import javax.swing.JCheckBoxMenuItem;
49 import javax.swing.JInternalFrame;
50 import javax.swing.JPanel;
51 import javax.swing.JPopupMenu;
52 import javax.swing.SwingUtilities;
55 * Panel displaying an overview of the full alignment, with an interactive box
56 * representing the viewport onto the alignment.
61 public class OverviewPanel extends JPanel
62 implements Runnable, ViewportListenerI
64 protected Image dragImage = new ImageIcon(
65 getClass().getResource("/images/dragcursor.png"))
68 private OverviewDimensions od;
70 private OverviewCanvas oviewCanvas;
72 private AlignViewport av;
74 private AlignmentPanel ap;
76 private JCheckBoxMenuItem displayToggle;
78 private boolean showHidden = true;
80 private boolean draggingBox = false;
82 private ProgressPanel progressPanel;
85 * Creates a new OverviewPanel object.
88 * The alignment panel which is shown in the overview panel
90 public OverviewPanel(AlignmentPanel alPanel)
95 showHidden = Cache.getDefault(Preferences.SHOW_OV_HIDDEN_AT_START,
99 od = new OverviewDimensionsShowHidden(av.getRanges(),
100 (av.isShowAnnotation()
101 && av.getAlignmentConservationAnnotation() != null));
105 od = new OverviewDimensionsHideHidden(av.getRanges(),
106 (av.isShowAnnotation()
107 && av.getAlignmentConservationAnnotation() != null));
110 setLayout(new BorderLayout());
111 progressPanel = new ProgressPanel(OverviewRenderer.UPDATE,
112 MessageManager.getString("label.oview_calc"), getWidth());
113 this.add(progressPanel, BorderLayout.SOUTH);
114 oviewCanvas = new OverviewCanvas(od, av, progressPanel);
116 add(oviewCanvas, BorderLayout.CENTER);
118 av.getRanges().addPropertyChangeListener(this);
120 // without this the overview window does not size to fit the overview canvas
121 setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
123 // set up custom cursor for use on Mac...
124 Point hotSpot = new Point(16, 16);
125 String cursorName = "Custom drag cursor";
128 if (Platform.isAMac())
130 tempCursor = getToolkit().createCustomCursor(dragImage, hotSpot,
135 tempCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
137 final Cursor dragCursor = tempCursor;
139 addComponentListener(new ComponentAdapter()
142 public void componentResized(ComponentEvent evt)
144 // Resize is called on the initial display of the overview.
145 // This code adjusts sizes to account for the progress bar if it has not
146 // already been accounted for, which triggers another resize call for
147 // the correct sizing, at which point the overview image is updated.
148 // (This avoids a double recalculation of the image.)
149 if (getWidth() == od.getWidth() && getHeight() == od.getHeight()
150 + progressPanel.getHeight())
152 updateOverviewImage();
156 if ((getWidth() > 0) && (getHeight() > 0))
158 od.setWidth(getWidth());
159 od.setHeight(getHeight() - progressPanel.getHeight());
162 setPreferredSize(new Dimension(od.getWidth(),
163 od.getHeight() + progressPanel.getHeight()));
169 addMouseMotionListener(new MouseMotionAdapter()
172 public void mouseDragged(MouseEvent evt)
174 if (!SwingUtilities.isRightMouseButton(evt))
178 // set the mouse position as a fixed point in the box
179 // and drag relative to that position
180 od.adjustViewportFromMouse(evt.getX(), evt.getY(),
181 av.getAlignment().getHiddenSequences(),
182 av.getAlignment().getHiddenColumns());
186 od.updateViewportFromMouse(evt.getX(), evt.getY(),
187 av.getAlignment().getHiddenSequences(),
188 av.getAlignment().getHiddenColumns());
194 public void mouseMoved(MouseEvent evt)
196 if (od.isPositionInBox(evt.getX(), evt.getY()))
198 // display drag cursor at mouse position
199 getParent().setCursor(dragCursor);
204 getParent().setCursor(
205 Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
211 addMouseListener(new MouseAdapter()
214 public void mousePressed(MouseEvent evt)
216 if (SwingUtilities.isRightMouseButton(evt))
218 if (!Platform.isAMac())
225 // don't do anything if the mouse press is in the overview's box
226 // (wait to see if it's a drag instead)
227 // otherwise update the viewport
228 if (!od.isPositionInBox(evt.getX(), evt.getY()))
231 od.updateViewportFromMouse(evt.getX(), evt.getY(),
232 av.getAlignment().getHiddenSequences(),
233 av.getAlignment().getHiddenColumns());
238 od.setDragPoint(evt.getX(), evt.getY(),
239 av.getAlignment().getHiddenSequences(),
240 av.getAlignment().getHiddenColumns());
246 public void mouseClicked(MouseEvent evt)
248 if (SwingUtilities.isRightMouseButton(evt))
252 // click in box should also reset the cursor
253 else if (od.isPositionInBox(evt.getX(), evt.getY()))
255 // display drag cursor at mouse position
256 getParent().setCursor(dragCursor);
261 getParent().setCursor(
262 Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
269 * Displays the popup menu and acts on user input
271 private void showPopupMenu(MouseEvent e)
273 JPopupMenu popup = new JPopupMenu();
274 ActionListener menuListener = new ActionListener()
277 public void actionPerformed(ActionEvent event)
279 // switch on/off the hidden columns view
280 toggleHiddenColumns();
281 displayToggle.setSelected(showHidden);
284 displayToggle = new JCheckBoxMenuItem(
285 MessageManager.getString("label.togglehidden"));
286 displayToggle.setEnabled(true);
287 displayToggle.setSelected(showHidden);
288 popup.add(displayToggle);
289 displayToggle.addActionListener(menuListener);
290 popup.show(this, e.getX(), e.getY());
294 * Toggle overview display between showing hidden columns and hiding hidden columns
296 private void toggleHiddenColumns()
301 od = new OverviewDimensionsHideHidden(av.getRanges(),
302 (av.isShowAnnotation()
303 && av.getAlignmentConservationAnnotation() != null));
308 od = new OverviewDimensionsShowHidden(av.getRanges(),
309 (av.isShowAnnotation()
310 && av.getAlignmentConservationAnnotation() != null));
312 oviewCanvas.resetOviewDims(od);
313 updateOverviewImage();
318 * Updates the overview image when the related alignment panel is updated
320 public void updateOverviewImage()
322 if (oviewCanvas == null)
325 * panel has been disposed
330 if ((getWidth() > 0) && (getHeight() > 0))
332 od.setWidth(getWidth());
333 od.setHeight(getHeight() - progressPanel.getHeight());
336 setPreferredSize(new Dimension(od.getWidth(),
337 od.getHeight() + progressPanel.getHeight()));
339 if (oviewCanvas.restartDraw())
344 Thread thread = new Thread(this);
354 if (oviewCanvas != null)
356 oviewCanvas.draw(av.isShowSequenceFeatures(),
357 (av.isShowAnnotation()
358 && av.getAlignmentConservationAnnotation() != null),
359 ap.getSeqPanel().seqCanvas.getFeatureRenderer());
365 * Update the overview panel box when the associated alignment panel is
369 private void setBoxPositionOnly()
373 int oldX = od.getBoxX();
374 int oldY = od.getBoxY();
375 int oldWidth = od.getBoxWidth();
376 int oldHeight = od.getBoxHeight();
377 od.setBoxPosition(av.getAlignment().getHiddenSequences(),
378 av.getAlignment().getHiddenColumns());
379 repaint(oldX - 1, oldY - 1, oldWidth + 2, oldHeight + 2);
380 repaint(od.getBoxX(), od.getBoxY(), od.getBoxWidth(),
385 private void setBoxPosition()
389 od.setBoxPosition(av.getAlignment().getHiddenSequences(),
390 av.getAlignment().getHiddenColumns());
396 public void propertyChange(PropertyChangeEvent evt)
398 setBoxPositionOnly();
402 * Removes this object as a property change listener, and nulls references
404 protected void dispose()
410 av.getRanges().removePropertyChangeListener(this);
413 oviewCanvas.dispose();
416 * close the parent frame (which also removes it from the
417 * Desktop Windows menu)
419 ((JInternalFrame) SwingUtilities.getAncestorOfClass(
420 JInternalFrame.class, (this))).setClosed(true);
421 } catch (PropertyVetoException e)
426 progressPanel = null;