2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.FeatureColourI;
24 import jalview.api.FeatureSettingsControllerI;
25 import jalview.bin.Jalview;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.SequenceI;
28 import jalview.datamodel.features.FeatureMatcher;
29 import jalview.datamodel.features.FeatureMatcherI;
30 import jalview.datamodel.features.FeatureMatcherSet;
31 import jalview.datamodel.features.FeatureMatcherSetI;
32 import jalview.gui.Help.HelpId;
33 import jalview.gui.JalviewColourChooser.ColourChooserListener;
34 import jalview.io.JalviewFileChooser;
35 import jalview.io.JalviewFileView;
36 import jalview.schemes.FeatureColour;
37 import jalview.util.MessageManager;
38 import jalview.util.Platform;
39 import jalview.util.dialogrunner.RunResponse;
40 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
41 import jalview.xml.binding.jalview.JalviewUserColours;
42 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
43 import jalview.xml.binding.jalview.JalviewUserColours.Filter;
44 import jalview.xml.binding.jalview.ObjectFactory;
46 import java.awt.BorderLayout;
47 import java.awt.Color;
48 import java.awt.Component;
49 import java.awt.Dimension;
51 import java.awt.Graphics;
52 import java.awt.GridLayout;
53 import java.awt.Point;
54 import java.awt.Rectangle;
55 import java.awt.event.ActionEvent;
56 import java.awt.event.ActionListener;
57 import java.awt.event.ItemEvent;
58 import java.awt.event.ItemListener;
59 import java.awt.event.MouseAdapter;
60 import java.awt.event.MouseEvent;
61 import java.awt.event.MouseMotionAdapter;
62 import java.beans.PropertyChangeEvent;
63 import java.beans.PropertyChangeListener;
65 import java.io.FileInputStream;
66 import java.io.FileOutputStream;
67 import java.io.InputStreamReader;
68 import java.io.OutputStreamWriter;
69 import java.io.PrintWriter;
70 import java.util.Arrays;
71 import java.util.Comparator;
72 import java.util.HashMap;
73 import java.util.HashSet;
74 import java.util.Hashtable;
75 import java.util.Iterator;
76 import java.util.List;
80 import javax.help.HelpSetException;
81 import javax.swing.AbstractCellEditor;
82 import javax.swing.BorderFactory;
83 import javax.swing.Icon;
84 import javax.swing.JButton;
85 import javax.swing.JCheckBox;
86 import javax.swing.JCheckBoxMenuItem;
87 import javax.swing.JInternalFrame;
88 import javax.swing.JLabel;
89 import javax.swing.JLayeredPane;
90 import javax.swing.JMenuItem;
91 import javax.swing.JPanel;
92 import javax.swing.JPopupMenu;
93 import javax.swing.JScrollPane;
94 import javax.swing.JSlider;
95 import javax.swing.JTable;
96 import javax.swing.ListSelectionModel;
97 import javax.swing.SwingConstants;
98 import javax.swing.ToolTipManager;
99 import javax.swing.border.Border;
100 import javax.swing.event.ChangeEvent;
101 import javax.swing.event.ChangeListener;
102 import javax.swing.plaf.TableUI;
103 import javax.swing.table.AbstractTableModel;
104 import javax.swing.table.TableCellEditor;
105 import javax.swing.table.TableCellRenderer;
106 import javax.swing.table.TableColumn;
107 import javax.xml.bind.JAXBContext;
108 import javax.xml.bind.JAXBElement;
109 import javax.xml.bind.Marshaller;
110 import javax.xml.stream.XMLInputFactory;
111 import javax.xml.stream.XMLStreamReader;
113 public class FeatureSettings extends JPanel
114 implements FeatureSettingsControllerI
116 private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
117 .getString("label.sequence_feature_colours");
120 * column indices of fields in Feature Settings table
122 static final int TYPE_COLUMN = 0;
124 static final int COLOUR_COLUMN = 1;
126 static final int FILTER_COLUMN = 2;
128 static final int SHOW_COLUMN = 3;
130 private static final int COLUMN_COUNT = 4;
132 private static final int MIN_WIDTH = 400;
134 private static final int MIN_HEIGHT = 400;
136 private final static String BASE_TOOLTIP = MessageManager.getString("label.click_to_edit");
138 final FeatureRenderer fr;
140 public final AlignFrame af;
143 * 'original' fields hold settings to restore on Cancel
145 Object[][] originalData;
147 float originalTransparency;
149 Map<String, FeatureMatcherSetI> originalFilters;
151 final JInternalFrame frame;
153 JScrollPane scrollPane = new JScrollPane();
159 JSlider transparency = new JSlider();
162 * when true, constructor is still executing - so ignore UI events
164 protected volatile boolean inConstruction = true;
166 int selectedRow = -1;
168 JButton fetchDAS = new JButton();
170 JButton saveDAS = new JButton();
172 JButton cancelDAS = new JButton();
174 boolean resettingTable = false;
177 * true when Feature Settings are updating from feature renderer
179 boolean handlingUpdate = false;
182 * holds {featureCount, totalExtent} for each feature type
184 Map<String, float[]> typeWidth = null;
191 public FeatureSettings(AlignFrame alignFrame)
193 this.af = alignFrame;
194 fr = af.getFeatureRenderer();
196 // save transparency for restore on Cancel
197 originalTransparency = fr.getTransparency();
198 int originalTransparencyAsPercent = (int) (originalTransparency * 100);
199 transparency.setMaximum(100 - originalTransparencyAsPercent);
201 originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
206 } catch (Exception ex)
208 ex.printStackTrace();
214 public String getToolTipText(MouseEvent e)
217 int column = table.columnAtPoint(e.getPoint());
218 int row = table.rowAtPoint(e.getPoint());
223 tip = JvSwingUtils.wrapTooltip(true, MessageManager
224 .getString("label.feature_settings_click_drag"));
227 FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
229 tip = getColorTooltip(colour, true);
232 FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
235 ? MessageManager.getString("label.filters_tooltip")
247 * Position the tooltip near the bottom edge of, and half way across, the
251 public Point getToolTipLocation(MouseEvent e)
253 Point point = e.getPoint();
254 int column = table.columnAtPoint(point);
255 int row = table.rowAtPoint(point);
256 Rectangle r = getCellRect(row, column, false);
257 Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3);
262 // next line is needed to avoid (quiet) exceptions thrown
263 // when column ordering changes so that the above constants
265 table.getTableHeader().setReorderingAllowed(false); // BH 2018
267 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
268 ToolTipManager.sharedInstance().registerComponent(table);
270 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
271 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
273 table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor(this));
274 table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
276 TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
277 new ColorRenderer(), new ColorEditor(this));
278 table.addColumn(colourColumn);
280 TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
281 new FilterRenderer(), new FilterEditor(this));
282 table.addColumn(filterColumn);
284 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
286 table.addMouseListener(new MouseAdapter()
289 public void mousePressed(MouseEvent evt)
291 selectedRow = table.rowAtPoint(evt.getPoint());
292 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
293 if (evt.isPopupTrigger())
295 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
296 showPopupMenu(selectedRow, type, colour, evt.getPoint());
298 else if (evt.getClickCount() == 2)
300 boolean invertSelection = evt.isAltDown();
301 boolean toggleSelection = Platform.isControlDown(evt);
302 boolean extendSelection = evt.isShiftDown();
303 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
304 invertSelection, extendSelection, toggleSelection, type);
308 // isPopupTrigger fires on mouseReleased on Windows
310 public void mouseReleased(MouseEvent evt)
312 selectedRow = table.rowAtPoint(evt.getPoint());
313 if (evt.isPopupTrigger())
315 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
316 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
317 showPopupMenu(selectedRow, type, colour, evt.getPoint());
322 table.addMouseMotionListener(new MouseMotionAdapter()
325 public void mouseDragged(MouseEvent evt)
327 int newRow = table.rowAtPoint(evt.getPoint());
328 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
331 * reposition 'selectedRow' to 'newRow' (the dragged to location)
332 * this could be more than one row away for a very fast drag action
333 * so just swap it with adjacent rows until we get it there
335 Object[][] data = ((FeatureTableModel) table.getModel())
337 int direction = newRow < selectedRow ? -1 : 1;
338 for (int i = selectedRow; i != newRow; i += direction)
340 Object[] temp = data[i];
341 data[i] = data[i + direction];
342 data[i + direction] = temp;
344 updateFeatureRenderer(data);
346 selectedRow = newRow;
350 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
351 // MessageManager.getString("label.feature_settings_click_drag")));
352 scrollPane.setViewportView(table);
354 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
356 fr.findAllFeatures(true); // display everything!
359 discoverAllFeatureData();
360 final PropertyChangeListener change;
361 final FeatureSettings fs = this;
362 fr.addPropertyChangeListener(change = new PropertyChangeListener()
365 public void propertyChange(PropertyChangeEvent evt)
367 if (!fs.resettingTable && !fs.handlingUpdate)
369 fs.handlingUpdate = true;
371 // new groups may be added with new sequence feature types only
372 fs.handlingUpdate = false;
378 frame = new JInternalFrame();
379 frame.setContentPane(this);
380 if (Platform.isAMac())
382 Desktop.addInternalFrame(frame,
383 MessageManager.getString("label.sequence_feature_settings"),
388 Desktop.addInternalFrame(frame,
389 MessageManager.getString("label.sequence_feature_settings"),
392 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
394 frame.addInternalFrameListener(
395 new javax.swing.event.InternalFrameAdapter()
398 public void internalFrameClosed(
399 javax.swing.event.InternalFrameEvent evt)
401 fr.removePropertyChangeListener(change);
404 frame.setLayer(JLayeredPane.PALETTE_LAYER);
405 inConstruction = false;
409 * Constructs and shows a popup menu of possible actions on the selected row and
417 protected void showPopupMenu(final int rowSelected, final String type,
418 final Object typeCol, final Point pt)
420 final FeatureColourI featureColour = (FeatureColourI) typeCol;
422 JPopupMenu men = new JPopupMenu(MessageManager
423 .formatMessage("label.settings_for_param", new String[]
425 JMenuItem scr = new JMenuItem(
426 MessageManager.getString("label.sort_by_score"));
428 final FeatureSettings me = this;
429 scr.addActionListener(new ActionListener()
433 public void actionPerformed(ActionEvent e)
436 .sortAlignmentByFeatureScore(Arrays.asList(new String[]
440 JMenuItem dens = new JMenuItem(
441 MessageManager.getString("label.sort_by_density"));
442 dens.addActionListener(new ActionListener()
446 public void actionPerformed(ActionEvent e)
449 .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
456 * variable colour options include colour by label, by score,
457 * by selected attribute text, or attribute value
459 final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
460 MessageManager.getString("label.variable_colour"));
461 variableColourCB.setSelected(!featureColour.isSimpleColour());
462 men.add(variableColourCB);
465 * checkbox action listener doubles up as listener to OK
466 * from the variable colour / filters dialog
468 variableColourCB.addActionListener(new ActionListener()
471 public void actionPerformed(ActionEvent e)
473 if (e.getSource() == variableColourCB)
475 if (featureColour.isSimpleColour())
478 * toggle simple colour to variable colour - show dialog
480 FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type);
481 fc.addActionListener(this);
486 * toggle variable to simple colour - show colour chooser
488 String title = MessageManager.formatMessage("label.select_colour_for", type);
489 ColourChooserListener listener = new ColourChooserListener()
492 public void colourSelected(Color c)
494 table.setValueAt(new FeatureColour(c), rowSelected,
497 me.updateFeatureRenderer(
498 ((FeatureTableModel) table.getModel()).getData(),
502 JalviewColourChooser.showColourChooser(me, title, featureColour.getMaxColour(), listener);
507 if (e.getSource() instanceof FeatureTypeSettings)
510 * update after OK in feature colour dialog; the updated
511 * colour will have already been set in the FeatureRenderer
513 FeatureColourI fci = fr.getFeatureColours().get(type);
514 table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
521 JMenuItem selCols = new JMenuItem(
522 MessageManager.getString("label.select_columns_containing"));
523 selCols.addActionListener(new ActionListener()
526 public void actionPerformed(ActionEvent arg0)
528 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
532 JMenuItem clearCols = new JMenuItem(MessageManager
533 .getString("label.select_columns_not_containing"));
534 clearCols.addActionListener(new ActionListener()
537 public void actionPerformed(ActionEvent arg0)
539 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
543 JMenuItem hideCols = new JMenuItem(
544 MessageManager.getString("label.hide_columns_containing"));
545 hideCols.addActionListener(new ActionListener()
548 public void actionPerformed(ActionEvent arg0)
550 fr.ap.alignFrame.hideFeatureColumns(type, true);
553 JMenuItem hideOtherCols = new JMenuItem(
554 MessageManager.getString("label.hide_columns_not_containing"));
555 hideOtherCols.addActionListener(new ActionListener()
558 public void actionPerformed(ActionEvent arg0)
560 fr.ap.alignFrame.hideFeatureColumns(type, false);
566 men.add(hideOtherCols);
567 men.show(table, pt.x, pt.y);
571 synchronized public void discoverAllFeatureData()
573 Set<String> allGroups = new HashSet<>();
574 AlignmentI alignment = af.getViewport().getAlignment();
576 for (int i = 0; i < alignment.getHeight(); i++)
578 SequenceI seq = alignment.getSequenceAt(i);
579 for (String group : seq.getFeatures().getFeatureGroups(true))
581 if (group != null && !allGroups.contains(group))
583 allGroups.add(group);
584 checkGroupState(group);
595 * Synchronise gui group list and check visibility of group
598 * @return true if group is visible
600 private boolean checkGroupState(String group)
602 boolean visible = fr.checkGroupVisibility(group, true);
604 for (int g = 0; g < groupPanel.getComponentCount(); g++)
606 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
608 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
613 final String grp = group;
614 final JCheckBox check = new JCheckBox(group, visible);
615 check.setFont(new Font("Serif", Font.BOLD, 12));
616 check.setToolTipText(group);
617 check.addItemListener(new ItemListener()
620 public void itemStateChanged(ItemEvent evt)
622 fr.setGroupVisibility(check.getText(), check.isSelected());
623 resetTable(new String[] { grp });
624 af.alignPanel.paintAlignment(true, true);
627 groupPanel.add(check);
631 synchronized void resetTable(String[] groupChanged)
637 resettingTable = true;
638 typeWidth = new Hashtable<>();
639 // TODO: change avWidth calculation to 'per-sequence' average and use long
642 Set<String> displayableTypes = new HashSet<>();
643 Set<String> foundGroups = new HashSet<>();
646 * determine which feature types may be visible depending on
647 * which groups are selected, and recompute average width data
649 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
652 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
655 * get the sequence's groups for positional features
656 * and keep track of which groups are visible
658 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
659 Set<String> visibleGroups = new HashSet<>();
660 for (String group : groups)
662 if (group == null || checkGroupState(group))
664 visibleGroups.add(group);
667 foundGroups.addAll(groups);
670 * get distinct feature types for visible groups
671 * record distinct visible types, and their count and total length
673 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
674 visibleGroups.toArray(new String[visibleGroups.size()]));
675 for (String type : types)
677 displayableTypes.add(type);
678 float[] avWidth = typeWidth.get(type);
681 avWidth = new float[2];
682 typeWidth.put(type, avWidth);
684 // todo this could include features with a non-visible group
685 // - do we greatly care?
686 // todo should we include non-displayable features here, and only
687 // update when features are added?
688 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
689 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
693 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
696 if (fr.hasRenderOrder())
700 fr.findAllFeatures(groupChanged != null); // prod to update
701 // colourschemes. but don't
703 // First add the checks in the previous render order,
704 // in case the window has been closed and reopened
706 List<String> frl = fr.getRenderOrder();
707 for (int ro = frl.size() - 1; ro > -1; ro--)
709 String type = frl.get(ro);
711 if (!displayableTypes.contains(type))
716 data[dataIndex][TYPE_COLUMN] = type;
717 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
718 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
719 data[dataIndex][FILTER_COLUMN] = featureFilter == null
720 ? new FeatureMatcherSet()
722 data[dataIndex][SHOW_COLUMN] = new Boolean(
723 af.getViewport().getFeaturesDisplayed().isVisible(type));
725 displayableTypes.remove(type);
730 * process any extra features belonging only to
731 * a group which was just selected
733 while (!displayableTypes.isEmpty())
735 String type = displayableTypes.iterator().next();
736 data[dataIndex][TYPE_COLUMN] = type;
738 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
739 if (data[dataIndex][COLOUR_COLUMN] == null)
741 // "Colour has been updated in another view!!"
742 fr.clearRenderOrder();
745 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
746 data[dataIndex][FILTER_COLUMN] = featureFilter == null
747 ? new FeatureMatcherSet()
749 data[dataIndex][SHOW_COLUMN] = new Boolean(true);
751 displayableTypes.remove(type);
754 if (originalData == null)
756 originalData = new Object[data.length][COLUMN_COUNT];
757 for (int i = 0; i < data.length; i++)
759 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
764 updateOriginalData(data);
767 table.setModel(new FeatureTableModel(data));
768 table.getColumnModel().getColumn(0).setPreferredWidth(200);
770 groupPanel.setLayout(
771 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
772 pruneGroups(foundGroups);
773 groupPanel.validate();
775 updateFeatureRenderer(data, groupChanged != null);
776 resettingTable = false;
780 * Updates 'originalData' (used for restore on Cancel) if we detect that changes
781 * have been made outwith this dialog
783 * <li>a new feature type added (and made visible)</li>
784 * <li>a feature colour changed (in the Amend Features dialog)</li>
789 protected void updateOriginalData(Object[][] foundData)
791 // todo LinkedHashMap instead of Object[][] would be nice
793 Object[][] currentData = ((FeatureTableModel) table.getModel())
795 for (Object[] row : foundData)
797 String type = (String) row[TYPE_COLUMN];
798 boolean found = false;
799 for (Object[] current : currentData)
801 if (type.equals(current[TYPE_COLUMN]))
805 * currently dependent on object equality here;
806 * really need an equals method on FeatureColour
808 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
811 * feature colour has changed externally - update originalData
813 for (Object[] original : originalData)
815 if (type.equals(original[TYPE_COLUMN]))
817 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
828 * new feature detected - add to original data (on top)
830 Object[][] newData = new Object[originalData.length
832 for (int i = 0; i < originalData.length; i++)
834 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
838 originalData = newData;
844 * Remove from the groups panel any checkboxes for groups that are not in the
845 * foundGroups set. This enables removing a group from the display when the last
846 * feature in that group is deleted.
850 protected void pruneGroups(Set<String> foundGroups)
852 for (int g = 0; g < groupPanel.getComponentCount(); g++)
854 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
855 if (!foundGroups.contains(checkbox.getText()))
857 groupPanel.remove(checkbox);
863 * reorder data based on the featureRenderers global priority list.
867 private void ensureOrder(Object[][] data)
869 boolean sort = false;
870 float[] order = new float[data.length];
871 for (int i = 0; i < order.length; i++)
873 order[i] = fr.getOrder(data[i][0].toString());
876 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
880 sort = sort || order[i - 1] > order[i];
885 jalview.util.QuickSort.sort(order, data);
890 * Offers a file chooser dialog, and then loads the feature colours and
891 * filters from file in XML format and unmarshals to Jalview feature settings
895 JalviewFileChooser chooser = new JalviewFileChooser("fc",
896 SEQUENCE_FEATURE_COLOURS);
897 chooser.setFileView(new JalviewFileView());
898 chooser.setDialogTitle(
899 MessageManager.getString("label.load_feature_colours"));
900 chooser.setToolTipText(MessageManager.getString("action.load"));
901 chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION){
905 File file = chooser.getSelectedFile();
908 chooser.showOpenDialog(this);
912 * Loads feature colours and filters from XML stored in the given file
920 InputStreamReader in = new InputStreamReader(
921 new FileInputStream(file), "UTF-8");
923 JAXBContext jc = JAXBContext
924 .newInstance("jalview.xml.binding.jalview");
925 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
926 XMLStreamReader streamReader = XMLInputFactory.newInstance()
927 .createXMLStreamReader(in);
928 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
929 JalviewUserColours.class);
930 JalviewUserColours jucs = jbe.getValue();
932 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
935 * load feature colours
937 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
939 Colour newcol = jucs.getColour().get(i);
940 FeatureColourI colour = jalview.project.Jalview2XML
941 .parseColour(newcol);
942 fr.setColour(newcol.getName(), colour);
943 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
947 * load feature filters; loaded filters will replace any that are
948 * currently defined, other defined filters are left unchanged
950 for (int i = 0; i < jucs.getFilter().size(); i++)
952 Filter filterModel = jucs.getFilter().get(i);
953 String featureType = filterModel.getFeatureType();
954 FeatureMatcherSetI filter = jalview.project.Jalview2XML
955 .parseFilter(featureType, filterModel.getMatcherSet());
956 if (!filter.isEmpty())
958 fr.setFeatureFilter(featureType, filter);
963 * update feature settings table
968 Object[][] data = ((FeatureTableModel) table.getModel())
971 updateFeatureRenderer(data, false);
974 } catch (Exception ex)
976 System.out.println("Error loading User Colour File\n" + ex);
981 * Offers a file chooser dialog, and then saves the current feature colours
982 * and any filters to the selected file in XML format
986 JalviewFileChooser chooser = new JalviewFileChooser("fc",
987 SEQUENCE_FEATURE_COLOURS);
988 chooser.setFileView(new JalviewFileView());
989 chooser.setDialogTitle(
990 MessageManager.getString("label.save_feature_colours"));
991 chooser.setToolTipText(MessageManager.getString("action.save"));
992 int option = chooser.showSaveDialog(this);
993 if (option == JalviewFileChooser.APPROVE_OPTION)
995 File file = chooser.getSelectedFile();
1001 * Saves feature colours and filters to the given file
1005 void save(File file)
1007 JalviewUserColours ucs = new JalviewUserColours();
1008 ucs.setSchemeName("Sequence Features");
1011 PrintWriter out = new PrintWriter(new OutputStreamWriter(
1012 new FileOutputStream(file), "UTF-8"));
1015 * sort feature types by colour order, from 0 (highest)
1018 Set<String> fr_colours = fr.getAllFeatureColours();
1019 String[] sortedTypes = fr_colours
1020 .toArray(new String[fr_colours.size()]);
1021 Arrays.sort(sortedTypes, new Comparator<String>()
1024 public int compare(String type1, String type2)
1026 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
1031 * save feature colours
1033 for (String featureType : sortedTypes)
1035 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1036 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
1038 ucs.getColour().add(col);
1042 * save any feature filters
1044 for (String featureType : sortedTypes)
1046 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1047 if (filter != null && !filter.isEmpty())
1049 Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
1050 FeatureMatcherI firstMatcher = iterator.next();
1051 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
1052 .marshalFilter(firstMatcher, iterator,
1054 Filter filterModel = new Filter();
1055 filterModel.setFeatureType(featureType);
1056 filterModel.setMatcherSet(ms);
1057 ucs.getFilter().add(filterModel);
1060 JAXBContext jaxbContext = JAXBContext
1061 .newInstance(JalviewUserColours.class);
1062 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1063 jaxbMarshaller.marshal(
1064 new ObjectFactory().createJalviewUserColours(ucs), out);
1066 // jaxbMarshaller.marshal(object, pout);
1067 // marshaller.marshal(object);
1070 // ucs.marshal(out);
1072 } catch (Exception ex)
1074 ex.printStackTrace();
1078 public void invertSelection()
1080 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1081 for (int i = 0; i < data.length; i++)
1083 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1085 updateFeatureRenderer(data, true);
1089 public void orderByAvWidth()
1091 if (table == null || table.getModel() == null)
1095 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1096 float[] width = new float[data.length];
1100 for (int i = 0; i < data.length; i++)
1102 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1105 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1106 // weight - but have to make per
1107 // sequence, too (awidth[2])
1108 // if (width[i]==1) // hack to distinguish single width sequences.
1119 boolean sort = false;
1120 for (int i = 0; i < width.length; i++)
1122 // awidth = (float[]) typeWidth.get(data[i][0]);
1125 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1128 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1134 width[i] /= max; // normalize
1135 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
1139 sort = sort || width[i - 1] > width[i];
1144 jalview.util.QuickSort.sort(width, data);
1145 // update global priority order
1148 updateFeatureRenderer(data, false);
1153 * Repaints the table using alternative code for Java and J2S
1155 private void repaintTable()
1158 // Here is a needed intervention
1159 // because generally we don't "repaint"
1160 // the table. We re-create the HTML divs
1161 // that is associated with it. A better
1162 // way to do this would be to fire a property change.
1163 @SuppressWarnings("unused")
1164 TableUI ui = table.getUI();
1166 * @j2sNative ui.repaintTable$();
1177 frame.setClosed(true);
1178 } catch (Exception exe)
1184 public void updateFeatureRenderer(Object[][] data)
1186 updateFeatureRenderer(data, true);
1190 * Update the priority order of features; only repaint if this changed the order
1191 * of visible features
1196 void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1198 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1200 if (fr.setFeaturePriority(rowData, visibleNew))
1202 af.alignPanel.paintAlignment(true, true);
1207 * Converts table data into an array of data beans
1209 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1211 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1212 for (int i = 0; i < data.length; i++)
1214 String type = (String) data[i][TYPE_COLUMN];
1215 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1216 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1217 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1218 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1224 private void jbInit() throws Exception
1226 this.setLayout(new BorderLayout());
1228 JPanel settingsPane = new JPanel();
1229 settingsPane.setLayout(new BorderLayout());
1231 JPanel bigPanel = new JPanel();
1232 bigPanel.setLayout(new BorderLayout());
1234 groupPanel = new JPanel();
1235 bigPanel.add(groupPanel, BorderLayout.NORTH);
1237 JButton invert = new JButton(
1238 MessageManager.getString("label.invert_selection"));
1239 invert.setFont(JvSwingUtils.getLabelFont());
1240 invert.addActionListener(new ActionListener()
1243 public void actionPerformed(ActionEvent e)
1249 JButton optimizeOrder = new JButton(
1250 MessageManager.getString("label.optimise_order"));
1251 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1252 optimizeOrder.addActionListener(new ActionListener()
1255 public void actionPerformed(ActionEvent e)
1261 JButton sortByScore = new JButton(
1262 MessageManager.getString("label.seq_sort_by_score"));
1263 sortByScore.setFont(JvSwingUtils.getLabelFont());
1264 sortByScore.addActionListener(new ActionListener()
1267 public void actionPerformed(ActionEvent e)
1269 af.avc.sortAlignmentByFeatureScore(null);
1272 JButton sortByDens = new JButton(
1273 MessageManager.getString("label.sequence_sort_by_density"));
1274 sortByDens.setFont(JvSwingUtils.getLabelFont());
1275 sortByDens.addActionListener(new ActionListener()
1278 public void actionPerformed(ActionEvent e)
1280 af.avc.sortAlignmentByFeatureDensity(null);
1284 JButton help = new JButton(MessageManager.getString("action.help"));
1285 help.setFont(JvSwingUtils.getLabelFont());
1286 help.addActionListener(new ActionListener()
1289 public void actionPerformed(ActionEvent e)
1293 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1294 } catch (HelpSetException e1)
1296 e1.printStackTrace();
1300 help.setFont(JvSwingUtils.getLabelFont());
1301 help.setText(MessageManager.getString("action.help"));
1302 help.addActionListener(new ActionListener()
1305 public void actionPerformed(ActionEvent e)
1309 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1310 } catch (HelpSetException e1)
1312 e1.printStackTrace();
1317 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1318 cancel.setFont(JvSwingUtils.getLabelFont());
1319 cancel.addActionListener(new ActionListener()
1322 public void actionPerformed(ActionEvent e)
1324 fr.setTransparency(originalTransparency);
1325 fr.setFeatureFilters(originalFilters);
1326 updateFeatureRenderer(originalData);
1331 JButton ok = new JButton(MessageManager.getString("action.ok"));
1332 ok.setFont(JvSwingUtils.getLabelFont());
1333 ok.addActionListener(new ActionListener()
1336 public void actionPerformed(ActionEvent e)
1342 JButton loadColours = new JButton(
1343 MessageManager.getString("label.load_colours"));
1344 loadColours.setFont(JvSwingUtils.getLabelFont());
1345 loadColours.setToolTipText(
1346 MessageManager.getString("label.load_colours_tooltip"));
1347 loadColours.addActionListener(new ActionListener()
1350 public void actionPerformed(ActionEvent e)
1356 JButton saveColours = new JButton(
1357 MessageManager.getString("label.save_colours"));
1358 saveColours.setFont(JvSwingUtils.getLabelFont());
1359 saveColours.setToolTipText(
1360 MessageManager.getString("label.save_colours_tooltip"));
1361 saveColours.addActionListener(new ActionListener()
1364 public void actionPerformed(ActionEvent e)
1369 transparency.addChangeListener(new ChangeListener()
1372 public void stateChanged(ChangeEvent evt)
1374 if (!inConstruction)
1376 fr.setTransparency((100 - transparency.getValue()) / 100f);
1377 af.alignPanel.paintAlignment(true, true);
1382 transparency.setMaximum(70);
1383 transparency.setToolTipText(
1384 MessageManager.getString("label.transparency_tip"));
1386 JPanel transPanel = new JPanel(new GridLayout(1, 2));
1387 bigPanel.add(transPanel, BorderLayout.SOUTH);
1389 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1390 transbuttons.add(optimizeOrder);
1391 transbuttons.add(invert);
1392 transbuttons.add(sortByScore);
1393 transbuttons.add(sortByDens);
1394 transbuttons.add(help);
1395 transPanel.add(transparency);
1396 transPanel.add(transbuttons);
1398 JPanel buttonPanel = new JPanel();
1399 buttonPanel.add(ok);
1400 buttonPanel.add(cancel);
1401 buttonPanel.add(loadColours);
1402 buttonPanel.add(saveColours);
1403 bigPanel.add(scrollPane, BorderLayout.CENTER);
1404 settingsPane.add(bigPanel, BorderLayout.CENTER);
1405 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1406 this.add(settingsPane);
1410 * Answers a suitable tooltip to show on the colour cell of the table
1414 * if true include 'click to edit' and similar text
1417 public static String getColorTooltip(FeatureColourI fcol,
1424 if (fcol.isSimpleColour())
1426 return withHint ? BASE_TOOLTIP : null;
1428 String description = fcol.getDescription();
1429 description = description.replaceAll("<", "<");
1430 description = description.replaceAll(">", ">");
1431 StringBuilder tt = new StringBuilder(description);
1434 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1436 return JvSwingUtils.wrapTooltip(true, tt.toString());
1439 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1442 boolean thr = false;
1443 StringBuilder tx = new StringBuilder();
1445 if (gcol.isColourByAttribute())
1447 tx.append(FeatureMatcher
1448 .toAttributeDisplayName(gcol.getAttributeName()));
1450 else if (!gcol.isColourByLabel())
1452 tx.append(MessageManager.getString("label.score"));
1455 if (gcol.isAboveThreshold())
1460 if (gcol.isBelowThreshold())
1465 if (gcol.isColourByLabel())
1471 if (!gcol.isColourByAttribute())
1479 Color newColor = gcol.getMaxColour();
1480 comp.setBackground(newColor);
1481 // System.err.println("Width is " + w / 2);
1482 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1483 comp.setIcon(ficon);
1484 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1485 // + newColor.getGreen() + ", " + newColor.getBlue()
1486 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1487 // + ", " + minCol.getBlue() + ")");
1489 comp.setHorizontalAlignment(SwingConstants.CENTER);
1490 comp.setText(tx.toString());
1493 // ///////////////////////////////////////////////////////////////////////
1494 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1495 // ///////////////////////////////////////////////////////////////////////
1496 class FeatureTableModel extends AbstractTableModel
1498 private String[] columnNames = {
1499 MessageManager.getString("label.feature_type"),
1500 MessageManager.getString("action.colour"),
1501 MessageManager.getString("label.filter"),
1502 MessageManager.getString("label.show") };
1504 private Object[][] data;
1506 FeatureTableModel(Object[][] data)
1511 public Object[][] getData()
1516 public void setData(Object[][] data)
1522 public int getColumnCount()
1524 return columnNames.length;
1527 public Object[] getRow(int row)
1533 public int getRowCount()
1539 public String getColumnName(int col)
1541 return columnNames[col];
1545 public Object getValueAt(int row, int col)
1547 return data[row][col];
1551 * Answers the class of the object in column c of the first row of the table
1554 public Class<?> getColumnClass(int c)
1556 Object v = getValueAt(0, c);
1557 return v == null ? null : v.getClass();
1561 public boolean isCellEditable(int row, int col)
1563 return col == 0 ? false : true;
1567 public void setValueAt(Object value, int row, int col)
1569 data[row][col] = value;
1570 fireTableCellUpdated(row, col);
1571 updateFeatureRenderer(data);
1576 class ColorRenderer extends JLabel implements TableCellRenderer
1578 Border unselectedBorder = null;
1580 Border selectedBorder = null;
1582 public ColorRenderer()
1584 setOpaque(true); // MUST do this for background to show up.
1585 setHorizontalTextPosition(SwingConstants.CENTER);
1586 setVerticalTextPosition(SwingConstants.CENTER);
1590 public Component getTableCellRendererComponent(JTable tbl, Object color,
1591 boolean isSelected, boolean hasFocus, int row, int column)
1593 FeatureColourI cellColour = (FeatureColourI) color;
1595 setBackground(tbl.getBackground());
1596 if (!cellColour.isSimpleColour())
1598 Rectangle cr = tbl.getCellRect(row, column, false);
1599 FeatureSettings.renderGraduatedColor(this, cellColour,
1600 (int) cr.getWidth(), (int) cr.getHeight());
1606 setBackground(cellColour.getColour());
1610 if (selectedBorder == null)
1612 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1613 tbl.getSelectionBackground());
1615 setBorder(selectedBorder);
1619 if (unselectedBorder == null)
1621 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1622 tbl.getBackground());
1624 setBorder(unselectedBorder);
1631 class FilterRenderer extends JLabel implements TableCellRenderer
1633 javax.swing.border.Border unselectedBorder = null;
1635 javax.swing.border.Border selectedBorder = null;
1637 public FilterRenderer()
1639 setOpaque(true); // MUST do this for background to show up.
1640 setHorizontalTextPosition(SwingConstants.CENTER);
1641 setVerticalTextPosition(SwingConstants.CENTER);
1645 public Component getTableCellRendererComponent(JTable tbl,
1646 Object filter, boolean isSelected, boolean hasFocus, int row,
1649 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1651 String asText = theFilter.toString();
1652 setBackground(tbl.getBackground());
1653 this.setText(asText);
1658 if (selectedBorder == null)
1660 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1661 tbl.getSelectionBackground());
1663 setBorder(selectedBorder);
1667 if (unselectedBorder == null)
1669 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1670 tbl.getBackground());
1672 setBorder(unselectedBorder);
1680 * update comp using rendering settings from gcol
1685 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1687 int w = comp.getWidth(), h = comp.getHeight();
1690 w = (int) comp.getPreferredSize().getWidth();
1691 h = (int) comp.getPreferredSize().getHeight();
1698 renderGraduatedColor(comp, gcol, w, h);
1701 class ColorEditor extends AbstractCellEditor
1702 implements TableCellEditor, ActionListener
1706 FeatureColourI currentColor;
1708 FeatureTypeSettings chooser;
1714 protected static final String EDIT = "edit";
1716 int rowSelected = 0;
1718 public ColorEditor(FeatureSettings fs)
1721 // Set up the editor (from the table's point of view),
1722 // which is a button.
1723 // This button brings up the color chooser dialog,
1724 // which is the editor from the user's point of view.
1725 button = new JButton();
1726 button.setActionCommand(EDIT);
1727 button.addActionListener(this);
1728 button.setBorderPainted(false);
1732 * Handles events from the editor button, and from the colour/filters
1733 * dialog's OK button
1736 public void actionPerformed(ActionEvent e)
1738 if (button == e.getSource())
1740 if (currentColor.isSimpleColour())
1743 * simple colour chooser
1745 String ttl = MessageManager.formatMessage("label.select_colour_for", type);
1746 ColourChooserListener listener = new ColourChooserListener()
1749 public void colourSelected(Color c)
1751 currentColor = new FeatureColour(c);
1752 me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1753 fireEditingStopped();
1756 public void cancel()
1758 fireEditingStopped();
1761 JalviewColourChooser.showColourChooser(button, ttl, currentColor.getColour(), listener);
1766 * variable colour and filters dialog
1768 chooser = new FeatureTypeSettings(me.fr, type);
1769 if (!Jalview.isJS())
1771 chooser.setRequestFocusEnabled(true);
1772 chooser.requestFocus();
1774 chooser.addActionListener(this);
1775 fireEditingStopped();
1781 * after OK in variable colour dialog, any changes to colour
1782 * (or filters!) are already set in FeatureRenderer, so just
1783 * update table data without triggering updateFeatureRenderer
1785 currentColor = fr.getFeatureColours().get(type);
1786 FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
1787 if (currentFilter == null)
1789 currentFilter = new FeatureMatcherSet();
1791 Object[] data = ((FeatureTableModel) table.getModel())
1792 .getData()[rowSelected];
1793 data[COLOUR_COLUMN] = currentColor;
1794 data[FILTER_COLUMN] = currentFilter;
1796 fireEditingStopped();
1797 me.table.validate();
1801 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1803 public Object getCellEditorValue()
1805 return currentColor;
1808 // Implement the one method defined by TableCellEditor.
1810 public Component getTableCellEditorComponent(JTable theTable, Object value,
1811 boolean isSelected, int row, int column)
1813 currentColor = (FeatureColourI) value;
1814 this.rowSelected = row;
1815 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1816 button.setOpaque(true);
1817 button.setBackground(me.getBackground());
1818 if (!currentColor.isSimpleColour())
1820 JLabel btn = new JLabel();
1821 btn.setSize(button.getSize());
1822 FeatureSettings.renderGraduatedColor(btn, currentColor);
1823 button.setBackground(btn.getBackground());
1824 button.setIcon(btn.getIcon());
1825 button.setText(btn.getText());
1830 button.setIcon(null);
1831 button.setBackground(currentColor.getColour());
1838 * The cell editor for the Filter column. It displays the text of any filters
1839 * for the feature type in that row (in full as a tooltip, possible abbreviated
1840 * as display text). On click in the cell, opens the Feature Display Settings
1841 * dialog at the Filters tab.
1843 class FilterEditor extends AbstractCellEditor
1844 implements TableCellEditor, ActionListener
1848 FeatureMatcherSetI currentFilter;
1856 protected static final String EDIT = "edit";
1858 int rowSelected = 0;
1860 public FilterEditor(FeatureSettings me)
1863 button = new JButton();
1864 button.setActionCommand(EDIT);
1865 button.addActionListener(this);
1866 button.setBorderPainted(false);
1870 * Handles events from the editor button
1873 public void actionPerformed(ActionEvent e)
1875 if (button == e.getSource())
1877 FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
1878 chooser.addActionListener(this);
1879 chooser.setRequestFocusEnabled(true);
1880 chooser.requestFocus();
1881 if (lastLocation != null)
1883 // todo open at its last position on screen
1884 chooser.setBounds(lastLocation.x, lastLocation.y,
1885 chooser.getWidth(), chooser.getHeight());
1888 fireEditingStopped();
1890 else if (e.getSource() instanceof Component)
1894 * after OK in variable colour dialog, any changes to filter
1895 * (or colours!) are already set in FeatureRenderer, so just
1896 * update table data without triggering updateFeatureRenderer
1898 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1899 currentFilter = me.fr.getFeatureFilter(type);
1900 if (currentFilter == null)
1902 currentFilter = new FeatureMatcherSet();
1904 Object[] data = ((FeatureTableModel) table.getModel())
1905 .getData()[rowSelected];
1906 data[COLOUR_COLUMN] = currentColor;
1907 data[FILTER_COLUMN] = currentFilter;
1908 fireEditingStopped();
1909 me.table.validate();
1914 public Object getCellEditorValue()
1916 return currentFilter;
1920 public Component getTableCellEditorComponent(JTable theTable, Object value,
1921 boolean isSelected, int row, int column)
1923 currentFilter = (FeatureMatcherSetI) value;
1924 this.rowSelected = row;
1925 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1926 button.setOpaque(true);
1927 button.setBackground(me.getBackground());
1928 button.setText(currentFilter.toString());
1929 button.setIcon(null);
1935 class FeatureIcon implements Icon
1937 FeatureColourI gcol;
1941 boolean midspace = false;
1943 int width = 50, height = 20;
1945 int s1, e1; // start and end of midpoint band for thresholded symbol
1947 Color mpcolour = Color.white;
1949 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1969 public int getIconWidth()
1975 public int getIconHeight()
1981 public void paintIcon(Component c, Graphics g, int x, int y)
1984 if (gcol.isColourByLabel())
1987 g.fillRect(0, 0, width, height);
1988 // need an icon here.
1989 g.setColor(gcol.getMaxColour());
1991 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1993 // g.setFont(g.getFont().deriveFont(
1994 // AffineTransform.getScaleInstance(
1995 // width/g.getFontMetrics().stringWidth("Label"),
1996 // height/g.getFontMetrics().getHeight())));
1998 g.drawString(MessageManager.getString("label.label"), 0, 0);
2003 Color minCol = gcol.getMinColour();
2005 g.fillRect(0, 0, s1, height);
2008 g.setColor(Color.white);
2009 g.fillRect(s1, 0, e1 - s1, height);
2011 g.setColor(gcol.getMaxColour());
2012 g.fillRect(0, e1, width - e1, height);