5fbefb5b5c015a1ebf32c6a7f070173e0b003aba
[jalview.git] / src / jalview / gui / OverviewPanel.java
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.util.MessageManager;
24 import jalview.util.Platform;
25 import jalview.viewmodel.OverviewDimensions;
26 import jalview.viewmodel.OverviewDimensionsHideHidden;
27 import jalview.viewmodel.OverviewDimensionsShowHidden;
28 import jalview.viewmodel.ViewportListenerI;
29
30 import java.awt.BorderLayout;
31 import java.awt.Cursor;
32 import java.awt.Dimension;
33 import java.awt.event.ActionEvent;
34 import java.awt.event.ActionListener;
35 import java.awt.event.ComponentAdapter;
36 import java.awt.event.ComponentEvent;
37 import java.awt.event.MouseAdapter;
38 import java.awt.event.MouseEvent;
39 import java.awt.event.MouseMotionAdapter;
40 import java.beans.PropertyChangeEvent;
41
42 import javax.swing.JCheckBoxMenuItem;
43 import javax.swing.JPanel;
44 import javax.swing.JPopupMenu;
45 import javax.swing.SwingUtilities;
46
47 /**
48  * Panel displaying an overview of the full alignment, with an interactive box
49  * representing the viewport onto the alignment.
50  * 
51  * @author $author$
52  * @version $Revision$
53  */
54 public class OverviewPanel extends JPanel implements Runnable,
55         ViewportListenerI
56 {
57   private OverviewDimensions od;
58
59   private OverviewCanvas oviewCanvas;
60
61   private AlignViewport av;
62
63   private AlignmentPanel ap;
64
65   private JCheckBoxMenuItem displayToggle;
66
67   private boolean showHidden = true;
68
69   private boolean draggingBox = false;
70
71   /**
72    * Creates a new OverviewPanel object.
73    * 
74    * @param alPanel
75    *          The alignment panel which is shown in the overview panel
76    */
77   public OverviewPanel(AlignmentPanel alPanel)
78   {
79     this.av = alPanel.av;
80     this.ap = alPanel;
81
82     od = new OverviewDimensionsShowHidden(av.getRanges(),
83             (av.isShowAnnotation() && av
84                     .getAlignmentConservationAnnotation() != null));
85
86     setSize(od.getWidth(), od.getHeight());
87
88     oviewCanvas = new OverviewCanvas(od, av);
89     setLayout(new BorderLayout());
90     add(oviewCanvas, BorderLayout.CENTER);
91
92     av.getRanges().addPropertyChangeListener(this);
93
94     addComponentListener(new ComponentAdapter()
95     {
96       @Override
97       public void componentResized(ComponentEvent evt)
98       {
99         if ((getWidth() != od.getWidth())
100                 || (getHeight() != (od.getHeight())))
101         {
102           updateOverviewImage();
103           setBoxPosition();
104         }
105       }
106     });
107
108     addMouseMotionListener(new MouseMotionAdapter()
109     {
110       @Override
111       public void mouseDragged(MouseEvent evt)
112       {
113         if (!SwingUtilities.isRightMouseButton(evt)
114                 && !av.getWrapAlignment())
115         {
116           if (draggingBox)
117           {
118             od.adjustViewportFromMouse(evt.getX(),
119                     evt.getY(), av.getAlignment().getHiddenSequences(),
120                     av.getAlignment().getHiddenColumns());
121           }
122           else
123           {
124             od.updateViewportFromMouse(evt.getX(), evt.getY(), av
125                   .getAlignment().getHiddenSequences(), av.getAlignment()
126                   .getHiddenColumns());
127           }
128
129         }
130       }
131
132       @Override
133       public void mouseMoved(MouseEvent evt)
134       {
135         if (od.isPositionInBox(evt.getX(), evt.getY()))
136         {
137           // display drag cursor at mouse position
138           setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
139         }
140         else
141         {
142           // reset cursor
143           setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
144         }
145       }
146     });
147
148     addMouseListener(new MouseAdapter()
149     {
150       @Override
151       public void mousePressed(MouseEvent evt)
152       {
153         if (SwingUtilities.isRightMouseButton(evt))
154         {
155           if (!Platform.isAMac())
156           {
157             showPopupMenu(evt);
158           }
159         }
160         else if (!av.getWrapAlignment())
161         {
162           if (!od.isPositionInBox(evt.getX(), evt.getY()))
163           {
164             // don't do anything if the mouse press is in the overview's box
165             // (wait to see if it's a drag instead)
166             // otherwise update the viewport
167             od.updateViewportFromMouse(evt.getX(), evt.getY(),
168                     av.getAlignment().getHiddenSequences(),
169                     av.getAlignment().getHiddenColumns());
170           }
171           else
172           {
173             draggingBox = true;
174             od.setDragPoint(evt.getX(), evt.getY(),
175                     av.getAlignment().getHiddenSequences(),
176                     av.getAlignment().getHiddenColumns());
177           }
178         }
179       }
180
181       @Override
182       public void mouseReleased(MouseEvent evt)
183       {
184         if (draggingBox)
185         {
186           draggingBox = false;
187         }
188       }
189
190       @Override
191       public void mouseClicked(MouseEvent evt)
192       {
193         if (SwingUtilities.isRightMouseButton(evt))
194         {
195           showPopupMenu(evt);
196         }
197       }
198
199
200     });
201
202
203     updateOverviewImage();
204   }
205
206   /*
207    * Displays the popup menu and acts on user input
208    */
209   private void showPopupMenu(MouseEvent e)
210   {
211     JPopupMenu popup = new JPopupMenu();
212     ActionListener menuListener = new ActionListener()
213     {
214       @Override
215       public void actionPerformed(ActionEvent event)
216       {
217         // switch on/off the hidden columns view
218         toggleHiddenColumns();
219         displayToggle.setSelected(showHidden);
220       }
221     };
222     displayToggle = new JCheckBoxMenuItem(
223             MessageManager.getString("label.togglehidden"));
224     displayToggle.setEnabled(true);
225     displayToggle.setSelected(showHidden);
226     popup.add(displayToggle);
227     displayToggle.addActionListener(menuListener);
228     popup.show(this, e.getX(), e.getY());
229   }
230
231   /*
232    * Toggle overview display between showing hidden columns and hiding hidden columns
233    */
234   private void toggleHiddenColumns()
235   {
236     if (showHidden)
237     {
238       showHidden = false;
239       od = new OverviewDimensionsHideHidden(av.getRanges(),
240               (av.isShowAnnotation() && av
241                       .getAlignmentConservationAnnotation() != null));
242     }
243     else
244     {
245       showHidden = true;
246       od = new OverviewDimensionsShowHidden(av.getRanges(),
247               (av.isShowAnnotation() && av
248                       .getAlignmentConservationAnnotation() != null));
249     }
250     oviewCanvas.resetOviewDims(od);
251     updateOverviewImage();
252     setBoxPosition();
253   }
254
255   /**
256    * Updates the overview image when the related alignment panel is updated
257    */
258   public void updateOverviewImage()
259   {
260     if ((getWidth() > 0) && (getHeight() > 0))
261     {
262       od.setWidth(getWidth());
263       od.setHeight(getHeight());
264     }
265     
266     setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
267
268     if (oviewCanvas.restartDraw())
269     {
270       return;
271     }
272
273     Thread thread = new Thread(this);
274     thread.start();
275     repaint();
276
277   }
278
279   @Override
280   public void run()
281   {
282     oviewCanvas.draw(av.isShowSequenceFeatures(),
283             (av.isShowAnnotation() && av
284                     .getAlignmentConservationAnnotation() != null), ap
285                     .getSeqPanel().seqCanvas.getFeatureRenderer());
286     setBoxPosition();
287   }
288
289   /**
290    * Update the overview panel box when the associated alignment panel is
291    * changed
292    * 
293    */
294   private void setBoxPosition()
295   {
296     od.setBoxPosition(av.getAlignment().getHiddenSequences(), av
297             .getAlignment().getHiddenColumns());
298     repaint();
299   }
300
301   @Override
302   public void propertyChange(PropertyChangeEvent evt)
303   {
304     setBoxPosition();
305   }
306 }