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.bin.Jalview;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.SequenceI;
28 import jalview.datamodel.features.FeatureMatcher;
29 import jalview.datamodel.features.FeatureMatcherI;
30 import jalview.datamodel.features.FeatureMatcherSet;
31 import jalview.datamodel.features.FeatureMatcherSetI;
32 import jalview.gui.Help.HelpId;
33 import jalview.gui.JalviewColourChooser.ColourChooserListener;
34 import jalview.io.JalviewFileChooser;
35 import jalview.io.JalviewFileView;
36 import jalview.schemes.FeatureColour;
37 import jalview.util.MessageManager;
38 import jalview.util.Platform;
39 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
40 import jalview.xml.binding.jalview.JalviewUserColours;
41 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
42 import jalview.xml.binding.jalview.JalviewUserColours.Filter;
43 import jalview.xml.binding.jalview.ObjectFactory;
45 import java.awt.BorderLayout;
46 import java.awt.Color;
47 import java.awt.Component;
48 import java.awt.Dimension;
50 import java.awt.Graphics;
51 import java.awt.GridLayout;
52 import java.awt.Point;
53 import java.awt.Rectangle;
54 import java.awt.event.ActionEvent;
55 import java.awt.event.ActionListener;
56 import java.awt.event.ItemEvent;
57 import java.awt.event.ItemListener;
58 import java.awt.event.MouseAdapter;
59 import java.awt.event.MouseEvent;
60 import java.awt.event.MouseMotionAdapter;
61 import java.beans.PropertyChangeEvent;
62 import java.beans.PropertyChangeListener;
64 import java.io.FileInputStream;
65 import java.io.FileOutputStream;
66 import java.io.InputStreamReader;
67 import java.io.OutputStreamWriter;
68 import java.io.PrintWriter;
69 import java.util.Arrays;
70 import java.util.Comparator;
71 import java.util.HashMap;
72 import java.util.HashSet;
73 import java.util.Hashtable;
74 import java.util.Iterator;
75 import java.util.List;
79 import javax.help.HelpSetException;
80 import javax.swing.AbstractCellEditor;
81 import javax.swing.BorderFactory;
82 import javax.swing.Icon;
83 import javax.swing.JButton;
84 import javax.swing.JCheckBox;
85 import javax.swing.JCheckBoxMenuItem;
86 import javax.swing.JInternalFrame;
87 import javax.swing.JLabel;
88 import javax.swing.JLayeredPane;
89 import javax.swing.JMenuItem;
90 import javax.swing.JPanel;
91 import javax.swing.JPopupMenu;
92 import javax.swing.JScrollPane;
93 import javax.swing.JSlider;
94 import javax.swing.JTable;
95 import javax.swing.ListSelectionModel;
96 import javax.swing.SwingConstants;
97 import javax.swing.ToolTipManager;
98 import javax.swing.border.Border;
99 import javax.swing.event.ChangeEvent;
100 import javax.swing.event.ChangeListener;
101 import javax.swing.plaf.TableUI;
102 import javax.swing.table.AbstractTableModel;
103 import javax.swing.table.TableCellEditor;
104 import javax.swing.table.TableCellRenderer;
105 import javax.swing.table.TableColumn;
106 import javax.xml.bind.JAXBContext;
107 import javax.xml.bind.JAXBElement;
108 import javax.xml.bind.Marshaller;
109 import javax.xml.stream.XMLInputFactory;
110 import javax.xml.stream.XMLStreamReader;
112 public class FeatureSettings extends JPanel
113 implements FeatureSettingsControllerI
115 private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
116 .getString("label.sequence_feature_colours");
119 * column indices of fields in Feature Settings table
121 static final int TYPE_COLUMN = 0;
123 static final int COLOUR_COLUMN = 1;
125 static final int FILTER_COLUMN = 2;
127 static final int SHOW_COLUMN = 3;
129 private static final int COLUMN_COUNT = 4;
131 private static final int MIN_WIDTH = 400;
133 private static final int MIN_HEIGHT = 400;
135 private final static String BASE_TOOLTIP = MessageManager.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 JButton fetchDAS = new JButton();
169 JButton saveDAS = new JButton();
171 JButton cancelDAS = new JButton();
173 boolean resettingTable = false;
176 * true when Feature Settings are updating from feature renderer
178 boolean handlingUpdate = false;
181 * holds {featureCount, totalExtent} for each feature type
183 Map<String, float[]> typeWidth = null;
190 public FeatureSettings(AlignFrame alignFrame)
192 this.af = alignFrame;
193 fr = af.getFeatureRenderer();
195 // save transparency for restore on Cancel
196 originalTransparency = fr.getTransparency();
197 int originalTransparencyAsPercent = (int) (originalTransparency * 100);
198 transparency.setMaximum(100 - originalTransparencyAsPercent);
200 originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
205 } catch (Exception ex)
207 ex.printStackTrace();
213 public String getToolTipText(MouseEvent e)
216 int column = table.columnAtPoint(e.getPoint());
217 int row = table.rowAtPoint(e.getPoint());
222 tip = JvSwingUtils.wrapTooltip(true, MessageManager
223 .getString("label.feature_settings_click_drag"));
226 FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
228 tip = getColorTooltip(colour, true);
231 FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
234 ? MessageManager.getString("label.filters_tooltip")
246 * Position the tooltip near the bottom edge of, and half way across, the
250 public Point getToolTipLocation(MouseEvent e)
252 Point point = e.getPoint();
253 int column = table.columnAtPoint(point);
254 int row = table.rowAtPoint(point);
255 Rectangle r = getCellRect(row, column, false);
256 Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3);
261 // next line is needed to avoid (quiet) exceptions thrown
262 // when column ordering changes so that the above constants
264 table.getTableHeader().setReorderingAllowed(false); // BH 2018
266 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
267 ToolTipManager.sharedInstance().registerComponent(table);
269 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
270 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
272 table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor(this));
273 table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
275 TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
276 new ColorRenderer(), new ColorEditor(this));
277 table.addColumn(colourColumn);
279 TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
280 new FilterRenderer(), new FilterEditor(this));
281 table.addColumn(filterColumn);
283 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
285 table.addMouseListener(new MouseAdapter()
288 public void mousePressed(MouseEvent evt)
290 selectedRow = table.rowAtPoint(evt.getPoint());
291 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
292 if (evt.isPopupTrigger())
294 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
295 showPopupMenu(selectedRow, type, colour, evt.getPoint());
297 else if (evt.getClickCount() == 2)
299 boolean invertSelection = evt.isAltDown();
300 boolean toggleSelection = Platform.isControlDown(evt);
301 boolean extendSelection = evt.isShiftDown();
302 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
303 invertSelection, extendSelection, toggleSelection, type);
307 // isPopupTrigger fires on mouseReleased on Windows
309 public void mouseReleased(MouseEvent evt)
311 selectedRow = table.rowAtPoint(evt.getPoint());
312 if (evt.isPopupTrigger())
314 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
315 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
316 showPopupMenu(selectedRow, type, colour, evt.getPoint());
321 table.addMouseMotionListener(new MouseMotionAdapter()
324 public void mouseDragged(MouseEvent evt)
326 int newRow = table.rowAtPoint(evt.getPoint());
327 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
330 * reposition 'selectedRow' to 'newRow' (the dragged to location)
331 * this could be more than one row away for a very fast drag action
332 * so just swap it with adjacent rows until we get it there
334 Object[][] data = ((FeatureTableModel) table.getModel())
336 int direction = newRow < selectedRow ? -1 : 1;
337 for (int i = selectedRow; i != newRow; i += direction)
339 Object[] temp = data[i];
340 data[i] = data[i + direction];
341 data[i + direction] = temp;
343 updateFeatureRenderer(data);
345 selectedRow = newRow;
349 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
350 // MessageManager.getString("label.feature_settings_click_drag")));
351 scrollPane.setViewportView(table);
353 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
355 fr.findAllFeatures(true); // display everything!
358 discoverAllFeatureData();
359 final PropertyChangeListener change;
360 final FeatureSettings fs = this;
361 fr.addPropertyChangeListener(change = new PropertyChangeListener()
364 public void propertyChange(PropertyChangeEvent evt)
366 if (!fs.resettingTable && !fs.handlingUpdate)
368 fs.handlingUpdate = true;
370 // new groups may be added with new sequence feature types only
371 fs.handlingUpdate = false;
377 frame = new JInternalFrame();
378 frame.setContentPane(this);
379 if (Platform.isAMac())
381 Desktop.addInternalFrame(frame,
382 MessageManager.getString("label.sequence_feature_settings"),
387 Desktop.addInternalFrame(frame,
388 MessageManager.getString("label.sequence_feature_settings"),
391 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
393 frame.addInternalFrameListener(
394 new javax.swing.event.InternalFrameAdapter()
397 public void internalFrameClosed(
398 javax.swing.event.InternalFrameEvent evt)
400 fr.removePropertyChangeListener(change);
403 frame.setLayer(JLayeredPane.PALETTE_LAYER);
404 inConstruction = false;
408 * Constructs and shows a popup menu of possible actions on the selected row and
416 protected void showPopupMenu(final int rowSelected, final String type,
417 final Object typeCol, final Point pt)
419 final FeatureColourI featureColour = (FeatureColourI) typeCol;
421 JPopupMenu men = new JPopupMenu(MessageManager
422 .formatMessage("label.settings_for_param", new String[]
424 JMenuItem scr = new JMenuItem(
425 MessageManager.getString("label.sort_by_score"));
427 final FeatureSettings me = this;
428 scr.addActionListener(new ActionListener()
432 public void actionPerformed(ActionEvent e)
435 .sortAlignmentByFeatureScore(Arrays.asList(new String[]
439 JMenuItem dens = new JMenuItem(
440 MessageManager.getString("label.sort_by_density"));
441 dens.addActionListener(new ActionListener()
445 public void actionPerformed(ActionEvent e)
448 .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
455 * variable colour options include colour by label, by score,
456 * by selected attribute text, or attribute value
458 final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
459 MessageManager.getString("label.variable_colour"));
460 variableColourCB.setSelected(!featureColour.isSimpleColour());
461 men.add(variableColourCB);
464 * checkbox action listener doubles up as listener to OK
465 * from the variable colour / filters dialog
467 variableColourCB.addActionListener(new ActionListener()
470 public void actionPerformed(ActionEvent e)
472 if (e.getSource() == variableColourCB)
474 men.setVisible(true); // BH 2018 for JavaScript because this is a checkbox
475 men.setVisible(false); // BH 2018 for JavaScript because this is a checkbox
476 if (featureColour.isSimpleColour())
479 * toggle simple colour to variable colour - show dialog
481 FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type);
482 fc.addActionListener(this);
487 * toggle variable to simple colour - show colour chooser
489 String title = MessageManager.formatMessage("label.select_colour_for", type);
490 ColourChooserListener listener = new ColourChooserListener()
493 public void colourSelected(Color c)
495 table.setValueAt(new FeatureColour(c), rowSelected,
498 me.updateFeatureRenderer(
499 ((FeatureTableModel) table.getModel()).getData(),
503 JalviewColourChooser.showColourChooser(me, title, featureColour.getMaxColour(), listener);
508 if (e.getSource() instanceof FeatureTypeSettings)
511 * update after OK in feature colour dialog; the updated
512 * colour will have already been set in the FeatureRenderer
514 FeatureColourI fci = fr.getFeatureColours().get(type);
515 table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
516 // BH 2018 setting a table value does not invalidate it.
517 System.out.println("FeatureSettings is valied" + table.isValid());
524 JMenuItem selCols = new JMenuItem(
525 MessageManager.getString("label.select_columns_containing"));
526 selCols.addActionListener(new ActionListener()
529 public void actionPerformed(ActionEvent arg0)
531 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
535 JMenuItem clearCols = new JMenuItem(MessageManager
536 .getString("label.select_columns_not_containing"));
537 clearCols.addActionListener(new ActionListener()
540 public void actionPerformed(ActionEvent arg0)
542 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
546 JMenuItem hideCols = new JMenuItem(
547 MessageManager.getString("label.hide_columns_containing"));
548 hideCols.addActionListener(new ActionListener()
551 public void actionPerformed(ActionEvent arg0)
553 fr.ap.alignFrame.hideFeatureColumns(type, true);
556 JMenuItem hideOtherCols = new JMenuItem(
557 MessageManager.getString("label.hide_columns_not_containing"));
558 hideOtherCols.addActionListener(new ActionListener()
561 public void actionPerformed(ActionEvent arg0)
563 fr.ap.alignFrame.hideFeatureColumns(type, false);
569 men.add(hideOtherCols);
570 men.show(table, pt.x, pt.y);
574 synchronized public void discoverAllFeatureData()
576 Set<String> allGroups = new HashSet<>();
577 AlignmentI alignment = af.getViewport().getAlignment();
579 for (int i = 0; i < alignment.getHeight(); i++)
581 SequenceI seq = alignment.getSequenceAt(i);
582 for (String group : seq.getFeatures().getFeatureGroups(true))
584 if (group != null && !allGroups.contains(group))
586 allGroups.add(group);
587 checkGroupState(group);
598 * Synchronise gui group list and check visibility of group
601 * @return true if group is visible
603 private boolean checkGroupState(String group)
605 boolean visible = fr.checkGroupVisibility(group, true);
607 for (int g = 0; g < groupPanel.getComponentCount(); g++)
609 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
611 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
616 final String grp = group;
617 final JCheckBox check = new JCheckBox(group, visible);
618 check.setFont(new Font("Serif", Font.BOLD, 12));
619 check.setToolTipText(group);
620 check.addItemListener(new ItemListener()
623 public void itemStateChanged(ItemEvent evt)
625 fr.setGroupVisibility(check.getText(), check.isSelected());
626 resetTable(new String[] { grp });
627 af.alignPanel.paintAlignment(true, true);
630 groupPanel.add(check);
634 synchronized void resetTable(String[] groupChanged)
640 resettingTable = true;
641 typeWidth = new Hashtable<>();
642 // TODO: change avWidth calculation to 'per-sequence' average and use long
645 Set<String> displayableTypes = new HashSet<>();
646 Set<String> foundGroups = new HashSet<>();
649 * determine which feature types may be visible depending on
650 * which groups are selected, and recompute average width data
652 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
655 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
658 * get the sequence's groups for positional features
659 * and keep track of which groups are visible
661 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
662 Set<String> visibleGroups = new HashSet<>();
663 for (String group : groups)
665 if (group == null || checkGroupState(group))
667 visibleGroups.add(group);
670 foundGroups.addAll(groups);
673 * get distinct feature types for visible groups
674 * record distinct visible types, and their count and total length
676 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
677 visibleGroups.toArray(new String[visibleGroups.size()]));
678 for (String type : types)
680 displayableTypes.add(type);
681 float[] avWidth = typeWidth.get(type);
684 avWidth = new float[2];
685 typeWidth.put(type, avWidth);
687 // todo this could include features with a non-visible group
688 // - do we greatly care?
689 // todo should we include non-displayable features here, and only
690 // update when features are added?
691 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
692 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
696 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
699 if (fr.hasRenderOrder())
703 fr.findAllFeatures(groupChanged != null); // prod to update
704 // colourschemes. but don't
706 // First add the checks in the previous render order,
707 // in case the window has been closed and reopened
709 List<String> frl = fr.getRenderOrder();
710 for (int ro = frl.size() - 1; ro > -1; ro--)
712 String type = frl.get(ro);
714 if (!displayableTypes.contains(type))
719 data[dataIndex][TYPE_COLUMN] = type;
720 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
721 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
722 data[dataIndex][FILTER_COLUMN] = featureFilter == null
723 ? new FeatureMatcherSet()
725 data[dataIndex][SHOW_COLUMN] = new Boolean(
726 af.getViewport().getFeaturesDisplayed().isVisible(type));
728 displayableTypes.remove(type);
733 * process any extra features belonging only to
734 * a group which was just selected
736 while (!displayableTypes.isEmpty())
738 String type = displayableTypes.iterator().next();
739 data[dataIndex][TYPE_COLUMN] = type;
741 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
742 if (data[dataIndex][COLOUR_COLUMN] == null)
744 // "Colour has been updated in another view!!"
745 fr.clearRenderOrder();
748 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
749 data[dataIndex][FILTER_COLUMN] = featureFilter == null
750 ? new FeatureMatcherSet()
752 data[dataIndex][SHOW_COLUMN] = new Boolean(true);
754 displayableTypes.remove(type);
757 if (originalData == null)
759 originalData = new Object[data.length][COLUMN_COUNT];
760 for (int i = 0; i < data.length; i++)
762 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
767 updateOriginalData(data);
770 table.setModel(new FeatureTableModel(data));
771 table.getColumnModel().getColumn(0).setPreferredWidth(200);
773 groupPanel.setLayout(
774 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
775 pruneGroups(foundGroups);
776 groupPanel.validate();
778 updateFeatureRenderer(data, groupChanged != null);
779 resettingTable = false;
783 * Updates 'originalData' (used for restore on Cancel) if we detect that changes
784 * have been made outwith this dialog
786 * <li>a new feature type added (and made visible)</li>
787 * <li>a feature colour changed (in the Amend Features dialog)</li>
792 protected void updateOriginalData(Object[][] foundData)
794 // todo LinkedHashMap instead of Object[][] would be nice
796 Object[][] currentData = ((FeatureTableModel) table.getModel())
798 for (Object[] row : foundData)
800 String type = (String) row[TYPE_COLUMN];
801 boolean found = false;
802 for (Object[] current : currentData)
804 if (type.equals(current[TYPE_COLUMN]))
808 * currently dependent on object equality here;
809 * really need an equals method on FeatureColour
811 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
814 * feature colour has changed externally - update originalData
816 for (Object[] original : originalData)
818 if (type.equals(original[TYPE_COLUMN]))
820 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
831 * new feature detected - add to original data (on top)
833 Object[][] newData = new Object[originalData.length
835 for (int i = 0; i < originalData.length; i++)
837 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
841 originalData = newData;
847 * Remove from the groups panel any checkboxes for groups that are not in the
848 * foundGroups set. This enables removing a group from the display when the last
849 * feature in that group is deleted.
853 protected void pruneGroups(Set<String> foundGroups)
855 for (int g = 0; g < groupPanel.getComponentCount(); g++)
857 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
858 if (!foundGroups.contains(checkbox.getText()))
860 groupPanel.remove(checkbox);
866 * reorder data based on the featureRenderers global priority list.
870 private void ensureOrder(Object[][] data)
872 boolean sort = false;
873 float[] order = new float[data.length];
874 for (int i = 0; i < order.length; i++)
876 order[i] = fr.getOrder(data[i][0].toString());
879 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
883 sort = sort || order[i - 1] > order[i];
888 jalview.util.QuickSort.sort(order, data);
893 * Offers a file chooser dialog, and then loads the feature colours and
894 * filters from file in XML format and unmarshals to Jalview feature settings
898 JalviewFileChooser chooser = new JalviewFileChooser("fc",
899 SEQUENCE_FEATURE_COLOURS);
900 chooser.setFileView(new JalviewFileView());
901 chooser.setDialogTitle(
902 MessageManager.getString("label.load_feature_colours"));
903 chooser.setToolTipText(MessageManager.getString("action.load"));
904 chooser.setResponseHandler(0, new Runnable()
909 File file = chooser.getSelectedFile();
913 chooser.showOpenDialog(this);
917 * Loads feature colours and filters from XML stored in the given file
925 InputStreamReader in = new InputStreamReader(
926 new FileInputStream(file), "UTF-8");
928 JAXBContext jc = JAXBContext
929 .newInstance("jalview.xml.binding.jalview");
930 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
931 XMLStreamReader streamReader = XMLInputFactory.newInstance()
932 .createXMLStreamReader(in);
933 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
934 JalviewUserColours.class);
935 JalviewUserColours jucs = jbe.getValue();
937 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
940 * load feature colours
942 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
944 Colour newcol = jucs.getColour().get(i);
945 FeatureColourI colour = jalview.project.Jalview2XML
946 .parseColour(newcol);
947 fr.setColour(newcol.getName(), colour);
948 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
952 * load feature filters; loaded filters will replace any that are
953 * currently defined, other defined filters are left unchanged
955 for (int i = 0; i < jucs.getFilter().size(); i++)
957 Filter filterModel = jucs.getFilter().get(i);
958 String featureType = filterModel.getFeatureType();
959 FeatureMatcherSetI filter = jalview.project.Jalview2XML
960 .parseFilter(featureType, filterModel.getMatcherSet());
961 if (!filter.isEmpty())
963 fr.setFeatureFilter(featureType, filter);
968 * update feature settings table
973 Object[][] data = ((FeatureTableModel) table.getModel())
976 updateFeatureRenderer(data, false);
979 } catch (Exception ex)
981 System.out.println("Error loading User Colour File\n" + ex);
986 * Offers a file chooser dialog, and then saves the current feature colours
987 * and any filters to the selected file in XML format
991 JalviewFileChooser chooser = new JalviewFileChooser("fc",
992 SEQUENCE_FEATURE_COLOURS);
993 chooser.setFileView(new JalviewFileView());
994 chooser.setDialogTitle(
995 MessageManager.getString("label.save_feature_colours"));
996 chooser.setToolTipText(MessageManager.getString("action.save"));
997 int option = chooser.showSaveDialog(this);
998 if (option == JalviewFileChooser.APPROVE_OPTION)
1000 File file = chooser.getSelectedFile();
1006 * Saves feature colours and filters to the given file
1010 void save(File file)
1012 JalviewUserColours ucs = new JalviewUserColours();
1013 ucs.setSchemeName("Sequence Features");
1016 PrintWriter out = new PrintWriter(new OutputStreamWriter(
1017 new FileOutputStream(file), "UTF-8"));
1020 * sort feature types by colour order, from 0 (highest)
1023 Set<String> fr_colours = fr.getAllFeatureColours();
1024 String[] sortedTypes = fr_colours
1025 .toArray(new String[fr_colours.size()]);
1026 Arrays.sort(sortedTypes, new Comparator<String>()
1029 public int compare(String type1, String type2)
1031 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
1036 * save feature colours
1038 for (String featureType : sortedTypes)
1040 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1041 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
1043 ucs.getColour().add(col);
1047 * save any feature filters
1049 for (String featureType : sortedTypes)
1051 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1052 if (filter != null && !filter.isEmpty())
1054 Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
1055 FeatureMatcherI firstMatcher = iterator.next();
1056 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
1057 .marshalFilter(firstMatcher, iterator,
1059 Filter filterModel = new Filter();
1060 filterModel.setFeatureType(featureType);
1061 filterModel.setMatcherSet(ms);
1062 ucs.getFilter().add(filterModel);
1065 JAXBContext jaxbContext = JAXBContext
1066 .newInstance(JalviewUserColours.class);
1067 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1068 jaxbMarshaller.marshal(
1069 new ObjectFactory().createJalviewUserColours(ucs), out);
1071 // jaxbMarshaller.marshal(object, pout);
1072 // marshaller.marshal(object);
1075 // ucs.marshal(out);
1077 } catch (Exception ex)
1079 ex.printStackTrace();
1083 public void invertSelection()
1085 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1086 for (int i = 0; i < data.length; i++)
1088 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1090 updateFeatureRenderer(data, true);
1094 public void orderByAvWidth()
1096 if (table == null || table.getModel() == null)
1100 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1101 float[] width = new float[data.length];
1105 for (int i = 0; i < data.length; i++)
1107 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1110 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1111 // weight - but have to make per
1112 // sequence, too (awidth[2])
1113 // if (width[i]==1) // hack to distinguish single width sequences.
1124 boolean sort = false;
1125 for (int i = 0; i < width.length; i++)
1127 // awidth = (float[]) typeWidth.get(data[i][0]);
1130 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1133 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1139 width[i] /= max; // normalize
1140 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
1144 sort = sort || width[i - 1] > width[i];
1149 jalview.util.QuickSort.sort(width, data);
1150 // update global priority order
1153 updateFeatureRenderer(data, false);
1158 * Repaints the table using alternative code for Java and J2S
1160 private void repaintTable()
1165 // Here is a needed intervention
1166 // because generally we don't "repaint"
1167 // the table. We re-create the HTML divs
1168 // that is associated with it. A better
1169 // way to do this would be to fire a property change.
1170 @SuppressWarnings("unused")
1171 TableUI ui = table.getUI();
1173 * @j2sNative ui.repaintTable$();
1184 frame.setClosed(true);
1185 } catch (Exception exe)
1191 public void updateFeatureRenderer(Object[][] data)
1193 updateFeatureRenderer(data, true);
1197 * Update the priority order of features; only repaint if this changed the order
1198 * of visible features
1203 void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1205 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1207 if (fr.setFeaturePriority(rowData, visibleNew))
1209 af.alignPanel.paintAlignment(true, true);
1214 * Converts table data into an array of data beans
1216 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1218 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1219 for (int i = 0; i < data.length; i++)
1221 String type = (String) data[i][TYPE_COLUMN];
1222 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1223 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1224 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1225 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1231 private void jbInit() throws Exception
1233 this.setLayout(new BorderLayout());
1235 JPanel settingsPane = new JPanel();
1236 settingsPane.setLayout(new BorderLayout());
1238 JPanel bigPanel = new JPanel();
1239 bigPanel.setLayout(new BorderLayout());
1241 groupPanel = new JPanel();
1242 bigPanel.add(groupPanel, BorderLayout.NORTH);
1244 JButton invert = new JButton(
1245 MessageManager.getString("label.invert_selection"));
1246 invert.setFont(JvSwingUtils.getLabelFont());
1247 invert.addActionListener(new ActionListener()
1250 public void actionPerformed(ActionEvent e)
1256 JButton optimizeOrder = new JButton(
1257 MessageManager.getString("label.optimise_order"));
1258 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1259 optimizeOrder.addActionListener(new ActionListener()
1262 public void actionPerformed(ActionEvent e)
1268 JButton sortByScore = new JButton(
1269 MessageManager.getString("label.seq_sort_by_score"));
1270 sortByScore.setFont(JvSwingUtils.getLabelFont());
1271 sortByScore.addActionListener(new ActionListener()
1274 public void actionPerformed(ActionEvent e)
1276 af.avc.sortAlignmentByFeatureScore(null);
1279 JButton sortByDens = new JButton(
1280 MessageManager.getString("label.sequence_sort_by_density"));
1281 sortByDens.setFont(JvSwingUtils.getLabelFont());
1282 sortByDens.addActionListener(new ActionListener()
1285 public void actionPerformed(ActionEvent e)
1287 af.avc.sortAlignmentByFeatureDensity(null);
1291 JButton help = new JButton(MessageManager.getString("action.help"));
1292 help.setFont(JvSwingUtils.getLabelFont());
1293 help.addActionListener(new ActionListener()
1296 public void actionPerformed(ActionEvent e)
1300 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1301 } catch (HelpSetException e1)
1303 e1.printStackTrace();
1307 help.setFont(JvSwingUtils.getLabelFont());
1308 help.setText(MessageManager.getString("action.help"));
1309 help.addActionListener(new ActionListener()
1312 public void actionPerformed(ActionEvent e)
1316 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1317 } catch (HelpSetException e1)
1319 e1.printStackTrace();
1324 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1325 cancel.setFont(JvSwingUtils.getLabelFont());
1326 cancel.addActionListener(new ActionListener()
1329 public void actionPerformed(ActionEvent e)
1331 fr.setTransparency(originalTransparency);
1332 fr.setFeatureFilters(originalFilters);
1333 updateFeatureRenderer(originalData);
1338 JButton ok = new JButton(MessageManager.getString("action.ok"));
1339 ok.setFont(JvSwingUtils.getLabelFont());
1340 ok.addActionListener(new ActionListener()
1343 public void actionPerformed(ActionEvent e)
1349 JButton loadColours = new JButton(
1350 MessageManager.getString("label.load_colours"));
1351 loadColours.setFont(JvSwingUtils.getLabelFont());
1352 loadColours.setToolTipText(
1353 MessageManager.getString("label.load_colours_tooltip"));
1354 loadColours.addActionListener(new ActionListener()
1357 public void actionPerformed(ActionEvent e)
1363 JButton saveColours = new JButton(
1364 MessageManager.getString("label.save_colours"));
1365 saveColours.setFont(JvSwingUtils.getLabelFont());
1366 saveColours.setToolTipText(
1367 MessageManager.getString("label.save_colours_tooltip"));
1368 saveColours.addActionListener(new ActionListener()
1371 public void actionPerformed(ActionEvent e)
1376 transparency.addChangeListener(new ChangeListener()
1379 public void stateChanged(ChangeEvent evt)
1381 if (!inConstruction)
1383 fr.setTransparency((100 - transparency.getValue()) / 100f);
1384 af.alignPanel.paintAlignment(true, true);
1389 transparency.setMaximum(70);
1390 transparency.setToolTipText(
1391 MessageManager.getString("label.transparency_tip"));
1393 JPanel transPanel = new JPanel(new GridLayout(1, 2));
1394 bigPanel.add(transPanel, BorderLayout.SOUTH);
1396 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1397 transbuttons.add(optimizeOrder);
1398 transbuttons.add(invert);
1399 transbuttons.add(sortByScore);
1400 transbuttons.add(sortByDens);
1401 transbuttons.add(help);
1402 transPanel.add(transparency);
1403 transPanel.add(transbuttons);
1405 JPanel buttonPanel = new JPanel();
1406 buttonPanel.add(ok);
1407 buttonPanel.add(cancel);
1408 buttonPanel.add(loadColours);
1409 buttonPanel.add(saveColours);
1410 bigPanel.add(scrollPane, BorderLayout.CENTER);
1411 settingsPane.add(bigPanel, BorderLayout.CENTER);
1412 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1413 this.add(settingsPane);
1417 * Answers a suitable tooltip to show on the colour cell of the table
1421 * if true include 'click to edit' and similar text
1424 public static String getColorTooltip(FeatureColourI fcol,
1431 if (fcol.isSimpleColour())
1433 return withHint ? BASE_TOOLTIP : null;
1435 String description = fcol.getDescription();
1436 description = description.replaceAll("<", "<");
1437 description = description.replaceAll(">", ">");
1438 StringBuilder tt = new StringBuilder(description);
1441 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1443 return JvSwingUtils.wrapTooltip(true, tt.toString());
1446 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1449 boolean thr = false;
1450 StringBuilder tx = new StringBuilder();
1452 if (gcol.isColourByAttribute())
1454 tx.append(FeatureMatcher
1455 .toAttributeDisplayName(gcol.getAttributeName()));
1457 else if (!gcol.isColourByLabel())
1459 tx.append(MessageManager.getString("label.score"));
1462 if (gcol.isAboveThreshold())
1467 if (gcol.isBelowThreshold())
1472 if (gcol.isColourByLabel())
1478 if (!gcol.isColourByAttribute())
1486 Color newColor = gcol.getMaxColour();
1487 comp.setBackground(newColor);
1488 // System.err.println("Width is " + w / 2);
1489 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1490 comp.setIcon(ficon);
1491 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1492 // + newColor.getGreen() + ", " + newColor.getBlue()
1493 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1494 // + ", " + minCol.getBlue() + ")");
1496 comp.setHorizontalAlignment(SwingConstants.CENTER);
1497 comp.setText(tx.toString());
1500 // ///////////////////////////////////////////////////////////////////////
1501 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1502 // ///////////////////////////////////////////////////////////////////////
1503 class FeatureTableModel extends AbstractTableModel
1505 private String[] columnNames = {
1506 MessageManager.getString("label.feature_type"),
1507 MessageManager.getString("action.colour"),
1508 MessageManager.getString("label.filter"),
1509 MessageManager.getString("label.show") };
1511 private Object[][] data;
1513 FeatureTableModel(Object[][] data)
1518 public Object[][] getData()
1523 public void setData(Object[][] data)
1529 public int getColumnCount()
1531 return columnNames.length;
1534 public Object[] getRow(int row)
1540 public int getRowCount()
1546 public String getColumnName(int col)
1548 return columnNames[col];
1552 public Object getValueAt(int row, int col)
1554 return data[row][col];
1558 * Answers the class of the object in column c of the first row of the table
1561 public Class<?> getColumnClass(int c)
1563 Object v = getValueAt(0, c);
1564 return v == null ? null : v.getClass();
1568 public boolean isCellEditable(int row, int col)
1570 return col == 0 ? false : true;
1574 public void setValueAt(Object value, int row, int col)
1576 data[row][col] = value;
1577 fireTableCellUpdated(row, col);
1578 updateFeatureRenderer(data);
1583 class ColorRenderer extends JLabel implements TableCellRenderer
1585 Border unselectedBorder = null;
1587 Border selectedBorder = null;
1589 public ColorRenderer()
1591 setOpaque(true); // MUST do this for background to show up.
1592 setHorizontalTextPosition(SwingConstants.CENTER);
1593 setVerticalTextPosition(SwingConstants.CENTER);
1597 public Component getTableCellRendererComponent(JTable tbl, Object color,
1598 boolean isSelected, boolean hasFocus, int row, int column)
1600 FeatureColourI cellColour = (FeatureColourI) color;
1602 setBackground(tbl.getBackground());
1603 if (!cellColour.isSimpleColour())
1605 Rectangle cr = tbl.getCellRect(row, column, false);
1606 FeatureSettings.renderGraduatedColor(this, cellColour,
1607 (int) cr.getWidth(), (int) cr.getHeight());
1613 setBackground(cellColour.getColour());
1617 if (selectedBorder == null)
1619 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1620 tbl.getSelectionBackground());
1622 setBorder(selectedBorder);
1626 if (unselectedBorder == null)
1628 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1629 tbl.getBackground());
1631 setBorder(unselectedBorder);
1638 class FilterRenderer extends JLabel implements TableCellRenderer
1640 javax.swing.border.Border unselectedBorder = null;
1642 javax.swing.border.Border selectedBorder = null;
1644 public FilterRenderer()
1646 setOpaque(true); // MUST do this for background to show up.
1647 setHorizontalTextPosition(SwingConstants.CENTER);
1648 setVerticalTextPosition(SwingConstants.CENTER);
1652 public Component getTableCellRendererComponent(JTable tbl,
1653 Object filter, boolean isSelected, boolean hasFocus, int row,
1656 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1658 String asText = theFilter.toString();
1659 setBackground(tbl.getBackground());
1660 this.setText(asText);
1665 if (selectedBorder == null)
1667 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1668 tbl.getSelectionBackground());
1670 setBorder(selectedBorder);
1674 if (unselectedBorder == null)
1676 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1677 tbl.getBackground());
1679 setBorder(unselectedBorder);
1687 * update comp using rendering settings from gcol
1692 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1694 int w = comp.getWidth(), h = comp.getHeight();
1697 w = (int) comp.getPreferredSize().getWidth();
1698 h = (int) comp.getPreferredSize().getHeight();
1705 renderGraduatedColor(comp, gcol, w, h);
1708 class ColorEditor extends AbstractCellEditor
1709 implements TableCellEditor, ActionListener
1713 FeatureColourI currentColor;
1715 FeatureTypeSettings chooser;
1721 protected static final String EDIT = "edit";
1723 int rowSelected = 0;
1725 public ColorEditor(FeatureSettings fs)
1728 // Set up the editor (from the table's point of view),
1729 // which is a button.
1730 // This button brings up the color chooser dialog,
1731 // which is the editor from the user's point of view.
1732 button = new JButton();
1733 button.setActionCommand(EDIT);
1734 button.addActionListener(this);
1735 button.setBorderPainted(false);
1739 * Handles events from the editor button, and from the colour/filters
1740 * dialog's OK button
1743 public void actionPerformed(ActionEvent e)
1745 if (button == e.getSource())
1747 if (currentColor.isSimpleColour())
1750 * simple colour chooser
1752 String ttl = MessageManager.formatMessage("label.select_colour_for", type);
1753 ColourChooserListener listener = new ColourChooserListener()
1756 public void colourSelected(Color c)
1758 currentColor = new FeatureColour(c);
1759 me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1760 fireEditingStopped();
1763 public void cancel()
1765 fireEditingStopped();
1768 JalviewColourChooser.showColourChooser(button, ttl, currentColor.getColour(), listener);
1773 * variable colour and filters dialog
1775 chooser = new FeatureTypeSettings(me.fr, type);
1776 if (!Jalview.isJS())
1778 chooser.setRequestFocusEnabled(true);
1779 chooser.requestFocus();
1781 chooser.addActionListener(this);
1782 fireEditingStopped();
1788 * after OK in variable colour dialog, any changes to colour
1789 * (or filters!) are already set in FeatureRenderer, so just
1790 * update table data without triggering updateFeatureRenderer
1792 currentColor = fr.getFeatureColours().get(type);
1793 FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
1794 if (currentFilter == null)
1796 currentFilter = new FeatureMatcherSet();
1798 Object[] data = ((FeatureTableModel) table.getModel())
1799 .getData()[rowSelected];
1800 data[COLOUR_COLUMN] = currentColor;
1801 data[FILTER_COLUMN] = currentFilter;
1803 fireEditingStopped();
1804 me.table.validate();
1808 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1810 public Object getCellEditorValue()
1812 return currentColor;
1815 // Implement the one method defined by TableCellEditor.
1817 public Component getTableCellEditorComponent(JTable theTable, Object value,
1818 boolean isSelected, int row, int column)
1820 currentColor = (FeatureColourI) value;
1821 this.rowSelected = row;
1822 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1823 button.setOpaque(true);
1824 button.setBackground(me.getBackground());
1825 if (!currentColor.isSimpleColour())
1827 JLabel btn = new JLabel();
1828 btn.setSize(button.getSize());
1829 FeatureSettings.renderGraduatedColor(btn, currentColor);
1830 button.setBackground(btn.getBackground());
1831 button.setIcon(btn.getIcon());
1832 button.setText(btn.getText());
1837 button.setIcon(null);
1838 button.setBackground(currentColor.getColour());
1845 * The cell editor for the Filter column. It displays the text of any filters
1846 * for the feature type in that row (in full as a tooltip, possible abbreviated
1847 * as display text). On click in the cell, opens the Feature Display Settings
1848 * dialog at the Filters tab.
1850 class FilterEditor extends AbstractCellEditor
1851 implements TableCellEditor, ActionListener
1855 FeatureMatcherSetI currentFilter;
1863 protected static final String EDIT = "edit";
1865 int rowSelected = 0;
1867 public FilterEditor(FeatureSettings me)
1870 button = new JButton();
1871 button.setActionCommand(EDIT);
1872 button.addActionListener(this);
1873 button.setBorderPainted(false);
1877 * Handles events from the editor button
1880 public void actionPerformed(ActionEvent e)
1882 if (button == e.getSource())
1884 FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
1885 chooser.addActionListener(this);
1886 chooser.setRequestFocusEnabled(true);
1887 chooser.requestFocus();
1888 if (lastLocation != null)
1890 // todo open at its last position on screen
1891 chooser.setBounds(lastLocation.x, lastLocation.y,
1892 chooser.getWidth(), chooser.getHeight());
1895 fireEditingStopped();
1897 else if (e.getSource() instanceof Component)
1901 * after OK in variable colour dialog, any changes to filter
1902 * (or colours!) are already set in FeatureRenderer, so just
1903 * update table data without triggering updateFeatureRenderer
1905 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1906 currentFilter = me.fr.getFeatureFilter(type);
1907 if (currentFilter == null)
1909 currentFilter = new FeatureMatcherSet();
1911 Object[] data = ((FeatureTableModel) table.getModel())
1912 .getData()[rowSelected];
1913 data[COLOUR_COLUMN] = currentColor;
1914 data[FILTER_COLUMN] = currentFilter;
1915 fireEditingStopped();
1916 me.table.validate();
1921 public Object getCellEditorValue()
1923 return currentFilter;
1927 public Component getTableCellEditorComponent(JTable theTable, Object value,
1928 boolean isSelected, int row, int column)
1930 currentFilter = (FeatureMatcherSetI) value;
1931 this.rowSelected = row;
1932 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1933 button.setOpaque(true);
1934 button.setBackground(me.getBackground());
1935 button.setText(currentFilter.toString());
1936 button.setIcon(null);
1942 class FeatureIcon implements Icon
1944 FeatureColourI gcol;
1948 boolean midspace = false;
1950 int width = 50, height = 20;
1952 int s1, e1; // start and end of midpoint band for thresholded symbol
1954 Color mpcolour = Color.white;
1956 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1976 public int getIconWidth()
1982 public int getIconHeight()
1988 public void paintIcon(Component c, Graphics g, int x, int y)
1991 if (gcol.isColourByLabel())
1994 g.fillRect(0, 0, width, height);
1995 // need an icon here.
1996 g.setColor(gcol.getMaxColour());
1998 g.setFont(new Font("Verdana", Font.PLAIN, 9));
2000 // g.setFont(g.getFont().deriveFont(
2001 // AffineTransform.getScaleInstance(
2002 // width/g.getFontMetrics().stringWidth("Label"),
2003 // height/g.getFontMetrics().getHeight())));
2005 g.drawString(MessageManager.getString("label.label"), 0, 0);
2010 Color minCol = gcol.getMinColour();
2012 g.fillRect(0, 0, s1, height);
2015 g.setColor(Color.white);
2016 g.fillRect(s1, 0, e1 - s1, height);
2018 g.setColor(gcol.getMaxColour());
2019 // g.fillRect(0, e1, width - e1, height); // BH 2018
2020 g.fillRect(e1, 0, width - e1, height);