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 popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
299 else if (evt.getClickCount() == 2)
301 boolean invertSelection = evt.isAltDown();
302 boolean toggleSelection = Platform.isControlDown(evt);
303 boolean extendSelection = evt.isShiftDown();
304 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
305 invertSelection, extendSelection, toggleSelection, type);
309 // isPopupTrigger fires on mouseReleased on Windows
311 public void mouseReleased(MouseEvent evt)
313 selectedRow = table.rowAtPoint(evt.getPoint());
314 if (evt.isPopupTrigger())
316 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
317 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
318 popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
324 table.addMouseMotionListener(new MouseMotionAdapter()
327 public void mouseDragged(MouseEvent evt)
329 int newRow = table.rowAtPoint(evt.getPoint());
330 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
333 * reposition 'selectedRow' to 'newRow' (the dragged to location)
334 * this could be more than one row away for a very fast drag action
335 * so just swap it with adjacent rows until we get it there
337 Object[][] data = ((FeatureTableModel) table.getModel())
339 int direction = newRow < selectedRow ? -1 : 1;
340 for (int i = selectedRow; i != newRow; i += direction)
342 Object[] temp = data[i];
343 data[i] = data[i + direction];
344 data[i + direction] = temp;
346 updateFeatureRenderer(data);
348 selectedRow = newRow;
352 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
353 // MessageManager.getString("label.feature_settings_click_drag")));
354 scrollPane.setViewportView(table);
356 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
358 fr.findAllFeatures(true); // display everything!
361 discoverAllFeatureData();
362 final PropertyChangeListener change;
363 final FeatureSettings fs = this;
364 fr.addPropertyChangeListener(change = new PropertyChangeListener()
367 public void propertyChange(PropertyChangeEvent evt)
369 if (!fs.resettingTable && !fs.handlingUpdate)
371 fs.handlingUpdate = true;
373 // new groups may be added with new sequence feature types only
374 fs.handlingUpdate = false;
380 frame = new JInternalFrame();
381 frame.setContentPane(this);
382 if (Platform.isAMac())
384 Desktop.addInternalFrame(frame,
385 MessageManager.getString("label.sequence_feature_settings"),
390 Desktop.addInternalFrame(frame,
391 MessageManager.getString("label.sequence_feature_settings"),
394 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
396 frame.addInternalFrameListener(
397 new javax.swing.event.InternalFrameAdapter()
400 public void internalFrameClosed(
401 javax.swing.event.InternalFrameEvent evt)
403 fr.removePropertyChangeListener(change);
406 frame.setLayer(JLayeredPane.PALETTE_LAYER);
407 inConstruction = false;
410 protected void popupSort(final int rowSelected, final String type,
411 final Object typeCol, final Map<String, float[][]> minmax, int x,
414 final FeatureColourI featureColour = (FeatureColourI) typeCol;
416 JPopupMenu men = new JPopupMenu(MessageManager
417 .formatMessage("label.settings_for_param", new String[]
419 JMenuItem scr = new JMenuItem(
420 MessageManager.getString("label.sort_by_score"));
422 final FeatureSettings me = this;
423 scr.addActionListener(new ActionListener()
427 public void actionPerformed(ActionEvent e)
430 .sortAlignmentByFeatureScore(Arrays.asList(new String[]
435 JMenuItem dens = new JMenuItem(
436 MessageManager.getString("label.sort_by_density"));
437 dens.addActionListener(new ActionListener()
441 public void actionPerformed(ActionEvent e)
444 .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
452 * variable colour options include colour by label, by score,
453 * by selected attribute text, or attribute value
455 final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
456 MessageManager.getString("label.variable_colour"));
457 variableColourCB.setSelected(!featureColour.isSimpleColour());
458 men.add(variableColourCB);
461 * checkbox action listener doubles up as listener to OK
462 * from the variable colour / filters dialog
464 variableColourCB.addActionListener(new ActionListener()
467 public void actionPerformed(ActionEvent e)
469 if (e.getSource() == variableColourCB)
471 if (featureColour.isSimpleColour())
474 * toggle simple colour to variable colour - show dialog
476 FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type);
477 fc.addActionListener(this);
482 * toggle variable to simple colour - show colour chooser
484 String title = MessageManager.getString("label.select_colour");
485 ColourChooserListener listener = new ColourChooserListener()
488 public void colourSelected(Color c)
490 table.setValueAt(new FeatureColour(c), rowSelected,
493 me.updateFeatureRenderer(
494 ((FeatureTableModel) table.getModel()).getData(),
498 JalviewColourChooser.showColourChooser(me, title, featureColour.getMaxColour(), listener);
502 if (e.getSource() instanceof FeatureTypeSettings)
505 * update after OK in feature colour dialog; the updated
506 * colour will have already been set in the FeatureRenderer
508 FeatureColourI fci = fr.getFeatureColours().get(type);
509 table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
517 JMenuItem selCols = new JMenuItem(
518 MessageManager.getString("label.select_columns_containing"));
519 selCols.addActionListener(new ActionListener()
522 public void actionPerformed(ActionEvent arg0)
524 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
528 JMenuItem clearCols = new JMenuItem(MessageManager
529 .getString("label.select_columns_not_containing"));
530 clearCols.addActionListener(new ActionListener()
533 public void actionPerformed(ActionEvent arg0)
535 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
539 JMenuItem hideCols = new JMenuItem(
540 MessageManager.getString("label.hide_columns_containing"));
541 hideCols.addActionListener(new ActionListener()
544 public void actionPerformed(ActionEvent arg0)
546 fr.ap.alignFrame.hideFeatureColumns(type, true);
549 JMenuItem hideOtherCols = new JMenuItem(
550 MessageManager.getString("label.hide_columns_not_containing"));
551 hideOtherCols.addActionListener(new ActionListener()
554 public void actionPerformed(ActionEvent arg0)
556 fr.ap.alignFrame.hideFeatureColumns(type, false);
562 men.add(hideOtherCols);
563 men.show(table, x, y);
567 synchronized public void discoverAllFeatureData()
569 Set<String> allGroups = new HashSet<>();
570 AlignmentI alignment = af.getViewport().getAlignment();
572 for (int i = 0; i < alignment.getHeight(); i++)
574 SequenceI seq = alignment.getSequenceAt(i);
575 for (String group : seq.getFeatures().getFeatureGroups(true))
577 if (group != null && !allGroups.contains(group))
579 allGroups.add(group);
580 checkGroupState(group);
591 * Synchronise gui group list and check visibility of group
594 * @return true if group is visible
596 private boolean checkGroupState(String group)
598 boolean visible = fr.checkGroupVisibility(group, true);
600 for (int g = 0; g < groupPanel.getComponentCount(); g++)
602 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
604 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
609 final String grp = group;
610 final JCheckBox check = new JCheckBox(group, visible);
611 check.setFont(new Font("Serif", Font.BOLD, 12));
612 check.setToolTipText(group);
613 check.addItemListener(new ItemListener()
616 public void itemStateChanged(ItemEvent evt)
618 fr.setGroupVisibility(check.getText(), check.isSelected());
619 resetTable(new String[] { grp });
620 af.alignPanel.paintAlignment(true, true);
623 groupPanel.add(check);
627 synchronized void resetTable(String[] groupChanged)
633 resettingTable = true;
634 typeWidth = new Hashtable<>();
635 // TODO: change avWidth calculation to 'per-sequence' average and use long
638 Set<String> displayableTypes = new HashSet<>();
639 Set<String> foundGroups = new HashSet<>();
642 * determine which feature types may be visible depending on
643 * which groups are selected, and recompute average width data
645 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
648 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
651 * get the sequence's groups for positional features
652 * and keep track of which groups are visible
654 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
655 Set<String> visibleGroups = new HashSet<>();
656 for (String group : groups)
658 if (group == null || checkGroupState(group))
660 visibleGroups.add(group);
663 foundGroups.addAll(groups);
666 * get distinct feature types for visible groups
667 * record distinct visible types, and their count and total length
669 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
670 visibleGroups.toArray(new String[visibleGroups.size()]));
671 for (String type : types)
673 displayableTypes.add(type);
674 float[] avWidth = typeWidth.get(type);
677 avWidth = new float[2];
678 typeWidth.put(type, avWidth);
680 // todo this could include features with a non-visible group
681 // - do we greatly care?
682 // todo should we include non-displayable features here, and only
683 // update when features are added?
684 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
685 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
689 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
692 if (fr.hasRenderOrder())
696 fr.findAllFeatures(groupChanged != null); // prod to update
697 // colourschemes. but don't
699 // First add the checks in the previous render order,
700 // in case the window has been closed and reopened
702 List<String> frl = fr.getRenderOrder();
703 for (int ro = frl.size() - 1; ro > -1; ro--)
705 String type = frl.get(ro);
707 if (!displayableTypes.contains(type))
712 data[dataIndex][TYPE_COLUMN] = type;
713 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
714 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
715 data[dataIndex][FILTER_COLUMN] = featureFilter == null
716 ? new FeatureMatcherSet()
718 data[dataIndex][SHOW_COLUMN] = new Boolean(
719 af.getViewport().getFeaturesDisplayed().isVisible(type));
721 displayableTypes.remove(type);
726 * process any extra features belonging only to
727 * a group which was just selected
729 while (!displayableTypes.isEmpty())
731 String type = displayableTypes.iterator().next();
732 data[dataIndex][TYPE_COLUMN] = type;
734 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
735 if (data[dataIndex][COLOUR_COLUMN] == null)
737 // "Colour has been updated in another view!!"
738 fr.clearRenderOrder();
741 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
742 data[dataIndex][FILTER_COLUMN] = featureFilter == null
743 ? new FeatureMatcherSet()
745 data[dataIndex][SHOW_COLUMN] = new Boolean(true);
747 displayableTypes.remove(type);
750 if (originalData == null)
752 originalData = new Object[data.length][COLUMN_COUNT];
753 for (int i = 0; i < data.length; i++)
755 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
760 updateOriginalData(data);
763 table.setModel(new FeatureTableModel(data));
764 table.getColumnModel().getColumn(0).setPreferredWidth(200);
766 groupPanel.setLayout(
767 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
768 pruneGroups(foundGroups);
769 groupPanel.validate();
771 updateFeatureRenderer(data, groupChanged != null);
772 resettingTable = false;
776 * Updates 'originalData' (used for restore on Cancel) if we detect that changes
777 * have been made outwith this dialog
779 * <li>a new feature type added (and made visible)</li>
780 * <li>a feature colour changed (in the Amend Features dialog)</li>
785 protected void updateOriginalData(Object[][] foundData)
787 // todo LinkedHashMap instead of Object[][] would be nice
789 Object[][] currentData = ((FeatureTableModel) table.getModel())
791 for (Object[] row : foundData)
793 String type = (String) row[TYPE_COLUMN];
794 boolean found = false;
795 for (Object[] current : currentData)
797 if (type.equals(current[TYPE_COLUMN]))
801 * currently dependent on object equality here;
802 * really need an equals method on FeatureColour
804 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
807 * feature colour has changed externally - update originalData
809 for (Object[] original : originalData)
811 if (type.equals(original[TYPE_COLUMN]))
813 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
824 * new feature detected - add to original data (on top)
826 Object[][] newData = new Object[originalData.length
828 for (int i = 0; i < originalData.length; i++)
830 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
834 originalData = newData;
840 * Remove from the groups panel any checkboxes for groups that are not in the
841 * foundGroups set. This enables removing a group from the display when the last
842 * feature in that group is deleted.
846 protected void pruneGroups(Set<String> foundGroups)
848 for (int g = 0; g < groupPanel.getComponentCount(); g++)
850 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
851 if (!foundGroups.contains(checkbox.getText()))
853 groupPanel.remove(checkbox);
859 * reorder data based on the featureRenderers global priority list.
863 private void ensureOrder(Object[][] data)
865 boolean sort = false;
866 float[] order = new float[data.length];
867 for (int i = 0; i < order.length; i++)
869 order[i] = fr.getOrder(data[i][0].toString());
872 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
876 sort = sort || order[i - 1] > order[i];
881 jalview.util.QuickSort.sort(order, data);
886 * Offers a file chooser dialog, and then loads the feature colours and
887 * filters from file in XML format and unmarshals to Jalview feature settings
891 JalviewFileChooser chooser = new JalviewFileChooser("fc",
892 SEQUENCE_FEATURE_COLOURS);
893 chooser.setFileView(new JalviewFileView());
894 chooser.setDialogTitle(
895 MessageManager.getString("label.load_feature_colours"));
896 chooser.setToolTipText(MessageManager.getString("action.load"));
897 chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION){
901 File file = chooser.getSelectedFile();
904 chooser.showOpenDialog(this);
908 * Loads feature colours and filters from XML stored in the given file
916 InputStreamReader in = new InputStreamReader(
917 new FileInputStream(file), "UTF-8");
919 JAXBContext jc = JAXBContext
920 .newInstance("jalview.xml.binding.jalview");
921 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
922 XMLStreamReader streamReader = XMLInputFactory.newInstance()
923 .createXMLStreamReader(in);
924 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
925 JalviewUserColours.class);
926 JalviewUserColours jucs = jbe.getValue();
928 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
931 * load feature colours
933 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
935 Colour newcol = jucs.getColour().get(i);
936 FeatureColourI colour = jalview.project.Jalview2XML
937 .parseColour(newcol);
938 fr.setColour(newcol.getName(), colour);
939 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
943 * load feature filters; loaded filters will replace any that are
944 * currently defined, other defined filters are left unchanged
946 for (int i = 0; i < jucs.getFilter().size(); i++)
948 Filter filterModel = jucs.getFilter().get(i);
949 String featureType = filterModel.getFeatureType();
950 FeatureMatcherSetI filter = jalview.project.Jalview2XML
951 .parseFilter(featureType, filterModel.getMatcherSet());
952 if (!filter.isEmpty())
954 fr.setFeatureFilter(featureType, filter);
959 * update feature settings table
964 Object[][] data = ((FeatureTableModel) table.getModel())
967 updateFeatureRenderer(data, false);
970 } catch (Exception ex)
972 System.out.println("Error loading User Colour File\n" + ex);
977 * Offers a file chooser dialog, and then saves the current feature colours
978 * and any filters to the selected file in XML format
982 JalviewFileChooser chooser = new JalviewFileChooser("fc",
983 SEQUENCE_FEATURE_COLOURS);
984 chooser.setFileView(new JalviewFileView());
985 chooser.setDialogTitle(
986 MessageManager.getString("label.save_feature_colours"));
987 chooser.setToolTipText(MessageManager.getString("action.save"));
988 int option = chooser.showSaveDialog(this);
989 if (option == JalviewFileChooser.APPROVE_OPTION)
991 File file = chooser.getSelectedFile();
997 * Saves feature colours and filters to the given file
1001 void save(File file)
1003 JalviewUserColours ucs = new JalviewUserColours();
1004 ucs.setSchemeName("Sequence Features");
1007 PrintWriter out = new PrintWriter(new OutputStreamWriter(
1008 new FileOutputStream(file), "UTF-8"));
1011 * sort feature types by colour order, from 0 (highest)
1014 Set<String> fr_colours = fr.getAllFeatureColours();
1015 String[] sortedTypes = fr_colours
1016 .toArray(new String[fr_colours.size()]);
1017 Arrays.sort(sortedTypes, new Comparator<String>()
1020 public int compare(String type1, String type2)
1022 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
1027 * save feature colours
1029 for (String featureType : sortedTypes)
1031 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1032 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
1034 ucs.getColour().add(col);
1038 * save any feature filters
1040 for (String featureType : sortedTypes)
1042 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1043 if (filter != null && !filter.isEmpty())
1045 Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
1046 FeatureMatcherI firstMatcher = iterator.next();
1047 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
1048 .marshalFilter(firstMatcher, iterator,
1050 Filter filterModel = new Filter();
1051 filterModel.setFeatureType(featureType);
1052 filterModel.setMatcherSet(ms);
1053 ucs.getFilter().add(filterModel);
1056 JAXBContext jaxbContext = JAXBContext
1057 .newInstance(JalviewUserColours.class);
1058 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1059 jaxbMarshaller.marshal(
1060 new ObjectFactory().createJalviewUserColours(ucs), out);
1062 // jaxbMarshaller.marshal(object, pout);
1063 // marshaller.marshal(object);
1066 // ucs.marshal(out);
1068 } catch (Exception ex)
1070 ex.printStackTrace();
1074 public void invertSelection()
1076 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1077 for (int i = 0; i < data.length; i++)
1079 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1081 updateFeatureRenderer(data, true);
1085 public void orderByAvWidth()
1087 if (table == null || table.getModel() == null)
1091 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1092 float[] width = new float[data.length];
1096 for (int i = 0; i < data.length; i++)
1098 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1101 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1102 // weight - but have to make per
1103 // sequence, too (awidth[2])
1104 // if (width[i]==1) // hack to distinguish single width sequences.
1115 boolean sort = false;
1116 for (int i = 0; i < width.length; i++)
1118 // awidth = (float[]) typeWidth.get(data[i][0]);
1121 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1124 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1130 width[i] /= max; // normalize
1131 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
1135 sort = sort || width[i - 1] > width[i];
1140 jalview.util.QuickSort.sort(width, data);
1141 // update global priority order
1144 updateFeatureRenderer(data, false);
1149 * Repaints the table using alternative code for Java and J2S
1151 private void repaintTable()
1154 // Here is a needed intervention
1155 // because generally we don't "repaint"
1156 // the table. We re-create the HTML divs
1157 // that is associated with it. A better
1158 // way to do this would be to fire a property change.
1159 @SuppressWarnings("unused")
1160 TableUI ui = table.getUI();
1162 * @j2sNative ui.repaintTable$();
1173 frame.setClosed(true);
1174 } catch (Exception exe)
1180 public void updateFeatureRenderer(Object[][] data)
1182 updateFeatureRenderer(data, true);
1186 * Update the priority order of features; only repaint if this changed the order
1187 * of visible features
1192 void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1194 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1196 if (fr.setFeaturePriority(rowData, visibleNew))
1198 af.alignPanel.paintAlignment(true, true);
1203 * Converts table data into an array of data beans
1205 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1207 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1208 for (int i = 0; i < data.length; i++)
1210 String type = (String) data[i][TYPE_COLUMN];
1211 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1212 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1213 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1214 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1220 private void jbInit() throws Exception
1222 this.setLayout(new BorderLayout());
1224 JPanel settingsPane = new JPanel();
1225 settingsPane.setLayout(new BorderLayout());
1227 JPanel bigPanel = new JPanel();
1228 bigPanel.setLayout(new BorderLayout());
1230 groupPanel = new JPanel();
1231 bigPanel.add(groupPanel, BorderLayout.NORTH);
1233 JButton invert = new JButton(
1234 MessageManager.getString("label.invert_selection"));
1235 invert.setFont(JvSwingUtils.getLabelFont());
1236 invert.addActionListener(new ActionListener()
1239 public void actionPerformed(ActionEvent e)
1245 JButton optimizeOrder = new JButton(
1246 MessageManager.getString("label.optimise_order"));
1247 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1248 optimizeOrder.addActionListener(new ActionListener()
1251 public void actionPerformed(ActionEvent e)
1257 JButton sortByScore = new JButton(
1258 MessageManager.getString("label.seq_sort_by_score"));
1259 sortByScore.setFont(JvSwingUtils.getLabelFont());
1260 sortByScore.addActionListener(new ActionListener()
1263 public void actionPerformed(ActionEvent e)
1265 af.avc.sortAlignmentByFeatureScore(null);
1268 JButton sortByDens = new JButton(
1269 MessageManager.getString("label.sequence_sort_by_density"));
1270 sortByDens.setFont(JvSwingUtils.getLabelFont());
1271 sortByDens.addActionListener(new ActionListener()
1274 public void actionPerformed(ActionEvent e)
1276 af.avc.sortAlignmentByFeatureDensity(null);
1280 JButton help = new JButton(MessageManager.getString("action.help"));
1281 help.setFont(JvSwingUtils.getLabelFont());
1282 help.addActionListener(new ActionListener()
1285 public void actionPerformed(ActionEvent e)
1289 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1290 } catch (HelpSetException e1)
1292 e1.printStackTrace();
1296 help.setFont(JvSwingUtils.getLabelFont());
1297 help.setText(MessageManager.getString("action.help"));
1298 help.addActionListener(new ActionListener()
1301 public void actionPerformed(ActionEvent e)
1305 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1306 } catch (HelpSetException e1)
1308 e1.printStackTrace();
1313 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1314 cancel.setFont(JvSwingUtils.getLabelFont());
1315 cancel.addActionListener(new ActionListener()
1318 public void actionPerformed(ActionEvent e)
1320 fr.setTransparency(originalTransparency);
1321 fr.setFeatureFilters(originalFilters);
1322 updateFeatureRenderer(originalData);
1327 JButton ok = new JButton(MessageManager.getString("action.ok"));
1328 ok.setFont(JvSwingUtils.getLabelFont());
1329 ok.addActionListener(new ActionListener()
1332 public void actionPerformed(ActionEvent e)
1338 JButton loadColours = new JButton(
1339 MessageManager.getString("label.load_colours"));
1340 loadColours.setFont(JvSwingUtils.getLabelFont());
1341 loadColours.setToolTipText(
1342 MessageManager.getString("label.load_colours_tooltip"));
1343 loadColours.addActionListener(new ActionListener()
1346 public void actionPerformed(ActionEvent e)
1352 JButton saveColours = new JButton(
1353 MessageManager.getString("label.save_colours"));
1354 saveColours.setFont(JvSwingUtils.getLabelFont());
1355 saveColours.setToolTipText(
1356 MessageManager.getString("label.save_colours_tooltip"));
1357 saveColours.addActionListener(new ActionListener()
1360 public void actionPerformed(ActionEvent e)
1365 transparency.addChangeListener(new ChangeListener()
1368 public void stateChanged(ChangeEvent evt)
1370 if (!inConstruction)
1372 fr.setTransparency((100 - transparency.getValue()) / 100f);
1373 af.alignPanel.paintAlignment(true, true);
1378 transparency.setMaximum(70);
1379 transparency.setToolTipText(
1380 MessageManager.getString("label.transparency_tip"));
1382 JPanel transPanel = new JPanel(new GridLayout(1, 2));
1383 bigPanel.add(transPanel, BorderLayout.SOUTH);
1385 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1386 transbuttons.add(optimizeOrder);
1387 transbuttons.add(invert);
1388 transbuttons.add(sortByScore);
1389 transbuttons.add(sortByDens);
1390 transbuttons.add(help);
1391 transPanel.add(transparency);
1392 transPanel.add(transbuttons);
1394 JPanel buttonPanel = new JPanel();
1395 buttonPanel.add(ok);
1396 buttonPanel.add(cancel);
1397 buttonPanel.add(loadColours);
1398 buttonPanel.add(saveColours);
1399 bigPanel.add(scrollPane, BorderLayout.CENTER);
1400 settingsPane.add(bigPanel, BorderLayout.CENTER);
1401 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1402 this.add(settingsPane);
1406 * Answers a suitable tooltip to show on the colour cell of the table
1410 * if true include 'click to edit' and similar text
1413 public static String getColorTooltip(FeatureColourI fcol,
1420 if (fcol.isSimpleColour())
1422 return withHint ? BASE_TOOLTIP : null;
1424 String description = fcol.getDescription();
1425 description = description.replaceAll("<", "<");
1426 description = description.replaceAll(">", ">");
1427 StringBuilder tt = new StringBuilder(description);
1430 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1432 return JvSwingUtils.wrapTooltip(true, tt.toString());
1435 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1438 boolean thr = false;
1439 StringBuilder tx = new StringBuilder();
1441 if (gcol.isColourByAttribute())
1443 tx.append(FeatureMatcher
1444 .toAttributeDisplayName(gcol.getAttributeName()));
1446 else if (!gcol.isColourByLabel())
1448 tx.append(MessageManager.getString("label.score"));
1451 if (gcol.isAboveThreshold())
1456 if (gcol.isBelowThreshold())
1461 if (gcol.isColourByLabel())
1467 if (!gcol.isColourByAttribute())
1475 Color newColor = gcol.getMaxColour();
1476 comp.setBackground(newColor);
1477 // System.err.println("Width is " + w / 2);
1478 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1479 comp.setIcon(ficon);
1480 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1481 // + newColor.getGreen() + ", " + newColor.getBlue()
1482 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1483 // + ", " + minCol.getBlue() + ")");
1485 comp.setHorizontalAlignment(SwingConstants.CENTER);
1486 comp.setText(tx.toString());
1489 // ///////////////////////////////////////////////////////////////////////
1490 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1491 // ///////////////////////////////////////////////////////////////////////
1492 class FeatureTableModel extends AbstractTableModel
1494 private String[] columnNames = {
1495 MessageManager.getString("label.feature_type"),
1496 MessageManager.getString("action.colour"),
1497 MessageManager.getString("label.filter"),
1498 MessageManager.getString("label.show") };
1500 private Object[][] data;
1502 FeatureTableModel(Object[][] data)
1507 public Object[][] getData()
1512 public void setData(Object[][] data)
1518 public int getColumnCount()
1520 return columnNames.length;
1523 public Object[] getRow(int row)
1529 public int getRowCount()
1535 public String getColumnName(int col)
1537 return columnNames[col];
1541 public Object getValueAt(int row, int col)
1543 return data[row][col];
1547 * Answers the class of the object in column c of the first row of the table
1550 public Class<?> getColumnClass(int c)
1552 Object v = getValueAt(0, c);
1553 return v == null ? null : v.getClass();
1557 public boolean isCellEditable(int row, int col)
1559 return col == 0 ? false : true;
1563 public void setValueAt(Object value, int row, int col)
1565 data[row][col] = value;
1566 fireTableCellUpdated(row, col);
1567 updateFeatureRenderer(data);
1572 class ColorRenderer extends JLabel implements TableCellRenderer
1574 Border unselectedBorder = null;
1576 Border selectedBorder = null;
1578 public ColorRenderer()
1580 setOpaque(true); // MUST do this for background to show up.
1581 setHorizontalTextPosition(SwingConstants.CENTER);
1582 setVerticalTextPosition(SwingConstants.CENTER);
1586 public Component getTableCellRendererComponent(JTable tbl, Object color,
1587 boolean isSelected, boolean hasFocus, int row, int column)
1589 FeatureColourI cellColour = (FeatureColourI) color;
1591 setBackground(tbl.getBackground());
1592 if (!cellColour.isSimpleColour())
1594 Rectangle cr = tbl.getCellRect(row, column, false);
1595 FeatureSettings.renderGraduatedColor(this, cellColour,
1596 (int) cr.getWidth(), (int) cr.getHeight());
1602 setBackground(cellColour.getColour());
1606 if (selectedBorder == null)
1608 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1609 tbl.getSelectionBackground());
1611 setBorder(selectedBorder);
1615 if (unselectedBorder == null)
1617 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1618 tbl.getBackground());
1620 setBorder(unselectedBorder);
1627 class FilterRenderer extends JLabel implements TableCellRenderer
1629 javax.swing.border.Border unselectedBorder = null;
1631 javax.swing.border.Border selectedBorder = null;
1633 public FilterRenderer()
1635 setOpaque(true); // MUST do this for background to show up.
1636 setHorizontalTextPosition(SwingConstants.CENTER);
1637 setVerticalTextPosition(SwingConstants.CENTER);
1641 public Component getTableCellRendererComponent(JTable tbl,
1642 Object filter, boolean isSelected, boolean hasFocus, int row,
1645 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1647 String asText = theFilter.toString();
1648 setBackground(tbl.getBackground());
1649 this.setText(asText);
1654 if (selectedBorder == null)
1656 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1657 tbl.getSelectionBackground());
1659 setBorder(selectedBorder);
1663 if (unselectedBorder == null)
1665 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1666 tbl.getBackground());
1668 setBorder(unselectedBorder);
1676 * update comp using rendering settings from gcol
1681 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1683 int w = comp.getWidth(), h = comp.getHeight();
1686 w = (int) comp.getPreferredSize().getWidth();
1687 h = (int) comp.getPreferredSize().getHeight();
1694 renderGraduatedColor(comp, gcol, w, h);
1697 class ColorEditor extends AbstractCellEditor
1698 implements TableCellEditor, ActionListener
1702 FeatureColourI currentColor;
1704 FeatureTypeSettings chooser;
1710 protected static final String EDIT = "edit";
1712 int rowSelected = 0;
1714 public ColorEditor(FeatureSettings fs)
1717 // Set up the editor (from the table's point of view),
1718 // which is a button.
1719 // This button brings up the color chooser dialog,
1720 // which is the editor from the user's point of view.
1721 button = new JButton();
1722 button.setActionCommand(EDIT);
1723 button.addActionListener(this);
1724 button.setBorderPainted(false);
1728 * Handles events from the editor button, and from the colour/filters
1729 * dialog's OK button
1732 public void actionPerformed(ActionEvent e)
1734 if (button == e.getSource())
1736 if (currentColor.isSimpleColour())
1739 * simple colour chooser
1741 String ttl = MessageManager.getString("label.select_colour");
1742 ColourChooserListener listener = new ColourChooserListener() {
1744 public void colourSelected(Color c)
1746 currentColor = new FeatureColour(c);
1747 me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1750 JalviewColourChooser.showColourChooser(button, ttl, currentColor.getColour(), listener);
1755 * variable colour and filters dialog
1757 chooser = new FeatureTypeSettings(me.fr, type);
1758 if (!Jalview.isJS())
1760 chooser.setRequestFocusEnabled(true);
1761 chooser.requestFocus();
1763 chooser.addActionListener(this);
1764 // Make the renderer reappear.
1765 fireEditingStopped();
1771 * after OK in variable colour dialog, any changes to colour
1772 * (or filters!) are already set in FeatureRenderer, so just
1773 * update table data without triggering updateFeatureRenderer
1775 currentColor = fr.getFeatureColours().get(type);
1776 FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
1777 if (currentFilter == null)
1779 currentFilter = new FeatureMatcherSet();
1781 Object[] data = ((FeatureTableModel) table.getModel())
1782 .getData()[rowSelected];
1783 data[COLOUR_COLUMN] = currentColor;
1784 data[FILTER_COLUMN] = currentFilter;
1786 fireEditingStopped();
1787 me.table.validate();
1791 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1793 public Object getCellEditorValue()
1795 return currentColor;
1798 // Implement the one method defined by TableCellEditor.
1800 public Component getTableCellEditorComponent(JTable theTable, Object value,
1801 boolean isSelected, int row, int column)
1803 currentColor = (FeatureColourI) value;
1804 this.rowSelected = row;
1805 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1806 button.setOpaque(true);
1807 button.setBackground(me.getBackground());
1808 if (!currentColor.isSimpleColour())
1810 JLabel btn = new JLabel();
1811 btn.setSize(button.getSize());
1812 FeatureSettings.renderGraduatedColor(btn, currentColor);
1813 button.setBackground(btn.getBackground());
1814 button.setIcon(btn.getIcon());
1815 button.setText(btn.getText());
1820 button.setIcon(null);
1821 button.setBackground(currentColor.getColour());
1828 * The cell editor for the Filter column. It displays the text of any filters
1829 * for the feature type in that row (in full as a tooltip, possible abbreviated
1830 * as display text). On click in the cell, opens the Feature Display Settings
1831 * dialog at the Filters tab.
1833 class FilterEditor extends AbstractCellEditor
1834 implements TableCellEditor, ActionListener
1838 FeatureMatcherSetI currentFilter;
1846 protected static final String EDIT = "edit";
1848 int rowSelected = 0;
1850 public FilterEditor(FeatureSettings me)
1853 button = new JButton();
1854 button.setActionCommand(EDIT);
1855 button.addActionListener(this);
1856 button.setBorderPainted(false);
1860 * Handles events from the editor button
1863 public void actionPerformed(ActionEvent e)
1865 if (button == e.getSource())
1867 FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
1868 chooser.addActionListener(this);
1869 chooser.setRequestFocusEnabled(true);
1870 chooser.requestFocus();
1871 if (lastLocation != null)
1873 // todo open at its last position on screen
1874 chooser.setBounds(lastLocation.x, lastLocation.y,
1875 chooser.getWidth(), chooser.getHeight());
1878 fireEditingStopped();
1880 else if (e.getSource() instanceof Component)
1884 * after OK in variable colour dialog, any changes to filter
1885 * (or colours!) are already set in FeatureRenderer, so just
1886 * update table data without triggering updateFeatureRenderer
1888 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1889 currentFilter = me.fr.getFeatureFilter(type);
1890 if (currentFilter == null)
1892 currentFilter = new FeatureMatcherSet();
1894 Object[] data = ((FeatureTableModel) table.getModel())
1895 .getData()[rowSelected];
1896 data[COLOUR_COLUMN] = currentColor;
1897 data[FILTER_COLUMN] = currentFilter;
1898 fireEditingStopped();
1899 me.table.validate();
1904 public Object getCellEditorValue()
1906 return currentFilter;
1910 public Component getTableCellEditorComponent(JTable theTable, Object value,
1911 boolean isSelected, int row, int column)
1913 currentFilter = (FeatureMatcherSetI) value;
1914 this.rowSelected = row;
1915 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1916 button.setOpaque(true);
1917 button.setBackground(me.getBackground());
1918 button.setText(currentFilter.toString());
1919 button.setIcon(null);
1925 class FeatureIcon implements Icon
1927 FeatureColourI gcol;
1931 boolean midspace = false;
1933 int width = 50, height = 20;
1935 int s1, e1; // start and end of midpoint band for thresholded symbol
1937 Color mpcolour = Color.white;
1939 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1959 public int getIconWidth()
1965 public int getIconHeight()
1971 public void paintIcon(Component c, Graphics g, int x, int y)
1974 if (gcol.isColourByLabel())
1977 g.fillRect(0, 0, width, height);
1978 // need an icon here.
1979 g.setColor(gcol.getMaxColour());
1981 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1983 // g.setFont(g.getFont().deriveFont(
1984 // AffineTransform.getScaleInstance(
1985 // width/g.getFontMetrics().stringWidth("Label"),
1986 // height/g.getFontMetrics().getHeight())));
1988 g.drawString(MessageManager.getString("label.label"), 0, 0);
1993 Color minCol = gcol.getMinColour();
1995 g.fillRect(0, 0, s1, height);
1998 g.setColor(Color.white);
1999 g.fillRect(s1, 0, e1 - s1, height);
2001 g.setColor(gcol.getMaxColour());
2002 g.fillRect(0, e1, width - e1, height);