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 selectedRow = table.rowAtPoint(evt.getPoint());
286 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
287 if (evt.isPopupTrigger())
289 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
290 popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
293 else if (evt.getClickCount() == 2)
295 boolean invertSelection = evt.isAltDown();
296 boolean toggleSelection = Platform.isControlDown(evt);
297 boolean extendSelection = evt.isShiftDown();
298 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
299 invertSelection, extendSelection, toggleSelection, type);
300 fr.ap.av.sendSelection();
304 // isPopupTrigger fires on mouseReleased on Windows
306 public void mouseReleased(MouseEvent evt)
308 selectedRow = table.rowAtPoint(evt.getPoint());
309 if (evt.isPopupTrigger())
311 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
312 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
313 popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
319 table.addMouseMotionListener(new MouseMotionAdapter()
322 public void mouseDragged(MouseEvent evt)
324 int newRow = table.rowAtPoint(evt.getPoint());
325 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
328 * reposition 'selectedRow' to 'newRow' (the dragged to location)
329 * this could be more than one row away for a very fast drag action
330 * so just swap it with adjacent rows until we get it there
332 Object[][] data = ((FeatureTableModel) table.getModel())
334 int direction = newRow < selectedRow ? -1 : 1;
335 for (int i = selectedRow; i != newRow; i += direction)
337 Object[] temp = data[i];
338 data[i] = data[i + direction];
339 data[i + direction] = temp;
341 updateFeatureRenderer(data);
343 selectedRow = newRow;
347 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
348 // MessageManager.getString("label.feature_settings_click_drag")));
349 scrollPane.setViewportView(table);
351 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
353 fr.findAllFeatures(true); // display everything!
356 discoverAllFeatureData();
357 final PropertyChangeListener change;
358 final FeatureSettings fs = this;
359 fr.addPropertyChangeListener(change = new PropertyChangeListener()
362 public void propertyChange(PropertyChangeEvent evt)
364 if (!fs.resettingTable && !fs.handlingUpdate)
366 fs.handlingUpdate = true;
368 // new groups may be added with new sequence feature types only
369 fs.handlingUpdate = false;
375 frame = new JInternalFrame();
376 frame.setContentPane(this);
377 if (Platform.isAMac())
379 Desktop.addInternalFrame(frame,
380 MessageManager.getString("label.sequence_feature_settings"),
385 Desktop.addInternalFrame(frame,
386 MessageManager.getString("label.sequence_feature_settings"),
389 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
391 frame.addInternalFrameListener(
392 new javax.swing.event.InternalFrameAdapter()
395 public void internalFrameClosed(
396 javax.swing.event.InternalFrameEvent evt)
398 fr.removePropertyChangeListener(change);
401 frame.setLayer(JLayeredPane.PALETTE_LAYER);
402 inConstruction = false;
405 protected void popupSort(final int rowSelected, final String type,
406 final Object typeCol, final Map<String, float[][]> minmax, int x,
409 JPopupMenu men = new JPopupMenu(MessageManager
410 .formatMessage("label.settings_for_param", new String[]
412 JMenuItem scr = new JMenuItem(
413 MessageManager.getString("label.sort_by_score"));
415 final FeatureSettings me = this;
416 scr.addActionListener(new ActionListener()
420 public void actionPerformed(ActionEvent e)
423 .sortAlignmentByFeatureScore(Arrays.asList(new String[]
428 JMenuItem dens = new JMenuItem(
429 MessageManager.getString("label.sort_by_density"));
430 dens.addActionListener(new ActionListener()
434 public void actionPerformed(ActionEvent e)
437 .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
444 JMenuItem selCols = new JMenuItem(
445 MessageManager.getString("label.select_columns_containing"));
446 selCols.addActionListener(new ActionListener()
449 public void actionPerformed(ActionEvent arg0)
451 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
453 fr.ap.av.sendSelection();
456 JMenuItem clearCols = new JMenuItem(MessageManager
457 .getString("label.select_columns_not_containing"));
458 clearCols.addActionListener(new ActionListener()
461 public void actionPerformed(ActionEvent arg0)
463 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
465 fr.ap.av.sendSelection();
468 JMenuItem hideCols = new JMenuItem(
469 MessageManager.getString("label.hide_columns_containing"));
470 hideCols.addActionListener(new ActionListener()
473 public void actionPerformed(ActionEvent arg0)
475 fr.ap.alignFrame.hideFeatureColumns(type, true);
476 fr.ap.av.sendSelection();
479 JMenuItem hideOtherCols = new JMenuItem(
480 MessageManager.getString("label.hide_columns_not_containing"));
481 hideOtherCols.addActionListener(new ActionListener()
484 public void actionPerformed(ActionEvent arg0)
486 fr.ap.alignFrame.hideFeatureColumns(type, false);
487 fr.ap.av.sendSelection();
493 men.add(hideOtherCols);
494 men.show(table, x, y);
498 synchronized public void discoverAllFeatureData()
500 Set<String> allGroups = new HashSet<>();
501 AlignmentI alignment = af.getViewport().getAlignment();
503 for (int i = 0; i < alignment.getHeight(); i++)
505 SequenceI seq = alignment.getSequenceAt(i);
506 for (String group : seq.getFeatures().getFeatureGroups(true))
508 if (group != null && !allGroups.contains(group))
510 allGroups.add(group);
511 checkGroupState(group);
522 * Synchronise gui group list and check visibility of group
525 * @return true if group is visible
527 private boolean checkGroupState(String group)
529 boolean visible = fr.checkGroupVisibility(group, true);
531 for (int g = 0; g < groupPanel.getComponentCount(); g++)
533 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
535 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
540 final String grp = group;
541 final JCheckBox check = new JCheckBox(group, visible);
542 check.setFont(new Font("Serif", Font.BOLD, 12));
543 check.setToolTipText(group);
544 check.addItemListener(new ItemListener()
547 public void itemStateChanged(ItemEvent evt)
549 fr.setGroupVisibility(check.getText(), check.isSelected());
550 resetTable(new String[] { grp });
554 groupPanel.add(check);
558 synchronized void resetTable(String[] groupChanged)
564 resettingTable = true;
565 typeWidth = new Hashtable<>();
566 // TODO: change avWidth calculation to 'per-sequence' average and use long
569 Set<String> displayableTypes = new HashSet<>();
570 Set<String> foundGroups = new HashSet<>();
573 * determine which feature types may be visible depending on
574 * which groups are selected, and recompute average width data
576 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
579 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
582 * get the sequence's groups for positional features
583 * and keep track of which groups are visible
585 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
586 Set<String> visibleGroups = new HashSet<>();
587 for (String group : groups)
589 if (group == null || checkGroupState(group))
591 visibleGroups.add(group);
594 foundGroups.addAll(groups);
597 * get distinct feature types for visible groups
598 * record distinct visible types, and their count and total length
600 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
601 visibleGroups.toArray(new String[visibleGroups.size()]));
602 for (String type : types)
604 displayableTypes.add(type);
605 float[] avWidth = typeWidth.get(type);
608 avWidth = new float[2];
609 typeWidth.put(type, avWidth);
611 // todo this could include features with a non-visible group
612 // - do we greatly care?
613 // todo should we include non-displayable features here, and only
614 // update when features are added?
615 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
616 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
620 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
623 if (fr.hasRenderOrder())
627 fr.findAllFeatures(groupChanged != null); // prod to update
628 // colourschemes. but don't
630 // First add the checks in the previous render order,
631 // in case the window has been closed and reopened
633 List<String> frl = fr.getRenderOrder();
634 for (int ro = frl.size() - 1; ro > -1; ro--)
636 String type = frl.get(ro);
638 if (!displayableTypes.contains(type))
643 data[dataIndex][TYPE_COLUMN] = type;
644 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
645 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
646 data[dataIndex][FILTER_COLUMN] = featureFilter == null
647 ? new FeatureMatcherSet()
649 data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(
650 af.getViewport().getFeaturesDisplayed().isVisible(type));
652 displayableTypes.remove(type);
657 * process any extra features belonging only to
658 * a group which was just selected
660 while (!displayableTypes.isEmpty())
662 String type = displayableTypes.iterator().next();
663 data[dataIndex][TYPE_COLUMN] = type;
665 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
666 if (data[dataIndex][COLOUR_COLUMN] == null)
668 // "Colour has been updated in another view!!"
669 fr.clearRenderOrder();
672 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
673 data[dataIndex][FILTER_COLUMN] = featureFilter == null
674 ? new FeatureMatcherSet()
676 data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(true);
678 displayableTypes.remove(type);
681 if (originalData == null)
683 originalData = new Object[data.length][COLUMN_COUNT];
684 for (int i = 0; i < data.length; i++)
686 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
691 updateOriginalData(data);
694 table.setModel(new FeatureTableModel(data));
695 table.getColumnModel().getColumn(0).setPreferredWidth(200);
697 groupPanel.setLayout(
698 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
699 pruneGroups(foundGroups);
700 groupPanel.validate();
702 updateFeatureRenderer(data, groupChanged != null);
703 resettingTable = false;
707 * Updates 'originalData' (used for restore on Cancel) if we detect that changes
708 * have been made outwith this dialog
710 * <li>a new feature type added (and made visible)</li>
711 * <li>a feature colour changed (in the Amend Features dialog)</li>
716 protected void updateOriginalData(Object[][] foundData)
718 // todo LinkedHashMap instead of Object[][] would be nice
720 Object[][] currentData = ((FeatureTableModel) table.getModel())
722 for (Object[] row : foundData)
724 String type = (String) row[TYPE_COLUMN];
725 boolean found = false;
726 for (Object[] current : currentData)
728 if (type.equals(current[TYPE_COLUMN]))
732 * currently dependent on object equality here;
733 * really need an equals method on FeatureColour
735 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
738 * feature colour has changed externally - update originalData
740 for (Object[] original : originalData)
742 if (type.equals(original[TYPE_COLUMN]))
744 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
755 * new feature detected - add to original data (on top)
757 Object[][] newData = new Object[originalData.length
759 for (int i = 0; i < originalData.length; i++)
761 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
765 originalData = newData;
771 * Remove from the groups panel any checkboxes for groups that are not in the
772 * foundGroups set. This enables removing a group from the display when the last
773 * feature in that group is deleted.
777 protected void pruneGroups(Set<String> foundGroups)
779 for (int g = 0; g < groupPanel.getComponentCount(); g++)
781 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
782 if (!foundGroups.contains(checkbox.getText()))
784 groupPanel.remove(checkbox);
790 * reorder data based on the featureRenderers global priority list.
794 private void ensureOrder(Object[][] data)
796 boolean sort = false;
797 float[] order = new float[data.length];
798 for (int i = 0; i < order.length; i++)
800 order[i] = fr.getOrder(data[i][0].toString());
803 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
807 sort = sort || order[i - 1] > order[i];
812 jalview.util.QuickSort.sort(order, data);
817 * Offers a file chooser dialog, and then loads the feature colours and
818 * filters from file in XML format and unmarshals to Jalview feature settings
822 JalviewFileChooser chooser = new JalviewFileChooser("fc",
823 SEQUENCE_FEATURE_COLOURS);
824 chooser.setFileView(new JalviewFileView());
825 chooser.setDialogTitle(
826 MessageManager.getString("label.load_feature_colours"));
827 chooser.setToolTipText(MessageManager.getString("action.load"));
829 int value = chooser.showOpenDialog(this);
831 if (value == JalviewFileChooser.APPROVE_OPTION)
833 File file = chooser.getSelectedFile();
839 * Loads feature colours and filters from XML stored in the given file
847 InputStreamReader in = new InputStreamReader(
848 new FileInputStream(file), "UTF-8");
850 JAXBContext jc = JAXBContext
851 .newInstance("jalview.xml.binding.jalview");
852 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
853 XMLStreamReader streamReader = XMLInputFactory.newInstance()
854 .createXMLStreamReader(in);
855 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
856 JalviewUserColours.class);
857 JalviewUserColours jucs = jbe.getValue();
859 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
862 * load feature colours
864 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
866 Colour newcol = jucs.getColour().get(i);
867 FeatureColourI colour = jalview.project.Jalview2XML
868 .parseColour(newcol);
869 fr.setColour(newcol.getName(), colour);
870 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
874 * load feature filters; loaded filters will replace any that are
875 * currently defined, other defined filters are left unchanged
877 for (int i = 0; i < jucs.getFilter().size(); i++)
879 Filter filterModel = jucs.getFilter().get(i);
880 String featureType = filterModel.getFeatureType();
881 FeatureMatcherSetI filter = jalview.project.Jalview2XML
882 .parseFilter(featureType, filterModel.getMatcherSet());
883 if (!filter.isEmpty())
885 fr.setFeatureFilter(featureType, filter);
890 * update feature settings table
895 Object[][] data = ((FeatureTableModel) table.getModel())
898 updateFeatureRenderer(data, false);
901 } catch (Exception ex)
903 System.out.println("Error loading User Colour File\n" + ex);
908 * Offers a file chooser dialog, and then saves the current feature colours
909 * and any filters to the selected file in XML format
913 JalviewFileChooser chooser = new JalviewFileChooser("fc",
914 SEQUENCE_FEATURE_COLOURS);
915 chooser.setFileView(new JalviewFileView());
916 chooser.setDialogTitle(
917 MessageManager.getString("label.save_feature_colours"));
918 chooser.setToolTipText(MessageManager.getString("action.save"));
920 int value = chooser.showSaveDialog(this);
922 if (value == JalviewFileChooser.APPROVE_OPTION)
924 save(chooser.getSelectedFile());
929 * Saves feature colours and filters to the given file
935 JalviewUserColours ucs = new JalviewUserColours();
936 ucs.setSchemeName("Sequence Features");
939 PrintWriter out = new PrintWriter(new OutputStreamWriter(
940 new FileOutputStream(file), "UTF-8"));
943 * sort feature types by colour order, from 0 (highest)
946 Set<String> fr_colours = fr.getAllFeatureColours();
947 String[] sortedTypes = fr_colours
948 .toArray(new String[fr_colours.size()]);
949 Arrays.sort(sortedTypes, new Comparator<String>()
952 public int compare(String type1, String type2)
954 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
959 * save feature colours
961 for (String featureType : sortedTypes)
963 FeatureColourI fcol = fr.getFeatureStyle(featureType);
964 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
966 ucs.getColour().add(col);
970 * save any feature filters
972 for (String featureType : sortedTypes)
974 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
975 if (filter != null && !filter.isEmpty())
977 Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
978 FeatureMatcherI firstMatcher = iterator.next();
979 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
980 .marshalFilter(firstMatcher, iterator,
982 Filter filterModel = new Filter();
983 filterModel.setFeatureType(featureType);
984 filterModel.setMatcherSet(ms);
985 ucs.getFilter().add(filterModel);
988 JAXBContext jaxbContext = JAXBContext
989 .newInstance(JalviewUserColours.class);
990 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
991 jaxbMarshaller.marshal(
992 new ObjectFactory().createJalviewUserColours(ucs), out);
994 // jaxbMarshaller.marshal(object, pout);
995 // marshaller.marshal(object);
1000 } catch (Exception ex)
1002 ex.printStackTrace();
1006 public void invertSelection()
1008 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1009 for (int i = 0; i < data.length; i++)
1011 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1013 updateFeatureRenderer(data, true);
1017 public void orderByAvWidth()
1019 if (table == null || table.getModel() == null)
1023 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1024 float[] width = new float[data.length];
1028 for (int i = 0; i < data.length; i++)
1030 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1033 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1034 // weight - but have to make per
1035 // sequence, too (awidth[2])
1036 // if (width[i]==1) // hack to distinguish single width sequences.
1047 boolean sort = false;
1048 for (int i = 0; i < width.length; i++)
1050 // awidth = (float[]) typeWidth.get(data[i][0]);
1053 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1056 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1062 width[i] /= max; // normalize
1063 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
1067 sort = sort || width[i - 1] > width[i];
1072 jalview.util.QuickSort.sort(width, data);
1073 // update global priority order
1076 updateFeatureRenderer(data, false);
1084 frame.setClosed(true);
1085 } catch (Exception exe)
1091 public void updateFeatureRenderer(Object[][] data)
1093 updateFeatureRenderer(data, true);
1097 * Update the priority order of features; only repaint if this changed the order
1098 * of visible features
1103 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1105 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1107 if (fr.setFeaturePriority(rowData, visibleNew))
1114 * Converts table data into an array of data beans
1116 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1118 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1119 for (int i = 0; i < data.length; i++)
1121 String type = (String) data[i][TYPE_COLUMN];
1122 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1123 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1124 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1125 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1131 private void jbInit() throws Exception
1133 this.setLayout(new BorderLayout());
1135 JPanel settingsPane = new JPanel();
1136 settingsPane.setLayout(new BorderLayout());
1138 JPanel bigPanel = new JPanel();
1139 bigPanel.setLayout(new BorderLayout());
1141 groupPanel = new JPanel();
1142 bigPanel.add(groupPanel, BorderLayout.NORTH);
1144 JButton invert = new JButton(
1145 MessageManager.getString("label.invert_selection"));
1146 invert.setFont(JvSwingUtils.getLabelFont());
1147 invert.addActionListener(new ActionListener()
1150 public void actionPerformed(ActionEvent e)
1156 JButton optimizeOrder = new JButton(
1157 MessageManager.getString("label.optimise_order"));
1158 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1159 optimizeOrder.addActionListener(new ActionListener()
1162 public void actionPerformed(ActionEvent e)
1168 JButton sortByScore = new JButton(
1169 MessageManager.getString("label.seq_sort_by_score"));
1170 sortByScore.setFont(JvSwingUtils.getLabelFont());
1171 sortByScore.addActionListener(new ActionListener()
1174 public void actionPerformed(ActionEvent e)
1176 af.avc.sortAlignmentByFeatureScore(null);
1179 JButton sortByDens = new JButton(
1180 MessageManager.getString("label.sequence_sort_by_density"));
1181 sortByDens.setFont(JvSwingUtils.getLabelFont());
1182 sortByDens.addActionListener(new ActionListener()
1185 public void actionPerformed(ActionEvent e)
1187 af.avc.sortAlignmentByFeatureDensity(null);
1191 JButton help = new JButton(MessageManager.getString("action.help"));
1192 help.setFont(JvSwingUtils.getLabelFont());
1193 help.addActionListener(new ActionListener()
1196 public void actionPerformed(ActionEvent e)
1200 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1201 } catch (HelpSetException e1)
1203 e1.printStackTrace();
1208 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1209 cancel.setFont(JvSwingUtils.getLabelFont());
1210 cancel.addActionListener(new ActionListener()
1213 public void actionPerformed(ActionEvent e)
1215 fr.setTransparency(originalTransparency);
1216 fr.setFeatureFilters(originalFilters);
1217 updateFeatureRenderer(originalData);
1218 af.getViewport().setViewStyle(originalViewStyle);
1223 JButton ok = new JButton(MessageManager.getString("action.ok"));
1224 ok.setFont(JvSwingUtils.getLabelFont());
1225 ok.addActionListener(new ActionListener()
1228 public void actionPerformed(ActionEvent e)
1234 JButton loadColours = new JButton(
1235 MessageManager.getString("label.load_colours"));
1236 loadColours.setFont(JvSwingUtils.getLabelFont());
1237 loadColours.setToolTipText(
1238 MessageManager.getString("label.load_colours_tooltip"));
1239 loadColours.addActionListener(new ActionListener()
1242 public void actionPerformed(ActionEvent e)
1248 JButton saveColours = new JButton(
1249 MessageManager.getString("label.save_colours"));
1250 saveColours.setFont(JvSwingUtils.getLabelFont());
1251 saveColours.setToolTipText(
1252 MessageManager.getString("label.save_colours_tooltip"));
1253 saveColours.addActionListener(new ActionListener()
1256 public void actionPerformed(ActionEvent e)
1261 transparency.addChangeListener(new ChangeListener()
1264 public void stateChanged(ChangeEvent evt)
1266 if (!inConstruction)
1268 fr.setTransparency((100 - transparency.getValue()) / 100f);
1274 transparency.setMaximum(70);
1275 transparency.setToolTipText(
1276 MessageManager.getString("label.transparency_tip"));
1278 boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
1279 String text = MessageManager.formatMessage("label.show_linked_features",
1281 ? MessageManager.getString("label.protein")
1284 JCheckBox showComplement = new JCheckBox(text);
1285 showComplement.setSelected(af.getViewport().isShowComplementFeatures());
1286 showComplement.addActionListener(new ActionListener()
1289 public void actionPerformed(ActionEvent e)
1292 .setShowComplementFeatures(showComplement.isSelected());
1297 JCheckBox showComplementOnTop = new JCheckBox(
1298 MessageManager.getString("label.on_top"));
1300 .setSelected(af.getViewport().isShowComplementFeaturesOnTop());
1301 showComplementOnTop.addActionListener(new ActionListener()
1304 public void actionPerformed(ActionEvent e)
1306 af.getViewport().setShowComplementFeaturesOnTop(
1307 showComplementOnTop.isSelected());
1312 JPanel lowerPanel = new JPanel(new GridLayout(1, 2));
1313 bigPanel.add(lowerPanel, BorderLayout.SOUTH);
1315 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1316 transbuttons.add(optimizeOrder);
1317 transbuttons.add(invert);
1318 transbuttons.add(sortByScore);
1319 transbuttons.add(sortByDens);
1320 transbuttons.add(help);
1322 boolean hasComplement = af.getViewport().getCodingComplement() != null;
1323 JPanel transPanelLeft = new JPanel(
1324 new GridLayout(hasComplement ? 3 : 2, 1));
1325 transPanelLeft.add(new JLabel(" Colour transparency" + ":"));
1326 transPanelLeft.add(transparency);
1329 JPanel cp = new JPanel(new FlowLayout(FlowLayout.LEFT));
1330 cp.add(showComplement);
1331 cp.add(showComplementOnTop);
1332 transPanelLeft.add(cp);
1334 lowerPanel.add(transPanelLeft);
1335 lowerPanel.add(transbuttons);
1337 JPanel buttonPanel = new JPanel();
1338 buttonPanel.add(ok);
1339 buttonPanel.add(cancel);
1340 buttonPanel.add(loadColours);
1341 buttonPanel.add(saveColours);
1342 bigPanel.add(scrollPane, BorderLayout.CENTER);
1343 settingsPane.add(bigPanel, BorderLayout.CENTER);
1344 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1345 this.add(settingsPane);
1349 * Repaints alignment, structure and overview (if shown). If there is a
1350 * complementary view which is showing this view's features, then also
1353 void refreshDisplay()
1355 af.alignPanel.paintAlignment(true, true);
1356 AlignViewportI complement = af.getViewport().getCodingComplement();
1357 if (complement != null && complement.isShowComplementFeatures())
1359 AlignFrame af2 = Desktop.getAlignFrameFor(complement);
1360 af2.alignPanel.paintAlignment(true, true);
1365 * Answers a suitable tooltip to show on the colour cell of the table
1369 * if true include 'click to edit' and similar text
1372 public static String getColorTooltip(FeatureColourI fcol,
1379 if (fcol.isSimpleColour())
1381 return withHint ? BASE_TOOLTIP : null;
1383 String description = fcol.getDescription();
1384 description = description.replaceAll("<", "<");
1385 description = description.replaceAll(">", ">");
1386 StringBuilder tt = new StringBuilder(description);
1389 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1391 return JvSwingUtils.wrapTooltip(true, tt.toString());
1394 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1397 boolean thr = false;
1398 StringBuilder tx = new StringBuilder();
1400 if (gcol.isColourByAttribute())
1402 tx.append(FeatureMatcher
1403 .toAttributeDisplayName(gcol.getAttributeName()));
1405 else if (!gcol.isColourByLabel())
1407 tx.append(MessageManager.getString("label.score"));
1410 if (gcol.isAboveThreshold())
1415 if (gcol.isBelowThreshold())
1420 if (gcol.isColourByLabel())
1426 if (!gcol.isColourByAttribute())
1434 Color newColor = gcol.getMaxColour();
1435 comp.setBackground(newColor);
1436 // System.err.println("Width is " + w / 2);
1437 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1438 comp.setIcon(ficon);
1439 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1440 // + newColor.getGreen() + ", " + newColor.getBlue()
1441 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1442 // + ", " + minCol.getBlue() + ")");
1444 comp.setHorizontalAlignment(SwingConstants.CENTER);
1445 comp.setText(tx.toString());
1448 // ///////////////////////////////////////////////////////////////////////
1449 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1450 // ///////////////////////////////////////////////////////////////////////
1451 class FeatureTableModel extends AbstractTableModel
1453 private String[] columnNames = {
1454 MessageManager.getString("label.feature_type"),
1455 MessageManager.getString("action.colour"),
1456 MessageManager.getString("label.configuration"),
1457 MessageManager.getString("label.show") };
1459 private Object[][] data;
1461 FeatureTableModel(Object[][] data)
1466 public Object[][] getData()
1471 public void setData(Object[][] data)
1477 public int getColumnCount()
1479 return columnNames.length;
1482 public Object[] getRow(int row)
1488 public int getRowCount()
1494 public String getColumnName(int col)
1496 return columnNames[col];
1500 public Object getValueAt(int row, int col)
1502 return data[row][col];
1506 * Answers the class of column c of the table
1509 public Class<?> getColumnClass(int c)
1514 return String.class;
1516 return FeatureColour.class;
1518 return FeatureMatcherSet.class;
1520 return Boolean.class;
1525 public boolean isCellEditable(int row, int col)
1527 return col == 0 ? false : true;
1531 public void setValueAt(Object value, int row, int col)
1533 data[row][col] = value;
1534 fireTableCellUpdated(row, col);
1535 updateFeatureRenderer(data);
1540 class ColorRenderer extends JLabel implements TableCellRenderer
1542 Border unselectedBorder = null;
1544 Border selectedBorder = null;
1546 public ColorRenderer()
1548 setOpaque(true); // MUST do this for background to show up.
1549 setHorizontalTextPosition(SwingConstants.CENTER);
1550 setVerticalTextPosition(SwingConstants.CENTER);
1554 public Component getTableCellRendererComponent(JTable tbl, Object color,
1555 boolean isSelected, boolean hasFocus, int row, int column)
1557 FeatureColourI cellColour = (FeatureColourI) color;
1559 setBackground(tbl.getBackground());
1560 if (!cellColour.isSimpleColour())
1562 Rectangle cr = tbl.getCellRect(row, column, false);
1563 FeatureSettings.renderGraduatedColor(this, cellColour,
1564 (int) cr.getWidth(), (int) cr.getHeight());
1570 setBackground(cellColour.getColour());
1574 if (selectedBorder == null)
1576 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1577 tbl.getSelectionBackground());
1579 setBorder(selectedBorder);
1583 if (unselectedBorder == null)
1585 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1586 tbl.getBackground());
1588 setBorder(unselectedBorder);
1595 class FilterRenderer extends JLabel implements TableCellRenderer
1597 javax.swing.border.Border unselectedBorder = null;
1599 javax.swing.border.Border selectedBorder = null;
1601 public FilterRenderer()
1603 setOpaque(true); // MUST do this for background to show up.
1604 setHorizontalTextPosition(SwingConstants.CENTER);
1605 setVerticalTextPosition(SwingConstants.CENTER);
1609 public Component getTableCellRendererComponent(JTable tbl,
1610 Object filter, boolean isSelected, boolean hasFocus, int row,
1613 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1615 String asText = theFilter.toString();
1616 setBackground(tbl.getBackground());
1617 this.setText(asText);
1622 if (selectedBorder == null)
1624 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1625 tbl.getSelectionBackground());
1627 setBorder(selectedBorder);
1631 if (unselectedBorder == null)
1633 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1634 tbl.getBackground());
1636 setBorder(unselectedBorder);
1644 * update comp using rendering settings from gcol
1649 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1651 int w = comp.getWidth(), h = comp.getHeight();
1654 w = (int) comp.getPreferredSize().getWidth();
1655 h = (int) comp.getPreferredSize().getHeight();
1662 renderGraduatedColor(comp, gcol, w, h);
1665 class ColorEditor extends AbstractCellEditor
1666 implements TableCellEditor, ActionListener
1670 FeatureColourI currentColor;
1672 FeatureTypeSettings chooser;
1678 JColorChooser colorChooser;
1682 protected static final String EDIT = "edit";
1684 int rowSelected = 0;
1686 public ColorEditor(FeatureSettings me)
1689 // Set up the editor (from the table's point of view),
1690 // which is a button.
1691 // This button brings up the color chooser dialog,
1692 // which is the editor from the user's point of view.
1693 button = new JButton();
1694 button.setActionCommand(EDIT);
1695 button.addActionListener(this);
1696 button.setBorderPainted(false);
1697 // Set up the dialog that the button brings up.
1698 colorChooser = new JColorChooser();
1699 dialog = JColorChooser.createDialog(button,
1700 MessageManager.getString("label.select_colour"), true, // modal
1701 colorChooser, this, // OK button handler
1702 null); // no CANCEL button handler
1706 * Handles events from the editor button and from the dialog's OK button.
1709 public void actionPerformed(ActionEvent e)
1711 // todo test e.getSource() instead here
1712 if (EDIT.equals(e.getActionCommand()))
1714 // The user has clicked the cell, so
1715 // bring up the dialog.
1716 if (currentColor.isSimpleColour())
1718 // bring up simple color chooser
1719 button.setBackground(currentColor.getColour());
1720 colorChooser.setColor(currentColor.getColour());
1721 dialog.setVisible(true);
1725 // bring up graduated chooser.
1726 chooser = new FeatureTypeSettings(me.fr, type);
1731 chooser.setRequestFocusEnabled(true);
1732 chooser.requestFocus();
1734 chooser.addActionListener(this);
1735 // Make the renderer reappear.
1736 fireEditingStopped();
1741 if (currentColor.isSimpleColour())
1744 * read off colour picked in colour chooser after OK pressed
1746 currentColor = new FeatureColour(colorChooser.getColor());
1747 me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1752 * after OK in variable colour dialog, any changes to colour
1753 * (or filters!) are already set in FeatureRenderer, so just
1754 * update table data without triggering updateFeatureRenderer
1756 currentColor = fr.getFeatureColours().get(type);
1757 FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
1758 if (currentFilter == null)
1760 currentFilter = new FeatureMatcherSet();
1762 Object[] data = ((FeatureTableModel) table.getModel())
1763 .getData()[rowSelected];
1764 data[COLOUR_COLUMN] = currentColor;
1765 data[FILTER_COLUMN] = currentFilter;
1767 fireEditingStopped();
1768 me.table.validate();
1772 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1774 public Object getCellEditorValue()
1776 return currentColor;
1779 // Implement the one method defined by TableCellEditor.
1781 public Component getTableCellEditorComponent(JTable theTable, Object value,
1782 boolean isSelected, int row, int column)
1784 currentColor = (FeatureColourI) value;
1785 this.rowSelected = row;
1786 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1787 button.setOpaque(true);
1788 button.setBackground(me.getBackground());
1789 if (!currentColor.isSimpleColour())
1791 JLabel btn = new JLabel();
1792 btn.setSize(button.getSize());
1793 FeatureSettings.renderGraduatedColor(btn, currentColor);
1794 button.setBackground(btn.getBackground());
1795 button.setIcon(btn.getIcon());
1796 button.setText(btn.getText());
1801 button.setIcon(null);
1802 button.setBackground(currentColor.getColour());
1809 * The cell editor for the Filter column. It displays the text of any filters
1810 * for the feature type in that row (in full as a tooltip, possible abbreviated
1811 * as display text). On click in the cell, opens the Feature Display Settings
1812 * dialog at the Filters tab.
1814 class FilterEditor extends AbstractCellEditor
1815 implements TableCellEditor, ActionListener
1819 FeatureMatcherSetI currentFilter;
1827 protected static final String EDIT = "edit";
1829 int rowSelected = 0;
1831 public FilterEditor(FeatureSettings me)
1834 button = new JButton();
1835 button.setActionCommand(EDIT);
1836 button.addActionListener(this);
1837 button.setBorderPainted(false);
1841 * Handles events from the editor button
1844 public void actionPerformed(ActionEvent e)
1846 if (button == e.getSource())
1848 FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
1849 chooser.addActionListener(this);
1850 chooser.setRequestFocusEnabled(true);
1851 chooser.requestFocus();
1852 if (lastLocation != null)
1854 // todo open at its last position on screen
1855 chooser.setBounds(lastLocation.x, lastLocation.y,
1856 chooser.getWidth(), chooser.getHeight());
1859 fireEditingStopped();
1861 else if (e.getSource() instanceof Component)
1865 * after OK in variable colour dialog, any changes to filter
1866 * (or colours!) are already set in FeatureRenderer, so just
1867 * update table data without triggering updateFeatureRenderer
1869 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1870 currentFilter = me.fr.getFeatureFilter(type);
1871 if (currentFilter == null)
1873 currentFilter = new FeatureMatcherSet();
1875 Object[] data = ((FeatureTableModel) table.getModel())
1876 .getData()[rowSelected];
1877 data[COLOUR_COLUMN] = currentColor;
1878 data[FILTER_COLUMN] = currentFilter;
1879 fireEditingStopped();
1880 me.table.validate();
1885 public Object getCellEditorValue()
1887 return currentFilter;
1891 public Component getTableCellEditorComponent(JTable theTable, Object value,
1892 boolean isSelected, int row, int column)
1894 currentFilter = (FeatureMatcherSetI) value;
1895 this.rowSelected = row;
1896 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1897 button.setOpaque(true);
1898 button.setBackground(me.getBackground());
1899 button.setText(currentFilter.toString());
1900 button.setIcon(null);
1906 class FeatureIcon implements Icon
1908 FeatureColourI gcol;
1912 boolean midspace = false;
1914 int width = 50, height = 20;
1916 int s1, e1; // start and end of midpoint band for thresholded symbol
1918 Color mpcolour = Color.white;
1920 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1940 public int getIconWidth()
1946 public int getIconHeight()
1952 public void paintIcon(Component c, Graphics g, int x, int y)
1955 if (gcol.isColourByLabel())
1958 g.fillRect(0, 0, width, height);
1959 // need an icon here.
1960 g.setColor(gcol.getMaxColour());
1962 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1964 // g.setFont(g.getFont().deriveFont(
1965 // AffineTransform.getScaleInstance(
1966 // width/g.getFontMetrics().stringWidth("Label"),
1967 // height/g.getFontMetrics().getHeight())));
1969 g.drawString(MessageManager.getString("label.label"), 0, 0);
1974 Color minCol = gcol.getMinColour();
1976 g.fillRect(0, 0, s1, height);
1979 g.setColor(Color.white);
1980 g.fillRect(s1, 0, e1 - s1, height);
1982 g.setColor(gcol.getMaxColour());
1983 g.fillRect(0, e1, width - e1, height);