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