JAL-2611 Pre-merge checkin
[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   /**
69    * Creates a new OverviewPanel object.
70    * 
71    * @param alPanel
72    *          The alignment panel which is shown in the overview panel
73    */
74   public OverviewPanel(AlignmentPanel alPanel)
75   {
76     this.av = alPanel.av;
77     this.ap = alPanel;
78
79     od = new OverviewDimensionsShowHidden(av.getRanges(),
80             (av.isShowAnnotation() && av
81                     .getAlignmentConservationAnnotation() != null));
82
83     setSize(od.getWidth(), od.getHeight());
84
85     oviewCanvas = new OverviewCanvas(od, av);
86     setLayout(new BorderLayout());
87     add(oviewCanvas, BorderLayout.CENTER);
88
89     av.getRanges().addPropertyChangeListener(this);
90
91     addComponentListener(new ComponentAdapter()
92     {
93       @Override
94       public void componentResized(ComponentEvent evt)
95       {
96         if ((getWidth() != od.getWidth())
97                 || (getHeight() != (od.getHeight())))
98         {
99           updateOverviewImage();
100           setBoxPosition();
101         }
102       }
103     });
104
105     addMouseMotionListener(new MouseMotionAdapter()
106     {
107       @Override
108       public void mouseDragged(MouseEvent evt)
109       {
110         if (!SwingUtilities.isRightMouseButton(evt)
111                 && !av.getWrapAlignment())
112         {
113           od.updateViewportFromMouse(evt.getX(), evt.getY(), av
114                   .getAlignment().getHiddenSequences(), av.getAlignment()
115                   .getHiddenColumns());
116
117         }
118       }
119
120       @Override
121       public void mouseMoved(MouseEvent evt)
122       {
123         if (od.isPositionInBox(evt.getX(), evt.getY()))
124         {
125           // display drag cursor at mouse position
126
127         }
128         else
129         {
130           // reset cursor
131
132         }
133       }
134     });
135
136     addMouseListener(new MouseAdapter()
137     {
138       @Override
139       public void mousePressed(MouseEvent evt)
140       {
141         if (SwingUtilities.isRightMouseButton(evt))
142         {
143           if (!Platform.isAMac())
144           {
145             showPopupMenu(evt);
146           }
147         }
148         else if (!av.getWrapAlignment())
149         {
150           if (!od.isPositionInBox(evt.getX(), evt.getY()))
151           {
152             // don't do anything if the mouse press is in the overview's box
153             // (wait to see if it's a drag instead)
154             // otherwise update the viewport
155             od.updateViewportFromMouse(evt.getX(), evt.getY(),
156                     av.getAlignment().getHiddenSequences(),
157                     av.getAlignment().getHiddenColumns());
158           }
159         }
160       }
161
162       @Override
163       public void mouseClicked(MouseEvent evt)
164       {
165         if (SwingUtilities.isRightMouseButton(evt))
166         {
167           showPopupMenu(evt);
168         }
169       }
170
171
172     });
173
174
175     updateOverviewImage();
176   }
177
178   /*
179    * Displays the popup menu and acts on user input
180    */
181   private void showPopupMenu(MouseEvent e)
182   {
183     JPopupMenu popup = new JPopupMenu();
184     ActionListener menuListener = new ActionListener()
185     {
186       @Override
187       public void actionPerformed(ActionEvent event)
188       {
189         // switch on/off the hidden columns view
190         toggleHiddenColumns();
191         displayToggle.setSelected(showHidden);
192       }
193     };
194     displayToggle = new JCheckBoxMenuItem(
195             MessageManager.getString("label.togglehidden"));
196     displayToggle.setEnabled(true);
197     displayToggle.setSelected(showHidden);
198     popup.add(displayToggle);
199     displayToggle.addActionListener(menuListener);
200     popup.show(this, e.getX(), e.getY());
201   }
202
203   /*
204    * Toggle overview display between showing hidden columns and hiding hidden columns
205    */
206   private void toggleHiddenColumns()
207   {
208     if (showHidden)
209     {
210       showHidden = false;
211       od = new OverviewDimensionsHideHidden(av.getRanges(),
212               (av.isShowAnnotation() && av
213                       .getAlignmentConservationAnnotation() != null));
214     }
215     else
216     {
217       showHidden = true;
218       od = new OverviewDimensionsShowHidden(av.getRanges(),
219               (av.isShowAnnotation() && av
220                       .getAlignmentConservationAnnotation() != null));
221     }
222     oviewCanvas.resetOviewDims(od);
223     updateOverviewImage();
224     setBoxPosition();
225   }
226
227   /**
228    * Updates the overview image when the related alignment panel is updated
229    */
230   public void updateOverviewImage()
231   {
232     if ((getWidth() > 0) && (getHeight() > 0))
233     {
234       od.setWidth(getWidth());
235       od.setHeight(getHeight());
236     }
237     
238     setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
239
240     if (oviewCanvas.restartDraw())
241     {
242       return;
243     }
244
245     Thread thread = new Thread(this);
246     thread.start();
247     repaint();
248
249   }
250
251   @Override
252   public void run()
253   {
254     oviewCanvas.draw(av.isShowSequenceFeatures(),
255             (av.isShowAnnotation() && av
256                     .getAlignmentConservationAnnotation() != null), ap
257                     .getSeqPanel().seqCanvas.getFeatureRenderer());
258     setBoxPosition();
259   }
260
261   /**
262    * Update the overview panel box when the associated alignment panel is
263    * changed
264    * 
265    */
266   private void setBoxPosition()
267   {
268     od.setBoxPosition(av.getAlignment().getHiddenSequences(), av
269             .getAlignment().getHiddenColumns());
270     repaint();
271   }
272
273   @Override
274   public void propertyChange(PropertyChangeEvent evt)
275   {
276     setBoxPosition();
277   }
278 }