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