spike branch updated from latest features/JAL-2446
[jalview.git] / src / jalview / appletgui / 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.appletgui;
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.CheckboxMenuItem;
32 import java.awt.Dimension;
33 import java.awt.Panel;
34 import java.awt.PopupMenu;
35 import java.awt.event.ComponentAdapter;
36 import java.awt.event.ComponentEvent;
37 import java.awt.event.InputEvent;
38 import java.awt.event.ItemEvent;
39 import java.awt.event.ItemListener;
40 import java.awt.event.MouseEvent;
41 import java.awt.event.MouseListener;
42 import java.awt.event.MouseMotionListener;
43 import java.beans.PropertyChangeEvent;
44
45 public class OverviewPanel extends Panel implements Runnable,
46         MouseMotionListener, MouseListener, ViewportListenerI
47 {
48   private OverviewDimensions od;
49
50   private OverviewCanvas oviewCanvas;
51
52   private AlignViewport av;
53
54   private AlignmentPanel ap;
55
56   private boolean showHidden = true;
57
58   private boolean updateRunning = false;
59
60   public OverviewPanel(AlignmentPanel alPanel)
61   {
62     this.av = alPanel.av;
63     this.ap = alPanel;
64     setLayout(null);
65
66     od = new OverviewDimensionsShowHidden(av.getRanges(),
67             (av.isShowAnnotation() && av.getSequenceConsensusHash() != null));
68
69     oviewCanvas = new OverviewCanvas(od, av);
70     setLayout(new BorderLayout());
71     add(oviewCanvas, BorderLayout.CENTER);
72
73     setSize(new Dimension(od.getWidth(), od.getHeight()));
74
75     av.getRanges().addPropertyChangeListener(this);
76
77     addComponentListener(new ComponentAdapter()
78     {
79
80       @Override
81       public void componentResized(ComponentEvent evt)
82       {
83         if ((getWidth() != od.getWidth())
84                 || (getHeight() != (od.getHeight())))
85         {
86           updateOverviewImage();
87         }
88       }
89     });
90
91     addMouseMotionListener(this);
92
93     addMouseListener(this);
94
95     updateOverviewImage();
96
97   }
98
99   @Override
100   public void mouseEntered(MouseEvent evt)
101   {
102   }
103
104   @Override
105   public void mouseExited(MouseEvent evt)
106   {
107   }
108
109   @Override
110   public void mouseClicked(MouseEvent evt)
111   {
112     if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
113     {
114       showPopupMenu(evt);
115     }
116   }
117
118   @Override
119   public void mouseMoved(MouseEvent evt)
120   {
121   }
122
123   @Override
124   public void mousePressed(MouseEvent evt)
125   {
126     mouseAction(evt);
127   }
128
129   @Override
130   public void mouseReleased(MouseEvent evt)
131   {
132     mouseAction(evt);
133   }
134
135   @Override
136   public void mouseDragged(MouseEvent evt)
137   {
138     mouseAction(evt);
139   }
140
141   private void mouseAction(MouseEvent evt)
142   {
143     if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
144     {
145       if (!Platform.isAMac())
146       {
147         showPopupMenu(evt);
148       }
149     }
150     else
151     {
152       od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
153               .getHiddenSequences(), av.getAlignment().getHiddenColumns());
154       ap.paintAlignment(false);
155     }
156   }
157
158   /**
159    * Updates the overview image when the related alignment panel is updated
160    */
161   public void updateOverviewImage()
162   {
163     if (oviewCanvas == null)
164     {
165       /*
166        * panel has been disposed
167        */
168       return;
169     }
170
171     if ((getSize().width > 0) && (getSize().height > 0))
172     {
173       od.setWidth(getSize().width);
174       od.setHeight(getSize().height);
175     }
176     setSize(new Dimension(od.getWidth(), od.getHeight()));
177
178     synchronized (this)
179     {
180       if (updateRunning)
181       {
182         oviewCanvas.restartDraw();
183         return;
184       }
185
186       updateRunning = true;
187     }
188     Thread thread = new Thread(this);
189     thread.start();
190     repaint();
191     updateRunning = false;
192   }
193
194   @Override
195   public void run()
196   {
197     oviewCanvas.draw(av.isShowSequenceFeatures(),
198             (av.isShowAnnotation() && av
199                     .getAlignmentConservationAnnotation() != null),
200             ap.seqPanel.seqCanvas.getFeatureRenderer());
201     setBoxPosition();
202   }
203
204   /**
205    * Update the overview panel box when the associated alignment panel is
206    * changed
207    * 
208    */
209   private void setBoxPosition()
210   {
211     od.setBoxPosition(av.getAlignment()
212 .getHiddenSequences(), av
213             .getAlignment().getHiddenColumns());
214     repaint();
215   }
216
217   /*
218    * Displays the popup menu and acts on user input
219    */
220   private void showPopupMenu(MouseEvent e)
221   {
222     PopupMenu popup = new PopupMenu();
223     ItemListener menuListener = new ItemListener()
224     {
225       @Override
226       public void itemStateChanged(ItemEvent e)
227       {
228         toggleHiddenColumns();
229       }
230     };
231     CheckboxMenuItem item = new CheckboxMenuItem(
232             MessageManager.getString("label.togglehidden"));
233     item.setState(showHidden);
234     popup.add(item);
235     item.addItemListener(menuListener);
236     this.add(popup);
237     popup.show(this, e.getX(), e.getY());
238   }
239
240   @Override
241   public void propertyChange(PropertyChangeEvent evt)
242   {
243     setBoxPosition();
244   }
245
246   /*
247    * Toggle overview display between showing hidden columns and hiding hidden columns
248    */
249   private void toggleHiddenColumns()
250   {
251     if (showHidden)
252     {
253       showHidden = false;
254       od = new OverviewDimensionsHideHidden(av.getRanges(),
255               (av.isShowAnnotation() && av
256                       .getAlignmentConservationAnnotation() != null));
257     }
258     else
259     {
260       showHidden = true;
261       od = new OverviewDimensionsShowHidden(av.getRanges(),
262               (av.isShowAnnotation() && av
263                       .getAlignmentConservationAnnotation() != null));
264     }
265     oviewCanvas.resetOviewDims(od);
266     updateOverviewImage();
267   }
268
269   /**
270    * Removes this object as a property change listener, and nulls references
271    */
272   protected void dispose()
273   {
274     try
275     {
276       av.getRanges().removePropertyChangeListener(this);
277     } finally
278     {
279       av = null;
280       oviewCanvas = null;
281       ap = null;
282       od = null;
283     }
284   }
285 }