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