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.util.dialogrunner.RunResponse;
40 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
41 import jalview.xml.binding.jalview.JalviewUserColours;
42 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
43 import jalview.xml.binding.jalview.JalviewUserColours.Filter;
44 import jalview.xml.binding.jalview.ObjectFactory;
46 import java.awt.BorderLayout;
47 import java.awt.Color;
48 import java.awt.Component;
49 import java.awt.Dimension;
51 import java.awt.Graphics;
52 import java.awt.GridLayout;
53 import java.awt.Point;
54 import java.awt.Rectangle;
55 import java.awt.event.ActionEvent;
56 import java.awt.event.ActionListener;
57 import java.awt.event.ItemEvent;
58 import java.awt.event.ItemListener;
59 import java.awt.event.MouseAdapter;
60 import java.awt.event.MouseEvent;
61 import java.awt.event.MouseMotionAdapter;
62 import java.beans.PropertyChangeEvent;
63 import java.beans.PropertyChangeListener;
65 import java.io.FileInputStream;
66 import java.io.FileOutputStream;
67 import java.io.InputStreamReader;
68 import java.io.OutputStreamWriter;
69 import java.io.PrintWriter;
70 import java.util.Arrays;
71 import java.util.Comparator;
72 import java.util.HashMap;
73 import java.util.HashSet;
74 import java.util.Hashtable;
75 import java.util.Iterator;
76 import java.util.List;
80 import javax.help.HelpSetException;
81 import javax.swing.AbstractCellEditor;
82 import javax.swing.BorderFactory;
83 import javax.swing.Icon;
84 import javax.swing.JButton;
85 import javax.swing.JCheckBox;
86 import javax.swing.JCheckBoxMenuItem;
87 import javax.swing.JInternalFrame;
88 import javax.swing.JLabel;
89 import javax.swing.JLayeredPane;
90 import javax.swing.JMenuItem;
91 import javax.swing.JPanel;
92 import javax.swing.JPopupMenu;
93 import javax.swing.JScrollPane;
94 import javax.swing.JSlider;
95 import javax.swing.JTable;
96 import javax.swing.ListSelectionModel;
97 import javax.swing.SwingConstants;
98 import javax.swing.ToolTipManager;
99 import javax.swing.border.Border;
100 import javax.swing.event.ChangeEvent;
101 import javax.swing.event.ChangeListener;
102 import javax.swing.plaf.TableUI;
103 import javax.swing.table.AbstractTableModel;
104 import javax.swing.table.TableCellEditor;
105 import javax.swing.table.TableCellRenderer;
106 import javax.swing.table.TableColumn;
107 import javax.xml.bind.JAXBContext;
108 import javax.xml.bind.JAXBElement;
109 import javax.xml.bind.Marshaller;
110 import javax.xml.stream.XMLInputFactory;
111 import javax.xml.stream.XMLStreamReader;
113 public class FeatureSettings extends JPanel
114 implements FeatureSettingsControllerI
116 private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
117 .getString("label.sequence_feature_colours");
120 * column indices of fields in Feature Settings table
122 static final int TYPE_COLUMN = 0;
124 static final int COLOUR_COLUMN = 1;
126 static final int FILTER_COLUMN = 2;
128 static final int SHOW_COLUMN = 3;
130 private static final int COLUMN_COUNT = 4;
132 private static final int MIN_WIDTH = 400;
134 private static final int MIN_HEIGHT = 400;
136 private final static String BASE_TOOLTIP = MessageManager.getString("label.click_to_edit");
138 final FeatureRenderer fr;
140 public final AlignFrame af;
143 * 'original' fields hold settings to restore on Cancel
145 Object[][] originalData;
147 float originalTransparency;
149 Map<String, FeatureMatcherSetI> originalFilters;
151 final JInternalFrame frame;
153 JScrollPane scrollPane = new JScrollPane();
159 JSlider transparency = new JSlider();
162 * when true, constructor is still executing - so ignore UI events
164 protected volatile boolean inConstruction = true;
166 int selectedRow = -1;
168 JButton fetchDAS = new JButton();
170 JButton saveDAS = new JButton();
172 JButton cancelDAS = new JButton();
174 boolean resettingTable = false;
177 * true when Feature Settings are updating from feature renderer
179 boolean handlingUpdate = false;
182 * holds {featureCount, totalExtent} for each feature type
184 Map<String, float[]> typeWidth = null;
191 public FeatureSettings(AlignFrame alignFrame)
193 this.af = alignFrame;
194 fr = af.getFeatureRenderer();
196 // save transparency for restore on Cancel
197 originalTransparency = fr.getTransparency();
198 int originalTransparencyAsPercent = (int) (originalTransparency * 100);
199 transparency.setMaximum(100 - originalTransparencyAsPercent);
201 originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
206 } catch (Exception ex)
208 ex.printStackTrace();
214 public String getToolTipText(MouseEvent e)
217 int column = table.columnAtPoint(e.getPoint());
218 int row = table.rowAtPoint(e.getPoint());
223 tip = JvSwingUtils.wrapTooltip(true, MessageManager
224 .getString("label.feature_settings_click_drag"));
227 FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
229 tip = getColorTooltip(colour, true);
232 FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
235 ? MessageManager.getString("label.filters_tooltip")
247 * Position the tooltip near the bottom edge of, and half way across, the
251 public Point getToolTipLocation(MouseEvent e)
253 Point point = e.getPoint();
254 int column = table.columnAtPoint(point);
255 int row = table.rowAtPoint(point);
256 Rectangle r = getCellRect(row, column, false);
257 Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3);
262 // next line is needed to avoid (quiet) exceptions thrown
263 // when column ordering changes so that the above constants
265 table.getTableHeader().setReorderingAllowed(false); // BH 2018
267 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
268 ToolTipManager.sharedInstance().registerComponent(table);
270 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
271 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
273 table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor(this));
274 table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
276 TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
277 new ColorRenderer(), new ColorEditor(this));
278 table.addColumn(colourColumn);
280 TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
281 new FilterRenderer(), new FilterEditor(this));
282 table.addColumn(filterColumn);
284 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
286 table.addMouseListener(new MouseAdapter()
289 public void mousePressed(MouseEvent evt)
291 selectedRow = table.rowAtPoint(evt.getPoint());
292 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
293 if (evt.isPopupTrigger())
295 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
296 showPopupMenu(selectedRow, type, colour, evt.getPoint());
298 else if (evt.getClickCount() == 2)
300 boolean invertSelection = evt.isAltDown();
301 boolean toggleSelection = Platform.isControlDown(evt);
302 boolean extendSelection = evt.isShiftDown();
303 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
304 invertSelection, extendSelection, toggleSelection, type);
308 // isPopupTrigger fires on mouseReleased on Windows
310 public void mouseReleased(MouseEvent evt)
312 selectedRow = table.rowAtPoint(evt.getPoint());
313 if (evt.isPopupTrigger())
315 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
316 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
317 showPopupMenu(selectedRow, type, colour, evt.getPoint());
322 table.addMouseMotionListener(new MouseMotionAdapter()
325 public void mouseDragged(MouseEvent evt)
327 int newRow = table.rowAtPoint(evt.getPoint());
328 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
331 * reposition 'selectedRow' to 'newRow' (the dragged to location)
332 * this could be more than one row away for a very fast drag action
333 * so just swap it with adjacent rows until we get it there
335 Object[][] data = ((FeatureTableModel) table.getModel())
337 int direction = newRow < selectedRow ? -1 : 1;
338 for (int i = selectedRow; i != newRow; i += direction)
340 Object[] temp = data[i];
341 data[i] = data[i + direction];
342 data[i + direction] = temp;
344 updateFeatureRenderer(data);
346 selectedRow = newRow;
350 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
351 // MessageManager.getString("label.feature_settings_click_drag")));
352 scrollPane.setViewportView(table);
354 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
356 fr.findAllFeatures(true); // display everything!
359 discoverAllFeatureData();
360 final PropertyChangeListener change;
361 final FeatureSettings fs = this;
362 fr.addPropertyChangeListener(change = new PropertyChangeListener()
365 public void propertyChange(PropertyChangeEvent evt)
367 if (!fs.resettingTable && !fs.handlingUpdate)
369 fs.handlingUpdate = true;
371 // new groups may be added with new sequence feature types only
372 fs.handlingUpdate = false;
378 frame = new JInternalFrame();
379 frame.setContentPane(this);
380 if (Platform.isAMac())
382 Desktop.addInternalFrame(frame,
383 MessageManager.getString("label.sequence_feature_settings"),
388 Desktop.addInternalFrame(frame,
389 MessageManager.getString("label.sequence_feature_settings"),
392 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
394 frame.addInternalFrameListener(
395 new javax.swing.event.InternalFrameAdapter()
398 public void internalFrameClosed(
399 javax.swing.event.InternalFrameEvent evt)
401 fr.removePropertyChangeListener(change);
404 frame.setLayer(JLayeredPane.PALETTE_LAYER);
405 inConstruction = false;
409 * Constructs and shows a popup menu of possible actions on the selected row and
417 protected void showPopupMenu(final int rowSelected, final String type,
418 final Object typeCol, final Point pt)
420 final FeatureColourI featureColour = (FeatureColourI) typeCol;
422 JPopupMenu men = new JPopupMenu(MessageManager
423 .formatMessage("label.settings_for_param", new String[]
425 JMenuItem scr = new JMenuItem(
426 MessageManager.getString("label.sort_by_score"));
428 final FeatureSettings me = this;
429 scr.addActionListener(new ActionListener()
433 public void actionPerformed(ActionEvent e)
436 .sortAlignmentByFeatureScore(Arrays.asList(new String[]
440 JMenuItem dens = new JMenuItem(
441 MessageManager.getString("label.sort_by_density"));
442 dens.addActionListener(new ActionListener()
446 public void actionPerformed(ActionEvent e)
449 .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
456 * variable colour options include colour by label, by score,
457 * by selected attribute text, or attribute value
459 final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
460 MessageManager.getString("label.variable_colour"));
461 variableColourCB.setSelected(!featureColour.isSimpleColour());
462 men.add(variableColourCB);
465 * checkbox action listener doubles up as listener to OK
466 * from the variable colour / filters dialog
468 variableColourCB.addActionListener(new ActionListener()
471 public void actionPerformed(ActionEvent e)
473 if (e.getSource() == variableColourCB)
475 men.setVisible(true); // BH 2018 for JavaScript because this is a checkbox
476 men.setVisible(false); // BH 2018 for JavaScript because this is a checkbox
477 if (featureColour.isSimpleColour())
480 * toggle simple colour to variable colour - show dialog
482 FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type);
483 fc.addActionListener(this);
488 * toggle variable to simple colour - show colour chooser
490 String title = MessageManager.formatMessage("label.select_colour_for", type);
491 ColourChooserListener listener = new ColourChooserListener()
494 public void colourSelected(Color c)
496 table.setValueAt(new FeatureColour(c), rowSelected,
499 me.updateFeatureRenderer(
500 ((FeatureTableModel) table.getModel()).getData(),
504 JalviewColourChooser.showColourChooser(me, title, featureColour.getMaxColour(), listener);
509 if (e.getSource() instanceof FeatureTypeSettings)
512 * update after OK in feature colour dialog; the updated
513 * colour will have already been set in the FeatureRenderer
515 FeatureColourI fci = fr.getFeatureColours().get(type);
516 table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
517 // BH 2018 setting a table value does not invalidate it.
518 System.out.println("FeatureSettings is valied" + table.isValid());
525 JMenuItem selCols = new JMenuItem(
526 MessageManager.getString("label.select_columns_containing"));
527 selCols.addActionListener(new ActionListener()
530 public void actionPerformed(ActionEvent arg0)
532 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
536 JMenuItem clearCols = new JMenuItem(MessageManager
537 .getString("label.select_columns_not_containing"));
538 clearCols.addActionListener(new ActionListener()
541 public void actionPerformed(ActionEvent arg0)
543 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
547 JMenuItem hideCols = new JMenuItem(
548 MessageManager.getString("label.hide_columns_containing"));
549 hideCols.addActionListener(new ActionListener()
552 public void actionPerformed(ActionEvent arg0)
554 fr.ap.alignFrame.hideFeatureColumns(type, true);
557 JMenuItem hideOtherCols = new JMenuItem(
558 MessageManager.getString("label.hide_columns_not_containing"));
559 hideOtherCols.addActionListener(new ActionListener()
562 public void actionPerformed(ActionEvent arg0)
564 fr.ap.alignFrame.hideFeatureColumns(type, false);
570 men.add(hideOtherCols);
571 men.show(table, pt.x, pt.y);
575 synchronized public void discoverAllFeatureData()
577 Set<String> allGroups = new HashSet<>();
578 AlignmentI alignment = af.getViewport().getAlignment();
580 for (int i = 0; i < alignment.getHeight(); i++)
582 SequenceI seq = alignment.getSequenceAt(i);
583 for (String group : seq.getFeatures().getFeatureGroups(true))
585 if (group != null && !allGroups.contains(group))
587 allGroups.add(group);
588 checkGroupState(group);
599 * Synchronise gui group list and check visibility of group
602 * @return true if group is visible
604 private boolean checkGroupState(String group)
606 boolean visible = fr.checkGroupVisibility(group, true);
608 for (int g = 0; g < groupPanel.getComponentCount(); g++)
610 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
612 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
617 final String grp = group;
618 final JCheckBox check = new JCheckBox(group, visible);
619 check.setFont(new Font("Serif", Font.BOLD, 12));
620 check.setToolTipText(group);
621 check.addItemListener(new ItemListener()
624 public void itemStateChanged(ItemEvent evt)
626 fr.setGroupVisibility(check.getText(), check.isSelected());
627 resetTable(new String[] { grp });
628 af.alignPanel.paintAlignment(true, true);
631 groupPanel.add(check);
635 synchronized void resetTable(String[] groupChanged)
641 resettingTable = true;
642 typeWidth = new Hashtable<>();
643 // TODO: change avWidth calculation to 'per-sequence' average and use long
646 Set<String> displayableTypes = new HashSet<>();
647 Set<String> foundGroups = new HashSet<>();
650 * determine which feature types may be visible depending on
651 * which groups are selected, and recompute average width data
653 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
656 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
659 * get the sequence's groups for positional features
660 * and keep track of which groups are visible
662 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
663 Set<String> visibleGroups = new HashSet<>();
664 for (String group : groups)
666 if (group == null || checkGroupState(group))
668 visibleGroups.add(group);
671 foundGroups.addAll(groups);
674 * get distinct feature types for visible groups
675 * record distinct visible types, and their count and total length
677 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
678 visibleGroups.toArray(new String[visibleGroups.size()]));
679 for (String type : types)
681 displayableTypes.add(type);
682 float[] avWidth = typeWidth.get(type);
685 avWidth = new float[2];
686 typeWidth.put(type, avWidth);
688 // todo this could include features with a non-visible group
689 // - do we greatly care?
690 // todo should we include non-displayable features here, and only
691 // update when features are added?
692 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
693 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
697 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
700 if (fr.hasRenderOrder())
704 fr.findAllFeatures(groupChanged != null); // prod to update
705 // colourschemes. but don't
707 // First add the checks in the previous render order,
708 // in case the window has been closed and reopened
710 List<String> frl = fr.getRenderOrder();
711 for (int ro = frl.size() - 1; ro > -1; ro--)
713 String type = frl.get(ro);
715 if (!displayableTypes.contains(type))
720 data[dataIndex][TYPE_COLUMN] = type;
721 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
722 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
723 data[dataIndex][FILTER_COLUMN] = featureFilter == null
724 ? new FeatureMatcherSet()
726 data[dataIndex][SHOW_COLUMN] = new Boolean(
727 af.getViewport().getFeaturesDisplayed().isVisible(type));
729 displayableTypes.remove(type);
734 * process any extra features belonging only to
735 * a group which was just selected
737 while (!displayableTypes.isEmpty())
739 String type = displayableTypes.iterator().next();
740 data[dataIndex][TYPE_COLUMN] = type;
742 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
743 if (data[dataIndex][COLOUR_COLUMN] == null)
745 // "Colour has been updated in another view!!"
746 fr.clearRenderOrder();
749 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
750 data[dataIndex][FILTER_COLUMN] = featureFilter == null
751 ? new FeatureMatcherSet()
753 data[dataIndex][SHOW_COLUMN] = new Boolean(true);
755 displayableTypes.remove(type);
758 if (originalData == null)
760 originalData = new Object[data.length][COLUMN_COUNT];
761 for (int i = 0; i < data.length; i++)
763 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
768 updateOriginalData(data);
771 table.setModel(new FeatureTableModel(data));
772 table.getColumnModel().getColumn(0).setPreferredWidth(200);
774 groupPanel.setLayout(
775 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
776 pruneGroups(foundGroups);
777 groupPanel.validate();
779 updateFeatureRenderer(data, groupChanged != null);
780 resettingTable = false;
784 * Updates 'originalData' (used for restore on Cancel) if we detect that changes
785 * have been made outwith this dialog
787 * <li>a new feature type added (and made visible)</li>
788 * <li>a feature colour changed (in the Amend Features dialog)</li>
793 protected void updateOriginalData(Object[][] foundData)
795 // todo LinkedHashMap instead of Object[][] would be nice
797 Object[][] currentData = ((FeatureTableModel) table.getModel())
799 for (Object[] row : foundData)
801 String type = (String) row[TYPE_COLUMN];
802 boolean found = false;
803 for (Object[] current : currentData)
805 if (type.equals(current[TYPE_COLUMN]))
809 * currently dependent on object equality here;
810 * really need an equals method on FeatureColour
812 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
815 * feature colour has changed externally - update originalData
817 for (Object[] original : originalData)
819 if (type.equals(original[TYPE_COLUMN]))
821 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
832 * new feature detected - add to original data (on top)
834 Object[][] newData = new Object[originalData.length
836 for (int i = 0; i < originalData.length; i++)
838 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
842 originalData = newData;
848 * Remove from the groups panel any checkboxes for groups that are not in the
849 * foundGroups set. This enables removing a group from the display when the last
850 * feature in that group is deleted.
854 protected void pruneGroups(Set<String> foundGroups)
856 for (int g = 0; g < groupPanel.getComponentCount(); g++)
858 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
859 if (!foundGroups.contains(checkbox.getText()))
861 groupPanel.remove(checkbox);
867 * reorder data based on the featureRenderers global priority list.
871 private void ensureOrder(Object[][] data)
873 boolean sort = false;
874 float[] order = new float[data.length];
875 for (int i = 0; i < order.length; i++)
877 order[i] = fr.getOrder(data[i][0].toString());
880 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
884 sort = sort || order[i - 1] > order[i];
889 jalview.util.QuickSort.sort(order, data);
894 * Offers a file chooser dialog, and then loads the feature colours and
895 * filters from file in XML format and unmarshals to Jalview feature settings
899 JalviewFileChooser chooser = new JalviewFileChooser("fc",
900 SEQUENCE_FEATURE_COLOURS);
901 chooser.setFileView(new JalviewFileView());
902 chooser.setDialogTitle(
903 MessageManager.getString("label.load_feature_colours"));
904 chooser.setToolTipText(MessageManager.getString("action.load"));
905 chooser.addResponse(new RunResponse(JalviewFileChooser.APPROVE_OPTION){
909 File file = chooser.getSelectedFile();
912 chooser.showOpenDialog(this);
916 * Loads feature colours and filters from XML stored in the given file
924 InputStreamReader in = new InputStreamReader(
925 new FileInputStream(file), "UTF-8");
927 JAXBContext jc = JAXBContext
928 .newInstance("jalview.xml.binding.jalview");
929 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
930 XMLStreamReader streamReader = XMLInputFactory.newInstance()
931 .createXMLStreamReader(in);
932 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
933 JalviewUserColours.class);
934 JalviewUserColours jucs = jbe.getValue();
936 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
939 * load feature colours
941 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
943 Colour newcol = jucs.getColour().get(i);
944 FeatureColourI colour = jalview.project.Jalview2XML
945 .parseColour(newcol);
946 fr.setColour(newcol.getName(), colour);
947 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
951 * load feature filters; loaded filters will replace any that are
952 * currently defined, other defined filters are left unchanged
954 for (int i = 0; i < jucs.getFilter().size(); i++)
956 Filter filterModel = jucs.getFilter().get(i);
957 String featureType = filterModel.getFeatureType();
958 FeatureMatcherSetI filter = jalview.project.Jalview2XML
959 .parseFilter(featureType, filterModel.getMatcherSet());
960 if (!filter.isEmpty())
962 fr.setFeatureFilter(featureType, filter);
967 * update feature settings table
972 Object[][] data = ((FeatureTableModel) table.getModel())
975 updateFeatureRenderer(data, false);
978 } catch (Exception ex)
980 System.out.println("Error loading User Colour File\n" + ex);
985 * Offers a file chooser dialog, and then saves the current feature colours
986 * and any filters to the selected file in XML format
990 JalviewFileChooser chooser = new JalviewFileChooser("fc",
991 SEQUENCE_FEATURE_COLOURS);
992 chooser.setFileView(new JalviewFileView());
993 chooser.setDialogTitle(
994 MessageManager.getString("label.save_feature_colours"));
995 chooser.setToolTipText(MessageManager.getString("action.save"));
996 int option = chooser.showSaveDialog(this);
997 if (option == JalviewFileChooser.APPROVE_OPTION)
999 File file = chooser.getSelectedFile();
1005 * Saves feature colours and filters to the given file
1009 void save(File file)
1011 JalviewUserColours ucs = new JalviewUserColours();
1012 ucs.setSchemeName("Sequence Features");
1015 PrintWriter out = new PrintWriter(new OutputStreamWriter(
1016 new FileOutputStream(file), "UTF-8"));
1019 * sort feature types by colour order, from 0 (highest)
1022 Set<String> fr_colours = fr.getAllFeatureColours();
1023 String[] sortedTypes = fr_colours
1024 .toArray(new String[fr_colours.size()]);
1025 Arrays.sort(sortedTypes, new Comparator<String>()
1028 public int compare(String type1, String type2)
1030 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
1035 * save feature colours
1037 for (String featureType : sortedTypes)
1039 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1040 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
1042 ucs.getColour().add(col);
1046 * save any feature filters
1048 for (String featureType : sortedTypes)
1050 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1051 if (filter != null && !filter.isEmpty())
1053 Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
1054 FeatureMatcherI firstMatcher = iterator.next();
1055 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
1056 .marshalFilter(firstMatcher, iterator,
1058 Filter filterModel = new Filter();
1059 filterModel.setFeatureType(featureType);
1060 filterModel.setMatcherSet(ms);
1061 ucs.getFilter().add(filterModel);
1064 JAXBContext jaxbContext = JAXBContext
1065 .newInstance(JalviewUserColours.class);
1066 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1067 jaxbMarshaller.marshal(
1068 new ObjectFactory().createJalviewUserColours(ucs), out);
1070 // jaxbMarshaller.marshal(object, pout);
1071 // marshaller.marshal(object);
1074 // ucs.marshal(out);
1076 } catch (Exception ex)
1078 ex.printStackTrace();
1082 public void invertSelection()
1084 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1085 for (int i = 0; i < data.length; i++)
1087 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1089 updateFeatureRenderer(data, true);
1093 public void orderByAvWidth()
1095 if (table == null || table.getModel() == null)
1099 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1100 float[] width = new float[data.length];
1104 for (int i = 0; i < data.length; i++)
1106 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1109 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1110 // weight - but have to make per
1111 // sequence, too (awidth[2])
1112 // if (width[i]==1) // hack to distinguish single width sequences.
1123 boolean sort = false;
1124 for (int i = 0; i < width.length; i++)
1126 // awidth = (float[]) typeWidth.get(data[i][0]);
1129 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1132 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1138 width[i] /= max; // normalize
1139 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
1143 sort = sort || width[i - 1] > width[i];
1148 jalview.util.QuickSort.sort(width, data);
1149 // update global priority order
1152 updateFeatureRenderer(data, false);
1160 frame.setClosed(true);
1161 } catch (Exception exe)
1167 public void updateFeatureRenderer(Object[][] data)
1169 updateFeatureRenderer(data, true);
1173 * Update the priority order of features; only repaint if this changed the order
1174 * of visible features
1179 void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1181 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1183 if (fr.setFeaturePriority(rowData, visibleNew))
1185 af.alignPanel.paintAlignment(true, true);
1190 * Converts table data into an array of data beans
1192 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1194 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1195 for (int i = 0; i < data.length; i++)
1197 String type = (String) data[i][TYPE_COLUMN];
1198 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1199 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1200 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1201 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1207 private void jbInit() throws Exception
1209 this.setLayout(new BorderLayout());
1211 JPanel settingsPane = new JPanel();
1212 settingsPane.setLayout(new BorderLayout());
1214 JPanel bigPanel = new JPanel();
1215 bigPanel.setLayout(new BorderLayout());
1217 groupPanel = new JPanel();
1218 bigPanel.add(groupPanel, BorderLayout.NORTH);
1220 JButton invert = new JButton(
1221 MessageManager.getString("label.invert_selection"));
1222 invert.setFont(JvSwingUtils.getLabelFont());
1223 invert.addActionListener(new ActionListener()
1226 public void actionPerformed(ActionEvent e)
1232 JButton optimizeOrder = new JButton(
1233 MessageManager.getString("label.optimise_order"));
1234 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1235 optimizeOrder.addActionListener(new ActionListener()
1238 public void actionPerformed(ActionEvent e)
1244 JButton sortByScore = new JButton(
1245 MessageManager.getString("label.seq_sort_by_score"));
1246 sortByScore.setFont(JvSwingUtils.getLabelFont());
1247 sortByScore.addActionListener(new ActionListener()
1250 public void actionPerformed(ActionEvent e)
1252 af.avc.sortAlignmentByFeatureScore(null);
1255 JButton sortByDens = new JButton(
1256 MessageManager.getString("label.sequence_sort_by_density"));
1257 sortByDens.setFont(JvSwingUtils.getLabelFont());
1258 sortByDens.addActionListener(new ActionListener()
1261 public void actionPerformed(ActionEvent e)
1263 af.avc.sortAlignmentByFeatureDensity(null);
1267 JButton help = new JButton(MessageManager.getString("action.help"));
1268 help.setFont(JvSwingUtils.getLabelFont());
1269 help.addActionListener(new ActionListener()
1272 public void actionPerformed(ActionEvent e)
1276 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1277 } catch (HelpSetException e1)
1279 e1.printStackTrace();
1283 help.setFont(JvSwingUtils.getLabelFont());
1284 help.setText(MessageManager.getString("action.help"));
1285 help.addActionListener(new ActionListener()
1288 public void actionPerformed(ActionEvent e)
1292 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1293 } catch (HelpSetException e1)
1295 e1.printStackTrace();
1300 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1301 cancel.setFont(JvSwingUtils.getLabelFont());
1302 cancel.addActionListener(new ActionListener()
1305 public void actionPerformed(ActionEvent e)
1307 fr.setTransparency(originalTransparency);
1308 fr.setFeatureFilters(originalFilters);
1309 updateFeatureRenderer(originalData);
1314 JButton ok = new JButton(MessageManager.getString("action.ok"));
1315 ok.setFont(JvSwingUtils.getLabelFont());
1316 ok.addActionListener(new ActionListener()
1319 public void actionPerformed(ActionEvent e)
1325 JButton loadColours = new JButton(
1326 MessageManager.getString("label.load_colours"));
1327 loadColours.setFont(JvSwingUtils.getLabelFont());
1328 loadColours.setToolTipText(
1329 MessageManager.getString("label.load_colours_tooltip"));
1330 loadColours.addActionListener(new ActionListener()
1333 public void actionPerformed(ActionEvent e)
1339 JButton saveColours = new JButton(
1340 MessageManager.getString("label.save_colours"));
1341 saveColours.setFont(JvSwingUtils.getLabelFont());
1342 saveColours.setToolTipText(
1343 MessageManager.getString("label.save_colours_tooltip"));
1344 saveColours.addActionListener(new ActionListener()
1347 public void actionPerformed(ActionEvent e)
1352 transparency.addChangeListener(new ChangeListener()
1355 public void stateChanged(ChangeEvent evt)
1357 if (!inConstruction)
1359 fr.setTransparency((100 - transparency.getValue()) / 100f);
1360 af.alignPanel.paintAlignment(true, true);
1365 transparency.setMaximum(70);
1366 transparency.setToolTipText(
1367 MessageManager.getString("label.transparency_tip"));
1369 JPanel transPanel = new JPanel(new GridLayout(1, 2));
1370 bigPanel.add(transPanel, BorderLayout.SOUTH);
1372 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1373 transbuttons.add(optimizeOrder);
1374 transbuttons.add(invert);
1375 transbuttons.add(sortByScore);
1376 transbuttons.add(sortByDens);
1377 transbuttons.add(help);
1378 transPanel.add(transparency);
1379 transPanel.add(transbuttons);
1381 JPanel buttonPanel = new JPanel();
1382 buttonPanel.add(ok);
1383 buttonPanel.add(cancel);
1384 buttonPanel.add(loadColours);
1385 buttonPanel.add(saveColours);
1386 bigPanel.add(scrollPane, BorderLayout.CENTER);
1387 settingsPane.add(bigPanel, BorderLayout.CENTER);
1388 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1389 this.add(settingsPane);
1393 * Answers a suitable tooltip to show on the colour cell of the table
1397 * if true include 'click to edit' and similar text
1400 public static String getColorTooltip(FeatureColourI fcol,
1407 if (fcol.isSimpleColour())
1409 return withHint ? BASE_TOOLTIP : null;
1411 String description = fcol.getDescription();
1412 description = description.replaceAll("<", "<");
1413 description = description.replaceAll(">", ">");
1414 StringBuilder tt = new StringBuilder(description);
1417 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1419 return JvSwingUtils.wrapTooltip(true, tt.toString());
1422 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1425 boolean thr = false;
1426 StringBuilder tx = new StringBuilder();
1428 if (gcol.isColourByAttribute())
1430 tx.append(FeatureMatcher
1431 .toAttributeDisplayName(gcol.getAttributeName()));
1433 else if (!gcol.isColourByLabel())
1435 tx.append(MessageManager.getString("label.score"));
1438 if (gcol.isAboveThreshold())
1443 if (gcol.isBelowThreshold())
1448 if (gcol.isColourByLabel())
1454 if (!gcol.isColourByAttribute())
1462 Color newColor = gcol.getMaxColour();
1463 comp.setBackground(newColor);
1464 // System.err.println("Width is " + w / 2);
1465 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1466 comp.setIcon(ficon);
1467 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1468 // + newColor.getGreen() + ", " + newColor.getBlue()
1469 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1470 // + ", " + minCol.getBlue() + ")");
1472 comp.setHorizontalAlignment(SwingConstants.CENTER);
1473 comp.setText(tx.toString());
1476 // ///////////////////////////////////////////////////////////////////////
1477 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1478 // ///////////////////////////////////////////////////////////////////////
1479 class FeatureTableModel extends AbstractTableModel
1481 private String[] columnNames = {
1482 MessageManager.getString("label.feature_type"),
1483 MessageManager.getString("action.colour"),
1484 MessageManager.getString("label.filter"),
1485 MessageManager.getString("label.show") };
1487 private Object[][] data;
1489 FeatureTableModel(Object[][] data)
1494 public Object[][] getData()
1499 public void setData(Object[][] data)
1505 public int getColumnCount()
1507 return columnNames.length;
1510 public Object[] getRow(int row)
1516 public int getRowCount()
1522 public String getColumnName(int col)
1524 return columnNames[col];
1528 public Object getValueAt(int row, int col)
1530 return data[row][col];
1534 * Answers the class of the object in column c of the first row of the table
1537 public Class<?> getColumnClass(int c)
1539 Object v = getValueAt(0, c);
1540 return v == null ? null : v.getClass();
1544 public boolean isCellEditable(int row, int col)
1546 return col == 0 ? false : true;
1550 public void setValueAt(Object value, int row, int col)
1552 data[row][col] = value;
1553 fireTableCellUpdated(row, col);
1554 updateFeatureRenderer(data);
1559 class ColorRenderer extends JLabel implements TableCellRenderer
1561 Border unselectedBorder = null;
1563 Border selectedBorder = null;
1565 public ColorRenderer()
1567 setOpaque(true); // MUST do this for background to show up.
1568 setHorizontalTextPosition(SwingConstants.CENTER);
1569 setVerticalTextPosition(SwingConstants.CENTER);
1573 public Component getTableCellRendererComponent(JTable tbl, Object color,
1574 boolean isSelected, boolean hasFocus, int row, int column)
1576 FeatureColourI cellColour = (FeatureColourI) color;
1578 setBackground(tbl.getBackground());
1579 if (!cellColour.isSimpleColour())
1581 Rectangle cr = tbl.getCellRect(row, column, false);
1582 FeatureSettings.renderGraduatedColor(this, cellColour,
1583 (int) cr.getWidth(), (int) cr.getHeight());
1589 setBackground(cellColour.getColour());
1593 if (selectedBorder == null)
1595 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1596 tbl.getSelectionBackground());
1598 setBorder(selectedBorder);
1602 if (unselectedBorder == null)
1604 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1605 tbl.getBackground());
1607 setBorder(unselectedBorder);
1614 class FilterRenderer extends JLabel implements TableCellRenderer
1616 javax.swing.border.Border unselectedBorder = null;
1618 javax.swing.border.Border selectedBorder = null;
1620 public FilterRenderer()
1622 setOpaque(true); // MUST do this for background to show up.
1623 setHorizontalTextPosition(SwingConstants.CENTER);
1624 setVerticalTextPosition(SwingConstants.CENTER);
1628 public Component getTableCellRendererComponent(JTable tbl,
1629 Object filter, boolean isSelected, boolean hasFocus, int row,
1632 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1634 String asText = theFilter.toString();
1635 setBackground(tbl.getBackground());
1636 this.setText(asText);
1641 if (selectedBorder == null)
1643 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1644 tbl.getSelectionBackground());
1646 setBorder(selectedBorder);
1650 if (unselectedBorder == null)
1652 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1653 tbl.getBackground());
1655 setBorder(unselectedBorder);
1663 * update comp using rendering settings from gcol
1668 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1670 int w = comp.getWidth(), h = comp.getHeight();
1673 w = (int) comp.getPreferredSize().getWidth();
1674 h = (int) comp.getPreferredSize().getHeight();
1681 renderGraduatedColor(comp, gcol, w, h);
1684 class ColorEditor extends AbstractCellEditor
1685 implements TableCellEditor, ActionListener
1689 FeatureColourI currentColor;
1691 FeatureTypeSettings chooser;
1697 protected static final String EDIT = "edit";
1699 int rowSelected = 0;
1701 public ColorEditor(FeatureSettings fs)
1704 // Set up the editor (from the table's point of view),
1705 // which is a button.
1706 // This button brings up the color chooser dialog,
1707 // which is the editor from the user's point of view.
1708 button = new JButton();
1709 button.setActionCommand(EDIT);
1710 button.addActionListener(this);
1711 button.setBorderPainted(false);
1715 * Handles events from the editor button, and from the colour/filters
1716 * dialog's OK button
1719 public void actionPerformed(ActionEvent e)
1721 if (button == e.getSource())
1723 if (currentColor.isSimpleColour())
1726 * simple colour chooser
1728 String ttl = MessageManager.formatMessage("label.select_colour_for", type);
1729 ColourChooserListener listener = new ColourChooserListener()
1732 public void colourSelected(Color c)
1734 currentColor = new FeatureColour(c);
1735 me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1736 fireEditingStopped();
1739 public void cancel()
1741 fireEditingStopped();
1744 JalviewColourChooser.showColourChooser(button, ttl, currentColor.getColour(), listener);
1749 * variable colour and filters dialog
1751 chooser = new FeatureTypeSettings(me.fr, type);
1752 if (!Jalview.isJS())
1754 chooser.setRequestFocusEnabled(true);
1755 chooser.requestFocus();
1757 chooser.addActionListener(this);
1758 fireEditingStopped();
1764 * after OK in variable colour dialog, any changes to colour
1765 * (or filters!) are already set in FeatureRenderer, so just
1766 * update table data without triggering updateFeatureRenderer
1768 currentColor = fr.getFeatureColours().get(type);
1769 FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
1770 if (currentFilter == null)
1772 currentFilter = new FeatureMatcherSet();
1774 Object[] data = ((FeatureTableModel) table.getModel())
1775 .getData()[rowSelected];
1776 data[COLOUR_COLUMN] = currentColor;
1777 data[FILTER_COLUMN] = currentFilter;
1779 fireEditingStopped();
1780 me.table.validate();
1784 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1786 public Object getCellEditorValue()
1788 return currentColor;
1791 // Implement the one method defined by TableCellEditor.
1793 public Component getTableCellEditorComponent(JTable theTable, Object value,
1794 boolean isSelected, int row, int column)
1796 currentColor = (FeatureColourI) value;
1797 this.rowSelected = row;
1798 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1799 button.setOpaque(true);
1800 button.setBackground(me.getBackground());
1801 if (!currentColor.isSimpleColour())
1803 JLabel btn = new JLabel();
1804 btn.setSize(button.getSize());
1805 FeatureSettings.renderGraduatedColor(btn, currentColor);
1806 button.setBackground(btn.getBackground());
1807 button.setIcon(btn.getIcon());
1808 button.setText(btn.getText());
1813 button.setIcon(null);
1814 button.setBackground(currentColor.getColour());
1821 * The cell editor for the Filter column. It displays the text of any filters
1822 * for the feature type in that row (in full as a tooltip, possible abbreviated
1823 * as display text). On click in the cell, opens the Feature Display Settings
1824 * dialog at the Filters tab.
1826 class FilterEditor extends AbstractCellEditor
1827 implements TableCellEditor, ActionListener
1831 FeatureMatcherSetI currentFilter;
1839 protected static final String EDIT = "edit";
1841 int rowSelected = 0;
1843 public FilterEditor(FeatureSettings me)
1846 button = new JButton();
1847 button.setActionCommand(EDIT);
1848 button.addActionListener(this);
1849 button.setBorderPainted(false);
1853 * Handles events from the editor button
1856 public void actionPerformed(ActionEvent e)
1858 if (button == e.getSource())
1860 FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
1861 chooser.addActionListener(this);
1862 chooser.setRequestFocusEnabled(true);
1863 chooser.requestFocus();
1864 if (lastLocation != null)
1866 // todo open at its last position on screen
1867 chooser.setBounds(lastLocation.x, lastLocation.y,
1868 chooser.getWidth(), chooser.getHeight());
1871 fireEditingStopped();
1873 else if (e.getSource() instanceof Component)
1877 * after OK in variable colour dialog, any changes to filter
1878 * (or colours!) are already set in FeatureRenderer, so just
1879 * update table data without triggering updateFeatureRenderer
1881 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1882 currentFilter = me.fr.getFeatureFilter(type);
1883 if (currentFilter == null)
1885 currentFilter = new FeatureMatcherSet();
1887 Object[] data = ((FeatureTableModel) table.getModel())
1888 .getData()[rowSelected];
1889 data[COLOUR_COLUMN] = currentColor;
1890 data[FILTER_COLUMN] = currentFilter;
1891 fireEditingStopped();
1892 me.table.validate();
1897 public Object getCellEditorValue()
1899 return currentFilter;
1903 public Component getTableCellEditorComponent(JTable theTable, Object value,
1904 boolean isSelected, int row, int column)
1906 currentFilter = (FeatureMatcherSetI) value;
1907 this.rowSelected = row;
1908 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1909 button.setOpaque(true);
1910 button.setBackground(me.getBackground());
1911 button.setText(currentFilter.toString());
1912 button.setIcon(null);
1918 class FeatureIcon implements Icon
1920 FeatureColourI gcol;
1924 boolean midspace = false;
1926 int width = 50, height = 20;
1928 int s1, e1; // start and end of midpoint band for thresholded symbol
1930 Color mpcolour = Color.white;
1932 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1952 public int getIconWidth()
1958 public int getIconHeight()
1964 public void paintIcon(Component c, Graphics g, int x, int y)
1967 if (gcol.isColourByLabel())
1970 g.fillRect(0, 0, width, height);
1971 // need an icon here.
1972 g.setColor(gcol.getMaxColour());
1974 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1976 // g.setFont(g.getFont().deriveFont(
1977 // AffineTransform.getScaleInstance(
1978 // width/g.getFontMetrics().stringWidth("Label"),
1979 // height/g.getFontMetrics().getHeight())));
1981 g.drawString(MessageManager.getString("label.label"), 0, 0);
1986 Color minCol = gcol.getMinColour();
1988 g.fillRect(0, 0, s1, height);
1991 g.setColor(Color.white);
1992 g.fillRect(s1, 0, e1 - s1, height);
1994 g.setColor(gcol.getMaxColour());
1995 // g.fillRect(0, e1, width - e1, height); // BH 2018
1996 g.fillRect(e1, 0, width - e1, height);