Merge remote-tracking branch 'origin/develop' into bug/JAL-2491
[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     oviewCanvas = new OverviewCanvas(od, av);
84     setLayout(new BorderLayout());
85     add(oviewCanvas, BorderLayout.CENTER);
86
87     av.getRanges().addPropertyChangeListener(this);
88
89     addComponentListener(new ComponentAdapter()
90     {
91       @Override
92       public void componentResized(ComponentEvent evt)
93       {
94         if ((getWidth() != od.getWidth())
95                 || (getHeight() != (od.getHeight())))
96         {
97           updateOverviewImage();
98           setBoxPosition();
99         }
100       }
101     });
102
103     addMouseMotionListener(new MouseMotionAdapter()
104     {
105       @Override
106       public void mouseDragged(MouseEvent evt)
107       {
108         if (!SwingUtilities.isRightMouseButton(evt)
109                 && !av.getWrapAlignment())
110         {
111           od.updateViewportFromMouse(evt.getX(), evt.getY(), av
112                   .getAlignment().getHiddenSequences(), av.getAlignment()
113                   .getHiddenColumns());
114
115         }
116       }
117     });
118
119     addMouseListener(new MouseAdapter()
120     {
121       @Override
122       public void mousePressed(MouseEvent evt)
123       {
124         if (SwingUtilities.isRightMouseButton(evt))
125         {
126           if (!Platform.isAMac())
127           {
128             showPopupMenu(evt);
129           }
130         }
131         else if (!av.getWrapAlignment())
132         {
133           od.updateViewportFromMouse(evt.getX(), evt.getY(), av
134                   .getAlignment().getHiddenSequences(), av.getAlignment()
135                   .getHiddenColumns());
136         }
137       }
138
139       @Override
140       public void mouseClicked(MouseEvent evt)
141       {
142         if (SwingUtilities.isRightMouseButton(evt))
143         {
144           showPopupMenu(evt);
145         }
146       }
147     });
148
149
150     updateOverviewImage();
151   }
152
153   /*
154    * Displays the popup menu and acts on user input
155    */
156   private void showPopupMenu(MouseEvent e)
157   {
158     JPopupMenu popup = new JPopupMenu();
159     ActionListener menuListener = new ActionListener()
160     {
161       @Override
162       public void actionPerformed(ActionEvent event)
163       {
164         // switch on/off the hidden columns view
165         toggleHiddenColumns();
166         displayToggle.setSelected(showHidden);
167       }
168     };
169     displayToggle = new JCheckBoxMenuItem(
170             MessageManager.getString("label.togglehidden"));
171     displayToggle.setEnabled(true);
172     displayToggle.setSelected(showHidden);
173     popup.add(displayToggle);
174     displayToggle.addActionListener(menuListener);
175     popup.show(this, e.getX(), e.getY());
176   }
177
178   /*
179    * Toggle overview display between showing hidden columns and hiding hidden columns
180    */
181   private void toggleHiddenColumns()
182   {
183     if (showHidden)
184     {
185       showHidden = false;
186       od = new OverviewDimensionsHideHidden(av.getRanges(),
187               (av.isShowAnnotation() && av
188                       .getAlignmentConservationAnnotation() != null));
189     }
190     else
191     {
192       showHidden = true;
193       od = new OverviewDimensionsShowHidden(av.getRanges(),
194               (av.isShowAnnotation() && av
195                       .getAlignmentConservationAnnotation() != null));
196     }
197     oviewCanvas.resetOviewDims(od);
198     updateOverviewImage();
199     setBoxPosition();
200   }
201
202   /**
203    * Updates the overview image when the related alignment panel is updated
204    */
205   public void updateOverviewImage()
206   {
207     if ((getWidth() > 0) && (getHeight() > 0))
208     {
209       od.setWidth(getWidth());
210       od.setHeight(getHeight());
211     }
212     
213     setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
214
215     if (oviewCanvas.restartDraw())
216     {
217       return;
218     }
219
220     Thread thread = new Thread(this);
221     thread.start();
222     repaint();
223
224   }
225
226   @Override
227   public void run()
228   {
229     oviewCanvas.draw(av.isShowSequenceFeatures(),
230             (av.isShowAnnotation() && av
231                     .getAlignmentConservationAnnotation() != null), ap
232                     .getSeqPanel().seqCanvas.getFeatureRenderer());
233     setBoxPosition();
234   }
235
236   /**
237    * Update the overview panel box when the associated alignment panel is
238    * changed
239    * 
240    */
241   private void setBoxPosition()
242   {
243     od.setBoxPosition(av.getAlignment().getHiddenSequences(), av
244             .getAlignment().getHiddenColumns());
245     repaint();
246   }
247
248   @Override
249   public void propertyChange(PropertyChangeEvent evt)
250   {
251     setBoxPosition();
252   }
253 }