Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
AnnotationColourChooser | 54 | 195 | 57 |
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.BorderLayout; | |
24 | import java.awt.Color; | |
25 | import java.awt.Dimension; | |
26 | import java.awt.FlowLayout; | |
27 | import java.awt.event.ActionEvent; | |
28 | import java.awt.event.ActionListener; | |
29 | import java.awt.event.MouseAdapter; | |
30 | import java.awt.event.MouseEvent; | |
31 | import java.util.Hashtable; | |
32 | import java.util.Vector; | |
33 | ||
34 | import javax.swing.BorderFactory; | |
35 | import javax.swing.JButton; | |
36 | import javax.swing.JCheckBox; | |
37 | import javax.swing.JComboBox; | |
38 | import javax.swing.JInternalFrame; | |
39 | import javax.swing.JLayeredPane; | |
40 | import javax.swing.JPanel; | |
41 | ||
42 | import jalview.bin.Cache; | |
43 | import jalview.datamodel.AlignmentAnnotation; | |
44 | import jalview.datamodel.Annotation; | |
45 | import jalview.datamodel.GraphLine; | |
46 | import jalview.datamodel.SequenceGroup; | |
47 | import jalview.gui.JalviewColourChooser.ColourChooserListener; | |
48 | import jalview.schemes.AnnotationColourGradient; | |
49 | import jalview.schemes.ColourSchemeI; | |
50 | import jalview.util.MessageManager; | |
51 | import net.miginfocom.swing.MigLayout; | |
52 | ||
53 | @SuppressWarnings("serial") | |
54 | public class AnnotationColourChooser extends AnnotationRowFilter | |
55 | { | |
56 | private ColourSchemeI oldcs; | |
57 | ||
58 | private JButton defColours; | |
59 | ||
60 | private Hashtable<SequenceGroup, ColourSchemeI> oldgroupColours; | |
61 | ||
62 | private JCheckBox useOriginalColours = new JCheckBox(); | |
63 | ||
64 | JPanel minColour = new JPanel(); | |
65 | ||
66 | JPanel maxColour = new JPanel(); | |
67 | ||
68 | private JCheckBox thresholdIsMin = new JCheckBox(); | |
69 | ||
70 | protected static final int MIN_WIDTH = 500; | |
71 | ||
72 | protected static final int MIN_HEIGHT = 240; | |
73 | ||
74 | 0 | public AnnotationColourChooser(AlignViewport av, final AlignmentPanel ap) |
75 | { | |
76 | 0 | this(av, ap, null); |
77 | } | |
78 | ||
79 | 0 | public AnnotationColourChooser(AlignViewport av, final AlignmentPanel ap, |
80 | AnnotationColourGradient initSettings) | |
81 | { | |
82 | 0 | super(av, ap); |
83 | 0 | oldcs = av.getGlobalColourScheme(); |
84 | 0 | if (av.getAlignment().getGroups() != null) |
85 | { | |
86 | 0 | oldgroupColours = new Hashtable<>(); |
87 | 0 | for (SequenceGroup sg : ap.av.getAlignment().getGroups()) |
88 | { | |
89 | 0 | if (sg.getColourScheme() != null) |
90 | { | |
91 | 0 | oldgroupColours.put(sg, sg.getColourScheme()); |
92 | } | |
93 | } | |
94 | } | |
95 | 0 | frame = new JInternalFrame(); |
96 | 0 | frame.setFrameIcon(null); |
97 | 0 | frame.setContentPane(this); |
98 | 0 | frame.setLayer(JLayeredPane.PALETTE_LAYER); |
99 | 0 | Desktop.addInternalFrame(frame, |
100 | MessageManager.getString("label.colour_by_annotation"), 520, | |
101 | 215); | |
102 | 0 | frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT)); |
103 | 0 | addSliderChangeListener(); |
104 | 0 | addSliderMouseListeners(); |
105 | ||
106 | 0 | if (av.getAlignment().getAlignmentAnnotation() == null) |
107 | { | |
108 | 0 | return; |
109 | } | |
110 | ||
111 | // Always get default shading from preferences. | |
112 | 0 | setDefaultMinMax(); |
113 | ||
114 | 0 | adjusting = true; |
115 | 0 | if (oldcs instanceof AnnotationColourGradient && initSettings == null) |
116 | { | |
117 | // init from oldcs | |
118 | 0 | initialiseFrom((AnnotationColourGradient) oldcs); |
119 | } | |
120 | else | |
121 | { | |
122 | // use initial colour gradient - if any.. | |
123 | 0 | initialiseFrom(initSettings); |
124 | } | |
125 | ||
126 | 0 | jbInit(); |
127 | 0 | adjusting = false; |
128 | ||
129 | 0 | updateView(); |
130 | 0 | frame.invalidate(); |
131 | 0 | frame.pack(); |
132 | } | |
133 | ||
134 | 0 | private void initialiseFrom(AnnotationColourGradient acg) |
135 | { | |
136 | 0 | if (acg != null) |
137 | { | |
138 | 0 | useOriginalColours.setSelected( |
139 | acg.isPredefinedColours() || acg.getBaseColour() != null); | |
140 | 0 | if (!acg.isPredefinedColours() && acg.getBaseColour() == null) |
141 | { | |
142 | 0 | minColour.setBackground(acg.getMinColour()); |
143 | 0 | maxColour.setBackground(acg.getMaxColour()); |
144 | } | |
145 | 0 | seqAssociated.setSelected(acg.isSeqAssociated()); |
146 | ||
147 | } | |
148 | 0 | Vector<String> annotItems = getAnnotationItems( |
149 | seqAssociated.isSelected()); | |
150 | 0 | annotations = new JComboBox<>(annotItems); |
151 | ||
152 | 0 | populateThresholdComboBox(threshold); |
153 | ||
154 | 0 | if (acg != null) |
155 | { | |
156 | 0 | String label = getAnnotationMenuLabel(acg.getAnnotation()); |
157 | // TODO: workaround below shouldn't be necessary - there's a bug in | |
158 | // getAnnotationMenuLabel! | |
159 | 0 | if (acg.isSeqAssociated()) |
160 | { | |
161 | 0 | label = acg.getAnnotation().label; |
162 | } | |
163 | 0 | annotations.setSelectedItem(label); |
164 | 0 | switch (acg.getAboveThreshold()) |
165 | { | |
166 | 0 | case AnnotationColourGradient.NO_THRESHOLD: |
167 | 0 | getThreshold().setSelectedIndex(0); |
168 | 0 | break; |
169 | 0 | case AnnotationColourGradient.ABOVE_THRESHOLD: |
170 | 0 | getThreshold().setSelectedIndex(1); |
171 | 0 | break; |
172 | 0 | case AnnotationColourGradient.BELOW_THRESHOLD: |
173 | 0 | getThreshold().setSelectedIndex(2); |
174 | 0 | break; |
175 | 0 | default: |
176 | 0 | throw new Error(MessageManager.getString( |
177 | "error.implementation_error_dont_know_about_threshold_setting")); | |
178 | } | |
179 | 0 | thresholdIsMin.setSelected(acg.isThresholdIsMinMax()); |
180 | 0 | thresholdValue.setText(String.valueOf(acg.getAnnotationThreshold())); |
181 | } | |
182 | } | |
183 | ||
184 | 0 | @Override |
185 | protected void jbInit() | |
186 | { | |
187 | 0 | super.jbInit(); |
188 | ||
189 | 0 | minColour.setFont(JvSwingUtils.getLabelFont()); |
190 | 0 | minColour.setBorder(BorderFactory.createEtchedBorder()); |
191 | 0 | minColour.setPreferredSize(new Dimension(40, 20)); |
192 | 0 | minColour.setToolTipText(MessageManager.getString("label.min_colour")); |
193 | 0 | minColour.addMouseListener(new MouseAdapter() |
194 | { | |
195 | 0 | @Override |
196 | public void mousePressed(MouseEvent e) | |
197 | { | |
198 | 0 | if (minColour.isEnabled()) |
199 | { | |
200 | 0 | showColourChooser(minColour, "label.select_colour_minimum_value"); |
201 | } | |
202 | } | |
203 | }); | |
204 | 0 | maxColour.setFont(JvSwingUtils.getLabelFont()); |
205 | 0 | maxColour.setBorder(BorderFactory.createEtchedBorder()); |
206 | 0 | maxColour.setPreferredSize(new Dimension(40, 20)); |
207 | 0 | maxColour.setToolTipText(MessageManager.getString("label.max_colour")); |
208 | 0 | maxColour.addMouseListener(new MouseAdapter() |
209 | { | |
210 | 0 | @Override |
211 | public void mousePressed(MouseEvent e) | |
212 | { | |
213 | 0 | if (maxColour.isEnabled()) |
214 | { | |
215 | 0 | showColourChooser(maxColour, "label.select_colour_maximum_value"); |
216 | } | |
217 | } | |
218 | }); | |
219 | ||
220 | 0 | defColours = new JButton(); |
221 | 0 | defColours.setOpaque(false); |
222 | 0 | defColours.setText(MessageManager.getString("action.set_defaults")); |
223 | 0 | defColours.setToolTipText(MessageManager |
224 | .getString("label.reset_min_max_colours_to_defaults")); | |
225 | 0 | defColours.addActionListener(new ActionListener() |
226 | { | |
227 | ||
228 | 0 | @Override |
229 | public void actionPerformed(ActionEvent arg0) | |
230 | { | |
231 | 0 | resetColours_actionPerformed(); |
232 | } | |
233 | }); | |
234 | ||
235 | 0 | useOriginalColours.setFont(JvSwingUtils.getLabelFont()); |
236 | 0 | useOriginalColours.setOpaque(false); |
237 | 0 | useOriginalColours.setText( |
238 | MessageManager.getString("label.use_original_colours")); | |
239 | 0 | useOriginalColours.addActionListener(new ActionListener() |
240 | { | |
241 | 0 | @Override |
242 | public void actionPerformed(ActionEvent e) | |
243 | { | |
244 | 0 | originalColours_actionPerformed(); |
245 | } | |
246 | }); | |
247 | 0 | thresholdIsMin.setBackground(Color.white); |
248 | 0 | thresholdIsMin.setFont(JvSwingUtils.getLabelFont()); |
249 | 0 | thresholdIsMin |
250 | .setText(MessageManager.getString("label.threshold_minmax")); | |
251 | 0 | thresholdIsMin.addActionListener(new ActionListener() |
252 | { | |
253 | 0 | @Override |
254 | public void actionPerformed(ActionEvent actionEvent) | |
255 | { | |
256 | 0 | thresholdIsMin_actionPerformed(); |
257 | } | |
258 | }); | |
259 | 0 | seqAssociated.setBackground(Color.white); |
260 | 0 | seqAssociated.setFont(JvSwingUtils.getLabelFont()); |
261 | 0 | seqAssociated |
262 | .setText(MessageManager.getString("label.per_sequence_only")); | |
263 | 0 | seqAssociated.addActionListener(new ActionListener() |
264 | { | |
265 | ||
266 | 0 | @Override |
267 | public void actionPerformed(ActionEvent arg0) | |
268 | { | |
269 | 0 | seqAssociated_actionPerformed(annotations); |
270 | } | |
271 | }); | |
272 | ||
273 | 0 | this.setLayout(new BorderLayout()); |
274 | 0 | JPanel jPanel1 = new JPanel(); |
275 | 0 | JPanel jPanel2 = new JPanel(); |
276 | 0 | jPanel2.setLayout(new MigLayout("", "[left][center][right]", "[][][]")); |
277 | 0 | jPanel1.setBackground(Color.white); |
278 | 0 | jPanel2.setBackground(Color.white); |
279 | ||
280 | 0 | jPanel1.add(ok); |
281 | 0 | jPanel1.add(cancel); |
282 | 0 | jPanel2.add(annotations, "grow, wrap"); |
283 | 0 | jPanel2.add(seqAssociated); |
284 | 0 | jPanel2.add(useOriginalColours); |
285 | 0 | JPanel colpanel = new JPanel(new FlowLayout()); |
286 | 0 | colpanel.setBackground(Color.white); |
287 | 0 | colpanel.add(minColour); |
288 | 0 | colpanel.add(maxColour); |
289 | 0 | jPanel2.add(colpanel, "wrap"); |
290 | 0 | jPanel2.add(getThreshold()); |
291 | 0 | jPanel2.add(defColours, "skip 1, wrap"); |
292 | 0 | jPanel2.add(thresholdIsMin); |
293 | 0 | jPanel2.add(slider, "grow"); |
294 | 0 | jPanel2.add(thresholdValue, "grow"); |
295 | 0 | this.add(jPanel1, java.awt.BorderLayout.SOUTH); |
296 | 0 | this.add(jPanel2, java.awt.BorderLayout.CENTER); |
297 | 0 | this.validate(); |
298 | } | |
299 | ||
300 | 0 | protected void resetColours_actionPerformed() |
301 | { | |
302 | 0 | setDefaultMinMax(); |
303 | 0 | updateView(); |
304 | } | |
305 | ||
306 | 0 | private void setDefaultMinMax() |
307 | { | |
308 | 0 | minColour.setBackground( |
309 | Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN", Color.orange)); | |
310 | 0 | maxColour.setBackground( |
311 | Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX", Color.red)); | |
312 | } | |
313 | ||
314 | 0 | protected void showColourChooser(JPanel colourPanel, String titleKey) |
315 | { | |
316 | 0 | String ttl = MessageManager.getString(titleKey); |
317 | 0 | ColourChooserListener listener = new ColourChooserListener() |
318 | { | |
319 | 0 | @Override |
320 | public void colourSelected(Color c) | |
321 | { | |
322 | 0 | colourPanel.setBackground(c); |
323 | 0 | colourPanel.repaint(); |
324 | 0 | updateView(); |
325 | } | |
326 | }; | |
327 | 0 | JalviewColourChooser.showColourChooser(Desktop.getDesktop(), ttl, |
328 | colourPanel.getBackground(), listener); | |
329 | } | |
330 | ||
331 | 0 | @Override |
332 | public void reset() | |
333 | { | |
334 | 0 | this.ap.alignFrame.changeColour(oldcs); |
335 | 0 | if (av.getAlignment().getGroups() != null) |
336 | { | |
337 | ||
338 | 0 | for (SequenceGroup sg : ap.av.getAlignment().getGroups()) |
339 | { | |
340 | 0 | sg.setColourScheme(oldgroupColours.get(sg)); |
341 | } | |
342 | } | |
343 | } | |
344 | ||
345 | 0 | @Override |
346 | public void valueChanged(boolean updateAllAnnotation) | |
347 | { | |
348 | 0 | if (slider.isEnabled()) |
349 | { | |
350 | 0 | if (useOriginalColours.isSelected() && !(av |
351 | .getGlobalColourScheme() instanceof AnnotationColourGradient)) | |
352 | { | |
353 | 0 | updateView(); |
354 | } | |
355 | 0 | getCurrentAnnotation().threshold.value = getSliderValue(); |
356 | 0 | propagateSeqAssociatedThreshold(updateAllAnnotation, |
357 | getCurrentAnnotation()); | |
358 | 0 | ap.paintAlignment(false, false); |
359 | } | |
360 | } | |
361 | ||
362 | 0 | public void originalColours_actionPerformed() |
363 | { | |
364 | 0 | boolean selected = useOriginalColours.isSelected(); |
365 | 0 | if (selected) |
366 | { | |
367 | 0 | reset(); |
368 | } | |
369 | 0 | maxColour.setEnabled(!selected); |
370 | 0 | minColour.setEnabled(!selected); |
371 | 0 | thresholdIsMin.setEnabled(!selected); |
372 | 0 | updateView(); |
373 | } | |
374 | ||
375 | 0 | @Override |
376 | public void updateView() | |
377 | { | |
378 | // Check if combobox is still adjusting | |
379 | 0 | if (adjusting) |
380 | { | |
381 | 0 | return; |
382 | } | |
383 | ||
384 | 0 | int selIndex = annotations.getSelectedIndex(); |
385 | 0 | int annIndex = annmap[selIndex]; |
386 | 0 | setCurrentAnnotation( |
387 | av.getAlignment().getAlignmentAnnotation()[annIndex]); | |
388 | ||
389 | 0 | int selectedThresholdItem = getSelectedThresholdItem( |
390 | getThreshold().getSelectedIndex()); | |
391 | ||
392 | 0 | slider.setEnabled(true); |
393 | 0 | thresholdValue.setEnabled(true); |
394 | 0 | thresholdIsMin.setEnabled(!useOriginalColours.isSelected()); |
395 | ||
396 | 0 | final AlignmentAnnotation currentAnnotation = getCurrentAnnotation(); |
397 | 0 | if (selectedThresholdItem == AnnotationColourGradient.NO_THRESHOLD) |
398 | { | |
399 | 0 | slider.setEnabled(false); |
400 | 0 | thresholdValue.setEnabled(false); |
401 | 0 | thresholdValue.setText(""); |
402 | 0 | thresholdIsMin.setEnabled(false); |
403 | } | |
404 | 0 | else if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD |
405 | && currentAnnotation.threshold == null) | |
406 | { | |
407 | 0 | currentAnnotation.setThreshold(new GraphLine( |
408 | (currentAnnotation.graphMax - currentAnnotation.graphMin) | |
409 | / 2f, | |
410 | "Threshold", Color.black)); | |
411 | } | |
412 | ||
413 | 0 | if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD) |
414 | { | |
415 | 0 | adjusting = true; |
416 | 0 | setSliderModel(currentAnnotation.graphMin, currentAnnotation.graphMax, |
417 | currentAnnotation.threshold.value); | |
418 | 0 | slider.setEnabled(true); |
419 | ||
420 | 0 | setThresholdValueText(); |
421 | 0 | thresholdValue.setEnabled(true); |
422 | 0 | adjusting = false; |
423 | } | |
424 | 0 | colorAlignmentContaining(currentAnnotation, selectedThresholdItem); |
425 | ||
426 | 0 | ap.alignmentChanged(); |
427 | } | |
428 | ||
429 | 0 | protected void colorAlignmentContaining(AlignmentAnnotation currentAnn, |
430 | int selectedThresholdOption) | |
431 | { | |
432 | ||
433 | 0 | AnnotationColourGradient acg = null; |
434 | 0 | if (useOriginalColours.isSelected()) |
435 | { | |
436 | 0 | acg = new AnnotationColourGradient(currentAnn, |
437 | av.getGlobalColourScheme(), selectedThresholdOption); | |
438 | } | |
439 | else | |
440 | { | |
441 | 0 | acg = new AnnotationColourGradient(currentAnn, |
442 | minColour.getBackground(), maxColour.getBackground(), | |
443 | selectedThresholdOption); | |
444 | } | |
445 | 0 | acg.setSeqAssociated(seqAssociated.isSelected()); |
446 | ||
447 | 0 | if (currentAnn.graphMin == 0f && currentAnn.graphMax == 0f) |
448 | { | |
449 | 0 | acg.setPredefinedColours(true); |
450 | } | |
451 | ||
452 | 0 | acg.setThresholdIsMinMax(thresholdIsMin.isSelected()); |
453 | ||
454 | 0 | this.ap.alignFrame.changeColour(acg); |
455 | ||
456 | 0 | if (av.getAlignment().getGroups() != null) |
457 | { | |
458 | ||
459 | 0 | for (SequenceGroup sg : ap.av.getAlignment().getGroups()) |
460 | { | |
461 | 0 | if (sg.cs == null) |
462 | { | |
463 | 0 | continue; |
464 | } | |
465 | 0 | sg.setColourScheme(acg.getInstance(av, sg)); |
466 | } | |
467 | } | |
468 | } | |
469 | ||
470 | 0 | @Override |
471 | protected void sliderDragReleased() | |
472 | { | |
473 | 0 | super.sliderDragReleased(); |
474 | 0 | ap.paintAlignment(true, true); |
475 | } | |
476 | ||
477 | /** | |
478 | * construct and display a colourchooser for a given annotation row | |
479 | * | |
480 | * @param av | |
481 | * @param ap | |
482 | * @param alignmentAnnotation | |
483 | * @param perseq | |
484 | * - when true, enable per-sequence if alignment annotation is per | |
485 | * sequence | |
486 | */ | |
487 | 0 | public static void displayFor(AlignViewport av, AlignmentPanel ap, |
488 | AlignmentAnnotation alignmentAnnotation, boolean perSeq) | |
489 | { | |
490 | 0 | ColourSchemeI global = av.getGlobalColourScheme(); |
491 | 0 | AnnotationColourGradient newCS = new AnnotationColourGradient( |
492 | alignmentAnnotation, global, | |
493 | 0 | alignmentAnnotation.threshold != null |
494 | ? AnnotationColourGradient.ABOVE_THRESHOLD | |
495 | : AnnotationColourGradient.NO_THRESHOLD); | |
496 | 0 | if (alignmentAnnotation.sequenceRef != null) |
497 | { | |
498 | 0 | newCS.setSeqAssociated(perSeq); |
499 | } | |
500 | 0 | for (int i = 0; i < alignmentAnnotation.annotations.length; i++) |
501 | { | |
502 | 0 | Annotation ann = alignmentAnnotation.annotations[i]; |
503 | 0 | if (ann != null && ann.colour != null |
504 | && !ann.colour.equals(Color.white)) | |
505 | { | |
506 | 0 | newCS.setPredefinedColours(true); |
507 | 0 | break; |
508 | } | |
509 | } | |
510 | 0 | AnnotationColourChooser achooser = new AnnotationColourChooser(av, ap, |
511 | newCS); | |
512 | } | |
513 | } |