2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.FeatureColourI;
24 import jalview.api.FeatureSettingsControllerI;
25 import jalview.bin.Jalview;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.SequenceI;
28 import jalview.datamodel.features.FeatureMatcher;
29 import jalview.datamodel.features.FeatureMatcherI;
30 import jalview.datamodel.features.FeatureMatcherSet;
31 import jalview.datamodel.features.FeatureMatcherSetI;
32 import jalview.gui.Help.HelpId;
33 import jalview.gui.JalviewColourChooser.ColourChooserListener;
34 import jalview.io.JalviewFileChooser;
35 import jalview.io.JalviewFileView;
36 import jalview.schemes.FeatureColour;
37 import jalview.util.MessageManager;
38 import jalview.util.Platform;
39 import jalview.util.dialogrunner.RunResponse;
40 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
41 import jalview.xml.binding.jalview.JalviewUserColours;
42 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
43 import jalview.xml.binding.jalview.JalviewUserColours.Filter;
44 import jalview.xml.binding.jalview.ObjectFactory;
46 import java.awt.BorderLayout;
47 import java.awt.Color;
48 import java.awt.Component;
49 import java.awt.Dimension;
51 import java.awt.Graphics;
52 import java.awt.GridLayout;
53 import java.awt.Point;
54 import java.awt.Rectangle;
55 import java.awt.event.ActionEvent;
56 import java.awt.event.ActionListener;
57 import java.awt.event.ItemEvent;
58 import java.awt.event.ItemListener;
59 import java.awt.event.MouseAdapter;
60 import java.awt.event.MouseEvent;
61 import java.awt.event.MouseMotionAdapter;
62 import java.beans.PropertyChangeEvent;
63 import java.beans.PropertyChangeListener;
65 import java.io.FileInputStream;
66 import java.io.FileOutputStream;
67 import java.io.InputStreamReader;
68 import java.io.OutputStreamWriter;
69 import java.io.PrintWriter;
70 import java.util.Arrays;
71 import java.util.Comparator;
72 import java.util.HashMap;
73 import java.util.HashSet;
74 import java.util.Hashtable;
75 import java.util.Iterator;
76 import java.util.List;
80 import javax.help.HelpSetException;
81 import javax.swing.AbstractCellEditor;
82 import javax.swing.BorderFactory;
83 import javax.swing.Icon;
84 import javax.swing.JButton;
85 import javax.swing.JCheckBox;
86 import javax.swing.JCheckBoxMenuItem;
87 import javax.swing.JInternalFrame;
88 import javax.swing.JLabel;
89 import javax.swing.JLayeredPane;
90 import javax.swing.JMenuItem;
91 import javax.swing.JPanel;
92 import javax.swing.JPopupMenu;
93 import javax.swing.JScrollPane;
94 import javax.swing.JSlider;
95 import javax.swing.JTable;
96 import javax.swing.ListSelectionModel;
97 import javax.swing.SwingConstants;
98 import javax.swing.ToolTipManager;
99 import javax.swing.border.Border;
100 import javax.swing.event.ChangeEvent;
101 import javax.swing.event.ChangeListener;
102 import javax.swing.plaf.TableUI;
103 import javax.swing.table.AbstractTableModel;
104 import javax.swing.table.TableCellEditor;
105 import javax.swing.table.TableCellRenderer;
106 import javax.swing.table.TableColumn;
107 import javax.xml.bind.JAXBContext;
108 import javax.xml.bind.JAXBElement;
109 import javax.xml.bind.Marshaller;
110 import javax.xml.stream.XMLInputFactory;
111 import javax.xml.stream.XMLStreamReader;
113 public class FeatureSettings extends JPanel
114 implements FeatureSettingsControllerI
116 private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
117 .getString("label.sequence_feature_colours");
120 * column indices of fields in Feature Settings table
122 static final int TYPE_COLUMN = 0;
124 static final int COLOUR_COLUMN = 1;
126 static final int FILTER_COLUMN = 2;
128 static final int SHOW_COLUMN = 3;
130 private static final int COLUMN_COUNT = 4;
132 private static final int MIN_WIDTH = 400;
134 private static final int MIN_HEIGHT = 400;
136 private final static String BASE_TOOLTIP = MessageManager.getString("label.click_to_edit");
138 final FeatureRenderer fr;
140 public final AlignFrame af;
143 * 'original' fields hold settings to restore on Cancel
145 Object[][] originalData;
147 float originalTransparency;
149 Map<String, FeatureMatcherSetI> originalFilters;
151 final JInternalFrame frame;
153 JScrollPane scrollPane = new JScrollPane();
159 JSlider transparency = new JSlider();
162 * when true, constructor is still executing - so ignore UI events
164 protected volatile boolean inConstruction = true;
166 int selectedRow = -1;
168 JButton fetchDAS = new JButton();
170 JButton saveDAS = new JButton();
172 JButton cancelDAS = new JButton();
174 boolean resettingTable = false;
177 * true when Feature Settings are updating from feature renderer
179 boolean handlingUpdate = false;
182 * holds {featureCount, totalExtent} for each feature type
184 Map<String, float[]> typeWidth = null;
191 public FeatureSettings(AlignFrame alignFrame)
193 this.af = alignFrame;
194 fr = af.getFeatureRenderer();
196 // save transparency for restore on Cancel
197 originalTransparency = fr.getTransparency();
198 int originalTransparencyAsPercent = (int) (originalTransparency * 100);
199 transparency.setMaximum(100 - originalTransparencyAsPercent);
201 originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
206 } catch (Exception ex)
208 ex.printStackTrace();
214 public String getToolTipText(MouseEvent e)
217 int column = table.columnAtPoint(e.getPoint());
218 int row = table.rowAtPoint(e.getPoint());
223 tip = JvSwingUtils.wrapTooltip(true, MessageManager
224 .getString("label.feature_settings_click_drag"));
227 FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
229 tip = getColorTooltip(colour, true);
232 FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
235 ? MessageManager.getString("label.filters_tooltip")
247 * Position the tooltip near the bottom edge of, and half way across, the
251 public Point getToolTipLocation(MouseEvent e)
253 Point point = e.getPoint();
254 int column = table.columnAtPoint(point);
255 int row = table.rowAtPoint(point);
256 Rectangle r = getCellRect(row, column, false);
257 Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3);
262 // next line is needed to avoid (quiet) exceptions thrown
263 // when column ordering changes so that the above constants
265 table.getTableHeader().setReorderingAllowed(false); // BH 2018
267 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
268 ToolTipManager.sharedInstance().registerComponent(table);
270 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
271 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
273 table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor(this));
274 table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
276 TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
277 new ColorRenderer(), new ColorEditor(this));
278 table.addColumn(colourColumn);
280 TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
281 new FilterRenderer(), new FilterEditor(this));
282 table.addColumn(filterColumn);
284 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
286 table.addMouseListener(new MouseAdapter()
289 public void mousePressed(MouseEvent evt)
291 selectedRow = table.rowAtPoint(evt.getPoint());
292 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
293 if (evt.isPopupTrigger())
295 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
296 showPopupMenu(selectedRow, type, colour, evt.getPoint());
298 else if (evt.getClickCount() == 2)
300 boolean invertSelection = evt.isAltDown();
301 boolean toggleSelection = Platform.isControlDown(evt);
302 boolean extendSelection = evt.isShiftDown();
303 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
304 invertSelection, extendSelection, toggleSelection, type);
308 // isPopupTrigger fires on mouseReleased on Windows
310 public void mouseReleased(MouseEvent evt)
312 selectedRow = table.rowAtPoint(evt.getPoint());
313 if (evt.isPopupTrigger())
315 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
316 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
317 showPopupMenu(selectedRow, type, colour, evt.getPoint());
322 table.addMouseMotionListener(new MouseMotionAdapter()
325 public void mouseDragged(MouseEvent evt)
327 int newRow = table.rowAtPoint(evt.getPoint());
328 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
331 * reposition 'selectedRow' to 'newRow' (the dragged to location)
332 * this could be more than one row away for a very fast drag action
333 * so just swap it with adjacent rows until we get it there
335 Object[][] data = ((FeatureTableModel) table.getModel())
337 int direction = newRow < selectedRow ? -1 : 1;
338 for (int i = selectedRow; i != newRow; i += direction)
340 Object[] temp = data[i];
341 data[i] = data[i + direction];
342 data[i + direction] = temp;
344 updateFeatureRenderer(data);
346 selectedRow = newRow;
350 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
351 // MessageManager.getString("label.feature_settings_click_drag")));
352 scrollPane.setViewportView(table);
354 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
356 fr.findAllFeatures(true); // display everything!
359 discoverAllFeatureData();
360 final PropertyChangeListener change;
361 final FeatureSettings fs = this;
362 fr.addPropertyChangeListener(change = new PropertyChangeListener()
365 public void propertyChange(PropertyChangeEvent evt)
367 if (!fs.resettingTable && !fs.handlingUpdate)
369 fs.handlingUpdate = true;
371 // new groups may be added with new sequence feature types only
372 fs.handlingUpdate = false;
378 frame = new JInternalFrame();
379 frame.setContentPane(this);
380 if (Platform.isAMac())
382 Desktop.addInternalFrame(frame,
383 MessageManager.getString("label.sequence_feature_settings"),
388 Desktop.addInternalFrame(frame,
389 MessageManager.getString("label.sequence_feature_settings"),
392 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
394 frame.addInternalFrameListener(
395 new javax.swing.event.InternalFrameAdapter()
398 public void internalFrameClosed(
399 javax.swing.event.InternalFrameEvent evt)
401 fr.removePropertyChangeListener(change);
404 frame.setLayer(JLayeredPane.PALETTE_LAYER);
405 inConstruction = false;
409 * Constructs and shows a popup menu of possible actions on the selected row and
417 protected void showPopupMenu(final int rowSelected, final String type,
418 final Object typeCol, final Point pt)
420 final FeatureColourI featureColour = (FeatureColourI) typeCol;
422 JPopupMenu men = new JPopupMenu(MessageManager
423 .formatMessage("label.settings_for_param", new String[]
425 JMenuItem scr = new JMenuItem(
426 MessageManager.getString("label.sort_by_score"));
428 final FeatureSettings me = this;
429 scr.addActionListener(new ActionListener()
433 public void actionPerformed(ActionEvent e)
436 .sortAlignmentByFeatureScore(Arrays.asList(new String[]
440 JMenuItem dens = new JMenuItem(
441 MessageManager.getString("label.sort_by_density"));
442 dens.addActionListener(new ActionListener()
446 public void actionPerformed(ActionEvent e)
449 .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
456 * variable colour options include colour by label, by score,
457 * by selected attribute text, or attribute value
459 final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
460 MessageManager.getString("label.variable_colour"));
461 variableColourCB.setSelected(!featureColour.isSimpleColour());
462 men.add(variableColourCB);
465 * checkbox action listener doubles up as listener to OK
466 * from the variable colour / filters dialog
468 variableColourCB.addActionListener(new ActionListener()
471 public void actionPerformed(ActionEvent e)
473 if (e.getSource() == variableColourCB)
475 men.setVisible(true); // BH 2018 for JavaScript because this is a checkbox
476 men.setVisible(false); // BH 2018 for JavaScript because this is a checkbox
477 if (featureColour.isSimpleColour())
480 * toggle simple colour to variable colour - show dialog
482 FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type);
483 fc.addActionListener(this);
488 * toggle variable to simple colour - show colour chooser
490 String title = MessageManager.formatMessage("label.select_colour_for", type);
491 ColourChooserListener listener = new ColourChooserListener()
494 public void colourSelected(Color c)
496 table.setValueAt(new FeatureColour(c), rowSelected,
499 me.updateFeatureRenderer(
500 ((FeatureTableModel) table.getModel()).getData(),
504 JalviewColourChooser.showColourChooser(me, title, featureColour.getMaxColour(), listener);
509 if (e.getSource() instanceof FeatureTypeSettings)
512 * update after OK in feature colour dialog; the updated
513 * colour will have already been set in the FeatureRenderer
515 FeatureColourI fci = fr.getFeatureColours().get(type);
516 table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
517 // BH 2018 setting a table value does not invalidate it.
518 System.out.println("FeatureSettings is valied" + table.isValid());
525 JMenuItem selCols = new JMenuItem(
526 MessageManager.getString("label.select_columns_containing"));
527 selCols.addActionListener(new ActionListener()
530 public void actionPerformed(ActionEvent arg0)
532 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
536 JMenuItem clearCols = new JMenuItem(MessageManager
537 .getString("label.select_columns_not_containing"));
538 clearCols.addActionListener(new ActionListener()
541 public void actionPerformed(ActionEvent arg0)
543 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
547 JMenuItem hideCols = new JMenuItem(
548 MessageManager.getString("label.hide_columns_containing"));
549 hideCols.addActionListener(new ActionListener()
552 public void actionPerformed(ActionEvent arg0)
554 fr.ap.alignFrame.hideFeatureColumns(type, true);
557 JMenuItem hideOtherCols = new JMenuItem(
558 MessageManager.getString("label.hide_columns_not_containing"));
559 hideOtherCols.addActionListener(new ActionListener()
562 public void actionPerformed(ActionEvent arg0)
564 fr.ap.alignFrame.hideFeatureColumns(type, false);
570 men.add(hideOtherCols);
571 men.show(table, pt.x, pt.y);
575 synchronized public void discoverAllFeatureData()
577 Set<String> allGroups = new HashSet<>();
578 AlignmentI alignment = af.getViewport().getAlignment();
580 for (int i = 0; i < alignment.getHeight(); i++)
582 SequenceI seq = alignment.getSequenceAt(i);
583 for (String group : seq.getFeatures().getFeatureGroups(true))
585 if (group != null && !allGroups.contains(group))
587 allGroups.add(group);
588 checkGroupState(group);
599 * Synchronise gui group list and check visibility of group
602 * @return true if group is visible
604 private boolean checkGroupState(String group)
606 boolean visible = fr.checkGroupVisibility(group, true);
608 for (int g = 0; g < groupPanel.getComponentCount(); g++)
610 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
612 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
617 final String grp = group;
618 final JCheckBox check = new JCheckBox(group, visible);
619 check.setFont(new Font("Serif", Font.BOLD, 12));
620 check.setToolTipText(group);
621 check.addItemListener(new ItemListener()
624 public void itemStateChanged(ItemEvent evt)
626 fr.setGroupVisibility(check.getText(), check.isSelected());
627 resetTable(new String[] { grp });
628 af.alignPanel.paintAlignment(true, true);
631 groupPanel.add(check);
635 synchronized void resetTable(String[] groupChanged)
641 resettingTable = true;
642 typeWidth = new Hashtable<>();
643 // TODO: change avWidth calculation to 'per-sequence' average and use long
646 Set<String> displayableTypes = new HashSet<>();
647 Set<String> foundGroups = new HashSet<>();
650 * determine which feature types may be visible depending on
651 * which groups are selected, and recompute average width data
653 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
656 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
659 * get the sequence's groups for positional features
660 * and keep track of which groups are visible
662 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
663 Set<String> visibleGroups = new HashSet<>();
664 for (String group : groups)
666 if (group == null || checkGroupState(group))
668 visibleGroups.add(group);
671 foundGroups.addAll(groups);
674 * get distinct feature types for visible groups
675 * record distinct visible types, and their count and total length
677 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
678 visibleGroups.toArray(new String[visibleGroups.size()]));
679 for (String type : types)
681 displayableTypes.add(type);
682 float[] avWidth = typeWidth.get(type);
685 avWidth = new float[2];
686 typeWidth.put(type, avWidth);
688 // todo this could include features with a non-visible group
689 // - do we greatly care?
690 // todo should we include non-displayable features here, and only
691 // update when features are added?
692 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
693 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
697 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
700 if (fr.hasRenderOrder())
704 fr.findAllFeatures(groupChanged != null); // prod to update
705 // colourschemes. but don't
707 // First add the checks in the previous render order,
708 // in case the window has been closed and reopened
710 List<String> frl = fr.getRenderOrder();
711 for (int ro = frl.size() - 1; ro > -1; ro--)
713 String type = frl.get(ro);
715 if (!displayableTypes.contains(type))
720 data[dataIndex][TYPE_COLUMN] = type;
721 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
722 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
723 data[dataIndex][FILTER_COLUMN] = featureFilter == null
724 ? new FeatureMatcherSet()
726 data[dataIndex][SHOW_COLUMN] = new Boolean(
727 af.getViewport().getFeaturesDisplayed().isVisible(type));
729 displayableTypes.remove(type);
734 * process any extra features belonging only to
735 * a group which was just selected
737 while (!displayableTypes.isEmpty())
739 String type = displayableTypes.iterator().next();
740 data[dataIndex][TYPE_COLUMN] = type;
742 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
743 if (data[dataIndex][COLOUR_COLUMN] == null)
745 // "Colour has been updated in another view!!"
746 fr.clearRenderOrder();
749 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
750 data[dataIndex][FILTER_COLUMN] = featureFilter == null
751 ? new FeatureMatcherSet()
753 data[dataIndex][SHOW_COLUMN] = new Boolean(true);
755 displayableTypes.remove(type);
758 if (originalData == null)
760 originalData = new Object[data.length][COLUMN_COUNT];
761 for (int i = 0; i < data.length; i++)
763 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
768 updateOriginalData(data);
771 table.setModel(new FeatureTableModel(data));
772 table.getColumnModel().getColumn(0).setPreferredWidth(200);
774 groupPanel.setLayout(
775 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
776 pruneGroups(foundGroups);
777 groupPanel.validate();
779 updateFeatureRenderer(data, groupChanged != null);
780 resettingTable = false;
784 * Updates 'originalData' (used for restore on Cancel) if we detect that changes
785 * have been made outwith this dialog
787 * <li>a new feature type added (and made visible)</li>
788 * <li>a feature colour changed (in the Amend Features dialog)</li>
793 protected void updateOriginalData(Object[][] foundData)
795 // todo LinkedHashMap instead of Object[][] would be nice
797 Object[][] currentData = ((FeatureTableModel) table.getModel())
799 for (Object[] row : foundData)
801 String type = (String) row[TYPE_COLUMN];
802 boolean found = false;
803 for (Object[] current : currentData)
805 if (type.equals(current[TYPE_COLUMN]))
809 * currently dependent on object equality here;
810 * really need an equals method on FeatureColour
812 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
815 * feature colour has changed externally - update originalData
817 for (Object[] original : originalData)
819 if (type.equals(original[TYPE_COLUMN]))
821 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
832 * new feature detected - add to original data (on top)
834 Object[][] newData = new Object[originalData.length
836 for (int i = 0; i < originalData.length; i++)
838 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
842 originalData = newData;
848 * Remove from the groups panel any checkboxes for groups that are not in the
849 * foundGroups set. This enables removing a group from the display when the last
850 * feature in that group is deleted.
854 protected void pruneGroups(Set<String> foundGroups)
856 for (int g = 0; g < groupPanel.getComponentCount(); g++)
858 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
859 if (!foundGroups.contains(checkbox.getText()))
861 groupPanel.remove(checkbox);
867 * reorder data based on the featureRenderers global priority list.
871 private void ensureOrder(Object[][] data)
873 boolean sort = false;
874 float[] order = new float[data.length];
875 for (int i = 0; i < order.length; i++)
877 order[i] = fr.getOrder(data[i][0].toString());
880 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
884 sort = sort || order[i - 1] > order[i];
889 jalview.util.QuickSort.sort(order, data);
894 * Offers a file chooser dialog, and then loads the feature colours and
895 * filters from file in XML format and unmarshals to Jalview feature settings
899 JalviewFileChooser chooser = new JalviewFileChooser("fc",
900 SEQUENCE_FEATURE_COLOURS);
901 chooser.setFileView(new JalviewFileView());
902 chooser.setDialogTitle(
903 MessageManager.getString("label.load_feature_colours"));
904 chooser.setToolTipText(MessageManager.getString("action.load"));
905 chooser.addResponse(new RunResponse(JalviewFileChooser.APPROVE_OPTION){
909 File file = chooser.getSelectedFile();
912 chooser.showOpenDialog(this);
916 * Loads feature colours and filters from XML stored in the given file
924 InputStreamReader in = new InputStreamReader(
925 new FileInputStream(file), "UTF-8");
927 JAXBContext jc = JAXBContext
928 .newInstance("jalview.xml.binding.jalview");
929 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
930 XMLStreamReader streamReader = XMLInputFactory.newInstance()
931 .createXMLStreamReader(in);
932 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
933 JalviewUserColours.class);
934 JalviewUserColours jucs = jbe.getValue();
936 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
939 * load feature colours
941 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
943 Colour newcol = jucs.getColour().get(i);
944 FeatureColourI colour = jalview.project.Jalview2XML
945 .parseColour(newcol);
946 fr.setColour(newcol.getName(), colour);
947 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
951 * load feature filters; loaded filters will replace any that are
952 * currently defined, other defined filters are left unchanged
954 for (int i = 0; i < jucs.getFilter().size(); i++)
956 Filter filterModel = jucs.getFilter().get(i);
957 String featureType = filterModel.getFeatureType();
958 FeatureMatcherSetI filter = jalview.project.Jalview2XML
959 .parseFilter(featureType, filterModel.getMatcherSet());
960 if (!filter.isEmpty())
962 fr.setFeatureFilter(featureType, filter);
967 * update feature settings table
972 Object[][] data = ((FeatureTableModel) table.getModel())
975 updateFeatureRenderer(data, false);
978 } catch (Exception ex)
980 System.out.println("Error loading User Colour File\n" + ex);
985 * Offers a file chooser dialog, and then saves the current feature colours
986 * and any filters to the selected file in XML format
990 JalviewFileChooser chooser = new JalviewFileChooser("fc",
991 SEQUENCE_FEATURE_COLOURS);
992 chooser.setFileView(new JalviewFileView());
993 chooser.setDialogTitle(
994 MessageManager.getString("label.save_feature_colours"));
995 chooser.setToolTipText(MessageManager.getString("action.save"));
996 int option = chooser.showSaveDialog(this);
997 if (option == JalviewFileChooser.APPROVE_OPTION)
999 File file = chooser.getSelectedFile();
1005 * Saves feature colours and filters to the given file
1009 void save(File file)
1011 JalviewUserColours ucs = new JalviewUserColours();
1012 ucs.setSchemeName("Sequence Features");
1015 PrintWriter out = new PrintWriter(new OutputStreamWriter(
1016 new FileOutputStream(file), "UTF-8"));
1019 * sort feature types by colour order, from 0 (highest)
1022 Set<String> fr_colours = fr.getAllFeatureColours();
1023 String[] sortedTypes = fr_colours
1024 .toArray(new String[fr_colours.size()]);
1025 Arrays.sort(sortedTypes, new Comparator<String>()
1028 public int compare(String type1, String type2)
1030 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
1035 * save feature colours
1037 for (String featureType : sortedTypes)
1039 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1040 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
1042 ucs.getColour().add(col);
1046 * save any feature filters
1048 for (String featureType : sortedTypes)
1050 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1051 if (filter != null && !filter.isEmpty())
1053 Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
1054 FeatureMatcherI firstMatcher = iterator.next();
1055 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
1056 .marshalFilter(firstMatcher, iterator,
1058 Filter filterModel = new Filter();
1059 filterModel.setFeatureType(featureType);
1060 filterModel.setMatcherSet(ms);
1061 ucs.getFilter().add(filterModel);
1064 JAXBContext jaxbContext = JAXBContext
1065 .newInstance(JalviewUserColours.class);
1066 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1067 jaxbMarshaller.marshal(
1068 new ObjectFactory().createJalviewUserColours(ucs), out);
1070 // jaxbMarshaller.marshal(object, pout);
1071 // marshaller.marshal(object);
1074 // ucs.marshal(out);
1076 } catch (Exception ex)
1078 ex.printStackTrace();
1082 public void invertSelection()
1084 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1085 for (int i = 0; i < data.length; i++)
1087 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1089 updateFeatureRenderer(data, true);
1093 public void orderByAvWidth()
1095 if (table == null || table.getModel() == null)
1099 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1100 float[] width = new float[data.length];
1104 for (int i = 0; i < data.length; i++)
1106 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1109 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1110 // weight - but have to make per
1111 // sequence, too (awidth[2])
1112 // if (width[i]==1) // hack to distinguish single width sequences.
1123 boolean sort = false;
1124 for (int i = 0; i < width.length; i++)
1126 // awidth = (float[]) typeWidth.get(data[i][0]);
1129 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1132 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1138 width[i] /= max; // normalize
1139 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
1143 sort = sort || width[i - 1] > width[i];
1148 jalview.util.QuickSort.sort(width, data);
1149 // update global priority order
1152 updateFeatureRenderer(data, false);
1157 * Repaints the table using alternative code for Java and J2S
1159 private void repaintTable()
1165 // // Here is a needed intervention
1166 // // because generally we don't "repaint"
1167 // // the table. We re-create the HTML divs
1168 // // that is associated with it. A better
1169 // // way to do this would be to fire a property change.
1170 // @SuppressWarnings("unused")
1171 // TableUI ui = table.getUI();
1173 // * @j2sNative ui.repaintTable$();
1183 frame.setClosed(true);
1184 } catch (Exception exe)
1190 public void updateFeatureRenderer(Object[][] data)
1192 updateFeatureRenderer(data, true);
1196 * Update the priority order of features; only repaint if this changed the order
1197 * of visible features
1202 void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1204 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1206 if (fr.setFeaturePriority(rowData, visibleNew))
1208 af.alignPanel.paintAlignment(true, true);
1213 * Converts table data into an array of data beans
1215 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1217 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1218 for (int i = 0; i < data.length; i++)
1220 String type = (String) data[i][TYPE_COLUMN];
1221 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1222 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1223 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1224 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1230 private void jbInit() throws Exception
1232 this.setLayout(new BorderLayout());
1234 JPanel settingsPane = new JPanel();
1235 settingsPane.setLayout(new BorderLayout());
1237 JPanel bigPanel = new JPanel();
1238 bigPanel.setLayout(new BorderLayout());
1240 groupPanel = new JPanel();
1241 bigPanel.add(groupPanel, BorderLayout.NORTH);
1243 JButton invert = new JButton(
1244 MessageManager.getString("label.invert_selection"));
1245 invert.setFont(JvSwingUtils.getLabelFont());
1246 invert.addActionListener(new ActionListener()
1249 public void actionPerformed(ActionEvent e)
1255 JButton optimizeOrder = new JButton(
1256 MessageManager.getString("label.optimise_order"));
1257 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1258 optimizeOrder.addActionListener(new ActionListener()
1261 public void actionPerformed(ActionEvent e)
1267 JButton sortByScore = new JButton(
1268 MessageManager.getString("label.seq_sort_by_score"));
1269 sortByScore.setFont(JvSwingUtils.getLabelFont());
1270 sortByScore.addActionListener(new ActionListener()
1273 public void actionPerformed(ActionEvent e)
1275 af.avc.sortAlignmentByFeatureScore(null);
1278 JButton sortByDens = new JButton(
1279 MessageManager.getString("label.sequence_sort_by_density"));
1280 sortByDens.setFont(JvSwingUtils.getLabelFont());
1281 sortByDens.addActionListener(new ActionListener()
1284 public void actionPerformed(ActionEvent e)
1286 af.avc.sortAlignmentByFeatureDensity(null);
1290 JButton help = new JButton(MessageManager.getString("action.help"));
1291 help.setFont(JvSwingUtils.getLabelFont());
1292 help.addActionListener(new ActionListener()
1295 public void actionPerformed(ActionEvent e)
1299 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1300 } catch (HelpSetException e1)
1302 e1.printStackTrace();
1306 help.setFont(JvSwingUtils.getLabelFont());
1307 help.setText(MessageManager.getString("action.help"));
1308 help.addActionListener(new ActionListener()
1311 public void actionPerformed(ActionEvent e)
1315 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1316 } catch (HelpSetException e1)
1318 e1.printStackTrace();
1323 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1324 cancel.setFont(JvSwingUtils.getLabelFont());
1325 cancel.addActionListener(new ActionListener()
1328 public void actionPerformed(ActionEvent e)
1330 fr.setTransparency(originalTransparency);
1331 fr.setFeatureFilters(originalFilters);
1332 updateFeatureRenderer(originalData);
1337 JButton ok = new JButton(MessageManager.getString("action.ok"));
1338 ok.setFont(JvSwingUtils.getLabelFont());
1339 ok.addActionListener(new ActionListener()
1342 public void actionPerformed(ActionEvent e)
1348 JButton loadColours = new JButton(
1349 MessageManager.getString("label.load_colours"));
1350 loadColours.setFont(JvSwingUtils.getLabelFont());
1351 loadColours.setToolTipText(
1352 MessageManager.getString("label.load_colours_tooltip"));
1353 loadColours.addActionListener(new ActionListener()
1356 public void actionPerformed(ActionEvent e)
1362 JButton saveColours = new JButton(
1363 MessageManager.getString("label.save_colours"));
1364 saveColours.setFont(JvSwingUtils.getLabelFont());
1365 saveColours.setToolTipText(
1366 MessageManager.getString("label.save_colours_tooltip"));
1367 saveColours.addActionListener(new ActionListener()
1370 public void actionPerformed(ActionEvent e)
1375 transparency.addChangeListener(new ChangeListener()
1378 public void stateChanged(ChangeEvent evt)
1380 if (!inConstruction)
1382 fr.setTransparency((100 - transparency.getValue()) / 100f);
1383 af.alignPanel.paintAlignment(true, true);
1388 transparency.setMaximum(70);
1389 transparency.setToolTipText(
1390 MessageManager.getString("label.transparency_tip"));
1392 JPanel transPanel = new JPanel(new GridLayout(1, 2));
1393 bigPanel.add(transPanel, BorderLayout.SOUTH);
1395 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1396 transbuttons.add(optimizeOrder);
1397 transbuttons.add(invert);
1398 transbuttons.add(sortByScore);
1399 transbuttons.add(sortByDens);
1400 transbuttons.add(help);
1401 transPanel.add(transparency);
1402 transPanel.add(transbuttons);
1404 JPanel buttonPanel = new JPanel();
1405 buttonPanel.add(ok);
1406 buttonPanel.add(cancel);
1407 buttonPanel.add(loadColours);
1408 buttonPanel.add(saveColours);
1409 bigPanel.add(scrollPane, BorderLayout.CENTER);
1410 settingsPane.add(bigPanel, BorderLayout.CENTER);
1411 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1412 this.add(settingsPane);
1416 * Answers a suitable tooltip to show on the colour cell of the table
1420 * if true include 'click to edit' and similar text
1423 public static String getColorTooltip(FeatureColourI fcol,
1430 if (fcol.isSimpleColour())
1432 return withHint ? BASE_TOOLTIP : null;
1434 String description = fcol.getDescription();
1435 description = description.replaceAll("<", "<");
1436 description = description.replaceAll(">", ">");
1437 StringBuilder tt = new StringBuilder(description);
1440 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1442 return JvSwingUtils.wrapTooltip(true, tt.toString());
1445 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1448 boolean thr = false;
1449 StringBuilder tx = new StringBuilder();
1451 if (gcol.isColourByAttribute())
1453 tx.append(FeatureMatcher
1454 .toAttributeDisplayName(gcol.getAttributeName()));
1456 else if (!gcol.isColourByLabel())
1458 tx.append(MessageManager.getString("label.score"));
1461 if (gcol.isAboveThreshold())
1466 if (gcol.isBelowThreshold())
1471 if (gcol.isColourByLabel())
1477 if (!gcol.isColourByAttribute())
1485 Color newColor = gcol.getMaxColour();
1486 comp.setBackground(newColor);
1487 // System.err.println("Width is " + w / 2);
1488 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1489 comp.setIcon(ficon);
1490 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1491 // + newColor.getGreen() + ", " + newColor.getBlue()
1492 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1493 // + ", " + minCol.getBlue() + ")");
1495 comp.setHorizontalAlignment(SwingConstants.CENTER);
1496 comp.setText(tx.toString());
1499 // ///////////////////////////////////////////////////////////////////////
1500 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1501 // ///////////////////////////////////////////////////////////////////////
1502 class FeatureTableModel extends AbstractTableModel
1504 private String[] columnNames = {
1505 MessageManager.getString("label.feature_type"),
1506 MessageManager.getString("action.colour"),
1507 MessageManager.getString("label.filter"),
1508 MessageManager.getString("label.show") };
1510 private Object[][] data;
1512 FeatureTableModel(Object[][] data)
1517 public Object[][] getData()
1522 public void setData(Object[][] data)
1528 public int getColumnCount()
1530 return columnNames.length;
1533 public Object[] getRow(int row)
1539 public int getRowCount()
1545 public String getColumnName(int col)
1547 return columnNames[col];
1551 public Object getValueAt(int row, int col)
1553 return data[row][col];
1557 * Answers the class of the object in column c of the first row of the table
1560 public Class<?> getColumnClass(int c)
1562 Object v = getValueAt(0, c);
1563 return v == null ? null : v.getClass();
1567 public boolean isCellEditable(int row, int col)
1569 return col == 0 ? false : true;
1573 public void setValueAt(Object value, int row, int col)
1575 data[row][col] = value;
1576 fireTableCellUpdated(row, col);
1577 updateFeatureRenderer(data);
1582 class ColorRenderer extends JLabel implements TableCellRenderer
1584 Border unselectedBorder = null;
1586 Border selectedBorder = null;
1588 public ColorRenderer()
1590 setOpaque(true); // MUST do this for background to show up.
1591 setHorizontalTextPosition(SwingConstants.CENTER);
1592 setVerticalTextPosition(SwingConstants.CENTER);
1596 public Component getTableCellRendererComponent(JTable tbl, Object color,
1597 boolean isSelected, boolean hasFocus, int row, int column)
1599 FeatureColourI cellColour = (FeatureColourI) color;
1601 setBackground(tbl.getBackground());
1602 if (!cellColour.isSimpleColour())
1604 Rectangle cr = tbl.getCellRect(row, column, false);
1605 FeatureSettings.renderGraduatedColor(this, cellColour,
1606 (int) cr.getWidth(), (int) cr.getHeight());
1612 setBackground(cellColour.getColour());
1616 if (selectedBorder == null)
1618 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1619 tbl.getSelectionBackground());
1621 setBorder(selectedBorder);
1625 if (unselectedBorder == null)
1627 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1628 tbl.getBackground());
1630 setBorder(unselectedBorder);
1637 class FilterRenderer extends JLabel implements TableCellRenderer
1639 javax.swing.border.Border unselectedBorder = null;
1641 javax.swing.border.Border selectedBorder = null;
1643 public FilterRenderer()
1645 setOpaque(true); // MUST do this for background to show up.
1646 setHorizontalTextPosition(SwingConstants.CENTER);
1647 setVerticalTextPosition(SwingConstants.CENTER);
1651 public Component getTableCellRendererComponent(JTable tbl,
1652 Object filter, boolean isSelected, boolean hasFocus, int row,
1655 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1657 String asText = theFilter.toString();
1658 setBackground(tbl.getBackground());
1659 this.setText(asText);
1664 if (selectedBorder == null)
1666 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1667 tbl.getSelectionBackground());
1669 setBorder(selectedBorder);
1673 if (unselectedBorder == null)
1675 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1676 tbl.getBackground());
1678 setBorder(unselectedBorder);
1686 * update comp using rendering settings from gcol
1691 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1693 int w = comp.getWidth(), h = comp.getHeight();
1696 w = (int) comp.getPreferredSize().getWidth();
1697 h = (int) comp.getPreferredSize().getHeight();
1704 renderGraduatedColor(comp, gcol, w, h);
1707 class ColorEditor extends AbstractCellEditor
1708 implements TableCellEditor, ActionListener
1712 FeatureColourI currentColor;
1714 FeatureTypeSettings chooser;
1720 protected static final String EDIT = "edit";
1722 int rowSelected = 0;
1724 public ColorEditor(FeatureSettings fs)
1727 // Set up the editor (from the table's point of view),
1728 // which is a button.
1729 // This button brings up the color chooser dialog,
1730 // which is the editor from the user's point of view.
1731 button = new JButton();
1732 button.setActionCommand(EDIT);
1733 button.addActionListener(this);
1734 button.setBorderPainted(false);
1738 * Handles events from the editor button, and from the colour/filters
1739 * dialog's OK button
1742 public void actionPerformed(ActionEvent e)
1744 if (button == e.getSource())
1746 if (currentColor.isSimpleColour())
1749 * simple colour chooser
1751 String ttl = MessageManager.formatMessage("label.select_colour_for", type);
1752 ColourChooserListener listener = new ColourChooserListener()
1755 public void colourSelected(Color c)
1757 currentColor = new FeatureColour(c);
1758 me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1759 fireEditingStopped();
1762 public void cancel()
1764 fireEditingStopped();
1767 JalviewColourChooser.showColourChooser(button, ttl, currentColor.getColour(), listener);
1772 * variable colour and filters dialog
1774 chooser = new FeatureTypeSettings(me.fr, type);
1775 if (!Jalview.isJS())
1777 chooser.setRequestFocusEnabled(true);
1778 chooser.requestFocus();
1780 chooser.addActionListener(this);
1781 fireEditingStopped();
1787 * after OK in variable colour dialog, any changes to colour
1788 * (or filters!) are already set in FeatureRenderer, so just
1789 * update table data without triggering updateFeatureRenderer
1791 currentColor = fr.getFeatureColours().get(type);
1792 FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
1793 if (currentFilter == null)
1795 currentFilter = new FeatureMatcherSet();
1797 Object[] data = ((FeatureTableModel) table.getModel())
1798 .getData()[rowSelected];
1799 data[COLOUR_COLUMN] = currentColor;
1800 data[FILTER_COLUMN] = currentFilter;
1802 fireEditingStopped();
1803 me.table.validate();
1807 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1809 public Object getCellEditorValue()
1811 return currentColor;
1814 // Implement the one method defined by TableCellEditor.
1816 public Component getTableCellEditorComponent(JTable theTable, Object value,
1817 boolean isSelected, int row, int column)
1819 currentColor = (FeatureColourI) value;
1820 this.rowSelected = row;
1821 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1822 button.setOpaque(true);
1823 button.setBackground(me.getBackground());
1824 if (!currentColor.isSimpleColour())
1826 JLabel btn = new JLabel();
1827 btn.setSize(button.getSize());
1828 FeatureSettings.renderGraduatedColor(btn, currentColor);
1829 button.setBackground(btn.getBackground());
1830 button.setIcon(btn.getIcon());
1831 button.setText(btn.getText());
1836 button.setIcon(null);
1837 button.setBackground(currentColor.getColour());
1844 * The cell editor for the Filter column. It displays the text of any filters
1845 * for the feature type in that row (in full as a tooltip, possible abbreviated
1846 * as display text). On click in the cell, opens the Feature Display Settings
1847 * dialog at the Filters tab.
1849 class FilterEditor extends AbstractCellEditor
1850 implements TableCellEditor, ActionListener
1854 FeatureMatcherSetI currentFilter;
1862 protected static final String EDIT = "edit";
1864 int rowSelected = 0;
1866 public FilterEditor(FeatureSettings me)
1869 button = new JButton();
1870 button.setActionCommand(EDIT);
1871 button.addActionListener(this);
1872 button.setBorderPainted(false);
1876 * Handles events from the editor button
1879 public void actionPerformed(ActionEvent e)
1881 if (button == e.getSource())
1883 FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
1884 chooser.addActionListener(this);
1885 chooser.setRequestFocusEnabled(true);
1886 chooser.requestFocus();
1887 if (lastLocation != null)
1889 // todo open at its last position on screen
1890 chooser.setBounds(lastLocation.x, lastLocation.y,
1891 chooser.getWidth(), chooser.getHeight());
1894 fireEditingStopped();
1896 else if (e.getSource() instanceof Component)
1900 * after OK in variable colour dialog, any changes to filter
1901 * (or colours!) are already set in FeatureRenderer, so just
1902 * update table data without triggering updateFeatureRenderer
1904 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1905 currentFilter = me.fr.getFeatureFilter(type);
1906 if (currentFilter == null)
1908 currentFilter = new FeatureMatcherSet();
1910 Object[] data = ((FeatureTableModel) table.getModel())
1911 .getData()[rowSelected];
1912 data[COLOUR_COLUMN] = currentColor;
1913 data[FILTER_COLUMN] = currentFilter;
1914 fireEditingStopped();
1915 me.table.validate();
1920 public Object getCellEditorValue()
1922 return currentFilter;
1926 public Component getTableCellEditorComponent(JTable theTable, Object value,
1927 boolean isSelected, int row, int column)
1929 currentFilter = (FeatureMatcherSetI) value;
1930 this.rowSelected = row;
1931 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1932 button.setOpaque(true);
1933 button.setBackground(me.getBackground());
1934 button.setText(currentFilter.toString());
1935 button.setIcon(null);
1941 class FeatureIcon implements Icon
1943 FeatureColourI gcol;
1947 boolean midspace = false;
1949 int width = 50, height = 20;
1951 int s1, e1; // start and end of midpoint band for thresholded symbol
1953 Color mpcolour = Color.white;
1955 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1975 public int getIconWidth()
1981 public int getIconHeight()
1987 public void paintIcon(Component c, Graphics g, int x, int y)
1990 if (gcol.isColourByLabel())
1993 g.fillRect(0, 0, width, height);
1994 // need an icon here.
1995 g.setColor(gcol.getMaxColour());
1997 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1999 // g.setFont(g.getFont().deriveFont(
2000 // AffineTransform.getScaleInstance(
2001 // width/g.getFontMetrics().stringWidth("Label"),
2002 // height/g.getFontMetrics().getHeight())));
2004 g.drawString(MessageManager.getString("label.label"), 0, 0);
2009 Color minCol = gcol.getMinColour();
2011 g.fillRect(0, 0, s1, height);
2014 g.setColor(Color.white);
2015 g.fillRect(s1, 0, e1 - s1, height);
2017 g.setColor(gcol.getMaxColour());
2018 // g.fillRect(0, e1, width - e1, height); // BH 2018
2019 g.fillRect(e1, 0, width - e1, height);