de55996b1bf7f0249f647ab9b799c8db8e247448
[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 SequenceRenderer sr;
55
56   private jalview.renderer.seqfeatures.FeatureRenderer fr;
57
58   private OverviewDimensions od;
59
60   private OverviewRenderer or = null;
61
62   private AlignViewportI av;
63
64   private OverviewResColourFinder cf;
65
66   private ProgressPanel progressPanel;
67
68   private boolean showSequenceFeatures;
69
70   private boolean showAnnotation;
71
72   private jalview.api.FeatureRenderer featureRenderer;
73
74   private OverviewPanel panel;
75
76   private 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
180     if (showProgress && or != null)
181     {
182       or.removePropertyChangeListener(progressPanel);
183     }
184     if (restart)
185     {
186       or = null;
187       restart = false;
188       if (!disposed)
189       {
190         draw(showSequenceFeatures, showAnnotation, featureRenderer);
191       }
192     }
193     else
194     {
195       if (showAnnotation && or != null)
196       {
197         or.drawGraph(av.getAlignmentConservationAnnotation());
198       }
199       or = null;
200       updaterunning = false;
201       lastMiniMe = miniMe;
202       repaint();
203     }
204   }
205
206   @Override
207   public void paintComponent(Graphics g)
208   {
209
210     int w = getWidth();
211     int h = getHeight();
212     if (w == 0 || od.getBoxWidth() <= 0)
213     {
214       // BH 2019.07.27 removes two unnecessary paints, since boxwidth can be -1
215       // or 0 during early-stage painting
216       return;
217     }
218
219     boolean drawMe = (lastMiniMe != null);
220     if (restart)
221     {
222       if (drawMe)
223       {
224         g.drawImage(lastMiniMe, 0, 0, w, h, this);
225       }
226       else
227       {
228         g.setColor(Color.white);
229         g.fillRect(0, 0, w, h);
230       }
231       g.setColor(TRANS_GREY);
232       g.fillRect(0, 0, w, h);
233       drawMe = false;
234     }
235     else if (drawMe)
236     {
237       // is this a resize?
238       if (w != od.getWidth() || h != od.getHeight())
239       {
240
241         lastMiniMe = null;
242         return;
243         // // if there is annotation, scale the alignment and annotation
244         // // separately
245         // if (od.getGraphHeight() <= 0 && od.getSequencesHeight() <= 0)
246         // {
247         // od.setWidth(w);
248         // od.setHeight(h);
249         // return;
250         // }
251         // try
252         // {
253         // BufferedImage topImage = lastMiniMe.getSubimage(0, 0,
254         // od.getWidth(), od.getSequencesHeight());
255         //
256         // BufferedImage bottomImage = lastMiniMe.getSubimage(0,
257         // od.getSequencesHeight(), od.getWidth(),
258         // od.getGraphHeight());
259         //
260         // // must be done at this point as we rely on using old width/height
261         // // above, and new width/height below
262         // od.setWidth(w);
263         // od.setHeight(h);
264         //
265         // // stick the images back together so lastMiniMe is consistent in the
266         // // event of a repaint - BUT probably not thread safe
267         //
268         // // right -- this fails with fast user action.
269         //
270         // lastMiniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
271         // Graphics lg = lastMiniMe.getGraphics();
272         // lg.drawImage(topImage, 0, 0, w, od.getSequencesHeight(), null);
273         // lg.drawImage(bottomImage, 0, od.getSequencesHeight(), w,
274         // od.getGraphHeight(), this);
275         // lg.dispose();
276         //
277         // } catch (RasterFormatException e)
278         // {
279         // System.out.println("OC Raster Exception " + lastMiniMe.getWidth()
280         // + "/" + w + "," + lastMiniMe.getHeight() + "/" + h + " "
281         // + od.getSequencesHeight() + " " + od.getGraphHeight());
282         // }
283         // BH 2019: removed -- this is now taken care of using vpbox in
284         // OverviewDimension
285         // // make sure the box is in the right place
286         // od.setBoxPosition(av.getAlignment().getHiddenSequences(),
287         // av.getAlignment().getHiddenColumns());
288       }
289     }
290
291     if (drawMe)
292     {
293       g.drawImage(lastMiniMe, 0, 0, w, h, this);
294     }
295     // draw the box
296     g.setColor(Color.red);
297     // System.out.println("OC paintComponent nd=" + ndraw + " nr=" + nrepaint
298     // + " np=" + ++npaint);
299     od.drawBox(g);
300   }
301
302   // private int ndraw, npaint, nrepaint;
303
304   // @Override
305   // public void repaint()
306   // {
307   // System.out.println("OC repaint " + (++nrepaint));
308   // super.repaint();
309   // }
310
311   public void dispose()
312   {
313     disposed = true;
314     od = null;
315     lastMiniMe = null;
316     synchronized (this)
317     {
318       setRestart("dispose");
319     }
320   }
321
322 }