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 if (Platform.isAMac())
390 Desktop.addInternalFrame(frame,
391 MessageManager.getString("label.sequence_feature_settings"),
396 Desktop.addInternalFrame(frame,
397 MessageManager.getString("label.sequence_feature_settings"),
400 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
402 frame.addInternalFrameListener(
403 new javax.swing.event.InternalFrameAdapter()
406 public void internalFrameClosed(
407 javax.swing.event.InternalFrameEvent evt)
409 closeFeatureSettings();
412 frame.setLayer(JLayeredPane.PALETTE_LAYER);
414 inConstruction = false;
417 PropertyChangeListener change;
420 public AlignViewControllerGuiI getAlignframe()
426 public void closeFeatureSettings()
428 fr.removePropertyChangeListener(change);
432 protected void popupSort(final int rowSelected, final String type,
433 final Object typeCol, final Map<String, float[][]> minmax, int x,
436 JPopupMenu men = new JPopupMenu(MessageManager
437 .formatMessage("label.settings_for_param", new String[]
439 JMenuItem scr = new JMenuItem(
440 MessageManager.getString("label.sort_by_score"));
442 final FeatureSettings me = this;
443 scr.addActionListener(new ActionListener()
447 public void actionPerformed(ActionEvent e)
450 .sortAlignmentByFeatureScore(Arrays.asList(new String[]
455 JMenuItem dens = new JMenuItem(
456 MessageManager.getString("label.sort_by_density"));
457 dens.addActionListener(new ActionListener()
461 public void actionPerformed(ActionEvent e)
464 .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
471 JMenuItem selCols = new JMenuItem(
472 MessageManager.getString("label.select_columns_containing"));
473 selCols.addActionListener(new ActionListener()
476 public void actionPerformed(ActionEvent arg0)
478 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
480 fr.ap.av.sendSelection();
483 JMenuItem clearCols = new JMenuItem(MessageManager
484 .getString("label.select_columns_not_containing"));
485 clearCols.addActionListener(new ActionListener()
488 public void actionPerformed(ActionEvent arg0)
490 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
492 fr.ap.av.sendSelection();
495 JMenuItem hideCols = new JMenuItem(
496 MessageManager.getString("label.hide_columns_containing"));
497 hideCols.addActionListener(new ActionListener()
500 public void actionPerformed(ActionEvent arg0)
502 fr.ap.alignFrame.hideFeatureColumns(type, true);
503 fr.ap.av.sendSelection();
506 JMenuItem hideOtherCols = new JMenuItem(
507 MessageManager.getString("label.hide_columns_not_containing"));
508 hideOtherCols.addActionListener(new ActionListener()
511 public void actionPerformed(ActionEvent arg0)
513 fr.ap.alignFrame.hideFeatureColumns(type, false);
514 fr.ap.av.sendSelection();
520 men.add(hideOtherCols);
521 men.show(table, x, y);
525 synchronized public void discoverAllFeatureData()
527 Set<String> allGroups = new HashSet<>();
528 AlignmentI alignment = af.getViewport().getAlignment();
530 for (int i = 0; i < alignment.getHeight(); i++)
532 SequenceI seq = alignment.getSequenceAt(i);
533 for (String group : seq.getFeatures().getFeatureGroups(true))
535 if (group != null && !allGroups.contains(group))
537 allGroups.add(group);
538 checkGroupState(group);
549 * Synchronise gui group list and check visibility of group
552 * @return true if group is visible
554 private boolean checkGroupState(String group)
556 boolean visible = fr.checkGroupVisibility(group, true);
558 for (int g = 0; g < groupPanel.getComponentCount(); g++)
560 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
562 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
567 final String grp = group;
568 final JCheckBox check = new JCheckBox(group, visible);
569 check.setFont(new Font("Serif", Font.BOLD, 12));
570 check.setToolTipText(group);
571 check.addItemListener(new ItemListener()
574 public void itemStateChanged(ItemEvent evt)
576 fr.setGroupVisibility(check.getText(), check.isSelected());
577 resetTable(new String[] { grp });
581 groupPanel.add(check);
585 synchronized void resetTable(String[] groupChanged)
591 resettingTable = true;
592 typeWidth = new Hashtable<>();
593 // TODO: change avWidth calculation to 'per-sequence' average and use long
596 Set<String> displayableTypes = new HashSet<>();
597 Set<String> foundGroups = new HashSet<>();
600 * determine which feature types may be visible depending on
601 * which groups are selected, and recompute average width data
603 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
606 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
609 * get the sequence's groups for positional features
610 * and keep track of which groups are visible
612 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
613 Set<String> visibleGroups = new HashSet<>();
614 for (String group : groups)
616 if (group == null || checkGroupState(group))
618 visibleGroups.add(group);
621 foundGroups.addAll(groups);
624 * get distinct feature types for visible groups
625 * record distinct visible types, and their count and total length
627 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
628 visibleGroups.toArray(new String[visibleGroups.size()]));
629 for (String type : types)
631 displayableTypes.add(type);
632 float[] avWidth = typeWidth.get(type);
635 avWidth = new float[2];
636 typeWidth.put(type, avWidth);
638 // todo this could include features with a non-visible group
639 // - do we greatly care?
640 // todo should we include non-displayable features here, and only
641 // update when features are added?
642 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
643 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
647 Object[][] data = new Object[displayableTypes.size()][COLUMN_COUNT];
650 if (fr.hasRenderOrder())
654 fr.findAllFeatures(groupChanged != null); // prod to update
655 // colourschemes. but don't
657 // First add the checks in the previous render order,
658 // in case the window has been closed and reopened
660 List<String> frl = fr.getRenderOrder();
661 for (int ro = frl.size() - 1; ro > -1; ro--)
663 String type = frl.get(ro);
665 if (!displayableTypes.contains(type))
670 data[dataIndex][TYPE_COLUMN] = type;
671 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
672 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
673 data[dataIndex][FILTER_COLUMN] = featureFilter == null
674 ? new FeatureMatcherSet()
676 data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(
677 af.getViewport().getFeaturesDisplayed().isVisible(type));
679 displayableTypes.remove(type);
684 * process any extra features belonging only to
685 * a group which was just selected
687 while (!displayableTypes.isEmpty())
689 String type = displayableTypes.iterator().next();
690 data[dataIndex][TYPE_COLUMN] = type;
692 data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
693 if (data[dataIndex][COLOUR_COLUMN] == null)
695 // "Colour has been updated in another view!!"
696 fr.clearRenderOrder();
699 FeatureMatcherSetI featureFilter = fr.getFeatureFilter(type);
700 data[dataIndex][FILTER_COLUMN] = featureFilter == null
701 ? new FeatureMatcherSet()
703 data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(true);
705 displayableTypes.remove(type);
708 if (originalData == null)
710 originalData = new Object[data.length][COLUMN_COUNT];
711 for (int i = 0; i < data.length; i++)
713 System.arraycopy(data[i], 0, originalData[i], 0, COLUMN_COUNT);
718 updateOriginalData(data);
721 table.setModel(new FeatureTableModel(data));
722 table.getColumnModel().getColumn(0).setPreferredWidth(200);
724 groupPanel.setLayout(
725 new GridLayout(fr.getFeatureGroupsSize() / 4 + 1, 4));
726 pruneGroups(foundGroups);
727 groupPanel.validate();
729 updateFeatureRenderer(data, groupChanged != null);
730 resettingTable = false;
734 * Updates 'originalData' (used for restore on Cancel) if we detect that changes
735 * have been made outwith this dialog
737 * <li>a new feature type added (and made visible)</li>
738 * <li>a feature colour changed (in the Amend Features dialog)</li>
743 protected void updateOriginalData(Object[][] foundData)
745 // todo LinkedHashMap instead of Object[][] would be nice
747 Object[][] currentData = ((FeatureTableModel) table.getModel())
749 for (Object[] row : foundData)
751 String type = (String) row[TYPE_COLUMN];
752 boolean found = false;
753 for (Object[] current : currentData)
755 if (type.equals(current[TYPE_COLUMN]))
759 * currently dependent on object equality here;
760 * really need an equals method on FeatureColour
762 if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
765 * feature colour has changed externally - update originalData
767 for (Object[] original : originalData)
769 if (type.equals(original[TYPE_COLUMN]))
771 original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
782 * new feature detected - add to original data (on top)
784 Object[][] newData = new Object[originalData.length
786 for (int i = 0; i < originalData.length; i++)
788 System.arraycopy(originalData[i], 0, newData[i + 1], 0,
792 originalData = newData;
798 * Remove from the groups panel any checkboxes for groups that are not in the
799 * foundGroups set. This enables removing a group from the display when the last
800 * feature in that group is deleted.
804 protected void pruneGroups(Set<String> foundGroups)
806 for (int g = 0; g < groupPanel.getComponentCount(); g++)
808 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
809 if (!foundGroups.contains(checkbox.getText()))
811 groupPanel.remove(checkbox);
817 * reorder data based on the featureRenderers global priority list.
821 private void ensureOrder(Object[][] data)
823 boolean sort = false;
824 float[] order = new float[data.length];
825 for (int i = 0; i < order.length; i++)
827 order[i] = fr.getOrder(data[i][0].toString());
830 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
834 sort = sort || order[i - 1] > order[i];
839 jalview.util.QuickSort.sort(order, data);
844 * Offers a file chooser dialog, and then loads the feature colours and
845 * filters from file in XML format and unmarshals to Jalview feature settings
849 JalviewFileChooser chooser = new JalviewFileChooser("fc",
850 SEQUENCE_FEATURE_COLOURS);
851 chooser.setFileView(new JalviewFileView());
852 chooser.setDialogTitle(
853 MessageManager.getString("label.load_feature_colours"));
854 chooser.setToolTipText(MessageManager.getString("action.load"));
856 int value = chooser.showOpenDialog(this);
858 if (value == JalviewFileChooser.APPROVE_OPTION)
860 File file = chooser.getSelectedFile();
866 * Loads feature colours and filters from XML stored in the given file
874 InputStreamReader in = new InputStreamReader(
875 new FileInputStream(file), "UTF-8");
877 JAXBContext jc = JAXBContext
878 .newInstance("jalview.xml.binding.jalview");
879 javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
880 XMLStreamReader streamReader = XMLInputFactory.newInstance()
881 .createXMLStreamReader(in);
882 JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
883 JalviewUserColours.class);
884 JalviewUserColours jucs = jbe.getValue();
886 // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
889 * load feature colours
891 for (int i = jucs.getColour().size() - 1; i >= 0; i--)
893 Colour newcol = jucs.getColour().get(i);
894 FeatureColourI colour = jalview.project.Jalview2XML
895 .parseColour(newcol);
896 fr.setColour(newcol.getName(), colour);
897 fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
901 * load feature filters; loaded filters will replace any that are
902 * currently defined, other defined filters are left unchanged
904 for (int i = 0; i < jucs.getFilter().size(); i++)
906 Filter filterModel = jucs.getFilter().get(i);
907 String featureType = filterModel.getFeatureType();
908 FeatureMatcherSetI filter = jalview.project.Jalview2XML
909 .parseFilter(featureType, filterModel.getMatcherSet());
910 if (!filter.isEmpty())
912 fr.setFeatureFilter(featureType, filter);
917 * update feature settings table
922 Object[][] data = ((FeatureTableModel) table.getModel())
925 updateFeatureRenderer(data, false);
928 } catch (Exception ex)
930 System.out.println("Error loading User Colour File\n" + ex);
935 * Offers a file chooser dialog, and then saves the current feature colours
936 * and any filters to the selected file in XML format
940 JalviewFileChooser chooser = new JalviewFileChooser("fc",
941 SEQUENCE_FEATURE_COLOURS);
942 chooser.setFileView(new JalviewFileView());
943 chooser.setDialogTitle(
944 MessageManager.getString("label.save_feature_colours"));
945 chooser.setToolTipText(MessageManager.getString("action.save"));
947 int value = chooser.showSaveDialog(this);
949 if (value == JalviewFileChooser.APPROVE_OPTION)
951 save(chooser.getSelectedFile());
956 * Saves feature colours and filters to the given file
962 JalviewUserColours ucs = new JalviewUserColours();
963 ucs.setSchemeName("Sequence Features");
966 PrintWriter out = new PrintWriter(new OutputStreamWriter(
967 new FileOutputStream(file), "UTF-8"));
970 * sort feature types by colour order, from 0 (highest)
973 Set<String> fr_colours = fr.getAllFeatureColours();
974 String[] sortedTypes = fr_colours
975 .toArray(new String[fr_colours.size()]);
976 Arrays.sort(sortedTypes, new Comparator<String>()
979 public int compare(String type1, String type2)
981 return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
986 * save feature colours
988 for (String featureType : sortedTypes)
990 FeatureColourI fcol = fr.getFeatureStyle(featureType);
991 Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
993 ucs.getColour().add(col);
997 * save any feature filters
999 for (String featureType : sortedTypes)
1001 FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
1002 if (filter != null && !filter.isEmpty())
1004 Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
1005 FeatureMatcherI firstMatcher = iterator.next();
1006 jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
1007 .marshalFilter(firstMatcher, iterator,
1009 Filter filterModel = new Filter();
1010 filterModel.setFeatureType(featureType);
1011 filterModel.setMatcherSet(ms);
1012 ucs.getFilter().add(filterModel);
1015 JAXBContext jaxbContext = JAXBContext
1016 .newInstance(JalviewUserColours.class);
1017 Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
1018 jaxbMarshaller.marshal(
1019 new ObjectFactory().createJalviewUserColours(ucs), out);
1021 // jaxbMarshaller.marshal(object, pout);
1022 // marshaller.marshal(object);
1025 // ucs.marshal(out);
1027 } catch (Exception ex)
1029 ex.printStackTrace();
1033 public void invertSelection()
1035 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1036 for (int i = 0; i < data.length; i++)
1038 data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
1040 updateFeatureRenderer(data, true);
1044 public void orderByAvWidth()
1046 if (table == null || table.getModel() == null)
1050 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
1051 float[] width = new float[data.length];
1055 for (int i = 0; i < data.length; i++)
1057 awidth = typeWidth.get(data[i][TYPE_COLUMN]);
1060 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
1061 // weight - but have to make per
1062 // sequence, too (awidth[2])
1063 // if (width[i]==1) // hack to distinguish single width sequences.
1074 boolean sort = false;
1075 for (int i = 0; i < width.length; i++)
1077 // awidth = (float[]) typeWidth.get(data[i][0]);
1080 width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
1083 width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
1089 width[i] /= max; // normalize
1090 fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
1094 sort = sort || width[i - 1] > width[i];
1099 jalview.util.QuickSort.sort(width, data);
1100 // update global priority order
1103 updateFeatureRenderer(data, false);
1113 frame.setClosed(true);
1117 SplitContainerI sc = af.getSplitViewContainer();
1118 sc.closeFeatureSettings(this);
1119 af.featureSettings = null;
1121 } catch (Exception exe)
1127 public void updateFeatureRenderer(Object[][] data)
1129 updateFeatureRenderer(data, true);
1133 * Update the priority order of features; only repaint if this changed the order
1134 * of visible features
1139 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1141 FeatureSettingsBean[] rowData = getTableAsBeans(data);
1143 if (fr.setFeaturePriority(rowData, visibleNew))
1150 * Converts table data into an array of data beans
1152 private FeatureSettingsBean[] getTableAsBeans(Object[][] data)
1154 FeatureSettingsBean[] rowData = new FeatureSettingsBean[data.length];
1155 for (int i = 0; i < data.length; i++)
1157 String type = (String) data[i][TYPE_COLUMN];
1158 FeatureColourI colour = (FeatureColourI) data[i][COLOUR_COLUMN];
1159 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) data[i][FILTER_COLUMN];
1160 Boolean isShown = (Boolean) data[i][SHOW_COLUMN];
1161 rowData[i] = new FeatureSettingsBean(type, colour, theFilter,
1167 private void jbInit() throws Exception
1169 this.setLayout(new BorderLayout());
1171 JPanel settingsPane = new JPanel();
1172 settingsPane.setLayout(new BorderLayout());
1174 JPanel bigPanel = new JPanel();
1175 bigPanel.setLayout(new BorderLayout());
1177 groupPanel = new JPanel();
1178 bigPanel.add(groupPanel, BorderLayout.NORTH);
1180 JButton invert = new JButton(
1181 MessageManager.getString("label.invert_selection"));
1182 invert.setFont(JvSwingUtils.getLabelFont());
1183 invert.addActionListener(new ActionListener()
1186 public void actionPerformed(ActionEvent e)
1192 JButton optimizeOrder = new JButton(
1193 MessageManager.getString("label.optimise_order"));
1194 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1195 optimizeOrder.addActionListener(new ActionListener()
1198 public void actionPerformed(ActionEvent e)
1204 JButton sortByScore = new JButton(
1205 MessageManager.getString("label.seq_sort_by_score"));
1206 sortByScore.setFont(JvSwingUtils.getLabelFont());
1207 sortByScore.addActionListener(new ActionListener()
1210 public void actionPerformed(ActionEvent e)
1212 af.avc.sortAlignmentByFeatureScore(null);
1215 JButton sortByDens = new JButton(
1216 MessageManager.getString("label.sequence_sort_by_density"));
1217 sortByDens.setFont(JvSwingUtils.getLabelFont());
1218 sortByDens.addActionListener(new ActionListener()
1221 public void actionPerformed(ActionEvent e)
1223 af.avc.sortAlignmentByFeatureDensity(null);
1227 JButton help = new JButton(MessageManager.getString("action.help"));
1228 help.setFont(JvSwingUtils.getLabelFont());
1229 help.addActionListener(new ActionListener()
1232 public void actionPerformed(ActionEvent e)
1236 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1237 } catch (HelpSetException e1)
1239 e1.printStackTrace();
1244 JButton cancel = new JButton(MessageManager.getString("action.cancel"));
1245 cancel.setFont(JvSwingUtils.getLabelFont());
1246 cancel.addActionListener(new ActionListener()
1249 public void actionPerformed(ActionEvent e)
1251 fr.setTransparency(originalTransparency);
1252 fr.setFeatureFilters(originalFilters);
1253 updateFeatureRenderer(originalData);
1254 af.getViewport().setViewStyle(originalViewStyle);
1259 JButton ok = new JButton(MessageManager.getString("action.ok"));
1260 ok.setFont(JvSwingUtils.getLabelFont());
1261 ok.addActionListener(new ActionListener()
1264 public void actionPerformed(ActionEvent e)
1270 JButton loadColours = new JButton(
1271 MessageManager.getString("label.load_colours"));
1272 loadColours.setFont(JvSwingUtils.getLabelFont());
1273 loadColours.setToolTipText(
1274 MessageManager.getString("label.load_colours_tooltip"));
1275 loadColours.addActionListener(new ActionListener()
1278 public void actionPerformed(ActionEvent e)
1284 JButton saveColours = new JButton(
1285 MessageManager.getString("label.save_colours"));
1286 saveColours.setFont(JvSwingUtils.getLabelFont());
1287 saveColours.setToolTipText(
1288 MessageManager.getString("label.save_colours_tooltip"));
1289 saveColours.addActionListener(new ActionListener()
1292 public void actionPerformed(ActionEvent e)
1297 transparency.addChangeListener(new ChangeListener()
1300 public void stateChanged(ChangeEvent evt)
1302 if (!inConstruction)
1304 fr.setTransparency((100 - transparency.getValue()) / 100f);
1310 transparency.setMaximum(70);
1311 transparency.setToolTipText(
1312 MessageManager.getString("label.transparency_tip"));
1314 boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
1315 String text = MessageManager.formatMessage("label.show_linked_features",
1317 ? MessageManager.getString("label.protein")
1320 JCheckBox showComplement = new JCheckBox(text);
1321 showComplement.setSelected(af.getViewport().isShowComplementFeatures());
1322 showComplement.addActionListener(new ActionListener()
1325 public void actionPerformed(ActionEvent e)
1328 .setShowComplementFeatures(showComplement.isSelected());
1333 JCheckBox showComplementOnTop = new JCheckBox(
1334 MessageManager.getString("label.on_top"));
1336 .setSelected(af.getViewport().isShowComplementFeaturesOnTop());
1337 showComplementOnTop.addActionListener(new ActionListener()
1340 public void actionPerformed(ActionEvent e)
1342 af.getViewport().setShowComplementFeaturesOnTop(
1343 showComplementOnTop.isSelected());
1347 // JButton viewComplementSettings = new JButton(MessageManager
1348 // .formatMessage("label.show_linked_feature_settings",
1350 // ? MessageManager.getString("label.protein")
1353 // viewComplementSettings.addActionListener(new ActionListener()
1357 // public void actionPerformed(ActionEvent e)
1359 // AlignViewControllerGuiI complAf = af.getSplitViewContainer()
1360 // .getComplementAlignFrame(af);
1361 // FeatureSettings complFeatureSettings = (FeatureSettings) complAf
1362 // .getFeatureSettingsUI();
1363 // if (complFeatureSettings != null)
1365 // complFeatureSettings.frame.setVisible(true);
1368 // complFeatureSettings.frame.setSelected(true);
1370 // } catch (Exception q)
1375 // complAf.showFeatureSettingsUI();
1379 JPanel lowerPanel = new JPanel(new GridLayout(1, 2));
1380 bigPanel.add(lowerPanel, BorderLayout.SOUTH);
1382 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1383 transbuttons.add(optimizeOrder);
1384 transbuttons.add(invert);
1385 transbuttons.add(sortByScore);
1386 transbuttons.add(sortByDens);
1387 transbuttons.add(help);
1389 boolean hasComplement = af.getViewport().getCodingComplement() != null;
1390 JPanel transPanelLeft = new JPanel(
1391 new GridLayout(hasComplement ? 4 : 2, 1));
1392 transPanelLeft.add(new JLabel(" Colour transparency" + ":"));
1393 transPanelLeft.add(transparency);
1396 JPanel cp = new JPanel(new FlowLayout(FlowLayout.LEFT));
1397 cp.add(showComplement);
1398 cp.add(showComplementOnTop);
1399 transPanelLeft.add(cp);
1401 lowerPanel.add(transPanelLeft);
1402 lowerPanel.add(transbuttons);
1404 JPanel buttonPanel = new JPanel();
1405 buttonPanel.add(ok);
1406 buttonPanel.add(cancel);
1407 buttonPanel.add(loadColours);
1408 buttonPanel.add(saveColours);
1409 bigPanel.add(scrollPane, BorderLayout.CENTER);
1410 settingsPane.add(bigPanel, BorderLayout.CENTER);
1411 settingsPane.add(buttonPanel, BorderLayout.SOUTH);
1412 this.add(settingsPane);
1416 * Repaints alignment, structure and overview (if shown). If there is a
1417 * complementary view which is showing this view's features, then also
1420 void refreshDisplay()
1422 af.alignPanel.paintAlignment(true, true);
1423 AlignViewportI complement = af.getViewport().getCodingComplement();
1424 if (complement != null && complement.isShowComplementFeatures())
1426 AlignFrame af2 = Desktop.getAlignFrameFor(complement);
1427 af2.alignPanel.paintAlignment(true, true);
1432 * Answers a suitable tooltip to show on the colour cell of the table
1436 * if true include 'click to edit' and similar text
1439 public static String getColorTooltip(FeatureColourI fcol,
1446 if (fcol.isSimpleColour())
1448 return withHint ? BASE_TOOLTIP : null;
1450 String description = fcol.getDescription();
1451 description = description.replaceAll("<", "<");
1452 description = description.replaceAll(">", ">");
1453 StringBuilder tt = new StringBuilder(description);
1456 tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
1458 return JvSwingUtils.wrapTooltip(true, tt.toString());
1461 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1464 boolean thr = false;
1465 StringBuilder tx = new StringBuilder();
1467 if (gcol.isColourByAttribute())
1469 tx.append(FeatureMatcher
1470 .toAttributeDisplayName(gcol.getAttributeName()));
1472 else if (!gcol.isColourByLabel())
1474 tx.append(MessageManager.getString("label.score"));
1477 if (gcol.isAboveThreshold())
1482 if (gcol.isBelowThreshold())
1487 if (gcol.isColourByLabel())
1493 if (!gcol.isColourByAttribute())
1501 Color newColor = gcol.getMaxColour();
1502 comp.setBackground(newColor);
1503 // System.err.println("Width is " + w / 2);
1504 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1505 comp.setIcon(ficon);
1506 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1507 // + newColor.getGreen() + ", " + newColor.getBlue()
1508 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1509 // + ", " + minCol.getBlue() + ")");
1511 comp.setHorizontalAlignment(SwingConstants.CENTER);
1512 comp.setText(tx.toString());
1515 // ///////////////////////////////////////////////////////////////////////
1516 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1517 // ///////////////////////////////////////////////////////////////////////
1518 class FeatureTableModel extends AbstractTableModel
1520 private String[] columnNames = {
1521 MessageManager.getString("label.feature_type"),
1522 MessageManager.getString("action.colour"),
1523 MessageManager.getString("label.configuration"),
1524 MessageManager.getString("label.show") };
1526 private Object[][] data;
1528 FeatureTableModel(Object[][] data)
1533 public Object[][] getData()
1538 public void setData(Object[][] data)
1544 public int getColumnCount()
1546 return columnNames.length;
1549 public Object[] getRow(int row)
1555 public int getRowCount()
1561 public String getColumnName(int col)
1563 return columnNames[col];
1567 public Object getValueAt(int row, int col)
1569 return data[row][col];
1573 * Answers the class of column c of the table
1576 public Class<?> getColumnClass(int c)
1581 return String.class;
1583 return FeatureColour.class;
1585 return FeatureMatcherSet.class;
1587 return Boolean.class;
1592 public boolean isCellEditable(int row, int col)
1594 return col == 0 ? false : true;
1598 public void setValueAt(Object value, int row, int col)
1600 data[row][col] = value;
1601 fireTableCellUpdated(row, col);
1602 updateFeatureRenderer(data);
1607 class ColorRenderer extends JLabel implements TableCellRenderer
1609 Border unselectedBorder = null;
1611 Border selectedBorder = null;
1613 public ColorRenderer()
1615 setOpaque(true); // MUST do this for background to show up.
1616 setHorizontalTextPosition(SwingConstants.CENTER);
1617 setVerticalTextPosition(SwingConstants.CENTER);
1621 public Component getTableCellRendererComponent(JTable tbl, Object color,
1622 boolean isSelected, boolean hasFocus, int row, int column)
1624 FeatureColourI cellColour = (FeatureColourI) color;
1626 setBackground(tbl.getBackground());
1627 if (!cellColour.isSimpleColour())
1629 Rectangle cr = tbl.getCellRect(row, column, false);
1630 FeatureSettings.renderGraduatedColor(this, cellColour,
1631 (int) cr.getWidth(), (int) cr.getHeight());
1637 setBackground(cellColour.getColour());
1641 if (selectedBorder == null)
1643 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1644 tbl.getSelectionBackground());
1646 setBorder(selectedBorder);
1650 if (unselectedBorder == null)
1652 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1653 tbl.getBackground());
1655 setBorder(unselectedBorder);
1662 class FilterRenderer extends JLabel implements TableCellRenderer
1664 javax.swing.border.Border unselectedBorder = null;
1666 javax.swing.border.Border selectedBorder = null;
1668 public FilterRenderer()
1670 setOpaque(true); // MUST do this for background to show up.
1671 setHorizontalTextPosition(SwingConstants.CENTER);
1672 setVerticalTextPosition(SwingConstants.CENTER);
1676 public Component getTableCellRendererComponent(JTable tbl,
1677 Object filter, boolean isSelected, boolean hasFocus, int row,
1680 FeatureMatcherSetI theFilter = (FeatureMatcherSetI) filter;
1682 String asText = theFilter.toString();
1683 setBackground(tbl.getBackground());
1684 this.setText(asText);
1689 if (selectedBorder == null)
1691 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1692 tbl.getSelectionBackground());
1694 setBorder(selectedBorder);
1698 if (unselectedBorder == null)
1700 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1701 tbl.getBackground());
1703 setBorder(unselectedBorder);
1711 * update comp using rendering settings from gcol
1716 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1718 int w = comp.getWidth(), h = comp.getHeight();
1721 w = (int) comp.getPreferredSize().getWidth();
1722 h = (int) comp.getPreferredSize().getHeight();
1729 renderGraduatedColor(comp, gcol, w, h);
1732 class ColorEditor extends AbstractCellEditor
1733 implements TableCellEditor, ActionListener
1737 FeatureColourI currentColor;
1739 FeatureTypeSettings chooser;
1745 JColorChooser colorChooser;
1749 protected static final String EDIT = "edit";
1751 int rowSelected = 0;
1753 public ColorEditor(FeatureSettings me)
1756 // Set up the editor (from the table's point of view),
1757 // which is a button.
1758 // This button brings up the color chooser dialog,
1759 // which is the editor from the user's point of view.
1760 button = new JButton();
1761 button.setActionCommand(EDIT);
1762 button.addActionListener(this);
1763 button.setBorderPainted(false);
1764 // Set up the dialog that the button brings up.
1765 colorChooser = new JColorChooser();
1766 dialog = JColorChooser.createDialog(button,
1767 MessageManager.getString("label.select_colour"), true, // modal
1768 colorChooser, this, // OK button handler
1769 null); // no CANCEL button handler
1773 * Handles events from the editor button and from the dialog's OK button.
1776 public void actionPerformed(ActionEvent e)
1778 // todo test e.getSource() instead here
1779 if (EDIT.equals(e.getActionCommand()))
1781 // The user has clicked the cell, so
1782 // bring up the dialog.
1783 if (currentColor.isSimpleColour())
1785 // bring up simple color chooser
1786 button.setBackground(currentColor.getColour());
1787 colorChooser.setColor(currentColor.getColour());
1788 dialog.setVisible(true);
1792 // bring up graduated chooser.
1793 chooser = new FeatureTypeSettings(me.fr, type);
1798 chooser.setRequestFocusEnabled(true);
1799 chooser.requestFocus();
1801 chooser.addActionListener(this);
1802 // Make the renderer reappear.
1803 fireEditingStopped();
1808 if (currentColor.isSimpleColour())
1811 * read off colour picked in colour chooser after OK pressed
1813 currentColor = new FeatureColour(colorChooser.getColor());
1814 me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
1819 * after OK in variable colour dialog, any changes to colour
1820 * (or filters!) are already set in FeatureRenderer, so just
1821 * update table data without triggering updateFeatureRenderer
1823 currentColor = fr.getFeatureColours().get(type);
1824 FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
1825 if (currentFilter == null)
1827 currentFilter = new FeatureMatcherSet();
1829 Object[] data = ((FeatureTableModel) table.getModel())
1830 .getData()[rowSelected];
1831 data[COLOUR_COLUMN] = currentColor;
1832 data[FILTER_COLUMN] = currentFilter;
1834 fireEditingStopped();
1835 me.table.validate();
1839 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1841 public Object getCellEditorValue()
1843 return currentColor;
1846 // Implement the one method defined by TableCellEditor.
1848 public Component getTableCellEditorComponent(JTable theTable, Object value,
1849 boolean isSelected, int row, int column)
1851 currentColor = (FeatureColourI) value;
1852 this.rowSelected = row;
1853 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1854 button.setOpaque(true);
1855 button.setBackground(me.getBackground());
1856 if (!currentColor.isSimpleColour())
1858 JLabel btn = new JLabel();
1859 btn.setSize(button.getSize());
1860 FeatureSettings.renderGraduatedColor(btn, currentColor);
1861 button.setBackground(btn.getBackground());
1862 button.setIcon(btn.getIcon());
1863 button.setText(btn.getText());
1868 button.setIcon(null);
1869 button.setBackground(currentColor.getColour());
1876 * The cell editor for the Filter column. It displays the text of any filters
1877 * for the feature type in that row (in full as a tooltip, possible abbreviated
1878 * as display text). On click in the cell, opens the Feature Display Settings
1879 * dialog at the Filters tab.
1881 class FilterEditor extends AbstractCellEditor
1882 implements TableCellEditor, ActionListener
1886 FeatureMatcherSetI currentFilter;
1894 protected static final String EDIT = "edit";
1896 int rowSelected = 0;
1898 public FilterEditor(FeatureSettings me)
1901 button = new JButton();
1902 button.setActionCommand(EDIT);
1903 button.addActionListener(this);
1904 button.setBorderPainted(false);
1908 * Handles events from the editor button
1911 public void actionPerformed(ActionEvent e)
1913 if (button == e.getSource())
1915 FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
1916 chooser.addActionListener(this);
1917 chooser.setRequestFocusEnabled(true);
1918 chooser.requestFocus();
1919 if (lastLocation != null)
1921 // todo open at its last position on screen
1922 chooser.setBounds(lastLocation.x, lastLocation.y,
1923 chooser.getWidth(), chooser.getHeight());
1926 fireEditingStopped();
1928 else if (e.getSource() instanceof Component)
1932 * after OK in variable colour dialog, any changes to filter
1933 * (or colours!) are already set in FeatureRenderer, so just
1934 * update table data without triggering updateFeatureRenderer
1936 FeatureColourI currentColor = fr.getFeatureColours().get(type);
1937 currentFilter = me.fr.getFeatureFilter(type);
1938 if (currentFilter == null)
1940 currentFilter = new FeatureMatcherSet();
1942 Object[] data = ((FeatureTableModel) table.getModel())
1943 .getData()[rowSelected];
1944 data[COLOUR_COLUMN] = currentColor;
1945 data[FILTER_COLUMN] = currentFilter;
1946 fireEditingStopped();
1947 me.table.validate();
1952 public Object getCellEditorValue()
1954 return currentFilter;
1958 public Component getTableCellEditorComponent(JTable theTable, Object value,
1959 boolean isSelected, int row, int column)
1961 currentFilter = (FeatureMatcherSetI) value;
1962 this.rowSelected = row;
1963 type = me.table.getValueAt(row, TYPE_COLUMN).toString();
1964 button.setOpaque(true);
1965 button.setBackground(me.getBackground());
1966 button.setText(currentFilter.toString());
1967 button.setIcon(null);
1973 class FeatureIcon implements Icon
1975 FeatureColourI gcol;
1979 boolean midspace = false;
1981 int width = 50, height = 20;
1983 int s1, e1; // start and end of midpoint band for thresholded symbol
1985 Color mpcolour = Color.white;
1987 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
2007 public int getIconWidth()
2013 public int getIconHeight()
2019 public void paintIcon(Component c, Graphics g, int x, int y)
2022 if (gcol.isColourByLabel())
2025 g.fillRect(0, 0, width, height);
2026 // need an icon here.
2027 g.setColor(gcol.getMaxColour());
2029 g.setFont(new Font("Verdana", Font.PLAIN, 9));
2031 // g.setFont(g.getFont().deriveFont(
2032 // AffineTransform.getScaleInstance(
2033 // width/g.getFontMetrics().stringWidth("Label"),
2034 // height/g.getFontMetrics().getHeight())));
2036 g.drawString(MessageManager.getString("label.label"), 0, 0);
2041 Color minCol = gcol.getMinColour();
2043 g.fillRect(0, 0, s1, height);
2046 g.setColor(Color.white);
2047 g.fillRect(s1, 0, e1 - s1, height);
2049 g.setColor(gcol.getMaxColour());
2050 g.fillRect(0, e1, width - e1, height);