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