JAL-3383 minor code tidying and commenting
[jalview.git] / src / jalview / gui / OverviewCanvas.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.api.AlignViewportI;
24 import jalview.bin.Cache;
25 import jalview.datamodel.AlignmentI;
26 import jalview.renderer.OverviewRenderer;
27 import jalview.renderer.OverviewResColourFinder;
28 import jalview.viewmodel.OverviewDimensions;
29
30 import java.awt.Color;
31 import java.awt.Dimension;
32 import java.awt.Graphics;
33 import java.awt.image.BufferedImage;
34
35 import javax.swing.JPanel;
36
37 @SuppressWarnings("serial")
38 public class OverviewCanvas extends JPanel
39 {
40   private static final Color TRANS_GREY = new Color(100, 100, 100, 25);
41
42   // This is set true if the alignment view changes whilst
43   // the overview is being calculated
44   private volatile boolean restart = false;
45
46   private volatile boolean updaterunning = false;
47
48   private boolean disposed = false;
49
50   BufferedImage lastMiniMe = null;
51
52   // Can set different properties in this seqCanvas than
53   // main visible SeqCanvas
54   private final SequenceRenderer sr;
55
56   private final jalview.renderer.seqfeatures.FeatureRenderer fr;
57
58   private OverviewDimensions od;
59
60   private OverviewRenderer or = null;
61
62   private final AlignViewportI av;
63
64   private final OverviewResColourFinder cf;
65
66   private final ProgressPanel progressPanel;
67
68   private boolean showSequenceFeatures;
69
70   private boolean showAnnotation;
71
72   private jalview.api.FeatureRenderer featureRenderer;
73
74   private final OverviewPanel panel;
75
76   private final boolean showProgress;
77
78   public OverviewCanvas(OverviewPanel panel,
79           OverviewDimensions overviewDims,
80           AlignViewportI alignvp, ProgressPanel pp)
81   {
82     this.panel = panel;
83     od = overviewDims;
84     lastMiniMe = null;
85     av = alignvp;
86     progressPanel = pp;
87     showProgress = (pp != null);
88     sr = new SequenceRenderer(av);
89     sr.renderGaps = false;
90     fr = new jalview.renderer.seqfeatures.FeatureRenderer(av);
91
92     boolean useLegacy = Cache.getDefault(Preferences.USE_LEGACY_GAP, false);
93     Color gapCol = Cache.getDefaultColour(Preferences.GAP_COLOUR,
94             jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP);
95     Color hiddenCol = Cache.getDefaultColour(Preferences.HIDDEN_COLOUR,
96             jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_HIDDEN);
97     cf = new OverviewResColourFinder(useLegacy, gapCol, hiddenCol);
98
99     setSize(od.getWidth(), od.getHeight());
100     setPreferredSize(getSize()); // BH 2019.07.29 added
101   }
102
103   /**
104    * Update the overview dimensions object used by the canvas (e.g. if we change
105    * from showing hidden columns to hiding them or vice versa)
106    * 
107    * @param overviewDims
108    */
109   public void resetOviewDims(OverviewDimensions overviewDims)
110   {
111     od = overviewDims;
112     lastMiniMe = null;
113   }
114
115   /**
116    * Signals to drawing code that the associated alignment viewport has changed
117    * and a redraw will be required
118    */
119   public boolean restartDraw()
120   {
121     synchronized (this)
122     {
123       if (updaterunning)
124       {
125         setRestart("restartDraw");
126       }
127       else
128       {
129         updaterunning = true;
130         restart = false;
131       }
132       return restart;
133     }
134   }
135
136   private void setRestart(String why)
137   {
138     // System.out.println("OC restart true " + why);
139     restart = true;
140     if (or != null)
141     {
142       or.setRedraw(true);
143     }
144   }
145
146   /**
147    * Draw the overview sequences
148    * 
149    * @param showSequenceFeatures
150    *          true if sequence features are to be shown
151    * @param showAnnotation
152    *          true if the annotation is to be shown
153    * @param featureRenderer
154    *          the renderer to transfer feature colouring from
155    */
156   public void draw(boolean showSequenceFeatures, boolean showAnnotation,
157           jalview.api.FeatureRenderer featureRenderer)
158   {
159     this.showSequenceFeatures = showSequenceFeatures;
160     this.showAnnotation = showAnnotation;
161     this.featureRenderer = featureRenderer;
162     if (showSequenceFeatures)
163     {
164       fr.transferSettings(featureRenderer);
165     }
166     setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
167     AlignmentI al = av.getAlignment();
168     or = new OverviewRenderer(panel.ap, fr, od, al, av.getResidueShading(),
169             cf, showProgress);
170     if (showProgress)
171     {
172       or.addPropertyChangeListener(progressPanel);
173     }
174     or.drawMiniMe();
175   }
176
177   synchronized void finalizeDraw(BufferedImage miniMe)
178   {
179     if (showProgress && or != null)
180     {
181       or.removePropertyChangeListener(progressPanel);
182     }
183     if (restart)
184     {
185       or = null;
186       restart = false;
187       if (!disposed)
188       {
189         draw(showSequenceFeatures, showAnnotation, featureRenderer);
190       }
191     }
192     else
193     {
194       if (showAnnotation && or != null)
195       {
196         or.drawGraph(av.getAlignmentConservationAnnotation());
197       }
198       or = null;
199       updaterunning = false;
200       lastMiniMe = miniMe;
201       repaint();
202     }
203   }
204
205   @Override
206   public void paintComponent(Graphics g)
207   {
208
209     int w = getWidth();
210     int h = getHeight();
211     if (w == 0 || od.getBoxWidth() <= 0)
212     {
213       // BH 2019.07.27 removes two unnecessary paints, since boxwidth can be -1
214       // or 0 during early-stage painting
215       return;
216     }
217
218     boolean drawMe = (lastMiniMe != null);
219     if (restart)
220     {
221       if (drawMe)
222       {
223         g.drawImage(lastMiniMe, 0, 0, w, h, this);
224       }
225       else
226       {
227         g.setColor(Color.white);
228         g.fillRect(0, 0, w, h);
229       }
230       g.setColor(TRANS_GREY);
231       g.fillRect(0, 0, w, h);
232       drawMe = false;
233     }
234     else if (drawMe)
235     {
236       // is this a resize?
237       if (w != od.getWidth() || h != od.getHeight())
238       {
239
240         lastMiniMe = null;
241         return;
242         // // if there is annotation, scale the alignment and annotation
243         // // separately
244         // if (od.getGraphHeight() <= 0 && od.getSequencesHeight() <= 0)
245         // {
246         // od.setWidth(w);
247         // od.setHeight(h);
248         // return;
249         // }
250         // try
251         // {
252         // BufferedImage topImage = lastMiniMe.getSubimage(0, 0,
253         // od.getWidth(), od.getSequencesHeight());
254         //
255         // BufferedImage bottomImage = lastMiniMe.getSubimage(0,
256         // od.getSequencesHeight(), od.getWidth(),
257         // od.getGraphHeight());
258         //
259         // // must be done at this point as we rely on using old width/height
260         // // above, and new width/height below
261         // od.setWidth(w);
262         // od.setHeight(h);
263         //
264         // // stick the images back together so lastMiniMe is consistent in the
265         // // event of a repaint - BUT probably not thread safe
266         //
267         // // right -- this fails with fast user action.
268         //
269         // lastMiniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
270         // Graphics lg = lastMiniMe.getGraphics();
271         // lg.drawImage(topImage, 0, 0, w, od.getSequencesHeight(), null);
272         // lg.drawImage(bottomImage, 0, od.getSequencesHeight(), w,
273         // od.getGraphHeight(), this);
274         // lg.dispose();
275         //
276         // } catch (RasterFormatException e)
277         // {
278         // System.out.println("OC Raster Exception " + lastMiniMe.getWidth()
279         // + "/" + w + "," + lastMiniMe.getHeight() + "/" + h + " "
280         // + od.getSequencesHeight() + " " + od.getGraphHeight());
281         // }
282         // BH 2019: removed -- this is now taken care of using vpbox in
283         // OverviewDimension
284         // // make sure the box is in the right place
285         // od.setBoxPosition(av.getAlignment().getHiddenSequences(),
286         // av.getAlignment().getHiddenColumns());
287       }
288     }
289
290     if (drawMe)
291     {
292       g.drawImage(lastMiniMe, 0, 0, w, h, this);
293     }
294     // draw the box
295     g.setColor(Color.red);
296     // System.out.println("OC paintComponent nd=" + ndraw + " nr=" + nrepaint
297     // + " np=" + ++npaint);
298     od.drawBox(g);
299   }
300
301   // private int ndraw, npaint, nrepaint;
302
303   // @Override
304   // public void repaint()
305   // {
306   // System.out.println("OC repaint " + (++nrepaint));
307   // super.repaint();
308   // }
309
310   public void dispose()
311   {
312     disposed = true;
313     od = null;
314     lastMiniMe = null;
315     synchronized (this)
316     {
317       setRestart("dispose");
318     }
319   }
320
321 }