2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import jalview.api.FeatureColourI;
24 import jalview.api.FeatureSettingsControllerI;
25 import jalview.datamodel.AlignmentI;
26 import jalview.datamodel.SequenceI;
27 import jalview.datamodel.features.FeatureMatcher;
28 import jalview.datamodel.features.FeatureMatcherI;
29 import jalview.datamodel.features.FeatureMatcherSet;
30 import jalview.datamodel.features.FeatureMatcherSetI;
31 import jalview.gui.Help.HelpId;
32 import jalview.gui.JalviewColourChooser.ColourChooserListener;
33 import jalview.io.JalviewFileChooser;
34 import jalview.io.JalviewFileView;
35 import jalview.schemes.FeatureColour;
36 import jalview.util.MessageManager;
37 import jalview.util.Platform;
38 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
39 import jalview.xml.binding.jalview.JalviewUserColours;
40 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
41 import jalview.xml.binding.jalview.JalviewUserColours.Filter;
42 import jalview.xml.binding.jalview.ObjectFactory;
44 import java.awt.BorderLayout;
45 import java.awt.Color;
46 import java.awt.Component;
47 import java.awt.Dimension;
49 import java.awt.Graphics;
50 import java.awt.GridLayout;
51 import java.awt.Point;
52 import java.awt.Rectangle;
53 import java.awt.event.ActionEvent;
54 import java.awt.event.ActionListener;
55 import java.awt.event.ItemEvent;
56 import java.awt.event.ItemListener;
57 import java.awt.event.MouseAdapter;
58 import java.awt.event.MouseEvent;
59 import java.awt.event.MouseMotionAdapter;
60 import java.beans.PropertyChangeEvent;
61 import java.beans.PropertyChangeListener;
63 import java.io.FileInputStream;
64 import java.io.FileOutputStream;
65 import java.io.InputStreamReader;
66 import java.io.OutputStreamWriter;
67 import java.io.PrintWriter;
68 import java.util.Arrays;
69 import java.util.Comparator;
70 import java.util.HashMap;
71 import java.util.HashSet;
72 import java.util.Hashtable;
73 import java.util.Iterator;
74 import java.util.List;
78 import javax.help.HelpSetException;
79 import javax.swing.AbstractCellEditor;
80 import javax.swing.BorderFactory;
81 import javax.swing.Icon;
82 import javax.swing.JButton;
83 import javax.swing.JCheckBox;
84 import javax.swing.JCheckBoxMenuItem;
85 import javax.swing.JInternalFrame;
86 import javax.swing.JLabel;
87 import javax.swing.JLayeredPane;
88 import javax.swing.JMenuItem;
89 import javax.swing.JPanel;
90 import javax.swing.JPopupMenu;
91 import javax.swing.JScrollPane;
92 import javax.swing.JSlider;
93 import javax.swing.JTable;
94 import javax.swing.ListSelectionModel;
95 import javax.swing.SwingConstants;
96 import javax.swing.ToolTipManager;
97 import javax.swing.border.Border;
98 import javax.swing.event.ChangeEvent;
99 import javax.swing.event.ChangeListener;
100 import javax.swing.table.AbstractTableModel;
101 import javax.swing.table.JTableHeader;
102 import javax.swing.table.TableCellEditor;
103 import javax.swing.table.TableCellRenderer;
104 import javax.swing.table.TableColumn;
105 import javax.xml.bind.JAXBContext;
106 import javax.xml.bind.JAXBElement;
107 import javax.xml.bind.Marshaller;
108 import javax.xml.stream.XMLInputFactory;
109 import javax.xml.stream.XMLStreamReader;
111 public class FeatureSettings extends JPanel
112 implements FeatureSettingsControllerI
114 private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
115 .getString("label.sequence_feature_colours");
118 * column indices of fields in Feature Settings table
120 static final int TYPE_COLUMN = 0;
122 static final int COLOUR_COLUMN = 1;
124 static final int FILTER_COLUMN = 2;
126 static final int SHOW_COLUMN = 3;
128 private static final int COLUMN_COUNT = 4;
130 private static final int MIN_WIDTH = 400;
132 private static final int MIN_HEIGHT = 400;
134 private final static String BASE_TOOLTIP = MessageManager
135 .getString("label.click_to_edit");
137 final FeatureRenderer fr;
139 public final AlignFrame af;
142 * 'original' fields hold settings to restore on Cancel
144 Object[][] originalData;
146 float originalTransparency;
148 Map<String, FeatureMatcherSetI> originalFilters;
150 final JInternalFrame frame;
152 JScrollPane scrollPane = new JScrollPane();
158 JSlider transparency = new JSlider();
161 * when true, constructor is still executing - so ignore UI events
163 protected volatile boolean inConstruction = true;
165 int selectedRow = -1;
167 boolean resettingTable = false;
170 * true when Feature Settings are updating from feature renderer
172 boolean handlingUpdate = false;
175 * holds {featureCount, totalExtent} for each feature type
177 Map<String, float[]> typeWidth = null;
184 public FeatureSettings(AlignFrame alignFrame)
186 this.af = alignFrame;
187 fr = af.getFeatureRenderer();
189 // save transparency for restore on Cancel
190 originalTransparency = fr.getTransparency();
191 int originalTransparencyAsPercent = (int) (originalTransparency * 100);
192 transparency.setMaximum(100 - originalTransparencyAsPercent);
194 originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
199 } catch (Exception ex)
201 ex.printStackTrace();
207 public String getToolTipText(MouseEvent e)
210 int column = table.columnAtPoint(e.getPoint());
211 int row = table.rowAtPoint(e.getPoint());
216 tip = JvSwingUtils.wrapTooltip(true, MessageManager
217 .getString("label.feature_settings_click_drag"));
220 FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
222 tip = getColorTooltip(colour, true);
225 FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
229 .getString("label.configure_feature_tooltip")
240 * Position the tooltip near the bottom edge of, and half way across, the
244 public Point getToolTipLocation(MouseEvent e)
246 Point point = e.getPoint();
247 int column = table.columnAtPoint(point);
248 int row = table.rowAtPoint(point);
249 Rectangle r = getCellRect(row, column, false);
250 Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3);
254 JTableHeader tableHeader = table.getTableHeader();
255 tableHeader.setFont(new Font("Verdana", Font.PLAIN, 12));
256 tableHeader.setReorderingAllowed(false);
257 table.setFont(new Font("Verdana", Font.PLAIN, 12));
258 ToolTipManager.sharedInstance().registerComponent(table);
259 table.setDefaultEditor(FeatureColour.class, new ColorEditor());
260 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
262 table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor());
263 table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
265 TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
266 new ColorRenderer(), new ColorEditor());
267 table.addColumn(colourColumn);
269 TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
270 new FilterRenderer(), new FilterEditor());
271 table.addColumn(filterColumn);
273 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
275 table.addMouseListener(new MouseAdapter()
278 public void mousePressed(MouseEvent evt)
280 selectedRow = table.rowAtPoint(evt.getPoint());
281 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
282 if (evt.isPopupTrigger())
284 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
285 showPopupMenu(selectedRow, type, colour, evt.getPoint());
287 else if (evt.getClickCount() == 2)
289 boolean invertSelection = evt.isAltDown();
290 boolean toggleSelection = Platform.isControlDown(evt);
291 boolean extendSelection = evt.isShiftDown();
292 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
293 invertSelection, extendSelection, toggleSelection, type);
297 // isPopupTrigger fires on mouseReleased on Windows
299 public void mouseReleased(MouseEvent evt)
301 selectedRow = table.rowAtPoint(evt.getPoint());
302 if (evt.isPopupTrigger())
304 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
305 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
306 showPopupMenu(selectedRow, type, colour, evt.getPoint());
311 table.addMouseMotionListener(new MouseMotionAdapter()
314 public void mouseDragged(MouseEvent evt)
316 int newRow = table.rowAtPoint(evt.getPoint());
317 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
320 * reposition 'selectedRow' to 'newRow' (the dragged to location)
321 * this could be more than one row away for a very fast drag action
322 * so just swap it with adjacent rows until we get it there
324 Object[][] data = ((FeatureTableModel) table.getModel())
326 int direction = newRow < selectedRow ? -1 : 1;
327 for (int i = selectedRow; i != newRow; i += direction)
329 Object[] temp = data[i];
330 data[i] = data[i + direction];
331 data[i + direction] = temp;
333 updateFeatureRenderer(data);
335 selectedRow = newRow;
339 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
340 // MessageManager.getString("label.feature_settings_click_drag")));
341 scrollPane.setViewportView(table);
343 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
345 fr.findAllFeatures(true); // display everything!
348 discoverAllFeatureData();
349 final PropertyChangeListener change;
350 final FeatureSettings fs = this;
351 fr.addPropertyChangeListener(change = new PropertyChangeListener()
354 public void propertyChange(PropertyChangeEvent evt)
356 if (!fs.resettingTable && !fs.handlingUpdate)
358 fs.handlingUpdate = true;
360 // new groups may be added with new sequence feature types only
361 fs.handlingUpdate = false;
367 frame = new JInternalFrame();
368 frame.setContentPane(this);
369 Desktop.addInternalFrame(frame,
370 MessageManager.getString("label.sequence_feature_settings"),
371 600, Platform.isAMacAndNotJS() ? 480 : 450);
372 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
374 frame.addInternalFrameListener(
375 new javax.swing.event.InternalFrameAdapter()
378 public void internalFrameClosed(
379 javax.swing.event.InternalFrameEvent evt)
381 fr.removePropertyChangeListener(change);
384 frame.setLayer(JLayeredPane.PALETTE_LAYER);
385 inConstruction = false;
389 * Constructs and shows a popup menu of possible actions on the selected row
397 protected void showPopupMenu(final int rowSelected, final String type,
398 final Object typeCol, final Point pt)
400 JPopupMenu men = new JPopupMenu(MessageManager
401 .formatMessage("label.settings_for_param", new String[]
403 final FeatureColourI featureColour = (FeatureColourI) typeCol;
406 * menu option to select (or deselect) variable colour
408 final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
409 MessageManager.getString("label.variable_colour"));
410 variableColourCB.setSelected(!featureColour.isSimpleColour());
411 men.add(variableColourCB);
414 * checkbox action listener doubles up as listener to OK
415 * from the variable colour / filters dialog
417 variableColourCB.addActionListener(new ActionListener()
420 public void actionPerformed(ActionEvent e)
422 if (e.getSource() == variableColourCB)
424 men.setVisible(true); // BH 2018 for JavaScript because this is a
426 men.setVisible(false); // BH 2018 for JavaScript because this is a
428 if (featureColour.isSimpleColour())
431 * toggle simple colour to variable colour - show dialog
433 FeatureTypeSettings fc = new FeatureTypeSettings(fr, type);
434 fc.addActionListener(this);
439 * toggle variable to simple colour - show colour chooser
441 String title = MessageManager
442 .formatMessage("label.select_colour_for", type);
443 ColourChooserListener listener = new ColourChooserListener()
446 public void colourSelected(Color c)
448 table.setValueAt(new FeatureColour(c), rowSelected,
451 updateFeatureRenderer(
452 ((FeatureTableModel) table.getModel()).getData(),
456 JalviewColourChooser.showColourChooser(FeatureSettings.this,
457 title, featureColour.getMaxColour(), listener);
462 if (e.getSource() instanceof FeatureTypeSettings)
465 * update after OK in feature colour dialog; the updated
466 * colour will have already been set in the FeatureRenderer
468 FeatureColourI fci = fr.getFeatureColours().get(type);
469 table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
470 // BH 2018 setting a table value does not invalidate it.
471 // System.out.println("FeatureSettings is valied" +
480 JMenuItem scr = new JMenuItem(
481 MessageManager.getString("label.sort_by_score"));
483 scr.addActionListener(new ActionListener()
487 public void actionPerformed(ActionEvent e)
489 af.avc.sortAlignmentByFeatureScore(Arrays.asList(new String[]
493 JMenuItem dens = new JMenuItem(
494 MessageManager.getString("label.sort_by_density"));
495 dens.addActionListener(new ActionListener()
499 public void actionPerformed(ActionEvent e)
501 af.avc.sortAlignmentByFeatureDensity(Arrays.asList(new String[]
507 JMenuItem selCols = new JMenuItem(
508 MessageManager.getString("label.select_columns_containing"));
509 selCols.addActionListener(new ActionListener()
512 public void actionPerformed(ActionEvent arg0)
514 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
518 JMenuItem clearCols = new JMenuItem(MessageManager
519 .getString("label.select_columns_not_containing"));
520 clearCols.addActionListener(new ActionListener()
523 public void actionPerformed(ActionEvent arg0)
525 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
529 JMenuItem hideCols = new JMenuItem(
530 MessageManager.getString("label.hide_columns_containing"));
531 hideCols.addActionListener(new ActionListener()
534 public void actionPerformed(ActionEvent arg0)
536 fr.ap.alignFrame.hideFeatureColumns(type, true);
539 JMenuItem hideOtherCols = new JMenuItem(
540 MessageManager.getString("label.hide_columns_not_containing"));
541 hideOtherCols.addActionListener(new ActionListener()
544 public void actionPerformed(ActionEvent arg0)
546 fr.ap.alignFrame.hideFeatureColumns(type, false);
552 men.add(hideOtherCols);
553 men.show(table, pt.x, pt.y);
557 synchronized public void discoverAllFeatureData()
559 Set<String> allGroups = new HashSet<>();
560 AlignmentI alignment = af.getViewport().getAlignment();
562 for (int i = 0; i < alignment.getHeight(); i++)
564 SequenceI seq = alignment.getSequenceAt(i);
565 for (String group : seq.getFeatures().getFeatureGroups(true))
567 if (group != null && !allGroups.contains(group))
569 allGroups.add(group);
570 checkGroupState(group);
581 * Synchronise gui group list and check visibility of group
584 * @return true if group is visible
586 private boolean checkGroupState(String group)
588 boolean visible = fr.checkGroupVisibility(group, true);
590 for (int g = 0; g < groupPanel.getComponentCount(); g++)
592 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
594 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
599 final String grp = group;
600 final JCheckBox check = new JCheckBox(group, visible);
601 check.setFont(new Font("Serif", Font.BOLD, 12));
602 check.setToolTipText(group);
603 check.addItemListener(new ItemListener()
606 public void itemStateChanged(ItemEvent evt)
608 fr.setGroupVisibility(check.getText(), check.isSelected());
609 resetTable(new String[] { grp });
610 af.alignPanel.paintAlignment(true, true);
613 groupPanel.add(check);
617 synchronized void resetTable(String[] groupChanged)
623 resettingTable = true;
624 typeWidth = new Hashtable<>();
625 // TODO: change avWidth calculation to 'per-sequence' average and use long
628 Set<String> displayableTypes = new HashSet<>();
629 Set<String> foundGroups = new HashSet<>();
632 * determine which feature types may be visible depending on
633 * which groups are selected, and recompute average width data
635 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
638 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
641 * get the sequence's groups for positional features
642 * and keep track of which groups are visible
644 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
645 Set<String> visibleGroups = new HashSet<>();
646 for (String group : groups)
648 if (group == null || checkGroupState(group))
650 visibleGroups.add(group);
653 foundGroups.addAll(groups);
656 * get distinct feature types for visible groups
657 * record distinct visible types, and their count and total length
659 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
660 visibleGroups.toArray(new String[visibleGroups.size()]));
661 for (String type : types)
663 displayableTypes.add(type);
664 float[] avWidth = typeWidth.get(type);
667 avWidth = new float[2];
668 typeWidth.put(type, avWidth);
670 // todo this could include features with a non-visible group
671 // - do we greatly care?
672 // todo should we include non-displayable features here, and only
673 // update when features are added?
674 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
675 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
679 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
682 if (fr.hasRenderOrder())
686 fr.findAllFeatures(groupChanged != null); // prod to update
687 // colourschemes. but don't
689 // First add the checks in the previous render order,
690 // in case the window has been closed and reopened
692 List<String> frl = fr.getRenderOrder();
693 for (int ro = frl.size() - 1; ro > -1; ro--)
695 String type = frl.get(ro);
697 if (!displayableTypes.contains(type))
702 data[dataIndex][TYPE_COLUMN] = type;
703 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
704 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
705 data[dataIndex][FILTER_COLUMN] = featureFilter == null
706 ? new FeatureMatcherSet()
708 data[dataIndex][SHOW_COLUMN] = new Boolean(
709 af.getViewport().getFeaturesDisplayed().isVisible(type));
711 displayableTypes.remove(type);
716 * process any extra features belonging only to
717 * a group which was just selected
719 while (!displayableTypes.isEmpty())
721 String type = displayableTypes.iterator().next();
722 data[dataIndex][TYPE_COLUMN] = type;
724 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
725 if (data[dataIndex][COLOUR_COLUMN] == null)
727 // "Colour has been updated in another view!!"
728 fr.clearRenderOrder();
731 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
732 data[dataIndex][FILTER_COLUMN] = featureFilter == null
733 ? new FeatureMatcherSet()
735 data[dataIndex][SHOW_COLUMN] = new Boolean(true);
737 displayableTypes.remove(type);
740 if (originalData == null)
742 originalData = new Object[data.length][COLUMN_COUNT];
743 for (int i = 0; i < data.length; i++)
745 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
750 updateOriginalData(data);
753 table.setModel(new FeatureTableModel(data));
754 table.getColumnModel().getColumn(0).setPreferredWidth(200);
756 groupPanel.setLayout(
757 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
758 pruneGroups(foundGroups);
759 groupPanel.validate();
761 updateFeatureRenderer(data, groupChanged != null);
762 resettingTable = false;
766 * Updates 'originalData' (used for restore on Cancel) if we detect that
767 * changes have been made outwith this dialog
769 * <li>a new feature type added (and made visible)</li>
770 * <li>a feature colour changed (in the Amend Features dialog)</li>
775 protected void updateOriginalData(Object[][] foundData)
777 // todo LinkedHashMap instead of Object[][] would be nice
779 Object[][] currentData = ((FeatureTableModel) table.getModel())
781 for (Object[] row : foundData)
783 String type = (String) row[TYPE_COLUMN];
784 boolean found = false;
785 for (Object[] current : currentData)
787 if (type.equals(current[TYPE_COLUMN]))
791 * currently dependent on object equality here;
792 * really need an equals method on FeatureColour
794 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
797 * feature colour has changed externally - update originalData
799 for (Object[] original : originalData)
801 if (type.equals(original[TYPE_COLUMN]))
803 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
814 * new feature detected - add to original data (on top)
816 Object[][] newData = new Object[originalData.length
818 for (int i = 0; i < originalData.length; i++)
820 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
824 originalData = newData;
830 * Remove from the groups panel any checkboxes for groups that are not in the
831 * foundGroups set. This enables removing a group from the display when the
832 * last feature in that group is deleted.
836 protected void pruneGroups(Set<String> foundGroups)
838 for (int g = 0; g < groupPanel.getComponentCount(); g++)
840 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
841 if (!foundGroups.contains(checkbox.getText()))
843 groupPanel.remove(checkbox);
849 * reorder data based on the featureRenderers global priority list.
853 private void ensureOrder(Object[][] data)
855 boolean sort = false;
856 float[] order = new float[data.length];
857 for (int i = 0; i < order.length; i++)
859 order[i] = fr.getOrder(data[i][0].toString());
862 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
866 sort = sort || order[i - 1] > order[i];
871 jalview.util.QuickSort.sort(order, data);
876 * Offers a file chooser dialog, and then loads the feature colours and
877 * filters from file in XML format and unmarshals to Jalview feature settings
881 JalviewFileChooser chooser = new JalviewFileChooser("fc",
882 SEQUENCE_FEATURE_COLOURS);
883 chooser.setFileView(new JalviewFileView());
884 chooser.setDialogTitle(
885 MessageManager.getString("label.load_feature_colours"));
886 chooser.setToolTipText(MessageManager.getString("action.load"));
887 chooser.setResponseHandler(0, new Runnable()
892 File file = chooser.getSelectedFile();
896 chooser.showOpenDialog(this);
900 * Loads feature colours and filters from XML stored in the given file
908 InputStreamReader in = new InputStreamReader(
909 new FileInputStream(file), "UTF-8");
911 JAXBContext jc = JAXBContext
912 .newInstance("jalview.xml.binding.jalview");
913 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
914 XMLStreamReader streamReader = XMLInputFactory.newInstance()
915 .createXMLStreamReader(in);
916 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
917 JalviewUserColours.class);
918 JalviewUserColours jucs = jbe.getValue();
920 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
923 * load feature colours
925 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
927 Colour newcol = jucs.getColour().get(i);
928 FeatureColourI colour = jalview.project.Jalview2XML
929 .parseColour(newcol);
930 fr.setColour(newcol.getName(), colour);
931 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
935 * load feature filters; loaded filters will replace any that are
936 * currently defined, other defined filters are left unchanged
938 for (int i = 0; i < jucs.getFilter().size(); i++)
940 Filter filterModel = jucs.getFilter().get(i);
941 String featureType = filterModel.getFeatureType();
942 FeatureMatcherSetI filter = jalview.project.Jalview2XML
943 .parseFilter(featureType, filterModel.getMatcherSet());
944 if (!filter.isEmpty())
946 fr.setFeatureFilter(featureType, filter);
951 * update feature settings table
956 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
958 updateFeatureRenderer(data, false);
961 } catch (Exception ex)
963 System.out.println("Error loading User Colour File\n" + ex);
968 * Offers a file chooser dialog, and then saves the current feature colours
969 * and any filters to the selected file in XML format
973 JalviewFileChooser chooser = new JalviewFileChooser("fc",
974 SEQUENCE_FEATURE_COLOURS);
975 chooser.setFileView(new JalviewFileView());
976 chooser.setDialogTitle(
977 MessageManager.getString("label.save_feature_colours"));
978 chooser.setToolTipText(MessageManager.getString("action.save"));
979 int option = chooser.showSaveDialog(this);
980 if (option == JalviewFileChooser.APPROVE_OPTION)
982 File file = chooser.getSelectedFile();
988 * Saves feature colours and filters to the given file
994 JalviewUserColours ucs = new JalviewUserColours();
995 ucs.setSchemeName("Sequence Features");
998 PrintWriter out = new PrintWriter(
999 new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
1002 * sort feature types by colour order, from 0 (highest)
1005 Set<String> fr_colours = fr.getAllFeatureColours();
1006 String[] sortedTypes = fr_colours
1007 .toArray(new String[fr_colours.size()]);
1008 Arrays.sort(sortedTypes, new Comparator<String>()
1011 public int compare(String type1, String type2)
1013 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
1018 * save feature colours
1020 for (String featureType : sortedTypes)
1022 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1023 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
1025 ucs.getColour().add(col);
1029 * save any feature filters
1031 for (String featureType : sortedTypes)
1033 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1034 if (filter != null && !filter.isEmpty())
1036 Iterator<FeatureMatcherI> iterator = filter.getMatchers()
1038 FeatureMatcherI firstMatcher = iterator.next();
1039 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
1040 .marshalFilter(firstMatcher, iterator, filter.isAnded());
1041 Filter filterModel = new Filter();
1042 filterModel.setFeatureType(featureType);
1043 filterModel.setMatcherSet(ms);
1044 ucs.getFilter().add(filterModel);
1047 JAXBContext jaxbContext = JAXBContext
1048 .newInstance(JalviewUserColours.class);
1049 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1050 jaxbMarshaller.marshal(
1051 new ObjectFactory().createJalviewUserColours(ucs), out);
1053 // jaxbMarshaller.marshal(object, pout);
1054 // marshaller.marshal(object);
1057 // ucs.marshal(out);
1059 } catch (Exception ex)
1061 ex.printStackTrace();
1065 public void invertSelection()
1067 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1068 for (int i = 0; i < data.length; i++)
1070 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1072 updateFeatureRenderer(data, true);
1076 public void orderByAvWidth()
1078 if (table == null || table.getModel() == null)
1082 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1083 float[] width = new float[data.length];
1087 for (int i = 0; i < data.length; i++)
1089 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1092 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1093 // weight - but have to make per
1094 // sequence, too (awidth[2])
1095 // if (width[i]==1) // hack to distinguish single width sequences.
1106 boolean sort = false;
1107 for (int i = 0; i < width.length; i++)
1109 // awidth = (float[]) typeWidth.get(data[i][0]);
1112 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1115 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1121 width[i] /= max; // normalize
1122 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for
1127 sort = sort || width[i - 1] > width[i];
1132 jalview.util.QuickSort.sort(width, data);
1133 // update global priority order
1136 updateFeatureRenderer(data, false);
1144 frame.setClosed(true);
1145 } catch (Exception exe)
1152 * Update the priority order of features; only repaint if this changed the
1153 * order of visible features. Any newly discovered feature types are set to
1154 * visible. Returns true if repaint was requested, false if not.
1159 public boolean updateFeatureRenderer(Object[][] data)
1161 return updateFeatureRenderer(data, true);
1165 * Update the priority order of features; only repaint if this changed the
1166 * order of visible features. Returns true if repaint was requested, false if
1173 boolean updateFeatureRenderer(Object[][] data, boolean visibleNew)
1176 .println("FeatureSettings.updateFeatureRenderer " + visibleNew);
1177 new NullPointerException("testing").printStackTrace();
1178 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1180 if (fr.setFeaturePriority(rowData, visibleNew))
1183 "FeatureSettings.updateFeatureRenderer paintingAlignment");
1184 af.alignPanel.paintAlignment(true, true);
1191 * Converts table data into an array of data beans
1193 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1195 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1196 for (int i = 0; i < data.length; i++)
1198 String type = (String) data[i][TYPE_COLUMN];
1199 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1200 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1201 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1202 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1208 private void jbInit() throws Exception
1210 this.setLayout(new BorderLayout());
1212 JPanel settingsPane = new JPanel();
1213 settingsPane.setLayout(new BorderLayout());
1215 JPanel bigPanel = new JPanel();
1216 bigPanel.setLayout(new BorderLayout());
1218 groupPanel = new JPanel();
1219 bigPanel.add(groupPanel, BorderLayout.NORTH);
1221 JButton invert = new JButton(
1222 MessageManager.getString("label.invert_selection"));
1223 invert.setFont(JvSwingUtils.getLabelFont());
1224 invert.addActionListener(new ActionListener()
1227 public void actionPerformed(ActionEvent e)
1233 JButton optimizeOrder = new JButton(
1234 MessageManager.getString("label.optimise_order"));
1235 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1236 optimizeOrder.addActionListener(new ActionListener()
1239 public void actionPerformed(ActionEvent e)
1245 JButton sortByScore = new JButton(
1246 MessageManager.getString("label.seq_sort_by_score"));
1247 sortByScore.setFont(JvSwingUtils.getLabelFont());
1248 sortByScore.addActionListener(new ActionListener()
1251 public void actionPerformed(ActionEvent e)
1253 af.avc.sortAlignmentByFeatureScore(null);
1256 JButton sortByDens = new JButton(
1257 MessageManager.getString("label.sequence_sort_by_density"));
1258 sortByDens.setFont(JvSwingUtils.getLabelFont());
1259 sortByDens.addActionListener(new ActionListener()
1262 public void actionPerformed(ActionEvent e)
1264 af.avc.sortAlignmentByFeatureDensity(null);
1268 JButton help = new JButton(MessageManager.getString("action.help"));
1269 help.setFont(JvSwingUtils.getLabelFont());
1270 help.addActionListener(new ActionListener()
1273 public void actionPerformed(ActionEvent e)
1277 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1278 } catch (HelpSetException e1)
1280 e1.printStackTrace();
1285 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1286 cancel.setFont(JvSwingUtils.getLabelFont());
1287 cancel.addActionListener(new ActionListener()
1290 public void actionPerformed(ActionEvent e)
1296 JButton ok = new JButton(MessageManager.getString("action.ok"));
1297 ok.setFont(JvSwingUtils.getLabelFont());
1298 ok.addActionListener(new ActionListener()
1301 public void actionPerformed(ActionEvent e)
1307 JButton loadColours = new JButton(
1308 MessageManager.getString("label.load_colours"));
1309 loadColours.setFont(JvSwingUtils.getLabelFont());
1310 loadColours.setToolTipText(
1311 MessageManager.getString("label.load_colours_tooltip"));
1312 loadColours.addActionListener(new ActionListener()
1315 public void actionPerformed(ActionEvent e)
1321 JButton saveColours = new JButton(
1322 MessageManager.getString("label.save_colours"));
1323 saveColours.setFont(JvSwingUtils.getLabelFont());
1324 saveColours.setToolTipText(
1325 MessageManager.getString("label.save_colours_tooltip"));
1326 saveColours.addActionListener(new ActionListener()
1329 public void actionPerformed(ActionEvent e)
1334 transparency.addChangeListener(new ChangeListener()
1337 public void stateChanged(ChangeEvent evt)
1339 if (!inConstruction)
1341 fr.setTransparency((100 - transparency.getValue()) / 100f);
1342 af.alignPanel.paintAlignment(true, true);
1347 transparency.setMaximum(70);
1348 transparency.setToolTipText(
1349 MessageManager.getString("label.transparency_tip"));
1351 JPanel transPanel = new JPanel(new GridLayout(1, 2));
1352 bigPanel.add(transPanel, BorderLayout.SOUTH);
1354 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1355 transbuttons.add(optimizeOrder);
1356 transbuttons.add(invert);
1357 transbuttons.add(sortByScore);
1358 transbuttons.add(sortByDens);
1359 transbuttons.add(help);
1360 transPanel.add(transparency);
1361 transPanel.add(transbuttons);
1363 JPanel buttonPanel = new JPanel();
1364 buttonPanel.add(ok);
1365 buttonPanel.add(cancel);
1366 buttonPanel.add(loadColours);
1367 buttonPanel.add(saveColours);
1368 bigPanel.add(scrollPane, BorderLayout.CENTER);
1369 settingsPane.add(bigPanel, BorderLayout.CENTER);
1370 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1371 this.add(settingsPane);
1375 * On Cancel, restore settings as they were when the dialog was opened (or
1376 * possibly with any new features added while the dialog was open)
1380 fr.setTransparency(originalTransparency);
1381 fr.setFeatureFilters(originalFilters);
1382 boolean repainted = updateFeatureRenderer(originalData);
1385 * ensure alignment (and Overview if visible) are redrawn
1389 af.alignPanel.paintAlignment(true, true);
1396 * Answers a suitable tooltip to show on the colour cell of the table
1400 * if true include 'click to edit' and similar text
1403 public static String getColorTooltip(FeatureColourI fcol,
1410 if (fcol.isSimpleColour())
1412 return withHint ? BASE_TOOLTIP : null;
1414 String description = fcol.getDescription();
1415 description = description.replaceAll("<", "<");
1416 description = description.replaceAll(">", ">");
1417 StringBuilder tt = new StringBuilder(description);
1420 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1422 return JvSwingUtils.wrapTooltip(true, tt.toString());
1425 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1428 boolean thr = false;
1429 StringBuilder tx = new StringBuilder();
1431 if (gcol.isColourByAttribute())
1433 tx.append(FeatureMatcher
1434 .toAttributeDisplayName(gcol.getAttributeName()));
1436 else if (!gcol.isColourByLabel())
1438 tx.append(MessageManager.getString("label.score"));
1441 if (gcol.isAboveThreshold())
1446 if (gcol.isBelowThreshold())
1451 if (gcol.isColourByLabel())
1457 if (!gcol.isColourByAttribute())
1465 Color newColor = gcol.getMaxColour();
1466 comp.setBackground(newColor);
1467 // System.err.println("Width is " + w / 2);
1468 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1469 comp.setIcon(ficon);
1470 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1471 // + newColor.getGreen() + ", " + newColor.getBlue()
1472 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1473 // + ", " + minCol.getBlue() + ")");
1475 comp.setHorizontalAlignment(SwingConstants.CENTER);
1476 comp.setText(tx.toString());
1479 // ///////////////////////////////////////////////////////////////////////
1480 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1481 // ///////////////////////////////////////////////////////////////////////
1482 class FeatureTableModel extends AbstractTableModel
1484 private String[] columnNames = {
1485 MessageManager.getString("label.feature_type"),
1486 MessageManager.getString("action.colour"),
1487 MessageManager.getString("label.configuration"),
1488 MessageManager.getString("label.show") };
1490 private Object[][] data;
1492 FeatureTableModel(Object[][] data)
1497 public Object[][] getData()
1502 public void setData(Object[][] data)
1508 public int getColumnCount()
1510 return columnNames.length;
1513 public Object[] getRow(int row)
1519 public int getRowCount()
1525 public String getColumnName(int col)
1527 return columnNames[col];
1531 public Object getValueAt(int row, int col)
1533 return data[row][col];
1537 * Answers the class of the object in column c of the first row of the table
1540 public Class<?> getColumnClass(int c)
1542 Object v = getValueAt(0, c);
1543 return v == null ? null : v.getClass();
1547 public boolean isCellEditable(int row, int col)
1549 return col == 0 ? false : true;
1553 public void setValueAt(Object value, int row, int col)
1555 data[row][col] = value;
1556 fireTableCellUpdated(row, col);
1557 updateFeatureRenderer(data);
1562 class ColorRenderer extends JLabel implements TableCellRenderer
1564 Border unselectedBorder = null;
1566 Border selectedBorder = null;
1568 public ColorRenderer()
1570 setOpaque(true); // MUST do this for background to show up.
1571 setHorizontalTextPosition(SwingConstants.CENTER);
1572 setVerticalTextPosition(SwingConstants.CENTER);
1576 public Component getTableCellRendererComponent(JTable tbl, Object color,
1577 boolean isSelected, boolean hasFocus, int row, int column)
1579 FeatureColourI cellColour = (FeatureColourI) color;
1581 setBackground(tbl.getBackground());
1582 if (!cellColour.isSimpleColour())
1584 Rectangle cr = tbl.getCellRect(row, column, false);
1585 FeatureSettings.renderGraduatedColor(this, cellColour,
1586 (int) cr.getWidth(), (int) cr.getHeight());
1592 setBackground(cellColour.getColour());
1596 if (selectedBorder == null)
1598 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1599 tbl.getSelectionBackground());
1601 setBorder(selectedBorder);
1605 if (unselectedBorder == null)
1607 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1608 tbl.getBackground());
1610 setBorder(unselectedBorder);
1617 class FilterRenderer extends JLabel implements TableCellRenderer
1619 javax.swing.border.Border unselectedBorder = null;
1621 javax.swing.border.Border selectedBorder = null;
1623 public FilterRenderer()
1625 setOpaque(true); // MUST do this for background to show up.
1626 setHorizontalTextPosition(SwingConstants.CENTER);
1627 setVerticalTextPosition(SwingConstants.CENTER);
1631 public Component getTableCellRendererComponent(JTable tbl,
1632 Object filter, boolean isSelected, boolean hasFocus, int row,
1635 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1637 String asText = theFilter.toString();
1638 setBackground(tbl.getBackground());
1639 this.setText(asText);
1644 if (selectedBorder == null)
1646 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1647 tbl.getSelectionBackground());
1649 setBorder(selectedBorder);
1653 if (unselectedBorder == null)
1655 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1656 tbl.getBackground());
1658 setBorder(unselectedBorder);
1666 * update comp using rendering settings from gcol
1671 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1673 int w = comp.getWidth(), h = comp.getHeight();
1676 w = (int) comp.getPreferredSize().getWidth();
1677 h = (int) comp.getPreferredSize().getHeight();
1684 renderGraduatedColor(comp, gcol, w, h);
1687 @SuppressWarnings("serial")
1688 class ColorEditor extends AbstractCellEditor
1689 implements TableCellEditor, ActionListener
1691 FeatureColourI currentColor;
1693 FeatureTypeSettings chooser;
1699 protected static final String EDIT = "edit";
1701 int rowSelected = 0;
1703 public ColorEditor()
1705 // Set up the editor (from the table's point of view),
1706 // which is a button.
1707 // This button brings up the color chooser dialog,
1708 // which is the editor from the user's point of view.
1709 button = new JButton();
1710 button.setActionCommand(EDIT);
1711 button.addActionListener(this);
1712 button.setBorderPainted(false);
1716 * Handles events from the editor button, and from the colour/filters
1717 * dialog's OK button
1720 public void actionPerformed(ActionEvent e)
1722 if (button == e.getSource())
1724 if (currentColor.isSimpleColour())
1727 * simple colour chooser
1729 String ttl = MessageManager
1730 .formatMessage("label.select_colour_for", type);
1731 ColourChooserListener listener = new ColourChooserListener()
1734 public void colourSelected(Color c)
1736 currentColor = new FeatureColour(c);
1737 table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1738 fireEditingStopped();
1742 public void cancel()
1744 fireEditingStopped();
1747 JalviewColourChooser.showColourChooser(button, ttl,
1748 currentColor.getColour(), listener);
1753 * variable colour and filters dialog
1755 chooser = new FeatureTypeSettings(fr, type);
1756 if (!Platform.isJS())
1763 chooser.setRequestFocusEnabled(true);
1764 chooser.requestFocus();
1766 chooser.addActionListener(this);
1767 fireEditingStopped();
1773 * after OK in variable colour dialog, any changes to colour
1774 * (or filters!) are already set in FeatureRenderer, so just
1775 * update table data without triggering updateFeatureRenderer
1777 currentColor = fr.getFeatureColours().get(type);
1778 FeatureMatcherSetI currentFilter = fr.getFeatureFilter(type);
1779 if (currentFilter == null)
1781 currentFilter = new FeatureMatcherSet();
1783 Object[] data = ((FeatureTableModel) table.getModel())
1784 .getData()[rowSelected];
1785 data[COLOUR_COLUMN] = currentColor;
1786 data[FILTER_COLUMN] = currentFilter;
1787 fireEditingStopped();
1788 // SwingJS needs an explicit repaint() here,
1789 // rather than relying upon no validation having
1790 // occurred since the stopEditing call was made.
1791 // Its laying out has not been stopped by the modal frame
1798 * Override allows access to this method from anonymous inner classes
1801 protected void fireEditingStopped()
1803 super.fireEditingStopped();
1806 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1808 public Object getCellEditorValue()
1810 return currentColor;
1813 // Implement the one method defined by TableCellEditor.
1815 public Component getTableCellEditorComponent(JTable theTable,
1816 Object value, boolean isSelected, int row, int column)
1818 currentColor = (FeatureColourI) value;
1819 this.rowSelected = row;
1820 type = table.getValueAt(row, TYPE_COLUMN).toString();
1821 button.setOpaque(true);
1822 button.setBackground(FeatureSettings.this.getBackground());
1823 if (!currentColor.isSimpleColour())
1825 JLabel btn = new JLabel();
1826 btn.setSize(button.getSize());
1827 FeatureSettings.renderGraduatedColor(btn, currentColor);
1828 button.setBackground(btn.getBackground());
1829 button.setIcon(btn.getIcon());
1830 button.setText(btn.getText());
1835 button.setIcon(null);
1836 button.setBackground(currentColor.getColour());
1843 * The cell editor for the Filter column. It displays the text of any filters
1844 * for the feature type in that row (in full as a tooltip, possible
1845 * abbreviated as display text). On click in the cell, opens the Feature
1846 * Display Settings dialog at the Filters tab.
1848 @SuppressWarnings("serial")
1849 class FilterEditor extends AbstractCellEditor
1850 implements TableCellEditor, ActionListener
1853 FeatureMatcherSetI currentFilter;
1861 protected static final String EDIT = "edit";
1863 int rowSelected = 0;
1865 public FilterEditor()
1867 button = new JButton();
1868 button.setActionCommand(EDIT);
1869 button.addActionListener(this);
1870 button.setBorderPainted(false);
1874 * Handles events from the editor button
1877 public void actionPerformed(ActionEvent e)
1879 if (button == e.getSource())
1881 FeatureTypeSettings chooser = new FeatureTypeSettings(fr, type);
1882 chooser.addActionListener(this);
1883 chooser.setRequestFocusEnabled(true);
1884 chooser.requestFocus();
1885 if (lastLocation != null)
1887 // todo open at its last position on screen
1888 chooser.setBounds(lastLocation.x, lastLocation.y,
1889 chooser.getWidth(), chooser.getHeight());
1892 fireEditingStopped();
1894 else if (e.getSource() instanceof Component)
1898 * after OK in variable colour dialog, any changes to filter
1899 * (or colours!) are already set in FeatureRenderer, so just
1900 * update table data without triggering updateFeatureRenderer
1902 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1903 currentFilter = fr.getFeatureFilter(type);
1904 if (currentFilter == null)
1906 currentFilter = new FeatureMatcherSet();
1909 Object[] data = ((FeatureTableModel) table.getModel())
1910 .getData()[rowSelected];
1911 data[COLOUR_COLUMN] = currentColor;
1912 data[FILTER_COLUMN] = currentFilter;
1913 fireEditingStopped();
1914 // SwingJS needs an explicit repaint() here,
1915 // rather than relying upon no validation having
1916 // occurred since the stopEditing call was made.
1917 // Its laying out has not been stopped by the modal frame
1924 public Object getCellEditorValue()
1926 return currentFilter;
1930 public Component getTableCellEditorComponent(JTable theTable,
1931 Object value, boolean isSelected, int row, int column)
1933 currentFilter = (FeatureMatcherSetI) value;
1934 this.rowSelected = row;
1935 type = table.getValueAt(row, TYPE_COLUMN).toString();
1936 button.setOpaque(true);
1937 button.setBackground(FeatureSettings.this.getBackground());
1938 button.setText(currentFilter.toString());
1939 button.setIcon(null);
1945 class FeatureIcon implements Icon
1947 FeatureColourI gcol;
1951 boolean midspace = false;
1953 int width = 50, height = 20;
1955 int s1, e1; // start and end of midpoint band for thresholded symbol
1957 Color mpcolour = Color.white;
1959 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1979 public int getIconWidth()
1985 public int getIconHeight()
1991 public void paintIcon(Component c, Graphics g, int x, int y)
1994 if (gcol.isColourByLabel())
1997 g.fillRect(0, 0, width, height);
1998 // need an icon here.
1999 g.setColor(gcol.getMaxColour());
2001 g.setFont(new Font("Verdana", Font.PLAIN, 9));
2003 // g.setFont(g.getFont().deriveFont(
2004 // AffineTransform.getScaleInstance(
2005 // width/g.getFontMetrics().stringWidth("Label"),
2006 // height/g.getFontMetrics().getHeight())));
2008 g.drawString(MessageManager.getString("label.label"), 0, 0);
2013 Color minCol = gcol.getMinColour();
2015 g.fillRect(0, 0, s1, height);
2018 g.setColor(Color.white);
2019 g.fillRect(s1, 0, e1 - s1, height);
2021 g.setColor(gcol.getMaxColour());
2022 // g.fillRect(0, e1, width - e1, height); // BH 2018
2023 g.fillRect(e1, 0, width - e1, height);