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.AlignViewControllerGuiI;
24 import jalview.api.AlignViewportI;
25 import jalview.api.FeatureColourI;
26 import jalview.api.FeatureSettingsControllerI;
27 import jalview.api.SplitContainerI;
28 import jalview.api.ViewStyleI;
29 import jalview.controller.FeatureSettingsControllerGuiI;
30 import jalview.datamodel.AlignmentI;
31 import jalview.datamodel.SequenceI;
32 import jalview.datamodel.features.FeatureMatcher;
33 import jalview.datamodel.features.FeatureMatcherI;
34 import jalview.datamodel.features.FeatureMatcherSet;
35 import jalview.datamodel.features.FeatureMatcherSetI;
36 import jalview.gui.Help.HelpId;
37 import jalview.io.JalviewFileChooser;
38 import jalview.io.JalviewFileView;
39 import jalview.schemes.FeatureColour;
40 import jalview.util.MessageManager;
41 import jalview.util.Platform;
42 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
43 import jalview.viewmodel.styles.ViewStyle;
44 import jalview.xml.binding.jalview.JalviewUserColours;
45 import jalview.xml.binding.jalview.JalviewUserColours.Colour;
46 import jalview.xml.binding.jalview.JalviewUserColours.Filter;
47 import jalview.xml.binding.jalview.ObjectFactory;
49 import java.awt.BorderLayout;
50 import java.awt.Color;
51 import java.awt.Component;
52 import java.awt.Dimension;
53 import java.awt.FlowLayout;
55 import java.awt.Graphics;
56 import java.awt.GridLayout;
57 import java.awt.Point;
58 import java.awt.Rectangle;
59 import java.awt.event.ActionEvent;
60 import java.awt.event.ActionListener;
61 import java.awt.event.ItemEvent;
62 import java.awt.event.ItemListener;
63 import java.awt.event.MouseAdapter;
64 import java.awt.event.MouseEvent;
65 import java.awt.event.MouseMotionAdapter;
66 import java.beans.PropertyChangeEvent;
67 import java.beans.PropertyChangeListener;
69 import java.io.FileInputStream;
70 import java.io.FileOutputStream;
71 import java.io.InputStreamReader;
72 import java.io.OutputStreamWriter;
73 import java.io.PrintWriter;
74 import java.util.Arrays;
75 import java.util.Comparator;
76 import java.util.HashMap;
77 import java.util.HashSet;
78 import java.util.Hashtable;
79 import java.util.Iterator;
80 import java.util.List;
84 import javax.help.HelpSetException;
85 import javax.swing.AbstractCellEditor;
86 import javax.swing.BorderFactory;
87 import javax.swing.Icon;
88 import javax.swing.JButton;
89 import javax.swing.JCheckBox;
90 import javax.swing.JColorChooser;
91 import javax.swing.JDialog;
92 import javax.swing.JInternalFrame;
93 import javax.swing.JLabel;
94 import javax.swing.JLayeredPane;
95 import javax.swing.JMenuItem;
96 import javax.swing.JPanel;
97 import javax.swing.JPopupMenu;
98 import javax.swing.JScrollPane;
99 import javax.swing.JSlider;
100 import javax.swing.JTable;
101 import javax.swing.ListSelectionModel;
102 import javax.swing.SwingConstants;
103 import javax.swing.border.Border;
104 import javax.swing.event.ChangeEvent;
105 import javax.swing.event.ChangeListener;
106 import javax.swing.table.AbstractTableModel;
107 import javax.swing.table.JTableHeader;
108 import javax.swing.table.TableCellEditor;
109 import javax.swing.table.TableCellRenderer;
110 import javax.swing.table.TableColumn;
111 import javax.xml.bind.JAXBContext;
112 import javax.xml.bind.JAXBElement;
113 import javax.xml.bind.Marshaller;
114 import javax.xml.stream.XMLInputFactory;
115 import javax.xml.stream.XMLStreamReader;
117 public class FeatureSettings extends JPanel
118 implements FeatureSettingsControllerI, FeatureSettingsControllerGuiI
120 private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
121 .getString("label.sequence_feature_colours");
124 * column indices of fields in Feature Settings table
126 static final int TYPE_COLUMN = 0;
128 static final int COLOUR_COLUMN = 1;
130 static final int FILTER_COLUMN = 2;
132 static final int SHOW_COLUMN = 3;
134 private static final int COLUMN_COUNT = 4;
136 private static final int MIN_WIDTH = 400;
138 private static final int MIN_HEIGHT = 400;
140 private final static String BASE_TOOLTIP = MessageManager.getString("label.click_to_edit");
142 final FeatureRenderer fr;
144 public final AlignFrame af;
147 * 'original' fields hold settings to restore on Cancel
149 Object[][] originalData;
151 private float originalTransparency;
153 private ViewStyleI originalViewStyle;
155 private Map<String, FeatureMatcherSetI> originalFilters;
157 final JInternalFrame frame;
159 JScrollPane scrollPane = new JScrollPane();
165 JSlider transparency = new JSlider();
168 * when true, constructor is still executing - so ignore UI events
170 protected volatile boolean inConstruction = true;
172 int selectedRow = -1;
174 boolean resettingTable = false;
177 * true when Feature Settings are updating from feature renderer
179 private 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
202 originalViewStyle = new ViewStyle(af.viewport.getViewStyle());
207 } catch (Exception ex)
209 ex.printStackTrace();
215 public String getToolTipText(MouseEvent e)
218 int column = table.columnAtPoint(e.getPoint());
219 int row = table.rowAtPoint(e.getPoint());
224 tip = JvSwingUtils.wrapTooltip(true, MessageManager
225 .getString("label.feature_settings_click_drag"));
228 FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
230 tip = getColorTooltip(colour, true);
233 FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
237 .getString("label.configure_feature_tooltip")
248 * Position the tooltip near the bottom edge of, and half way across, the
252 public Point getToolTipLocation(MouseEvent e)
254 Point point = e.getPoint();
255 int column = table.columnAtPoint(point);
256 int row = table.rowAtPoint(point);
257 Rectangle r = getCellRect(row, column, false);
258 Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3);
262 JTableHeader tableHeader = table.getTableHeader();
263 tableHeader.setFont(new Font("Verdana", Font.PLAIN, 12));
264 tableHeader.setReorderingAllowed(false);
265 table.setFont(new Font("Verdana", Font.PLAIN, 12));
267 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
268 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
270 table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor(this));
271 table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
273 TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
274 new ColorRenderer(), new ColorEditor(this));
275 table.addColumn(colourColumn);
277 TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
278 new FilterRenderer(), new FilterEditor(this));
279 table.addColumn(filterColumn);
281 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
283 table.addMouseListener(new MouseAdapter()
286 public void mousePressed(MouseEvent evt)
288 Point pt = evt.getPoint();
289 selectedRow = table.rowAtPoint(pt);
290 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
291 if (evt.isPopupTrigger())
293 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
294 popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
297 else if (evt.getClickCount() == 2
298 && table.columnAtPoint(pt) == TYPE_COLUMN)
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);
305 fr.ap.av.sendSelection();
309 // isPopupTrigger fires on mouseReleased on Windows
311 public void mouseReleased(MouseEvent evt)
313 selectedRow = table.rowAtPoint(evt.getPoint());
314 if (evt.isPopupTrigger())
316 String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
317 Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
318 popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
324 table.addMouseMotionListener(new MouseMotionAdapter()
327 public void mouseDragged(MouseEvent evt)
329 int newRow = table.rowAtPoint(evt.getPoint());
330 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
333 * reposition 'selectedRow' to 'newRow' (the dragged to location)
334 * this could be more than one row away for a very fast drag action
335 * so just swap it with adjacent rows until we get it there
337 Object[][] data = ((FeatureTableModel) table.getModel())
339 int direction = newRow < selectedRow ? -1 : 1;
340 for (int i = selectedRow; i != newRow; i += direction)
342 Object[] temp = data[i];
343 data[i] = data[i + direction];
344 data[i + direction] = temp;
346 updateFeatureRenderer(data);
348 selectedRow = newRow;
352 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
353 // MessageManager.getString("label.feature_settings_click_drag")));
354 scrollPane.setViewportView(table);
356 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
358 fr.findAllFeatures(true); // display everything!
361 discoverAllFeatureData();
362 final FeatureSettings fs = this;
363 fr.addPropertyChangeListener(change = new PropertyChangeListener()
366 public void propertyChange(PropertyChangeEvent evt)
368 if (!fs.resettingTable && !fs.handlingUpdate)
370 fs.handlingUpdate = true;
372 // new groups may be added with new sequence feature types only
373 fs.handlingUpdate = false;
378 SplitContainerI splitframe = af.getSplitViewContainer();
379 if (splitframe != null)
381 frame = null; // keeps eclipse happy
382 splitframe.addFeatureSettingsUI(this);
386 frame = new JInternalFrame();
387 frame.setContentPane(this);
388 Rectangle bounds = af.getFeatureSettingsGeometry();
390 if (af.getAlignPanels().size() > 1 || Desktop.getAlignmentPanels(
391 af.alignPanel.av.getSequenceSetId()).length > 1)
393 title = MessageManager.formatMessage(
394 "label.sequence_feature_settings_for_view",
395 af.alignPanel.getViewName());
399 title = MessageManager.getString("label.sequence_feature_settings");
403 if (Platform.isAMac())
405 Desktop.addInternalFrame(frame, title, 600, 480);
409 Desktop.addInternalFrame(frame, title, 600, 450);
414 Desktop.addInternalFrame(frame, title,
415 false, bounds.width, bounds.height);
416 frame.setBounds(bounds);
417 frame.setVisible(true);
419 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
421 frame.addInternalFrameListener(
422 new javax.swing.event.InternalFrameAdapter()
425 public void internalFrameClosed(
426 javax.swing.event.InternalFrameEvent evt)
428 featureSettings_isClosed();
431 frame.setLayer(JLayeredPane.PALETTE_LAYER);
433 inConstruction = false;
436 PropertyChangeListener change;
439 public AlignViewControllerGuiI getAlignframe()
445 public void featureSettings_isClosed()
447 fr.removePropertyChangeListener(change);
451 protected void popupSort(final int rowSelected, final String type,
452 final Object typeCol, final Map<String, float[][]> minmax, int x,
455 JPopupMenu men = new JPopupMenu(MessageManager
456 .formatMessage("label.settings_for_param", new String[]
458 JMenuItem scr = new JMenuItem(
459 MessageManager.getString("label.sort_by_score"));
461 final FeatureSettings me = this;
462 scr.addActionListener(new ActionListener()
466 public void actionPerformed(ActionEvent e)
469 .sortAlignmentByFeatureScore(Arrays.asList(new String[]
474 JMenuItem dens = new JMenuItem(
475 MessageManager.getString("label.sort_by_density"));
476 dens.addActionListener(new ActionListener()
480 public void actionPerformed(ActionEvent e)
483 .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
490 JMenuItem selCols = new JMenuItem(
491 MessageManager.getString("label.select_columns_containing"));
492 selCols.addActionListener(new ActionListener()
495 public void actionPerformed(ActionEvent arg0)
497 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
499 fr.ap.av.sendSelection();
502 JMenuItem clearCols = new JMenuItem(MessageManager
503 .getString("label.select_columns_not_containing"));
504 clearCols.addActionListener(new ActionListener()
507 public void actionPerformed(ActionEvent arg0)
509 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
511 fr.ap.av.sendSelection();
514 JMenuItem hideCols = new JMenuItem(
515 MessageManager.getString("label.hide_columns_containing"));
516 hideCols.addActionListener(new ActionListener()
519 public void actionPerformed(ActionEvent arg0)
521 fr.ap.alignFrame.hideFeatureColumns(type, true);
522 fr.ap.av.sendSelection();
525 JMenuItem hideOtherCols = new JMenuItem(
526 MessageManager.getString("label.hide_columns_not_containing"));
527 hideOtherCols.addActionListener(new ActionListener()
530 public void actionPerformed(ActionEvent arg0)
532 fr.ap.alignFrame.hideFeatureColumns(type, false);
533 fr.ap.av.sendSelection();
539 men.add(hideOtherCols);
540 men.show(table, x, y);
544 synchronized public void discoverAllFeatureData()
546 Set<String> allGroups = new HashSet<>();
547 AlignmentI alignment = af.getViewport().getAlignment();
549 for (int i = 0; i < alignment.getHeight(); i++)
551 SequenceI seq = alignment.getSequenceAt(i);
552 for (String group : seq.getFeatures().getFeatureGroups(true))
554 if (group != null && !allGroups.contains(group))
556 allGroups.add(group);
557 checkGroupState(group);
568 * Synchronise gui group list and check visibility of group
571 * @return true if group is visible
573 private boolean checkGroupState(String group)
575 boolean visible = fr.checkGroupVisibility(group, true);
577 for (int g = 0; g < groupPanel.getComponentCount(); g++)
579 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
581 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
586 final String grp = group;
587 final JCheckBox check = new JCheckBox(group, visible);
588 check.setFont(new Font("Serif", Font.BOLD, 12));
589 check.setToolTipText(group);
590 check.addItemListener(new ItemListener()
593 public void itemStateChanged(ItemEvent evt)
595 fr.setGroupVisibility(check.getText(), check.isSelected());
596 resetTable(new String[] { grp });
600 groupPanel.add(check);
604 synchronized void resetTable(String[] groupChanged)
610 resettingTable = true;
611 typeWidth = new Hashtable<>();
612 // TODO: change avWidth calculation to 'per-sequence' average and use long
615 Set<String> displayableTypes = new HashSet<>();
616 Set<String> foundGroups = new HashSet<>();
619 * determine which feature types may be visible depending on
620 * which groups are selected, and recompute average width data
622 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
625 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
628 * get the sequence's groups for positional features
629 * and keep track of which groups are visible
631 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
632 Set<String> visibleGroups = new HashSet<>();
633 for (String group : groups)
635 if (group == null || checkGroupState(group))
637 visibleGroups.add(group);
640 foundGroups.addAll(groups);
643 * get distinct feature types for visible groups
644 * record distinct visible types, and their count and total length
646 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
647 visibleGroups.toArray(new String[visibleGroups.size()]));
648 for (String type : types)
650 displayableTypes.add(type);
651 float[] avWidth = typeWidth.get(type);
654 avWidth = new float[2];
655 typeWidth.put(type, avWidth);
657 // todo this could include features with a non-visible group
658 // - do we greatly care?
659 // todo should we include non-displayable features here, and only
660 // update when features are added?
661 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
662 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
666 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
669 if (fr.hasRenderOrder())
673 fr.findAllFeatures(groupChanged != null); // prod to update
674 // colourschemes. but don't
676 // First add the checks in the previous render order,
677 // in case the window has been closed and reopened
679 List<String> frl = fr.getRenderOrder();
680 for (int ro = frl.size() - 1; ro > -1; ro--)
682 String type = frl.get(ro);
684 if (!displayableTypes.contains(type))
689 data[dataIndex][TYPE_COLUMN] = type;
690 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
691 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
692 data[dataIndex][FILTER_COLUMN] = featureFilter == null
693 ? new FeatureMatcherSet()
695 data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(
696 af.getViewport().getFeaturesDisplayed().isVisible(type));
698 displayableTypes.remove(type);
703 * process any extra features belonging only to
704 * a group which was just selected
706 while (!displayableTypes.isEmpty())
708 String type = displayableTypes.iterator().next();
709 data[dataIndex][TYPE_COLUMN] = type;
711 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
712 if (data[dataIndex][COLOUR_COLUMN] == null)
714 // "Colour has been updated in another view!!"
715 fr.clearRenderOrder();
718 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
719 data[dataIndex][FILTER_COLUMN] = featureFilter == null
720 ? new FeatureMatcherSet()
722 data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(true);
724 displayableTypes.remove(type);
727 if (originalData == null)
729 originalData = new Object[data.length][COLUMN_COUNT];
730 for (int i = 0; i < data.length; i++)
732 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
737 updateOriginalData(data);
740 table.setModel(new FeatureTableModel(data));
741 table.getColumnModel().getColumn(0).setPreferredWidth(200);
743 groupPanel.setLayout(
744 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
745 pruneGroups(foundGroups);
746 groupPanel.validate();
748 updateFeatureRenderer(data, groupChanged != null);
749 resettingTable = false;
753 * Updates 'originalData' (used for restore on Cancel) if we detect that changes
754 * have been made outwith this dialog
756 * <li>a new feature type added (and made visible)</li>
757 * <li>a feature colour changed (in the Amend Features dialog)</li>
762 protected void updateOriginalData(Object[][] foundData)
764 // todo LinkedHashMap instead of Object[][] would be nice
766 Object[][] currentData = ((FeatureTableModel) table.getModel())
768 for (Object[] row : foundData)
770 String type = (String) row[TYPE_COLUMN];
771 boolean found = false;
772 for (Object[] current : currentData)
774 if (type.equals(current[TYPE_COLUMN]))
778 * currently dependent on object equality here;
779 * really need an equals method on FeatureColour
781 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
784 * feature colour has changed externally - update originalData
786 for (Object[] original : originalData)
788 if (type.equals(original[TYPE_COLUMN]))
790 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
801 * new feature detected - add to original data (on top)
803 Object[][] newData = new Object[originalData.length
805 for (int i = 0; i < originalData.length; i++)
807 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
811 originalData = newData;
817 * Remove from the groups panel any checkboxes for groups that are not in the
818 * foundGroups set. This enables removing a group from the display when the last
819 * feature in that group is deleted.
823 protected void pruneGroups(Set<String> foundGroups)
825 for (int g = 0; g < groupPanel.getComponentCount(); g++)
827 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
828 if (!foundGroups.contains(checkbox.getText()))
830 groupPanel.remove(checkbox);
836 * reorder data based on the featureRenderers global priority list.
840 private void ensureOrder(Object[][] data)
842 boolean sort = false;
843 float[] order = new float[data.length];
844 for (int i = 0; i < order.length; i++)
846 order[i] = fr.getOrder(data[i][0].toString());
849 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
853 sort = sort || order[i - 1] > order[i];
858 jalview.util.QuickSort.sort(order, data);
863 * Offers a file chooser dialog, and then loads the feature colours and
864 * filters from file in XML format and unmarshals to Jalview feature settings
868 JalviewFileChooser chooser = new JalviewFileChooser("fc",
869 SEQUENCE_FEATURE_COLOURS);
870 chooser.setFileView(new JalviewFileView());
871 chooser.setDialogTitle(
872 MessageManager.getString("label.load_feature_colours"));
873 chooser.setToolTipText(MessageManager.getString("action.load"));
875 int value = chooser.showOpenDialog(this);
877 if (value == JalviewFileChooser.APPROVE_OPTION)
879 File file = chooser.getSelectedFile();
885 * Loads feature colours and filters from XML stored in the given file
893 InputStreamReader in = new InputStreamReader(
894 new FileInputStream(file), "UTF-8");
896 JAXBContext jc = JAXBContext
897 .newInstance("jalview.xml.binding.jalview");
898 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
899 XMLStreamReader streamReader = XMLInputFactory.newInstance()
900 .createXMLStreamReader(in);
901 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
902 JalviewUserColours.class);
903 JalviewUserColours jucs = jbe.getValue();
905 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
908 * load feature colours
910 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
912 Colour newcol = jucs.getColour().get(i);
913 FeatureColourI colour = jalview.project.Jalview2XML
914 .parseColour(newcol);
915 fr.setColour(newcol.getName(), colour);
916 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
920 * load feature filters; loaded filters will replace any that are
921 * currently defined, other defined filters are left unchanged
923 for (int i = 0; i < jucs.getFilter().size(); i++)
925 Filter filterModel = jucs.getFilter().get(i);
926 String featureType = filterModel.getFeatureType();
927 FeatureMatcherSetI filter = jalview.project.Jalview2XML
928 .parseFilter(featureType, filterModel.getMatcherSet());
929 if (!filter.isEmpty())
931 fr.setFeatureFilter(featureType, filter);
936 * update feature settings table
941 Object[][] data = ((FeatureTableModel) table.getModel())
944 updateFeatureRenderer(data, false);
947 } catch (Exception ex)
949 System.out.println("Error loading User Colour File\n" + ex);
954 * Offers a file chooser dialog, and then saves the current feature colours
955 * and any filters to the selected file in XML format
959 JalviewFileChooser chooser = new JalviewFileChooser("fc",
960 SEQUENCE_FEATURE_COLOURS);
961 chooser.setFileView(new JalviewFileView());
962 chooser.setDialogTitle(
963 MessageManager.getString("label.save_feature_colours"));
964 chooser.setToolTipText(MessageManager.getString("action.save"));
966 int value = chooser.showSaveDialog(this);
968 if (value == JalviewFileChooser.APPROVE_OPTION)
970 save(chooser.getSelectedFile());
975 * Saves feature colours and filters to the given file
981 JalviewUserColours ucs = new JalviewUserColours();
982 ucs.setSchemeName("Sequence Features");
985 PrintWriter out = new PrintWriter(new OutputStreamWriter(
986 new FileOutputStream(file), "UTF-8"));
989 * sort feature types by colour order, from 0 (highest)
992 Set<String> fr_colours = fr.getAllFeatureColours();
993 String[] sortedTypes = fr_colours
994 .toArray(new String[fr_colours.size()]);
995 Arrays.sort(sortedTypes, new Comparator<String>()
998 public int compare(String type1, String type2)
1000 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
1005 * save feature colours
1007 for (String featureType : sortedTypes)
1009 FeatureColourI fcol = fr.getFeatureStyle(featureType);
1010 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
1012 ucs.getColour().add(col);
1016 * save any feature filters
1018 for (String featureType : sortedTypes)
1020 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1021 if (filter != null && !filter.isEmpty())
1023 Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
1024 FeatureMatcherI firstMatcher = iterator.next();
1025 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
1026 .marshalFilter(firstMatcher, iterator,
1028 Filter filterModel = new Filter();
1029 filterModel.setFeatureType(featureType);
1030 filterModel.setMatcherSet(ms);
1031 ucs.getFilter().add(filterModel);
1034 JAXBContext jaxbContext = JAXBContext
1035 .newInstance(JalviewUserColours.class);
1036 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1037 jaxbMarshaller.marshal(
1038 new ObjectFactory().createJalviewUserColours(ucs), out);
1040 // jaxbMarshaller.marshal(object, pout);
1041 // marshaller.marshal(object);
1044 // ucs.marshal(out);
1046 } catch (Exception ex)
1048 ex.printStackTrace();
1052 public void invertSelection()
1054 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1055 for (int i = 0; i < data.length; i++)
1057 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1059 updateFeatureRenderer(data, true);
1063 public void orderByAvWidth()
1065 if (table == null || table.getModel() == null)
1069 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1070 float[] width = new float[data.length];
1074 for (int i = 0; i < data.length; i++)
1076 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1079 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1080 // weight - but have to make per
1081 // sequence, too (awidth[2])
1082 // if (width[i]==1) // hack to distinguish single width sequences.
1093 boolean sort = false;
1094 for (int i = 0; i < width.length; i++)
1096 // awidth = (float[]) typeWidth.get(data[i][0]);
1099 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1102 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1108 width[i] /= max; // normalize
1109 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
1113 sort = sort || width[i - 1] > width[i];
1118 jalview.util.QuickSort.sort(width, data);
1119 // update global priority order
1122 updateFeatureRenderer(data, false);
1132 af.setFeatureSettingsGeometry(frame.getBounds());
1133 frame.setClosed(true);
1137 SplitContainerI sc = af.getSplitViewContainer();
1138 sc.closeFeatureSettings(this, closeContainingFrame);
1139 af.featureSettings = null;
1141 } catch (Exception exe)
1147 public void updateFeatureRenderer(Object[][] data)
1149 updateFeatureRenderer(data, true);
1153 * Update the priority order of features; only repaint if this changed the order
1154 * of visible features
1159 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1161 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1163 if (fr.setFeaturePriority(rowData, visibleNew))
1170 * Converts table data into an array of data beans
1172 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1174 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1175 for (int i = 0; i < data.length; i++)
1177 String type = (String) data[i][TYPE_COLUMN];
1178 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1179 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1180 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1181 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1187 private void jbInit() throws Exception
1189 this.setLayout(new BorderLayout());
1191 JPanel settingsPane = new JPanel();
1192 settingsPane.setLayout(new BorderLayout());
1194 JPanel bigPanel = new JPanel();
1195 bigPanel.setLayout(new BorderLayout());
1197 groupPanel = new JPanel();
1198 bigPanel.add(groupPanel, BorderLayout.NORTH);
1200 JButton invert = new JButton(
1201 MessageManager.getString("label.invert_selection"));
1202 invert.setFont(JvSwingUtils.getLabelFont());
1203 invert.addActionListener(new ActionListener()
1206 public void actionPerformed(ActionEvent e)
1212 JButton optimizeOrder = new JButton(
1213 MessageManager.getString("label.optimise_order"));
1214 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1215 optimizeOrder.addActionListener(new ActionListener()
1218 public void actionPerformed(ActionEvent e)
1224 JButton sortByScore = new JButton(
1225 MessageManager.getString("label.seq_sort_by_score"));
1226 sortByScore.setFont(JvSwingUtils.getLabelFont());
1227 sortByScore.addActionListener(new ActionListener()
1230 public void actionPerformed(ActionEvent e)
1232 af.avc.sortAlignmentByFeatureScore(null);
1235 JButton sortByDens = new JButton(
1236 MessageManager.getString("label.sequence_sort_by_density"));
1237 sortByDens.setFont(JvSwingUtils.getLabelFont());
1238 sortByDens.addActionListener(new ActionListener()
1241 public void actionPerformed(ActionEvent e)
1243 af.avc.sortAlignmentByFeatureDensity(null);
1247 JButton help = new JButton(MessageManager.getString("action.help"));
1248 help.setFont(JvSwingUtils.getLabelFont());
1249 help.addActionListener(new ActionListener()
1252 public void actionPerformed(ActionEvent e)
1256 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1257 } catch (HelpSetException e1)
1259 e1.printStackTrace();
1264 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1265 cancel.setFont(JvSwingUtils.getLabelFont());
1266 cancel.addActionListener(new ActionListener()
1269 public void actionPerformed(ActionEvent e)
1271 fr.setTransparency(originalTransparency);
1272 fr.setFeatureFilters(originalFilters);
1273 updateFeatureRenderer(originalData);
1274 af.getViewport().setViewStyle(originalViewStyle);
1279 JButton ok = new JButton(MessageManager.getString("action.ok"));
1280 ok.setFont(JvSwingUtils.getLabelFont());
1281 ok.addActionListener(new ActionListener()
1284 public void actionPerformed(ActionEvent e)
1290 JButton loadColours = new JButton(
1291 MessageManager.getString("label.load_colours"));
1292 loadColours.setFont(JvSwingUtils.getLabelFont());
1293 loadColours.setToolTipText(
1294 MessageManager.getString("label.load_colours_tooltip"));
1295 loadColours.addActionListener(new ActionListener()
1298 public void actionPerformed(ActionEvent e)
1304 JButton saveColours = new JButton(
1305 MessageManager.getString("label.save_colours"));
1306 saveColours.setFont(JvSwingUtils.getLabelFont());
1307 saveColours.setToolTipText(
1308 MessageManager.getString("label.save_colours_tooltip"));
1309 saveColours.addActionListener(new ActionListener()
1312 public void actionPerformed(ActionEvent e)
1317 transparency.addChangeListener(new ChangeListener()
1320 public void stateChanged(ChangeEvent evt)
1322 if (!inConstruction)
1324 fr.setTransparency((100 - transparency.getValue()) / 100f);
1330 transparency.setMaximum(70);
1331 transparency.setToolTipText(
1332 MessageManager.getString("label.transparency_tip"));
1334 boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
1335 String text = MessageManager.formatMessage("label.show_linked_features",
1337 ? MessageManager.getString("label.protein")
1340 JCheckBox showComplement = new JCheckBox(text);
1341 showComplement.setSelected(af.getViewport().isShowComplementFeatures());
1342 showComplement.addActionListener(new ActionListener()
1345 public void actionPerformed(ActionEvent e)
1348 .setShowComplementFeatures(showComplement.isSelected());
1353 JCheckBox showComplementOnTop = new JCheckBox(
1354 MessageManager.getString("label.on_top"));
1356 .setSelected(af.getViewport().isShowComplementFeaturesOnTop());
1357 showComplementOnTop.addActionListener(new ActionListener()
1360 public void actionPerformed(ActionEvent e)
1362 af.getViewport().setShowComplementFeaturesOnTop(
1363 showComplementOnTop.isSelected());
1367 // JButton viewComplementSettings = new JButton(MessageManager
1368 // .formatMessage("label.show_linked_feature_settings",
1370 // ? MessageManager.getString("label.protein")
1373 // viewComplementSettings.addActionListener(new ActionListener()
1377 // public void actionPerformed(ActionEvent e)
1379 // AlignViewControllerGuiI complAf = af.getSplitViewContainer()
1380 // .getComplementAlignFrame(af);
1381 // FeatureSettings complFeatureSettings = (FeatureSettings) complAf
1382 // .getFeatureSettingsUI();
1383 // if (complFeatureSettings != null)
1385 // complFeatureSettings.frame.setVisible(true);
1388 // complFeatureSettings.frame.setSelected(true);
1390 // } catch (Exception q)
1395 // complAf.showFeatureSettingsUI();
1399 JPanel lowerPanel = new JPanel(new GridLayout(1, 2));
1400 bigPanel.add(lowerPanel, BorderLayout.SOUTH);
1402 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1403 transbuttons.add(optimizeOrder);
1404 transbuttons.add(invert);
1405 transbuttons.add(sortByScore);
1406 transbuttons.add(sortByDens);
1407 transbuttons.add(help);
1409 boolean hasComplement = af.getViewport().getCodingComplement() != null;
1410 JPanel transPanelLeft = new JPanel(
1411 new GridLayout(hasComplement ? 4 : 2, 1));
1412 transPanelLeft.add(new JLabel(" Colour transparency" + ":"));
1413 transPanelLeft.add(transparency);
1416 JPanel cp = new JPanel(new FlowLayout(FlowLayout.LEFT));
1417 cp.add(showComplement);
1418 cp.add(showComplementOnTop);
1419 transPanelLeft.add(cp);
1421 lowerPanel.add(transPanelLeft);
1422 lowerPanel.add(transbuttons);
1424 JPanel buttonPanel = new JPanel();
1425 buttonPanel.add(ok);
1426 buttonPanel.add(cancel);
1427 buttonPanel.add(loadColours);
1428 buttonPanel.add(saveColours);
1429 bigPanel.add(scrollPane, BorderLayout.CENTER);
1430 settingsPane.add(bigPanel, BorderLayout.CENTER);
1431 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1432 this.add(settingsPane);
1436 * Repaints alignment, structure and overview (if shown). If there is a
1437 * complementary view which is showing this view's features, then also
1440 void refreshDisplay()
1442 af.alignPanel.paintAlignment(true, true);
1443 AlignViewportI complement = af.getViewport().getCodingComplement();
1444 if (complement != null && complement.isShowComplementFeatures())
1446 AlignFrame af2 = Desktop.getAlignFrameFor(complement);
1447 af2.alignPanel.paintAlignment(true, true);
1452 * Answers a suitable tooltip to show on the colour cell of the table
1456 * if true include 'click to edit' and similar text
1459 public static String getColorTooltip(FeatureColourI fcol,
1466 if (fcol.isSimpleColour())
1468 return withHint ? BASE_TOOLTIP : null;
1470 String description = fcol.getDescription();
1471 description = description.replaceAll("<", "<");
1472 description = description.replaceAll(">", ">");
1473 StringBuilder tt = new StringBuilder(description);
1476 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1478 return JvSwingUtils.wrapTooltip(true, tt.toString());
1481 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1484 boolean thr = false;
1485 StringBuilder tx = new StringBuilder();
1487 if (gcol.isColourByAttribute())
1489 tx.append(FeatureMatcher
1490 .toAttributeDisplayName(gcol.getAttributeName()));
1492 else if (!gcol.isColourByLabel())
1494 tx.append(MessageManager.getString("label.score"));
1497 if (gcol.isAboveThreshold())
1502 if (gcol.isBelowThreshold())
1507 if (gcol.isColourByLabel())
1513 if (!gcol.isColourByAttribute())
1521 Color newColor = gcol.getMaxColour();
1522 comp.setBackground(newColor);
1523 // System.err.println("Width is " + w / 2);
1524 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1525 comp.setIcon(ficon);
1526 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1527 // + newColor.getGreen() + ", " + newColor.getBlue()
1528 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1529 // + ", " + minCol.getBlue() + ")");
1531 comp.setHorizontalAlignment(SwingConstants.CENTER);
1532 comp.setText(tx.toString());
1535 // ///////////////////////////////////////////////////////////////////////
1536 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1537 // ///////////////////////////////////////////////////////////////////////
1538 class FeatureTableModel extends AbstractTableModel
1540 private String[] columnNames = {
1541 MessageManager.getString("label.feature_type"),
1542 MessageManager.getString("action.colour"),
1543 MessageManager.getString("label.configuration"),
1544 MessageManager.getString("label.show") };
1546 private Object[][] data;
1548 FeatureTableModel(Object[][] data)
1553 public Object[][] getData()
1558 public void setData(Object[][] data)
1564 public int getColumnCount()
1566 return columnNames.length;
1569 public Object[] getRow(int row)
1575 public int getRowCount()
1581 public String getColumnName(int col)
1583 return columnNames[col];
1587 public Object getValueAt(int row, int col)
1589 return data[row][col];
1593 * Answers the class of column c of the table
1596 public Class<?> getColumnClass(int c)
1601 return String.class;
1603 return FeatureColour.class;
1605 return FeatureMatcherSet.class;
1607 return Boolean.class;
1612 public boolean isCellEditable(int row, int col)
1614 return col == 0 ? false : true;
1618 public void setValueAt(Object value, int row, int col)
1620 data[row][col] = value;
1621 fireTableCellUpdated(row, col);
1622 updateFeatureRenderer(data);
1627 class ColorRenderer extends JLabel implements TableCellRenderer
1629 Border unselectedBorder = null;
1631 Border selectedBorder = null;
1633 public ColorRenderer()
1635 setOpaque(true); // MUST do this for background to show up.
1636 setHorizontalTextPosition(SwingConstants.CENTER);
1637 setVerticalTextPosition(SwingConstants.CENTER);
1641 public Component getTableCellRendererComponent(JTable tbl, Object color,
1642 boolean isSelected, boolean hasFocus, int row, int column)
1644 FeatureColourI cellColour = (FeatureColourI) color;
1646 setBackground(tbl.getBackground());
1647 if (!cellColour.isSimpleColour())
1649 Rectangle cr = tbl.getCellRect(row, column, false);
1650 FeatureSettings.renderGraduatedColor(this, cellColour,
1651 (int) cr.getWidth(), (int) cr.getHeight());
1657 setBackground(cellColour.getColour());
1661 if (selectedBorder == null)
1663 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1664 tbl.getSelectionBackground());
1666 setBorder(selectedBorder);
1670 if (unselectedBorder == null)
1672 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1673 tbl.getBackground());
1675 setBorder(unselectedBorder);
1682 class FilterRenderer extends JLabel implements TableCellRenderer
1684 javax.swing.border.Border unselectedBorder = null;
1686 javax.swing.border.Border selectedBorder = null;
1688 public FilterRenderer()
1690 setOpaque(true); // MUST do this for background to show up.
1691 setHorizontalTextPosition(SwingConstants.CENTER);
1692 setVerticalTextPosition(SwingConstants.CENTER);
1696 public Component getTableCellRendererComponent(JTable tbl,
1697 Object filter, boolean isSelected, boolean hasFocus, int row,
1700 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1702 String asText = theFilter.toString();
1703 setBackground(tbl.getBackground());
1704 this.setText(asText);
1709 if (selectedBorder == null)
1711 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1712 tbl.getSelectionBackground());
1714 setBorder(selectedBorder);
1718 if (unselectedBorder == null)
1720 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1721 tbl.getBackground());
1723 setBorder(unselectedBorder);
1731 * update comp using rendering settings from gcol
1736 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1738 int w = comp.getWidth(), h = comp.getHeight();
1741 w = (int) comp.getPreferredSize().getWidth();
1742 h = (int) comp.getPreferredSize().getHeight();
1749 renderGraduatedColor(comp, gcol, w, h);
1752 class ColorEditor extends AbstractCellEditor
1753 implements TableCellEditor, ActionListener
1757 FeatureColourI currentColor;
1759 FeatureTypeSettings chooser;
1765 JColorChooser colorChooser;
1769 protected static final String EDIT = "edit";
1771 int rowSelected = 0;
1773 public ColorEditor(FeatureSettings me)
1776 // Set up the editor (from the table's point of view),
1777 // which is a button.
1778 // This button brings up the color chooser dialog,
1779 // which is the editor from the user's point of view.
1780 button = new JButton();
1781 button.setActionCommand(EDIT);
1782 button.addActionListener(this);
1783 button.setBorderPainted(false);
1784 // Set up the dialog that the button brings up.
1785 colorChooser = new JColorChooser();
1786 dialog = JColorChooser.createDialog(button,
1787 MessageManager.getString("label.select_colour"), true, // modal
1788 colorChooser, this, // OK button handler
1789 null); // no CANCEL button handler
1793 * Handles events from the editor button and from the dialog's OK button.
1796 public void actionPerformed(ActionEvent e)
1798 // todo test e.getSource() instead here
1799 if (EDIT.equals(e.getActionCommand()))
1801 // The user has clicked the cell, so
1802 // bring up the dialog.
1803 if (currentColor.isSimpleColour())
1805 // bring up simple color chooser
1806 button.setBackground(currentColor.getColour());
1807 colorChooser.setColor(currentColor.getColour());
1808 dialog.setVisible(true);
1812 // bring up graduated chooser.
1813 chooser = new FeatureTypeSettings(me.fr, type);
1818 chooser.setRequestFocusEnabled(true);
1819 chooser.requestFocus();
1821 chooser.addActionListener(this);
1822 // Make the renderer reappear.
1823 fireEditingStopped();
1828 if (currentColor.isSimpleColour())
1831 * read off colour picked in colour chooser after OK pressed
1833 currentColor = new FeatureColour(colorChooser.getColor());
1834 me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1839 * after OK in variable colour dialog, any changes to colour
1840 * (or filters!) are already set in FeatureRenderer, so just
1841 * update table data without triggering updateFeatureRenderer
1843 currentColor = fr.getFeatureColours().get(type);
1844 FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
1845 if (currentFilter == null)
1847 currentFilter = new FeatureMatcherSet();
1849 Object[] data = ((FeatureTableModel) table.getModel())
1850 .getData()[rowSelected];
1851 data[COLOUR_COLUMN] = currentColor;
1852 data[FILTER_COLUMN] = currentFilter;
1854 fireEditingStopped();
1855 me.table.validate();
1859 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1861 public Object getCellEditorValue()
1863 return currentColor;
1866 // Implement the one method defined by TableCellEditor.
1868 public Component getTableCellEditorComponent(JTable theTable, Object value,
1869 boolean isSelected, int row, int column)
1871 currentColor = (FeatureColourI) value;
1872 this.rowSelected = row;
1873 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1874 button.setOpaque(true);
1875 button.setBackground(me.getBackground());
1876 if (!currentColor.isSimpleColour())
1878 JLabel btn = new JLabel();
1879 btn.setSize(button.getSize());
1880 FeatureSettings.renderGraduatedColor(btn, currentColor);
1881 button.setBackground(btn.getBackground());
1882 button.setIcon(btn.getIcon());
1883 button.setText(btn.getText());
1888 button.setIcon(null);
1889 button.setBackground(currentColor.getColour());
1896 * The cell editor for the Filter column. It displays the text of any filters
1897 * for the feature type in that row (in full as a tooltip, possible abbreviated
1898 * as display text). On click in the cell, opens the Feature Display Settings
1899 * dialog at the Filters tab.
1901 class FilterEditor extends AbstractCellEditor
1902 implements TableCellEditor, ActionListener
1906 FeatureMatcherSetI currentFilter;
1914 protected static final String EDIT = "edit";
1916 int rowSelected = 0;
1918 public FilterEditor(FeatureSettings me)
1921 button = new JButton();
1922 button.setActionCommand(EDIT);
1923 button.addActionListener(this);
1924 button.setBorderPainted(false);
1928 * Handles events from the editor button
1931 public void actionPerformed(ActionEvent e)
1933 if (button == e.getSource())
1935 FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
1936 chooser.addActionListener(this);
1937 chooser.setRequestFocusEnabled(true);
1938 chooser.requestFocus();
1939 if (lastLocation != null)
1941 // todo open at its last position on screen
1942 chooser.setBounds(lastLocation.x, lastLocation.y,
1943 chooser.getWidth(), chooser.getHeight());
1946 fireEditingStopped();
1948 else if (e.getSource() instanceof Component)
1952 * after OK in variable colour dialog, any changes to filter
1953 * (or colours!) are already set in FeatureRenderer, so just
1954 * update table data without triggering updateFeatureRenderer
1956 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1957 currentFilter = me.fr.getFeatureFilter(type);
1958 if (currentFilter == null)
1960 currentFilter = new FeatureMatcherSet();
1962 Object[] data = ((FeatureTableModel) table.getModel())
1963 .getData()[rowSelected];
1964 data[COLOUR_COLUMN] = currentColor;
1965 data[FILTER_COLUMN] = currentFilter;
1966 fireEditingStopped();
1967 me.table.validate();
1972 public Object getCellEditorValue()
1974 return currentFilter;
1978 public Component getTableCellEditorComponent(JTable theTable, Object value,
1979 boolean isSelected, int row, int column)
1981 currentFilter = (FeatureMatcherSetI) value;
1982 this.rowSelected = row;
1983 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1984 button.setOpaque(true);
1985 button.setBackground(me.getBackground());
1986 button.setText(currentFilter.toString());
1987 button.setIcon(null);
1993 class FeatureIcon implements Icon
1995 FeatureColourI gcol;
1999 boolean midspace = false;
2001 int width = 50, height = 20;
2003 int s1, e1; // start and end of midpoint band for thresholded symbol
2005 Color mpcolour = Color.white;
2007 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
2027 public int getIconWidth()
2033 public int getIconHeight()
2039 public void paintIcon(Component c, Graphics g, int x, int y)
2042 if (gcol.isColourByLabel())
2045 g.fillRect(0, 0, width, height);
2046 // need an icon here.
2047 g.setColor(gcol.getMaxColour());
2049 g.setFont(new Font("Verdana", Font.PLAIN, 9));
2051 // g.setFont(g.getFont().deriveFont(
2052 // AffineTransform.getScaleInstance(
2053 // width/g.getFontMetrics().stringWidth("Label"),
2054 // height/g.getFontMetrics().getHeight())));
2056 g.drawString(MessageManager.getString("label.label"), 0, 0);
2061 Color minCol = gcol.getMinColour();
2063 g.fillRect(0, 0, s1, height);
2066 g.setColor(Color.white);
2067 g.fillRect(s1, 0, e1 - s1, height);
2069 g.setColor(gcol.getMaxColour());
2070 g.fillRect(0, e1, width - e1, height);