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.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
40 import jalview.xml.binding.jalview.JalviewUserColours;
41 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
42 import jalview.xml.binding.jalview.JalviewUserColours.Filter;
43 import jalview.xml.binding.jalview.ObjectFactory;
45 import java.awt.BorderLayout;
46 import java.awt.Color;
47 import java.awt.Component;
48 import java.awt.Dimension;
50 import java.awt.Graphics;
51 import java.awt.GridLayout;
52 import java.awt.Point;
53 import java.awt.Rectangle;
54 import java.awt.event.ActionEvent;
55 import java.awt.event.ActionListener;
56 import java.awt.event.ItemEvent;
57 import java.awt.event.ItemListener;
58 import java.awt.event.MouseAdapter;
59 import java.awt.event.MouseEvent;
60 import java.awt.event.MouseMotionAdapter;
61 import java.beans.PropertyChangeEvent;
62 import java.beans.PropertyChangeListener;
64 import java.io.FileInputStream;
65 import java.io.FileOutputStream;
66 import java.io.InputStreamReader;
67 import java.io.OutputStreamWriter;
68 import java.io.PrintWriter;
69 import java.util.Arrays;
70 import java.util.Comparator;
71 import java.util.HashMap;
72 import java.util.HashSet;
73 import java.util.Hashtable;
74 import java.util.Iterator;
75 import java.util.List;
79 import javax.help.HelpSetException;
80 import javax.swing.AbstractCellEditor;
81 import javax.swing.BorderFactory;
82 import javax.swing.Icon;
83 import javax.swing.JButton;
84 import javax.swing.JCheckBox;
85 import javax.swing.JCheckBoxMenuItem;
86 import javax.swing.JInternalFrame;
87 import javax.swing.JLabel;
88 import javax.swing.JLayeredPane;
89 import javax.swing.JMenuItem;
90 import javax.swing.JPanel;
91 import javax.swing.JPopupMenu;
92 import javax.swing.JScrollPane;
93 import javax.swing.JSlider;
94 import javax.swing.JTable;
95 import javax.swing.ListSelectionModel;
96 import javax.swing.SwingConstants;
97 import javax.swing.ToolTipManager;
98 import javax.swing.border.Border;
99 import javax.swing.event.ChangeEvent;
100 import javax.swing.event.ChangeListener;
101 import javax.swing.table.AbstractTableModel;
102 import javax.swing.table.TableCellEditor;
103 import javax.swing.table.TableCellRenderer;
104 import javax.swing.table.TableColumn;
105 import javax.xml.bind.JAXBContext;
106 import javax.xml.bind.JAXBElement;
107 import javax.xml.bind.Marshaller;
108 import javax.xml.stream.XMLInputFactory;
109 import javax.xml.stream.XMLStreamReader;
111 public class FeatureSettings extends JPanel
112 implements FeatureSettingsControllerI
114 private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
115 .getString("label.sequence_feature_colours");
118 * column indices of fields in Feature Settings table
120 static final int TYPE_COLUMN = 0;
122 static final int COLOUR_COLUMN = 1;
124 static final int FILTER_COLUMN = 2;
126 static final int SHOW_COLUMN = 3;
128 private static final int COLUMN_COUNT = 4;
130 private static final int MIN_WIDTH = 400;
132 private static final int MIN_HEIGHT = 400;
134 private final static String BASE_TOOLTIP = MessageManager.getString("label.click_to_edit");
136 final FeatureRenderer fr;
138 public final AlignFrame af;
141 * 'original' fields hold settings to restore on Cancel
143 Object[][] originalData;
145 float originalTransparency;
147 Map<String, FeatureMatcherSetI> originalFilters;
149 final JInternalFrame frame;
151 JScrollPane scrollPane = new JScrollPane();
157 JSlider transparency = new JSlider();
160 * when true, constructor is still executing - so ignore UI events
162 protected volatile boolean inConstruction = true;
164 int selectedRow = -1;
166 JButton fetchDAS = new JButton();
168 JButton saveDAS = new JButton();
170 JButton cancelDAS = new JButton();
172 boolean resettingTable = false;
175 * true when Feature Settings are updating from feature renderer
177 boolean handlingUpdate = false;
180 * holds {featureCount, totalExtent} for each feature type
182 Map<String, float[]> typeWidth = null;
189 public FeatureSettings(AlignFrame alignFrame)
191 this.af = alignFrame;
192 fr = af.getFeatureRenderer();
194 // save transparency for restore on Cancel
195 originalTransparency = fr.getTransparency();
196 int originalTransparencyAsPercent = (int) (originalTransparency * 100);
197 transparency.setMaximum(100 - originalTransparencyAsPercent);
199 originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
204 } catch (Exception ex)
206 ex.printStackTrace();
213 // public void repaint() {
214 // System.out.println("FS repaint");
220 // public void repaint(long tm, int x, int y, int width, int height) {
221 // System.out.println("FS repaint " + x + " " + y + " " + width + " " + height);
222 // super.repaint(tm, x, y, width, height);
226 // public void invalidate() {
228 // System.out.println("FS invalidating ");
229 // super.invalidate();
233 // public void validate() {
234 // System.out.println("FS validating " + isValid());
239 public String getToolTipText(MouseEvent e)
242 int column = table.columnAtPoint(e.getPoint());
243 int row = table.rowAtPoint(e.getPoint());
248 tip = JvSwingUtils.wrapTooltip(true, MessageManager
249 .getString("label.feature_settings_click_drag"));
252 FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
254 tip = getColorTooltip(colour, true);
257 FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
261 .getString("label.configure_feature_tooltip")
273 * Position the tooltip near the bottom edge of, and half way across, the
277 public Point getToolTipLocation(MouseEvent e)
279 Point point = e.getPoint();
280 int column = table.columnAtPoint(point);
281 int row = table.rowAtPoint(point);
282 Rectangle r = getCellRect(row, column, false);
283 Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3);
288 // next line is needed to avoid (quiet) exceptions thrown
289 // when column ordering changes so that the above constants
291 table.getTableHeader().setReorderingAllowed(false); // BH 2018
293 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
294 ToolTipManager.sharedInstance().registerComponent(table);
296 table.setDefaultEditor(FeatureColour.class, new ColorEditor());
297 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
299 table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor());
300 table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
302 TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
303 new ColorRenderer(), new ColorEditor());
304 table.addColumn(colourColumn);
306 TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
307 new FilterRenderer(), new FilterEditor());
308 table.addColumn(filterColumn);
310 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
312 table.addMouseListener(new MouseAdapter()
315 public void mousePressed(MouseEvent evt)
317 selectedRow = table.rowAtPoint(evt.getPoint());
318 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
319 if (evt.isPopupTrigger())
321 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
322 showPopupMenu(selectedRow, type, colour, evt.getPoint());
324 else if (evt.getClickCount() == 2)
326 boolean invertSelection = evt.isAltDown();
327 boolean toggleSelection = Platform.isControlDown(evt);
328 boolean extendSelection = evt.isShiftDown();
329 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
330 invertSelection, extendSelection, toggleSelection, type);
334 // isPopupTrigger fires on mouseReleased on Windows
336 public void mouseReleased(MouseEvent evt)
338 selectedRow = table.rowAtPoint(evt.getPoint());
339 if (evt.isPopupTrigger())
341 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
342 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
343 showPopupMenu(selectedRow, type, colour, evt.getPoint());
348 table.addMouseMotionListener(new MouseMotionAdapter()
351 public void mouseDragged(MouseEvent evt)
353 int newRow = table.rowAtPoint(evt.getPoint());
354 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
357 * reposition 'selectedRow' to 'newRow' (the dragged to location)
358 * this could be more than one row away for a very fast drag action
359 * so just swap it with adjacent rows until we get it there
361 Object[][] data = ((FeatureTableModel) table.getModel())
363 int direction = newRow < selectedRow ? -1 : 1;
364 for (int i = selectedRow; i != newRow; i += direction)
366 Object[] temp = data[i];
367 data[i] = data[i + direction];
368 data[i + direction] = temp;
370 updateFeatureRenderer(data);
372 selectedRow = newRow;
376 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
377 // MessageManager.getString("label.feature_settings_click_drag")));
378 scrollPane.setViewportView(table);
380 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
382 fr.findAllFeatures(true); // display everything!
385 discoverAllFeatureData();
386 final PropertyChangeListener change;
387 final FeatureSettings fs = this;
388 fr.addPropertyChangeListener(change = new PropertyChangeListener()
391 public void propertyChange(PropertyChangeEvent evt)
393 if (!fs.resettingTable && !fs.handlingUpdate)
395 fs.handlingUpdate = true;
397 // new groups may be added with new sequence feature types only
398 fs.handlingUpdate = false;
404 frame = new JInternalFrame();
405 frame.setContentPane(this);
406 if (Platform.isAMac())
408 Desktop.addInternalFrame(frame,
409 MessageManager.getString("label.sequence_feature_settings"),
414 Desktop.addInternalFrame(frame,
415 MessageManager.getString("label.sequence_feature_settings"),
418 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
420 frame.addInternalFrameListener(
421 new javax.swing.event.InternalFrameAdapter()
424 public void internalFrameClosed(
425 javax.swing.event.InternalFrameEvent evt)
427 fr.removePropertyChangeListener(change);
430 frame.setLayer(JLayeredPane.PALETTE_LAYER);
431 inConstruction = false;
435 * Constructs and shows a popup menu of possible actions on the selected row and
443 protected void showPopupMenu(final int rowSelected, final String type,
444 final Object typeCol, final Point pt)
446 JPopupMenu men = new JPopupMenu(MessageManager
447 .formatMessage("label.settings_for_param", new String[]
449 final FeatureColourI featureColour = (FeatureColourI) typeCol;
452 * menu option to select (or deselect) variable colour
454 final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
455 MessageManager.getString("label.variable_colour"));
456 variableColourCB.setSelected(!featureColour.isSimpleColour());
457 men.add(variableColourCB);
460 * checkbox action listener doubles up as listener to OK
461 * from the variable colour / filters dialog
463 variableColourCB.addActionListener(new ActionListener()
466 public void actionPerformed(ActionEvent e)
468 if (e.getSource() == variableColourCB)
470 men.setVisible(true); // BH 2018 for JavaScript because this is a checkbox
471 men.setVisible(false); // BH 2018 for JavaScript because this is a checkbox
472 if (featureColour.isSimpleColour())
475 * toggle simple colour to variable colour - show dialog
477 FeatureTypeSettings fc = new FeatureTypeSettings(fr, type);
478 fc.addActionListener(this);
483 * toggle variable to simple colour - show colour chooser
485 String title = MessageManager.formatMessage("label.select_colour_for", type);
486 ColourChooserListener listener = new ColourChooserListener()
489 public void colourSelected(Color c)
491 table.setValueAt(new FeatureColour(c), rowSelected,
494 updateFeatureRenderer(
495 ((FeatureTableModel) table.getModel()).getData(),
499 JalviewColourChooser.showColourChooser(FeatureSettings.this, title,
500 featureColour.getMaxColour(), listener);
505 if (e.getSource() instanceof FeatureTypeSettings)
508 * update after OK in feature colour dialog; the updated
509 * colour will have already been set in the FeatureRenderer
511 FeatureColourI fci = fr.getFeatureColours().get(type);
512 table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
513 // BH 2018 setting a table value does not invalidate it.
514 // System.out.println("FeatureSettings is valied" + table.isValid());
523 JMenuItem scr = new JMenuItem(
524 MessageManager.getString("label.sort_by_score"));
526 scr.addActionListener(new ActionListener()
530 public void actionPerformed(ActionEvent e)
532 af.avc.sortAlignmentByFeatureScore(Arrays.asList(new String[]
536 JMenuItem dens = new JMenuItem(
537 MessageManager.getString("label.sort_by_density"));
538 dens.addActionListener(new ActionListener()
542 public void actionPerformed(ActionEvent e)
544 af.avc.sortAlignmentByFeatureDensity(Arrays.asList(new String[]
550 JMenuItem selCols = new JMenuItem(
551 MessageManager.getString("label.select_columns_containing"));
552 selCols.addActionListener(new ActionListener()
555 public void actionPerformed(ActionEvent arg0)
557 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
561 JMenuItem clearCols = new JMenuItem(MessageManager
562 .getString("label.select_columns_not_containing"));
563 clearCols.addActionListener(new ActionListener()
566 public void actionPerformed(ActionEvent arg0)
568 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
572 JMenuItem hideCols = new JMenuItem(
573 MessageManager.getString("label.hide_columns_containing"));
574 hideCols.addActionListener(new ActionListener()
577 public void actionPerformed(ActionEvent arg0)
579 fr.ap.alignFrame.hideFeatureColumns(type, true);
582 JMenuItem hideOtherCols = new JMenuItem(
583 MessageManager.getString("label.hide_columns_not_containing"));
584 hideOtherCols.addActionListener(new ActionListener()
587 public void actionPerformed(ActionEvent arg0)
589 fr.ap.alignFrame.hideFeatureColumns(type, false);
595 men.add(hideOtherCols);
596 men.show(table, pt.x, pt.y);
600 synchronized public void discoverAllFeatureData()
602 Set<String> allGroups = new HashSet<>();
603 AlignmentI alignment = af.getViewport().getAlignment();
605 for (int i = 0; i < alignment.getHeight(); i++)
607 SequenceI seq = alignment.getSequenceAt(i);
608 for (String group : seq.getFeatures().getFeatureGroups(true))
610 if (group != null && !allGroups.contains(group))
612 allGroups.add(group);
613 checkGroupState(group);
624 * Synchronise gui group list and check visibility of group
627 * @return true if group is visible
629 private boolean checkGroupState(String group)
631 boolean visible = fr.checkGroupVisibility(group, true);
633 for (int g = 0; g < groupPanel.getComponentCount(); g++)
635 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
637 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
642 final String grp = group;
643 final JCheckBox check = new JCheckBox(group, visible);
644 check.setFont(new Font("Serif", Font.BOLD, 12));
645 check.setToolTipText(group);
646 check.addItemListener(new ItemListener()
649 public void itemStateChanged(ItemEvent evt)
651 fr.setGroupVisibility(check.getText(), check.isSelected());
652 resetTable(new String[] { grp });
653 af.alignPanel.paintAlignment(true, true);
656 groupPanel.add(check);
660 synchronized void resetTable(String[] groupChanged)
666 resettingTable = true;
667 typeWidth = new Hashtable<>();
668 // TODO: change avWidth calculation to 'per-sequence' average and use long
671 Set<String> displayableTypes = new HashSet<>();
672 Set<String> foundGroups = new HashSet<>();
675 * determine which feature types may be visible depending on
676 * which groups are selected, and recompute average width data
678 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
681 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
684 * get the sequence's groups for positional features
685 * and keep track of which groups are visible
687 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
688 Set<String> visibleGroups = new HashSet<>();
689 for (String group : groups)
691 if (group == null || checkGroupState(group))
693 visibleGroups.add(group);
696 foundGroups.addAll(groups);
699 * get distinct feature types for visible groups
700 * record distinct visible types, and their count and total length
702 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
703 visibleGroups.toArray(new String[visibleGroups.size()]));
704 for (String type : types)
706 displayableTypes.add(type);
707 float[] avWidth = typeWidth.get(type);
710 avWidth = new float[2];
711 typeWidth.put(type, avWidth);
713 // todo this could include features with a non-visible group
714 // - do we greatly care?
715 // todo should we include non-displayable features here, and only
716 // update when features are added?
717 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
718 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
722 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
725 if (fr.hasRenderOrder())
729 fr.findAllFeatures(groupChanged != null); // prod to update
730 // colourschemes. but don't
732 // First add the checks in the previous render order,
733 // in case the window has been closed and reopened
735 List<String> frl = fr.getRenderOrder();
736 for (int ro = frl.size() - 1; ro > -1; ro--)
738 String type = frl.get(ro);
740 if (!displayableTypes.contains(type))
745 data[dataIndex][TYPE_COLUMN] = type;
746 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
747 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
748 data[dataIndex][FILTER_COLUMN] = featureFilter == null
749 ? new FeatureMatcherSet()
751 data[dataIndex][SHOW_COLUMN] = new Boolean(
752 af.getViewport().getFeaturesDisplayed().isVisible(type));
754 displayableTypes.remove(type);
759 * process any extra features belonging only to
760 * a group which was just selected
762 while (!displayableTypes.isEmpty())
764 String type = displayableTypes.iterator().next();
765 data[dataIndex][TYPE_COLUMN] = type;
767 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
768 if (data[dataIndex][COLOUR_COLUMN] == null)
770 // "Colour has been updated in another view!!"
771 fr.clearRenderOrder();
774 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
775 data[dataIndex][FILTER_COLUMN] = featureFilter == null
776 ? new FeatureMatcherSet()
778 data[dataIndex][SHOW_COLUMN] = new Boolean(true);
780 displayableTypes.remove(type);
783 if (originalData == null)
785 originalData = new Object[data.length][COLUMN_COUNT];
786 for (int i = 0; i < data.length; i++)
788 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
793 updateOriginalData(data);
796 table.setModel(new FeatureTableModel(data));
797 table.getColumnModel().getColumn(0).setPreferredWidth(200);
799 groupPanel.setLayout(
800 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
801 pruneGroups(foundGroups);
802 groupPanel.validate();
804 updateFeatureRenderer(data, groupChanged != null);
805 resettingTable = false;
809 * Updates 'originalData' (used for restore on Cancel) if we detect that changes
810 * have been made outwith this dialog
812 * <li>a new feature type added (and made visible)</li>
813 * <li>a feature colour changed (in the Amend Features dialog)</li>
818 protected void updateOriginalData(Object[][] foundData)
820 // todo LinkedHashMap instead of Object[][] would be nice
822 Object[][] currentData = ((FeatureTableModel) table.getModel())
824 for (Object[] row : foundData)
826 String type = (String) row[TYPE_COLUMN];
827 boolean found = false;
828 for (Object[] current : currentData)
830 if (type.equals(current[TYPE_COLUMN]))
834 * currently dependent on object equality here;
835 * really need an equals method on FeatureColour
837 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
840 * feature colour has changed externally - update originalData
842 for (Object[] original : originalData)
844 if (type.equals(original[TYPE_COLUMN]))
846 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
857 * new feature detected - add to original data (on top)
859 Object[][] newData = new Object[originalData.length
861 for (int i = 0; i < originalData.length; i++)
863 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
867 originalData = newData;
873 * Remove from the groups panel any checkboxes for groups that are not in the
874 * foundGroups set. This enables removing a group from the display when the last
875 * feature in that group is deleted.
879 protected void pruneGroups(Set<String> foundGroups)
881 for (int g = 0; g < groupPanel.getComponentCount(); g++)
883 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
884 if (!foundGroups.contains(checkbox.getText()))
886 groupPanel.remove(checkbox);
892 * reorder data based on the featureRenderers global priority list.
896 private void ensureOrder(Object[][] data)
898 boolean sort = false;
899 float[] order = new float[data.length];
900 for (int i = 0; i < order.length; i++)
902 order[i] = fr.getOrder(data[i][0].toString());
905 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
909 sort = sort || order[i - 1] > order[i];
914 jalview.util.QuickSort.sort(order, data);
919 * Offers a file chooser dialog, and then loads the feature colours and
920 * filters from file in XML format and unmarshals to Jalview feature settings
924 JalviewFileChooser chooser = new JalviewFileChooser("fc",
925 SEQUENCE_FEATURE_COLOURS);
926 chooser.setFileView(new JalviewFileView());
927 chooser.setDialogTitle(
928 MessageManager.getString("label.load_feature_colours"));
929 chooser.setToolTipText(MessageManager.getString("action.load"));
930 chooser.setResponseHandler(0, new Runnable()
935 File file = chooser.getSelectedFile();
939 chooser.showOpenDialog(this);
943 * Loads feature colours and filters from XML stored in the given file
951 InputStreamReader in = new InputStreamReader(
952 new FileInputStream(file), "UTF-8");
954 JAXBContext jc = JAXBContext
955 .newInstance("jalview.xml.binding.jalview");
956 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
957 XMLStreamReader streamReader = XMLInputFactory.newInstance()
958 .createXMLStreamReader(in);
959 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
960 JalviewUserColours.class);
961 JalviewUserColours jucs = jbe.getValue();
963 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
966 * load feature colours
968 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
970 Colour newcol = jucs.getColour().get(i);
971 FeatureColourI colour = jalview.project.Jalview2XML
972 .parseColour(newcol);
973 fr.setColour(newcol.getName(), colour);
974 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
978 * load feature filters; loaded filters will replace any that are
979 * currently defined, other defined filters are left unchanged
981 for (int i = 0; i < jucs.getFilter().size(); i++)
983 Filter filterModel = jucs.getFilter().get(i);
984 String featureType = filterModel.getFeatureType();
985 FeatureMatcherSetI filter = jalview.project.Jalview2XML
986 .parseFilter(featureType, filterModel.getMatcherSet());
987 if (!filter.isEmpty())
989 fr.setFeatureFilter(featureType, filter);
994 * update feature settings table
999 Object[][] data = ((FeatureTableModel) table.getModel())
1002 updateFeatureRenderer(data, false);
1005 } catch (Exception ex)
1007 System.out.println("Error loading User Colour File\n" + ex);
1012 * Offers a file chooser dialog, and then saves the current feature colours
1013 * and any filters to the selected file in XML format
1017 JalviewFileChooser chooser = new JalviewFileChooser("fc",
1018 SEQUENCE_FEATURE_COLOURS);
1019 chooser.setFileView(new JalviewFileView());
1020 chooser.setDialogTitle(
1021 MessageManager.getString("label.save_feature_colours"));
1022 chooser.setToolTipText(MessageManager.getString("action.save"));
1023 int option = chooser.showSaveDialog(this);
1024 if (option == JalviewFileChooser.APPROVE_OPTION)
1026 File file = chooser.getSelectedFile();
1032 * Saves feature colours and filters to the given file
1036 void save(File file)
1038 JalviewUserColours ucs = new JalviewUserColours();
1039 ucs.setSchemeName("Sequence Features");
1042 PrintWriter out = new PrintWriter(new OutputStreamWriter(
1043 new FileOutputStream(file), "UTF-8"));
1046 * sort feature types by colour order, from 0 (highest)
1049 Set<String> fr_colours = fr.getAllFeatureColours();
1050 String[] sortedTypes = fr_colours
1051 .toArray(new String[fr_colours.size()]);
1052 Arrays.sort(sortedTypes, new Comparator<String>()
1055 public int compare(String type1, String type2)
1057 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
1062 * save feature colours
1064 for (String featureType : sortedTypes)
1066 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1067 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
1069 ucs.getColour().add(col);
1073 * save any feature filters
1075 for (String featureType : sortedTypes)
1077 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1078 if (filter != null && !filter.isEmpty())
1080 Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
1081 FeatureMatcherI firstMatcher = iterator.next();
1082 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
1083 .marshalFilter(firstMatcher, iterator,
1085 Filter filterModel = new Filter();
1086 filterModel.setFeatureType(featureType);
1087 filterModel.setMatcherSet(ms);
1088 ucs.getFilter().add(filterModel);
1091 JAXBContext jaxbContext = JAXBContext
1092 .newInstance(JalviewUserColours.class);
1093 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1094 jaxbMarshaller.marshal(
1095 new ObjectFactory().createJalviewUserColours(ucs), out);
1097 // jaxbMarshaller.marshal(object, pout);
1098 // marshaller.marshal(object);
1101 // ucs.marshal(out);
1103 } catch (Exception ex)
1105 ex.printStackTrace();
1109 public void invertSelection()
1111 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1112 for (int i = 0; i < data.length; i++)
1114 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1116 updateFeatureRenderer(data, true);
1120 public void orderByAvWidth()
1122 if (table == null || table.getModel() == null)
1126 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1127 float[] width = new float[data.length];
1131 for (int i = 0; i < data.length; i++)
1133 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1136 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1137 // weight - but have to make per
1138 // sequence, too (awidth[2])
1139 // if (width[i]==1) // hack to distinguish single width sequences.
1150 boolean sort = false;
1151 for (int i = 0; i < width.length; i++)
1153 // awidth = (float[]) typeWidth.get(data[i][0]);
1156 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1159 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1165 width[i] /= max; // normalize
1166 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
1170 sort = sort || width[i - 1] > width[i];
1175 jalview.util.QuickSort.sort(width, data);
1176 // update global priority order
1179 updateFeatureRenderer(data, false);
1187 frame.setClosed(true);
1188 } catch (Exception exe)
1194 public void updateFeatureRenderer(Object[][] data)
1196 updateFeatureRenderer(data, true);
1200 * Update the priority order of features; only repaint if this changed the order
1201 * of visible features
1206 void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1208 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1210 if (fr.setFeaturePriority(rowData, visibleNew))
1212 af.alignPanel.paintAlignment(true, true);
1217 * Converts table data into an array of data beans
1219 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1221 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1222 for (int i = 0; i < data.length; i++)
1224 String type = (String) data[i][TYPE_COLUMN];
1225 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1226 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1227 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1228 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1234 private void jbInit() throws Exception
1236 this.setLayout(new BorderLayout());
1238 JPanel settingsPane = new JPanel();
1239 settingsPane.setLayout(new BorderLayout());
1241 JPanel bigPanel = new JPanel();
1242 bigPanel.setLayout(new BorderLayout());
1244 groupPanel = new JPanel();
1245 bigPanel.add(groupPanel, BorderLayout.NORTH);
1247 JButton invert = new JButton(
1248 MessageManager.getString("label.invert_selection"));
1249 invert.setFont(JvSwingUtils.getLabelFont());
1250 invert.addActionListener(new ActionListener()
1253 public void actionPerformed(ActionEvent e)
1259 JButton optimizeOrder = new JButton(
1260 MessageManager.getString("label.optimise_order"));
1261 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1262 optimizeOrder.addActionListener(new ActionListener()
1265 public void actionPerformed(ActionEvent e)
1271 JButton sortByScore = new JButton(
1272 MessageManager.getString("label.seq_sort_by_score"));
1273 sortByScore.setFont(JvSwingUtils.getLabelFont());
1274 sortByScore.addActionListener(new ActionListener()
1277 public void actionPerformed(ActionEvent e)
1279 af.avc.sortAlignmentByFeatureScore(null);
1282 JButton sortByDens = new JButton(
1283 MessageManager.getString("label.sequence_sort_by_density"));
1284 sortByDens.setFont(JvSwingUtils.getLabelFont());
1285 sortByDens.addActionListener(new ActionListener()
1288 public void actionPerformed(ActionEvent e)
1290 af.avc.sortAlignmentByFeatureDensity(null);
1294 JButton help = new JButton(MessageManager.getString("action.help"));
1295 help.setFont(JvSwingUtils.getLabelFont());
1296 help.addActionListener(new ActionListener()
1299 public void actionPerformed(ActionEvent e)
1303 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1304 } catch (HelpSetException e1)
1306 e1.printStackTrace();
1310 help.setFont(JvSwingUtils.getLabelFont());
1311 help.setText(MessageManager.getString("action.help"));
1312 help.addActionListener(new ActionListener()
1315 public void actionPerformed(ActionEvent e)
1319 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1320 } catch (HelpSetException e1)
1322 e1.printStackTrace();
1327 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1328 cancel.setFont(JvSwingUtils.getLabelFont());
1329 cancel.addActionListener(new ActionListener()
1332 public void actionPerformed(ActionEvent e)
1334 fr.setTransparency(originalTransparency);
1335 fr.setFeatureFilters(originalFilters);
1336 updateFeatureRenderer(originalData);
1341 JButton ok = new JButton(MessageManager.getString("action.ok"));
1342 ok.setFont(JvSwingUtils.getLabelFont());
1343 ok.addActionListener(new ActionListener()
1346 public void actionPerformed(ActionEvent e)
1352 JButton loadColours = new JButton(
1353 MessageManager.getString("label.load_colours"));
1354 loadColours.setFont(JvSwingUtils.getLabelFont());
1355 loadColours.setToolTipText(
1356 MessageManager.getString("label.load_colours_tooltip"));
1357 loadColours.addActionListener(new ActionListener()
1360 public void actionPerformed(ActionEvent e)
1366 JButton saveColours = new JButton(
1367 MessageManager.getString("label.save_colours"));
1368 saveColours.setFont(JvSwingUtils.getLabelFont());
1369 saveColours.setToolTipText(
1370 MessageManager.getString("label.save_colours_tooltip"));
1371 saveColours.addActionListener(new ActionListener()
1374 public void actionPerformed(ActionEvent e)
1379 transparency.addChangeListener(new ChangeListener()
1382 public void stateChanged(ChangeEvent evt)
1384 if (!inConstruction)
1386 fr.setTransparency((100 - transparency.getValue()) / 100f);
1387 af.alignPanel.paintAlignment(true, true);
1392 transparency.setMaximum(70);
1393 transparency.setToolTipText(
1394 MessageManager.getString("label.transparency_tip"));
1396 JPanel transPanel = new JPanel(new GridLayout(1, 2));
1397 bigPanel.add(transPanel, BorderLayout.SOUTH);
1399 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1400 transbuttons.add(optimizeOrder);
1401 transbuttons.add(invert);
1402 transbuttons.add(sortByScore);
1403 transbuttons.add(sortByDens);
1404 transbuttons.add(help);
1405 transPanel.add(transparency);
1406 transPanel.add(transbuttons);
1408 JPanel buttonPanel = new JPanel();
1409 buttonPanel.add(ok);
1410 buttonPanel.add(cancel);
1411 buttonPanel.add(loadColours);
1412 buttonPanel.add(saveColours);
1413 bigPanel.add(scrollPane, BorderLayout.CENTER);
1414 settingsPane.add(bigPanel, BorderLayout.CENTER);
1415 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1416 this.add(settingsPane);
1420 * Answers a suitable tooltip to show on the colour cell of the table
1424 * if true include 'click to edit' and similar text
1427 public static String getColorTooltip(FeatureColourI fcol,
1434 if (fcol.isSimpleColour())
1436 return withHint ? BASE_TOOLTIP : null;
1438 String description = fcol.getDescription();
1439 description = description.replaceAll("<", "<");
1440 description = description.replaceAll(">", ">");
1441 StringBuilder tt = new StringBuilder(description);
1444 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1446 return JvSwingUtils.wrapTooltip(true, tt.toString());
1449 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1452 boolean thr = false;
1453 StringBuilder tx = new StringBuilder();
1455 if (gcol.isColourByAttribute())
1457 tx.append(FeatureMatcher
1458 .toAttributeDisplayName(gcol.getAttributeName()));
1460 else if (!gcol.isColourByLabel())
1462 tx.append(MessageManager.getString("label.score"));
1465 if (gcol.isAboveThreshold())
1470 if (gcol.isBelowThreshold())
1475 if (gcol.isColourByLabel())
1481 if (!gcol.isColourByAttribute())
1489 Color newColor = gcol.getMaxColour();
1490 comp.setBackground(newColor);
1491 // System.err.println("Width is " + w / 2);
1492 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1493 comp.setIcon(ficon);
1494 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1495 // + newColor.getGreen() + ", " + newColor.getBlue()
1496 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1497 // + ", " + minCol.getBlue() + ")");
1499 comp.setHorizontalAlignment(SwingConstants.CENTER);
1500 comp.setText(tx.toString());
1503 // ///////////////////////////////////////////////////////////////////////
1504 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1505 // ///////////////////////////////////////////////////////////////////////
1506 class FeatureTableModel extends AbstractTableModel
1508 private String[] columnNames = {
1509 MessageManager.getString("label.feature_type"),
1510 MessageManager.getString("action.colour"),
1511 MessageManager.getString("label.configuration"),
1512 MessageManager.getString("label.show") };
1514 private Object[][] data;
1516 FeatureTableModel(Object[][] data)
1521 public Object[][] getData()
1526 public void setData(Object[][] data)
1532 public int getColumnCount()
1534 return columnNames.length;
1537 public Object[] getRow(int row)
1543 public int getRowCount()
1549 public String getColumnName(int col)
1551 return columnNames[col];
1555 public Object getValueAt(int row, int col)
1557 return data[row][col];
1561 * Answers the class of the object in column c of the first row of the table
1564 public Class<?> getColumnClass(int c)
1566 Object v = getValueAt(0, c);
1567 return v == null ? null : v.getClass();
1571 public boolean isCellEditable(int row, int col)
1573 return col == 0 ? false : true;
1577 public void setValueAt(Object value, int row, int col)
1579 data[row][col] = value;
1580 fireTableCellUpdated(row, col);
1581 updateFeatureRenderer(data);
1586 class ColorRenderer extends JLabel implements TableCellRenderer
1588 Border unselectedBorder = null;
1590 Border selectedBorder = null;
1592 public ColorRenderer()
1594 setOpaque(true); // MUST do this for background to show up.
1595 setHorizontalTextPosition(SwingConstants.CENTER);
1596 setVerticalTextPosition(SwingConstants.CENTER);
1600 public Component getTableCellRendererComponent(JTable tbl, Object color,
1601 boolean isSelected, boolean hasFocus, int row, int column)
1603 FeatureColourI cellColour = (FeatureColourI) color;
1605 setBackground(tbl.getBackground());
1606 if (!cellColour.isSimpleColour())
1608 Rectangle cr = tbl.getCellRect(row, column, false);
1609 FeatureSettings.renderGraduatedColor(this, cellColour,
1610 (int) cr.getWidth(), (int) cr.getHeight());
1616 setBackground(cellColour.getColour());
1620 if (selectedBorder == null)
1622 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1623 tbl.getSelectionBackground());
1625 setBorder(selectedBorder);
1629 if (unselectedBorder == null)
1631 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1632 tbl.getBackground());
1634 setBorder(unselectedBorder);
1641 class FilterRenderer extends JLabel implements TableCellRenderer
1643 javax.swing.border.Border unselectedBorder = null;
1645 javax.swing.border.Border selectedBorder = null;
1647 public FilterRenderer()
1649 setOpaque(true); // MUST do this for background to show up.
1650 setHorizontalTextPosition(SwingConstants.CENTER);
1651 setVerticalTextPosition(SwingConstants.CENTER);
1655 public Component getTableCellRendererComponent(JTable tbl,
1656 Object filter, boolean isSelected, boolean hasFocus, int row,
1659 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1661 String asText = theFilter.toString();
1662 setBackground(tbl.getBackground());
1663 this.setText(asText);
1668 if (selectedBorder == null)
1670 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1671 tbl.getSelectionBackground());
1673 setBorder(selectedBorder);
1677 if (unselectedBorder == null)
1679 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1680 tbl.getBackground());
1682 setBorder(unselectedBorder);
1690 * update comp using rendering settings from gcol
1695 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1697 int w = comp.getWidth(), h = comp.getHeight();
1700 w = (int) comp.getPreferredSize().getWidth();
1701 h = (int) comp.getPreferredSize().getHeight();
1708 renderGraduatedColor(comp, gcol, w, h);
1711 @SuppressWarnings("serial")
1712 class ColorEditor extends AbstractCellEditor
1713 implements TableCellEditor, ActionListener
1715 FeatureColourI currentColor;
1717 FeatureTypeSettings chooser;
1723 protected static final String EDIT = "edit";
1725 int rowSelected = 0;
1727 public ColorEditor()
1729 // Set up the editor (from the table's point of view),
1730 // which is a button.
1731 // This button brings up the color chooser dialog,
1732 // which is the editor from the user's point of view.
1733 button = new JButton();
1734 button.setActionCommand(EDIT);
1735 button.addActionListener(this);
1736 button.setBorderPainted(false);
1740 * Handles events from the editor button, and from the colour/filters
1741 * dialog's OK button
1744 public void actionPerformed(ActionEvent e)
1746 if (button == e.getSource())
1748 if (currentColor.isSimpleColour())
1751 * simple colour chooser
1753 String ttl = MessageManager.formatMessage("label.select_colour_for", type);
1754 ColourChooserListener listener = new ColourChooserListener()
1757 public void colourSelected(Color c)
1759 currentColor = new FeatureColour(c);
1760 table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1761 fireEditingStopped();
1764 public void cancel()
1766 fireEditingStopped();
1769 JalviewColourChooser.showColourChooser(button, ttl, currentColor.getColour(), listener);
1774 * variable colour and filters dialog
1776 chooser = new FeatureTypeSettings(fr, type);
1777 if (!Jalview.isJS())
1779 chooser.setRequestFocusEnabled(true);
1780 chooser.requestFocus();
1782 chooser.addActionListener(this);
1783 fireEditingStopped();
1789 * after OK in variable colour dialog, any changes to colour
1790 * (or filters!) are already set in FeatureRenderer, so just
1791 * update table data without triggering updateFeatureRenderer
1793 currentColor = fr.getFeatureColours().get(type);
1794 FeatureMatcherSetI currentFilter = fr.getFeatureFilter(type);
1795 if (currentFilter == null)
1797 currentFilter = new FeatureMatcherSet();
1799 Object[] data = ((FeatureTableModel) table.getModel())
1800 .getData()[rowSelected];
1801 data[COLOUR_COLUMN] = currentColor;
1802 data[FILTER_COLUMN] = currentFilter;
1803 fireEditingStopped();
1804 // SwingJS needs an explicit repaint() here,
1805 // rather than relying upon no validation having
1806 // occurred since the stopEditing call was made.
1807 // Its laying out has not been stopped by the modal frame
1814 * Override allows access to this method from anonymous inner classes
1817 protected void fireEditingStopped()
1819 super.fireEditingStopped();
1822 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1824 public Object getCellEditorValue()
1826 return currentColor;
1829 // Implement the one method defined by TableCellEditor.
1831 public Component getTableCellEditorComponent(JTable theTable, Object value,
1832 boolean isSelected, int row, int column)
1834 currentColor = (FeatureColourI) value;
1835 this.rowSelected = row;
1836 type = table.getValueAt(row, TYPE_COLUMN).toString();
1837 button.setOpaque(true);
1838 button.setBackground(FeatureSettings.this.getBackground());
1839 if (!currentColor.isSimpleColour())
1841 JLabel btn = new JLabel();
1842 btn.setSize(button.getSize());
1843 FeatureSettings.renderGraduatedColor(btn, currentColor);
1844 button.setBackground(btn.getBackground());
1845 button.setIcon(btn.getIcon());
1846 button.setText(btn.getText());
1851 button.setIcon(null);
1852 button.setBackground(currentColor.getColour());
1859 * The cell editor for the Filter column. It displays the text of any filters
1860 * for the feature type in that row (in full as a tooltip, possible abbreviated
1861 * as display text). On click in the cell, opens the Feature Display Settings
1862 * dialog at the Filters tab.
1864 @SuppressWarnings("serial")
1865 class FilterEditor extends AbstractCellEditor
1866 implements TableCellEditor, ActionListener
1869 FeatureMatcherSetI currentFilter;
1877 protected static final String EDIT = "edit";
1879 int rowSelected = 0;
1881 public FilterEditor()
1883 button = new JButton();
1884 button.setActionCommand(EDIT);
1885 button.addActionListener(this);
1886 button.setBorderPainted(false);
1890 * Handles events from the editor button
1893 public void actionPerformed(ActionEvent e)
1895 if (button == e.getSource())
1897 FeatureTypeSettings chooser = new FeatureTypeSettings(fr, type);
1898 chooser.addActionListener(this);
1899 chooser.setRequestFocusEnabled(true);
1900 chooser.requestFocus();
1901 if (lastLocation != null)
1903 // todo open at its last position on screen
1904 chooser.setBounds(lastLocation.x, lastLocation.y,
1905 chooser.getWidth(), chooser.getHeight());
1908 fireEditingStopped();
1910 else if (e.getSource() instanceof Component)
1914 * after OK in variable colour dialog, any changes to filter
1915 * (or colours!) are already set in FeatureRenderer, so just
1916 * update table data without triggering updateFeatureRenderer
1918 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1919 currentFilter = fr.getFeatureFilter(type);
1920 if (currentFilter == null)
1922 currentFilter = new FeatureMatcherSet();
1925 Object[] data = ((FeatureTableModel) table.getModel())
1926 .getData()[rowSelected];
1927 data[COLOUR_COLUMN] = currentColor;
1928 data[FILTER_COLUMN] = currentFilter;
1929 fireEditingStopped();
1930 // SwingJS needs an explicit repaint() here,
1931 // rather than relying upon no validation having
1932 // occurred since the stopEditing call was made.
1933 // Its laying out has not been stopped by the modal frame
1940 public Object getCellEditorValue()
1942 return currentFilter;
1946 public Component getTableCellEditorComponent(JTable theTable, Object value,
1947 boolean isSelected, int row, int column)
1949 currentFilter = (FeatureMatcherSetI) value;
1950 this.rowSelected = row;
1951 type = table.getValueAt(row, TYPE_COLUMN).toString();
1952 button.setOpaque(true);
1953 button.setBackground(FeatureSettings.this.getBackground());
1954 button.setText(currentFilter.toString());
1955 button.setIcon(null);
1961 class FeatureIcon implements Icon
1963 FeatureColourI gcol;
1967 boolean midspace = false;
1969 int width = 50, height = 20;
1971 int s1, e1; // start and end of midpoint band for thresholded symbol
1973 Color mpcolour = Color.white;
1975 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1995 public int getIconWidth()
2001 public int getIconHeight()
2007 public void paintIcon(Component c, Graphics g, int x, int y)
2010 if (gcol.isColourByLabel())
2013 g.fillRect(0, 0, width, height);
2014 // need an icon here.
2015 g.setColor(gcol.getMaxColour());
2017 g.setFont(new Font("Verdana", Font.PLAIN, 9));
2019 // g.setFont(g.getFont().deriveFont(
2020 // AffineTransform.getScaleInstance(
2021 // width/g.getFontMetrics().stringWidth("Label"),
2022 // height/g.getFontMetrics().getHeight())));
2024 g.drawString(MessageManager.getString("label.label"), 0, 0);
2029 Color minCol = gcol.getMinColour();
2031 g.fillRect(0, 0, s1, height);
2034 g.setColor(Color.white);
2035 g.fillRect(s1, 0, e1 - s1, height);
2037 g.setColor(gcol.getMaxColour());
2038 // g.fillRect(0, e1, width - e1, height); // BH 2018
2039 g.fillRect(e1, 0, width - e1, height);