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.AlignViewportI;
24 import jalview.api.FeatureColourI;
25 import jalview.api.FeatureSettingsControllerI;
26 import jalview.api.ViewStyleI;
27 import jalview.datamodel.AlignmentI;
28 import jalview.datamodel.SequenceI;
29 import jalview.datamodel.features.FeatureMatcher;
30 import jalview.datamodel.features.FeatureMatcherI;
31 import jalview.datamodel.features.FeatureMatcherSet;
32 import jalview.datamodel.features.FeatureMatcherSetI;
33 import jalview.gui.Help.HelpId;
34 import jalview.io.JalviewFileChooser;
35 import jalview.io.JalviewFileView;
36 import jalview.schemes.FeatureColour;
37 import jalview.util.MessageManager;
38 import jalview.util.Platform;
39 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
40 import jalview.viewmodel.styles.ViewStyle;
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;
50 import java.awt.FlowLayout;
52 import java.awt.Graphics;
53 import java.awt.GridLayout;
54 import java.awt.Point;
55 import java.awt.Rectangle;
56 import java.awt.event.ActionEvent;
57 import java.awt.event.ActionListener;
58 import java.awt.event.ItemEvent;
59 import java.awt.event.ItemListener;
60 import java.awt.event.MouseAdapter;
61 import java.awt.event.MouseEvent;
62 import java.awt.event.MouseMotionAdapter;
63 import java.beans.PropertyChangeEvent;
64 import java.beans.PropertyChangeListener;
66 import java.io.FileInputStream;
67 import java.io.FileOutputStream;
68 import java.io.InputStreamReader;
69 import java.io.OutputStreamWriter;
70 import java.io.PrintWriter;
71 import java.util.Arrays;
72 import java.util.Comparator;
73 import java.util.HashMap;
74 import java.util.HashSet;
75 import java.util.Hashtable;
76 import java.util.Iterator;
77 import java.util.List;
81 import javax.help.HelpSetException;
82 import javax.swing.AbstractCellEditor;
83 import javax.swing.BorderFactory;
84 import javax.swing.Icon;
85 import javax.swing.JButton;
86 import javax.swing.JCheckBox;
87 import javax.swing.JColorChooser;
88 import javax.swing.JDialog;
89 import javax.swing.JInternalFrame;
90 import javax.swing.JLabel;
91 import javax.swing.JLayeredPane;
92 import javax.swing.JMenuItem;
93 import javax.swing.JPanel;
94 import javax.swing.JPopupMenu;
95 import javax.swing.JScrollPane;
96 import javax.swing.JSlider;
97 import javax.swing.JTable;
98 import javax.swing.ListSelectionModel;
99 import javax.swing.SwingConstants;
100 import javax.swing.border.Border;
101 import javax.swing.event.ChangeEvent;
102 import javax.swing.event.ChangeListener;
103 import javax.swing.table.AbstractTableModel;
104 import javax.swing.table.JTableHeader;
105 import javax.swing.table.TableCellEditor;
106 import javax.swing.table.TableCellRenderer;
107 import javax.swing.table.TableColumn;
108 import javax.xml.bind.JAXBContext;
109 import javax.xml.bind.JAXBElement;
110 import javax.xml.bind.Marshaller;
111 import javax.xml.stream.XMLInputFactory;
112 import javax.xml.stream.XMLStreamReader;
114 public class FeatureSettings extends JPanel
115 implements FeatureSettingsControllerI
117 private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
118 .getString("label.sequence_feature_colours");
121 * column indices of fields in Feature Settings table
123 static final int TYPE_COLUMN = 0;
125 static final int COLOUR_COLUMN = 1;
127 static final int FILTER_COLUMN = 2;
129 static final int SHOW_COLUMN = 3;
131 private static final int COLUMN_COUNT = 4;
133 private static final int MIN_WIDTH = 400;
135 private static final int MIN_HEIGHT = 400;
137 private final static String BASE_TOOLTIP = MessageManager.getString("label.click_to_edit");
139 final FeatureRenderer fr;
141 public final AlignFrame af;
144 * 'original' fields hold settings to restore on Cancel
146 Object[][] originalData;
148 private float originalTransparency;
150 private ViewStyleI originalViewStyle;
152 private Map<String, FeatureMatcherSetI> originalFilters;
154 final JInternalFrame frame;
156 JScrollPane scrollPane = new JScrollPane();
162 JSlider transparency = new JSlider();
165 * when true, constructor is still executing - so ignore UI events
167 protected volatile boolean inConstruction = true;
169 int selectedRow = -1;
171 boolean resettingTable = false;
174 * true when Feature Settings are updating from feature renderer
176 private boolean handlingUpdate = false;
179 * holds {featureCount, totalExtent} for each feature type
181 Map<String, float[]> typeWidth = null;
188 public FeatureSettings(AlignFrame alignFrame)
190 this.af = alignFrame;
191 fr = af.getFeatureRenderer();
193 // save transparency for restore on Cancel
194 originalTransparency = fr.getTransparency();
195 int originalTransparencyAsPercent = (int) (originalTransparency * 100);
196 transparency.setMaximum(100 - originalTransparencyAsPercent);
198 originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
199 originalViewStyle = new ViewStyle(af.viewport.getViewStyle());
204 } catch (Exception ex)
206 ex.printStackTrace();
212 public String getToolTipText(MouseEvent e)
215 int column = table.columnAtPoint(e.getPoint());
216 int row = table.rowAtPoint(e.getPoint());
221 tip = JvSwingUtils.wrapTooltip(true, MessageManager
222 .getString("label.feature_settings_click_drag"));
225 FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
227 tip = getColorTooltip(colour, true);
230 FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
234 .getString("label.configure_feature_tooltip")
245 * Position the tooltip near the bottom edge of, and half way across, the
249 public Point getToolTipLocation(MouseEvent e)
251 Point point = e.getPoint();
252 int column = table.columnAtPoint(point);
253 int row = table.rowAtPoint(point);
254 Rectangle r = getCellRect(row, column, false);
255 Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3);
259 JTableHeader tableHeader = table.getTableHeader();
260 tableHeader.setFont(new Font("Verdana", Font.PLAIN, 12));
261 tableHeader.setReorderingAllowed(false);
262 table.setFont(new Font("Verdana", Font.PLAIN, 12));
264 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
265 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
267 table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor(this));
268 table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
270 TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
271 new ColorRenderer(), new ColorEditor(this));
272 table.addColumn(colourColumn);
274 TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
275 new FilterRenderer(), new FilterEditor(this));
276 table.addColumn(filterColumn);
278 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
280 table.addMouseListener(new MouseAdapter()
283 public void mousePressed(MouseEvent evt)
285 Point pt = evt.getPoint();
286 selectedRow = table.rowAtPoint(pt);
287 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
288 if (evt.isPopupTrigger())
290 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
291 popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
294 else if (evt.getClickCount() == 2
295 && table.columnAtPoint(pt) == TYPE_COLUMN)
297 boolean invertSelection = evt.isAltDown();
298 boolean toggleSelection = Platform.isControlDown(evt);
299 boolean extendSelection = evt.isShiftDown();
300 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
301 invertSelection, extendSelection, toggleSelection, type);
302 fr.ap.av.sendSelection();
306 // isPopupTrigger fires on mouseReleased on Windows
308 public void mouseReleased(MouseEvent evt)
310 selectedRow = table.rowAtPoint(evt.getPoint());
311 if (evt.isPopupTrigger())
313 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
314 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
315 popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
321 table.addMouseMotionListener(new MouseMotionAdapter()
324 public void mouseDragged(MouseEvent evt)
326 int newRow = table.rowAtPoint(evt.getPoint());
327 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
330 * reposition 'selectedRow' to 'newRow' (the dragged to location)
331 * this could be more than one row away for a very fast drag action
332 * so just swap it with adjacent rows until we get it there
334 Object[][] data = ((FeatureTableModel) table.getModel())
336 int direction = newRow < selectedRow ? -1 : 1;
337 for (int i = selectedRow; i != newRow; i += direction)
339 Object[] temp = data[i];
340 data[i] = data[i + direction];
341 data[i + direction] = temp;
343 updateFeatureRenderer(data);
345 selectedRow = newRow;
349 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
350 // MessageManager.getString("label.feature_settings_click_drag")));
351 scrollPane.setViewportView(table);
353 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
355 fr.findAllFeatures(true); // display everything!
358 discoverAllFeatureData();
359 final PropertyChangeListener change;
360 final FeatureSettings fs = this;
361 fr.addPropertyChangeListener(change = new PropertyChangeListener()
364 public void propertyChange(PropertyChangeEvent evt)
366 if (!fs.resettingTable && !fs.handlingUpdate)
368 fs.handlingUpdate = true;
370 // new groups may be added with new sequence feature types only
371 fs.handlingUpdate = false;
377 frame = new JInternalFrame();
378 frame.setContentPane(this);
379 if (Platform.isAMac())
381 Desktop.addInternalFrame(frame,
382 MessageManager.getString("label.sequence_feature_settings"),
387 Desktop.addInternalFrame(frame,
388 MessageManager.getString("label.sequence_feature_settings"),
391 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
393 frame.addInternalFrameListener(
394 new javax.swing.event.InternalFrameAdapter()
397 public void internalFrameClosed(
398 javax.swing.event.InternalFrameEvent evt)
400 fr.removePropertyChangeListener(change);
403 frame.setLayer(JLayeredPane.PALETTE_LAYER);
404 inConstruction = false;
407 protected void popupSort(final int rowSelected, final String type,
408 final Object typeCol, final Map<String, float[][]> minmax, int x,
411 JPopupMenu men = new JPopupMenu(MessageManager
412 .formatMessage("label.settings_for_param", new String[]
414 JMenuItem scr = new JMenuItem(
415 MessageManager.getString("label.sort_by_score"));
417 final FeatureSettings me = this;
418 scr.addActionListener(new ActionListener()
422 public void actionPerformed(ActionEvent e)
425 .sortAlignmentByFeatureScore(Arrays.asList(new String[]
430 JMenuItem dens = new JMenuItem(
431 MessageManager.getString("label.sort_by_density"));
432 dens.addActionListener(new ActionListener()
436 public void actionPerformed(ActionEvent e)
439 .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
446 JMenuItem selCols = new JMenuItem(
447 MessageManager.getString("label.select_columns_containing"));
448 selCols.addActionListener(new ActionListener()
451 public void actionPerformed(ActionEvent arg0)
453 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
455 fr.ap.av.sendSelection();
458 JMenuItem clearCols = new JMenuItem(MessageManager
459 .getString("label.select_columns_not_containing"));
460 clearCols.addActionListener(new ActionListener()
463 public void actionPerformed(ActionEvent arg0)
465 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
467 fr.ap.av.sendSelection();
470 JMenuItem hideCols = new JMenuItem(
471 MessageManager.getString("label.hide_columns_containing"));
472 hideCols.addActionListener(new ActionListener()
475 public void actionPerformed(ActionEvent arg0)
477 fr.ap.alignFrame.hideFeatureColumns(type, true);
478 fr.ap.av.sendSelection();
481 JMenuItem hideOtherCols = new JMenuItem(
482 MessageManager.getString("label.hide_columns_not_containing"));
483 hideOtherCols.addActionListener(new ActionListener()
486 public void actionPerformed(ActionEvent arg0)
488 fr.ap.alignFrame.hideFeatureColumns(type, false);
489 fr.ap.av.sendSelection();
495 men.add(hideOtherCols);
496 men.show(table, x, y);
500 synchronized public void discoverAllFeatureData()
502 Set<String> allGroups = new HashSet<>();
503 AlignmentI alignment = af.getViewport().getAlignment();
505 for (int i = 0; i < alignment.getHeight(); i++)
507 SequenceI seq = alignment.getSequenceAt(i);
508 for (String group : seq.getFeatures().getFeatureGroups(true))
510 if (group != null && !allGroups.contains(group))
512 allGroups.add(group);
513 checkGroupState(group);
524 * Synchronise gui group list and check visibility of group
527 * @return true if group is visible
529 private boolean checkGroupState(String group)
531 boolean visible = fr.checkGroupVisibility(group, true);
533 for (int g = 0; g < groupPanel.getComponentCount(); g++)
535 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
537 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
542 final String grp = group;
543 final JCheckBox check = new JCheckBox(group, visible);
544 check.setFont(new Font("Serif", Font.BOLD, 12));
545 check.setToolTipText(group);
546 check.addItemListener(new ItemListener()
549 public void itemStateChanged(ItemEvent evt)
551 fr.setGroupVisibility(check.getText(), check.isSelected());
552 resetTable(new String[] { grp });
556 groupPanel.add(check);
560 synchronized void resetTable(String[] groupChanged)
566 resettingTable = true;
567 typeWidth = new Hashtable<>();
568 // TODO: change avWidth calculation to 'per-sequence' average and use long
571 Set<String> displayableTypes = new HashSet<>();
572 Set<String> foundGroups = new HashSet<>();
575 * determine which feature types may be visible depending on
576 * which groups are selected, and recompute average width data
578 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
581 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
584 * get the sequence's groups for positional features
585 * and keep track of which groups are visible
587 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
588 Set<String> visibleGroups = new HashSet<>();
589 for (String group : groups)
591 if (group == null || checkGroupState(group))
593 visibleGroups.add(group);
596 foundGroups.addAll(groups);
599 * get distinct feature types for visible groups
600 * record distinct visible types, and their count and total length
602 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
603 visibleGroups.toArray(new String[visibleGroups.size()]));
604 for (String type : types)
606 displayableTypes.add(type);
607 float[] avWidth = typeWidth.get(type);
610 avWidth = new float[2];
611 typeWidth.put(type, avWidth);
613 // todo this could include features with a non-visible group
614 // - do we greatly care?
615 // todo should we include non-displayable features here, and only
616 // update when features are added?
617 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
618 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
622 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
625 if (fr.hasRenderOrder())
629 fr.findAllFeatures(groupChanged != null); // prod to update
630 // colourschemes. but don't
632 // First add the checks in the previous render order,
633 // in case the window has been closed and reopened
635 List<String> frl = fr.getRenderOrder();
636 for (int ro = frl.size() - 1; ro > -1; ro--)
638 String type = frl.get(ro);
640 if (!displayableTypes.contains(type))
645 data[dataIndex][TYPE_COLUMN] = type;
646 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
647 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
648 data[dataIndex][FILTER_COLUMN] = featureFilter == null
649 ? new FeatureMatcherSet()
651 data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(
652 af.getViewport().getFeaturesDisplayed().isVisible(type));
654 displayableTypes.remove(type);
659 * process any extra features belonging only to
660 * a group which was just selected
662 while (!displayableTypes.isEmpty())
664 String type = displayableTypes.iterator().next();
665 data[dataIndex][TYPE_COLUMN] = type;
667 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
668 if (data[dataIndex][COLOUR_COLUMN] == null)
670 // "Colour has been updated in another view!!"
671 fr.clearRenderOrder();
674 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
675 data[dataIndex][FILTER_COLUMN] = featureFilter == null
676 ? new FeatureMatcherSet()
678 data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(true);
680 displayableTypes.remove(type);
683 if (originalData == null)
685 originalData = new Object[data.length][COLUMN_COUNT];
686 for (int i = 0; i < data.length; i++)
688 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
693 updateOriginalData(data);
696 table.setModel(new FeatureTableModel(data));
697 table.getColumnModel().getColumn(0).setPreferredWidth(200);
699 groupPanel.setLayout(
700 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
701 pruneGroups(foundGroups);
702 groupPanel.validate();
704 updateFeatureRenderer(data, groupChanged != null);
705 resettingTable = false;
709 * Updates 'originalData' (used for restore on Cancel) if we detect that changes
710 * have been made outwith this dialog
712 * <li>a new feature type added (and made visible)</li>
713 * <li>a feature colour changed (in the Amend Features dialog)</li>
718 protected void updateOriginalData(Object[][] foundData)
720 // todo LinkedHashMap instead of Object[][] would be nice
722 Object[][] currentData = ((FeatureTableModel) table.getModel())
724 for (Object[] row : foundData)
726 String type = (String) row[TYPE_COLUMN];
727 boolean found = false;
728 for (Object[] current : currentData)
730 if (type.equals(current[TYPE_COLUMN]))
734 * currently dependent on object equality here;
735 * really need an equals method on FeatureColour
737 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
740 * feature colour has changed externally - update originalData
742 for (Object[] original : originalData)
744 if (type.equals(original[TYPE_COLUMN]))
746 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
757 * new feature detected - add to original data (on top)
759 Object[][] newData = new Object[originalData.length
761 for (int i = 0; i < originalData.length; i++)
763 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
767 originalData = newData;
773 * Remove from the groups panel any checkboxes for groups that are not in the
774 * foundGroups set. This enables removing a group from the display when the last
775 * feature in that group is deleted.
779 protected void pruneGroups(Set<String> foundGroups)
781 for (int g = 0; g < groupPanel.getComponentCount(); g++)
783 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
784 if (!foundGroups.contains(checkbox.getText()))
786 groupPanel.remove(checkbox);
792 * reorder data based on the featureRenderers global priority list.
796 private void ensureOrder(Object[][] data)
798 boolean sort = false;
799 float[] order = new float[data.length];
800 for (int i = 0; i < order.length; i++)
802 order[i] = fr.getOrder(data[i][0].toString());
805 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
809 sort = sort || order[i - 1] > order[i];
814 jalview.util.QuickSort.sort(order, data);
819 * Offers a file chooser dialog, and then loads the feature colours and
820 * filters from file in XML format and unmarshals to Jalview feature settings
824 JalviewFileChooser chooser = new JalviewFileChooser("fc",
825 SEQUENCE_FEATURE_COLOURS);
826 chooser.setFileView(new JalviewFileView());
827 chooser.setDialogTitle(
828 MessageManager.getString("label.load_feature_colours"));
829 chooser.setToolTipText(MessageManager.getString("action.load"));
831 int value = chooser.showOpenDialog(this);
833 if (value == JalviewFileChooser.APPROVE_OPTION)
835 File file = chooser.getSelectedFile();
841 * Loads feature colours and filters from XML stored in the given file
849 InputStreamReader in = new InputStreamReader(
850 new FileInputStream(file), "UTF-8");
852 JAXBContext jc = JAXBContext
853 .newInstance("jalview.xml.binding.jalview");
854 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
855 XMLStreamReader streamReader = XMLInputFactory.newInstance()
856 .createXMLStreamReader(in);
857 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
858 JalviewUserColours.class);
859 JalviewUserColours jucs = jbe.getValue();
861 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
864 * load feature colours
866 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
868 Colour newcol = jucs.getColour().get(i);
869 FeatureColourI colour = jalview.project.Jalview2XML
870 .parseColour(newcol);
871 fr.setColour(newcol.getName(), colour);
872 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
876 * load feature filters; loaded filters will replace any that are
877 * currently defined, other defined filters are left unchanged
879 for (int i = 0; i < jucs.getFilter().size(); i++)
881 Filter filterModel = jucs.getFilter().get(i);
882 String featureType = filterModel.getFeatureType();
883 FeatureMatcherSetI filter = jalview.project.Jalview2XML
884 .parseFilter(featureType, filterModel.getMatcherSet());
885 if (!filter.isEmpty())
887 fr.setFeatureFilter(featureType, filter);
892 * update feature settings table
897 Object[][] data = ((FeatureTableModel) table.getModel())
900 updateFeatureRenderer(data, false);
903 } catch (Exception ex)
905 System.out.println("Error loading User Colour File\n" + ex);
910 * Offers a file chooser dialog, and then saves the current feature colours
911 * and any filters to the selected file in XML format
915 JalviewFileChooser chooser = new JalviewFileChooser("fc",
916 SEQUENCE_FEATURE_COLOURS);
917 chooser.setFileView(new JalviewFileView());
918 chooser.setDialogTitle(
919 MessageManager.getString("label.save_feature_colours"));
920 chooser.setToolTipText(MessageManager.getString("action.save"));
922 int value = chooser.showSaveDialog(this);
924 if (value == JalviewFileChooser.APPROVE_OPTION)
926 save(chooser.getSelectedFile());
931 * Saves feature colours and filters to the given file
937 JalviewUserColours ucs = new JalviewUserColours();
938 ucs.setSchemeName("Sequence Features");
941 PrintWriter out = new PrintWriter(new OutputStreamWriter(
942 new FileOutputStream(file), "UTF-8"));
945 * sort feature types by colour order, from 0 (highest)
948 Set<String> fr_colours = fr.getAllFeatureColours();
949 String[] sortedTypes = fr_colours
950 .toArray(new String[fr_colours.size()]);
951 Arrays.sort(sortedTypes, new Comparator<String>()
954 public int compare(String type1, String type2)
956 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
961 * save feature colours
963 for (String featureType : sortedTypes)
965 FeatureColourI fcol = fr.getFeatureStyle(featureType);
966 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
968 ucs.getColour().add(col);
972 * save any feature filters
974 for (String featureType : sortedTypes)
976 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
977 if (filter != null && !filter.isEmpty())
979 Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
980 FeatureMatcherI firstMatcher = iterator.next();
981 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
982 .marshalFilter(firstMatcher, iterator,
984 Filter filterModel = new Filter();
985 filterModel.setFeatureType(featureType);
986 filterModel.setMatcherSet(ms);
987 ucs.getFilter().add(filterModel);
990 JAXBContext jaxbContext = JAXBContext
991 .newInstance(JalviewUserColours.class);
992 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
993 jaxbMarshaller.marshal(
994 new ObjectFactory().createJalviewUserColours(ucs), out);
996 // jaxbMarshaller.marshal(object, pout);
997 // marshaller.marshal(object);
1000 // ucs.marshal(out);
1002 } catch (Exception ex)
1004 ex.printStackTrace();
1008 public void invertSelection()
1010 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1011 for (int i = 0; i < data.length; i++)
1013 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1015 updateFeatureRenderer(data, true);
1019 public void orderByAvWidth()
1021 if (table == null || table.getModel() == null)
1025 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1026 float[] width = new float[data.length];
1030 for (int i = 0; i < data.length; i++)
1032 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1035 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1036 // weight - but have to make per
1037 // sequence, too (awidth[2])
1038 // if (width[i]==1) // hack to distinguish single width sequences.
1049 boolean sort = false;
1050 for (int i = 0; i < width.length; i++)
1052 // awidth = (float[]) typeWidth.get(data[i][0]);
1055 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1058 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1064 width[i] /= max; // normalize
1065 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
1069 sort = sort || width[i - 1] > width[i];
1074 jalview.util.QuickSort.sort(width, data);
1075 // update global priority order
1078 updateFeatureRenderer(data, false);
1086 frame.setClosed(true);
1087 } catch (Exception exe)
1093 public void updateFeatureRenderer(Object[][] data)
1095 updateFeatureRenderer(data, true);
1099 * Update the priority order of features; only repaint if this changed the order
1100 * of visible features
1105 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1107 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1109 if (fr.setFeaturePriority(rowData, visibleNew))
1116 * Converts table data into an array of data beans
1118 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1120 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1121 for (int i = 0; i < data.length; i++)
1123 String type = (String) data[i][TYPE_COLUMN];
1124 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1125 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1126 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1127 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1133 private void jbInit() throws Exception
1135 this.setLayout(new BorderLayout());
1137 JPanel settingsPane = new JPanel();
1138 settingsPane.setLayout(new BorderLayout());
1140 JPanel bigPanel = new JPanel();
1141 bigPanel.setLayout(new BorderLayout());
1143 groupPanel = new JPanel();
1144 bigPanel.add(groupPanel, BorderLayout.NORTH);
1146 JButton invert = new JButton(
1147 MessageManager.getString("label.invert_selection"));
1148 invert.setFont(JvSwingUtils.getLabelFont());
1149 invert.addActionListener(new ActionListener()
1152 public void actionPerformed(ActionEvent e)
1158 JButton optimizeOrder = new JButton(
1159 MessageManager.getString("label.optimise_order"));
1160 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1161 optimizeOrder.addActionListener(new ActionListener()
1164 public void actionPerformed(ActionEvent e)
1170 JButton sortByScore = new JButton(
1171 MessageManager.getString("label.seq_sort_by_score"));
1172 sortByScore.setFont(JvSwingUtils.getLabelFont());
1173 sortByScore.addActionListener(new ActionListener()
1176 public void actionPerformed(ActionEvent e)
1178 af.avc.sortAlignmentByFeatureScore(null);
1181 JButton sortByDens = new JButton(
1182 MessageManager.getString("label.sequence_sort_by_density"));
1183 sortByDens.setFont(JvSwingUtils.getLabelFont());
1184 sortByDens.addActionListener(new ActionListener()
1187 public void actionPerformed(ActionEvent e)
1189 af.avc.sortAlignmentByFeatureDensity(null);
1193 JButton help = new JButton(MessageManager.getString("action.help"));
1194 help.setFont(JvSwingUtils.getLabelFont());
1195 help.addActionListener(new ActionListener()
1198 public void actionPerformed(ActionEvent e)
1202 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1203 } catch (HelpSetException e1)
1205 e1.printStackTrace();
1210 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1211 cancel.setFont(JvSwingUtils.getLabelFont());
1212 cancel.addActionListener(new ActionListener()
1215 public void actionPerformed(ActionEvent e)
1217 fr.setTransparency(originalTransparency);
1218 fr.setFeatureFilters(originalFilters);
1219 updateFeatureRenderer(originalData);
1220 af.getViewport().setViewStyle(originalViewStyle);
1225 JButton ok = new JButton(MessageManager.getString("action.ok"));
1226 ok.setFont(JvSwingUtils.getLabelFont());
1227 ok.addActionListener(new ActionListener()
1230 public void actionPerformed(ActionEvent e)
1236 JButton loadColours = new JButton(
1237 MessageManager.getString("label.load_colours"));
1238 loadColours.setFont(JvSwingUtils.getLabelFont());
1239 loadColours.setToolTipText(
1240 MessageManager.getString("label.load_colours_tooltip"));
1241 loadColours.addActionListener(new ActionListener()
1244 public void actionPerformed(ActionEvent e)
1250 JButton saveColours = new JButton(
1251 MessageManager.getString("label.save_colours"));
1252 saveColours.setFont(JvSwingUtils.getLabelFont());
1253 saveColours.setToolTipText(
1254 MessageManager.getString("label.save_colours_tooltip"));
1255 saveColours.addActionListener(new ActionListener()
1258 public void actionPerformed(ActionEvent e)
1263 transparency.addChangeListener(new ChangeListener()
1266 public void stateChanged(ChangeEvent evt)
1268 if (!inConstruction)
1270 fr.setTransparency((100 - transparency.getValue()) / 100f);
1276 transparency.setMaximum(70);
1277 transparency.setToolTipText(
1278 MessageManager.getString("label.transparency_tip"));
1280 boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
1281 String text = MessageManager.formatMessage("label.show_linked_features",
1283 ? MessageManager.getString("label.protein")
1286 JCheckBox showComplement = new JCheckBox(text);
1287 showComplement.setSelected(af.getViewport().isShowComplementFeatures());
1288 showComplement.addActionListener(new ActionListener()
1291 public void actionPerformed(ActionEvent e)
1294 .setShowComplementFeatures(showComplement.isSelected());
1299 JCheckBox showComplementOnTop = new JCheckBox(
1300 MessageManager.getString("label.on_top"));
1302 .setSelected(af.getViewport().isShowComplementFeaturesOnTop());
1303 showComplementOnTop.addActionListener(new ActionListener()
1306 public void actionPerformed(ActionEvent e)
1308 af.getViewport().setShowComplementFeaturesOnTop(
1309 showComplementOnTop.isSelected());
1314 JPanel lowerPanel = new JPanel(new GridLayout(1, 2));
1315 bigPanel.add(lowerPanel, BorderLayout.SOUTH);
1317 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1318 transbuttons.add(optimizeOrder);
1319 transbuttons.add(invert);
1320 transbuttons.add(sortByScore);
1321 transbuttons.add(sortByDens);
1322 transbuttons.add(help);
1324 boolean hasComplement = af.getViewport().getCodingComplement() != null;
1325 JPanel transPanelLeft = new JPanel(
1326 new GridLayout(hasComplement ? 3 : 2, 1));
1327 transPanelLeft.add(new JLabel(" Colour transparency" + ":"));
1328 transPanelLeft.add(transparency);
1331 JPanel cp = new JPanel(new FlowLayout(FlowLayout.LEFT));
1332 cp.add(showComplement);
1333 cp.add(showComplementOnTop);
1334 transPanelLeft.add(cp);
1336 lowerPanel.add(transPanelLeft);
1337 lowerPanel.add(transbuttons);
1339 JPanel buttonPanel = new JPanel();
1340 buttonPanel.add(ok);
1341 buttonPanel.add(cancel);
1342 buttonPanel.add(loadColours);
1343 buttonPanel.add(saveColours);
1344 bigPanel.add(scrollPane, BorderLayout.CENTER);
1345 settingsPane.add(bigPanel, BorderLayout.CENTER);
1346 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1347 this.add(settingsPane);
1351 * Repaints alignment, structure and overview (if shown). If there is a
1352 * complementary view which is showing this view's features, then also
1355 void refreshDisplay()
1357 af.alignPanel.paintAlignment(true, true);
1358 AlignViewportI complement = af.getViewport().getCodingComplement();
1359 if (complement != null && complement.isShowComplementFeatures())
1361 AlignFrame af2 = Desktop.getAlignFrameFor(complement);
1362 af2.alignPanel.paintAlignment(true, true);
1367 * Answers a suitable tooltip to show on the colour cell of the table
1371 * if true include 'click to edit' and similar text
1374 public static String getColorTooltip(FeatureColourI fcol,
1381 if (fcol.isSimpleColour())
1383 return withHint ? BASE_TOOLTIP : null;
1385 String description = fcol.getDescription();
1386 description = description.replaceAll("<", "<");
1387 description = description.replaceAll(">", ">");
1388 StringBuilder tt = new StringBuilder(description);
1391 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1393 return JvSwingUtils.wrapTooltip(true, tt.toString());
1396 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1399 boolean thr = false;
1400 StringBuilder tx = new StringBuilder();
1402 if (gcol.isColourByAttribute())
1404 tx.append(FeatureMatcher
1405 .toAttributeDisplayName(gcol.getAttributeName()));
1407 else if (!gcol.isColourByLabel())
1409 tx.append(MessageManager.getString("label.score"));
1412 if (gcol.isAboveThreshold())
1417 if (gcol.isBelowThreshold())
1422 if (gcol.isColourByLabel())
1428 if (!gcol.isColourByAttribute())
1436 Color newColor = gcol.getMaxColour();
1437 comp.setBackground(newColor);
1438 // System.err.println("Width is " + w / 2);
1439 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1440 comp.setIcon(ficon);
1441 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1442 // + newColor.getGreen() + ", " + newColor.getBlue()
1443 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1444 // + ", " + minCol.getBlue() + ")");
1446 comp.setHorizontalAlignment(SwingConstants.CENTER);
1447 comp.setText(tx.toString());
1450 // ///////////////////////////////////////////////////////////////////////
1451 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1452 // ///////////////////////////////////////////////////////////////////////
1453 class FeatureTableModel extends AbstractTableModel
1455 private String[] columnNames = {
1456 MessageManager.getString("label.feature_type"),
1457 MessageManager.getString("action.colour"),
1458 MessageManager.getString("label.configuration"),
1459 MessageManager.getString("label.show") };
1461 private Object[][] data;
1463 FeatureTableModel(Object[][] data)
1468 public Object[][] getData()
1473 public void setData(Object[][] data)
1479 public int getColumnCount()
1481 return columnNames.length;
1484 public Object[] getRow(int row)
1490 public int getRowCount()
1496 public String getColumnName(int col)
1498 return columnNames[col];
1502 public Object getValueAt(int row, int col)
1504 return data[row][col];
1508 * Answers the class of column c of the table
1511 public Class<?> getColumnClass(int c)
1516 return String.class;
1518 return FeatureColour.class;
1520 return FeatureMatcherSet.class;
1522 return Boolean.class;
1527 public boolean isCellEditable(int row, int col)
1529 return col == 0 ? false : true;
1533 public void setValueAt(Object value, int row, int col)
1535 data[row][col] = value;
1536 fireTableCellUpdated(row, col);
1537 updateFeatureRenderer(data);
1542 class ColorRenderer extends JLabel implements TableCellRenderer
1544 Border unselectedBorder = null;
1546 Border selectedBorder = null;
1548 public ColorRenderer()
1550 setOpaque(true); // MUST do this for background to show up.
1551 setHorizontalTextPosition(SwingConstants.CENTER);
1552 setVerticalTextPosition(SwingConstants.CENTER);
1556 public Component getTableCellRendererComponent(JTable tbl, Object color,
1557 boolean isSelected, boolean hasFocus, int row, int column)
1559 FeatureColourI cellColour = (FeatureColourI) color;
1561 setBackground(tbl.getBackground());
1562 if (!cellColour.isSimpleColour())
1564 Rectangle cr = tbl.getCellRect(row, column, false);
1565 FeatureSettings.renderGraduatedColor(this, cellColour,
1566 (int) cr.getWidth(), (int) cr.getHeight());
1572 setBackground(cellColour.getColour());
1576 if (selectedBorder == null)
1578 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1579 tbl.getSelectionBackground());
1581 setBorder(selectedBorder);
1585 if (unselectedBorder == null)
1587 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1588 tbl.getBackground());
1590 setBorder(unselectedBorder);
1597 class FilterRenderer extends JLabel implements TableCellRenderer
1599 javax.swing.border.Border unselectedBorder = null;
1601 javax.swing.border.Border selectedBorder = null;
1603 public FilterRenderer()
1605 setOpaque(true); // MUST do this for background to show up.
1606 setHorizontalTextPosition(SwingConstants.CENTER);
1607 setVerticalTextPosition(SwingConstants.CENTER);
1611 public Component getTableCellRendererComponent(JTable tbl,
1612 Object filter, boolean isSelected, boolean hasFocus, int row,
1615 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1617 String asText = theFilter.toString();
1618 setBackground(tbl.getBackground());
1619 this.setText(asText);
1624 if (selectedBorder == null)
1626 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1627 tbl.getSelectionBackground());
1629 setBorder(selectedBorder);
1633 if (unselectedBorder == null)
1635 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1636 tbl.getBackground());
1638 setBorder(unselectedBorder);
1646 * update comp using rendering settings from gcol
1651 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1653 int w = comp.getWidth(), h = comp.getHeight();
1656 w = (int) comp.getPreferredSize().getWidth();
1657 h = (int) comp.getPreferredSize().getHeight();
1664 renderGraduatedColor(comp, gcol, w, h);
1667 class ColorEditor extends AbstractCellEditor
1668 implements TableCellEditor, ActionListener
1672 FeatureColourI currentColor;
1674 FeatureTypeSettings chooser;
1680 JColorChooser colorChooser;
1684 protected static final String EDIT = "edit";
1686 int rowSelected = 0;
1688 public ColorEditor(FeatureSettings me)
1691 // Set up the editor (from the table's point of view),
1692 // which is a button.
1693 // This button brings up the color chooser dialog,
1694 // which is the editor from the user's point of view.
1695 button = new JButton();
1696 button.setActionCommand(EDIT);
1697 button.addActionListener(this);
1698 button.setBorderPainted(false);
1699 // Set up the dialog that the button brings up.
1700 colorChooser = new JColorChooser();
1701 dialog = JColorChooser.createDialog(button,
1702 MessageManager.getString("label.select_colour"), true, // modal
1703 colorChooser, this, // OK button handler
1704 null); // no CANCEL button handler
1708 * Handles events from the editor button and from the dialog's OK button.
1711 public void actionPerformed(ActionEvent e)
1713 // todo test e.getSource() instead here
1714 if (EDIT.equals(e.getActionCommand()))
1716 // The user has clicked the cell, so
1717 // bring up the dialog.
1718 if (currentColor.isSimpleColour())
1720 // bring up simple color chooser
1721 button.setBackground(currentColor.getColour());
1722 colorChooser.setColor(currentColor.getColour());
1723 dialog.setVisible(true);
1727 // bring up graduated chooser.
1728 chooser = new FeatureTypeSettings(me.fr, type);
1733 chooser.setRequestFocusEnabled(true);
1734 chooser.requestFocus();
1736 chooser.addActionListener(this);
1737 // Make the renderer reappear.
1738 fireEditingStopped();
1743 if (currentColor.isSimpleColour())
1746 * read off colour picked in colour chooser after OK pressed
1748 currentColor = new FeatureColour(colorChooser.getColor());
1749 me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1754 * after OK in variable colour dialog, any changes to colour
1755 * (or filters!) are already set in FeatureRenderer, so just
1756 * update table data without triggering updateFeatureRenderer
1758 currentColor = fr.getFeatureColours().get(type);
1759 FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
1760 if (currentFilter == null)
1762 currentFilter = new FeatureMatcherSet();
1764 Object[] data = ((FeatureTableModel) table.getModel())
1765 .getData()[rowSelected];
1766 data[COLOUR_COLUMN] = currentColor;
1767 data[FILTER_COLUMN] = currentFilter;
1769 fireEditingStopped();
1770 me.table.validate();
1774 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1776 public Object getCellEditorValue()
1778 return currentColor;
1781 // Implement the one method defined by TableCellEditor.
1783 public Component getTableCellEditorComponent(JTable theTable, Object value,
1784 boolean isSelected, int row, int column)
1786 currentColor = (FeatureColourI) value;
1787 this.rowSelected = row;
1788 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1789 button.setOpaque(true);
1790 button.setBackground(me.getBackground());
1791 if (!currentColor.isSimpleColour())
1793 JLabel btn = new JLabel();
1794 btn.setSize(button.getSize());
1795 FeatureSettings.renderGraduatedColor(btn, currentColor);
1796 button.setBackground(btn.getBackground());
1797 button.setIcon(btn.getIcon());
1798 button.setText(btn.getText());
1803 button.setIcon(null);
1804 button.setBackground(currentColor.getColour());
1811 * The cell editor for the Filter column. It displays the text of any filters
1812 * for the feature type in that row (in full as a tooltip, possible abbreviated
1813 * as display text). On click in the cell, opens the Feature Display Settings
1814 * dialog at the Filters tab.
1816 class FilterEditor extends AbstractCellEditor
1817 implements TableCellEditor, ActionListener
1821 FeatureMatcherSetI currentFilter;
1829 protected static final String EDIT = "edit";
1831 int rowSelected = 0;
1833 public FilterEditor(FeatureSettings me)
1836 button = new JButton();
1837 button.setActionCommand(EDIT);
1838 button.addActionListener(this);
1839 button.setBorderPainted(false);
1843 * Handles events from the editor button
1846 public void actionPerformed(ActionEvent e)
1848 if (button == e.getSource())
1850 FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
1851 chooser.addActionListener(this);
1852 chooser.setRequestFocusEnabled(true);
1853 chooser.requestFocus();
1854 if (lastLocation != null)
1856 // todo open at its last position on screen
1857 chooser.setBounds(lastLocation.x, lastLocation.y,
1858 chooser.getWidth(), chooser.getHeight());
1861 fireEditingStopped();
1863 else if (e.getSource() instanceof Component)
1867 * after OK in variable colour dialog, any changes to filter
1868 * (or colours!) are already set in FeatureRenderer, so just
1869 * update table data without triggering updateFeatureRenderer
1871 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1872 currentFilter = me.fr.getFeatureFilter(type);
1873 if (currentFilter == null)
1875 currentFilter = new FeatureMatcherSet();
1877 Object[] data = ((FeatureTableModel) table.getModel())
1878 .getData()[rowSelected];
1879 data[COLOUR_COLUMN] = currentColor;
1880 data[FILTER_COLUMN] = currentFilter;
1881 fireEditingStopped();
1882 me.table.validate();
1887 public Object getCellEditorValue()
1889 return currentFilter;
1893 public Component getTableCellEditorComponent(JTable theTable, Object value,
1894 boolean isSelected, int row, int column)
1896 currentFilter = (FeatureMatcherSetI) value;
1897 this.rowSelected = row;
1898 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1899 button.setOpaque(true);
1900 button.setBackground(me.getBackground());
1901 button.setText(currentFilter.toString());
1902 button.setIcon(null);
1908 class FeatureIcon implements Icon
1910 FeatureColourI gcol;
1914 boolean midspace = false;
1916 int width = 50, height = 20;
1918 int s1, e1; // start and end of midpoint band for thresholded symbol
1920 Color mpcolour = Color.white;
1922 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1942 public int getIconWidth()
1948 public int getIconHeight()
1954 public void paintIcon(Component c, Graphics g, int x, int y)
1957 if (gcol.isColourByLabel())
1960 g.fillRect(0, 0, width, height);
1961 // need an icon here.
1962 g.setColor(gcol.getMaxColour());
1964 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1966 // g.setFont(g.getFont().deriveFont(
1967 // AffineTransform.getScaleInstance(
1968 // width/g.getFontMetrics().stringWidth("Label"),
1969 // height/g.getFontMetrics().getHeight())));
1971 g.drawString(MessageManager.getString("label.label"), 0, 0);
1976 Color minCol = gcol.getMinColour();
1978 g.fillRect(0, 0, s1, height);
1981 g.setColor(Color.white);
1982 g.fillRect(s1, 0, e1 - s1, height);
1984 g.setColor(gcol.getMaxColour());
1985 g.fillRect(0, e1, width - e1, height);