2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.FeatureColourI;
24 import jalview.api.FeatureSettingsControllerI;
25 import jalview.bin.Cache;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.SequenceI;
28 import jalview.gui.Help.HelpId;
29 import jalview.io.JalviewFileChooser;
30 import jalview.io.JalviewFileView;
31 import jalview.schemabinding.version2.JalviewUserColours;
32 import jalview.schemes.FeatureColour;
33 import jalview.util.Format;
34 import jalview.util.MessageManager;
35 import jalview.util.Platform;
36 import jalview.util.QuickSort;
37 import jalview.viewmodel.AlignmentViewport;
38 import jalview.ws.dbsources.das.api.jalviewSourceI;
40 import java.awt.BorderLayout;
41 import java.awt.Color;
42 import java.awt.Component;
44 import java.awt.Graphics;
45 import java.awt.GridLayout;
46 import java.awt.Rectangle;
47 import java.awt.event.ActionEvent;
48 import java.awt.event.ActionListener;
49 import java.awt.event.ItemEvent;
50 import java.awt.event.ItemListener;
51 import java.awt.event.MouseAdapter;
52 import java.awt.event.MouseEvent;
53 import java.awt.event.MouseMotionAdapter;
54 import java.beans.PropertyChangeEvent;
55 import java.beans.PropertyChangeListener;
57 import java.io.FileInputStream;
58 import java.io.FileOutputStream;
59 import java.io.InputStreamReader;
60 import java.io.OutputStreamWriter;
61 import java.io.PrintWriter;
62 import java.util.Arrays;
63 import java.util.HashSet;
64 import java.util.Hashtable;
65 import java.util.Iterator;
66 import java.util.List;
69 import java.util.Vector;
71 import javax.help.HelpSetException;
72 import javax.swing.AbstractCellEditor;
73 import javax.swing.BorderFactory;
74 import javax.swing.Icon;
75 import javax.swing.JButton;
76 import javax.swing.JCheckBox;
77 import javax.swing.JCheckBoxMenuItem;
78 import javax.swing.JColorChooser;
79 import javax.swing.JDialog;
80 import javax.swing.JInternalFrame;
81 import javax.swing.JLabel;
82 import javax.swing.JLayeredPane;
83 import javax.swing.JMenuItem;
84 import javax.swing.JPanel;
85 import javax.swing.JPopupMenu;
86 import javax.swing.JScrollPane;
87 import javax.swing.JSlider;
88 import javax.swing.JTabbedPane;
89 import javax.swing.JTable;
90 import javax.swing.ListSelectionModel;
91 import javax.swing.SwingConstants;
92 import javax.swing.SwingUtilities;
93 import javax.swing.event.ChangeEvent;
94 import javax.swing.event.ChangeListener;
95 import javax.swing.table.AbstractTableModel;
96 import javax.swing.table.TableCellEditor;
97 import javax.swing.table.TableCellRenderer;
99 public class FeatureSettings extends JPanel implements
100 FeatureSettingsControllerI
102 DasSourceBrowser dassourceBrowser;
104 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
106 JPanel settingsPane = new JPanel();
108 JPanel dasSettingsPane = new JPanel();
110 final FeatureRenderer fr;
112 public final AlignFrame af;
114 Object[][] originalData;
116 private float originalTransparency;
118 final JInternalFrame frame;
120 JScrollPane scrollPane = new JScrollPane();
126 JSlider transparency = new JSlider();
128 JPanel transPanel = new JPanel(new GridLayout(1, 2));
130 public FeatureSettings(AlignFrame af)
133 fr = af.getFeatureRenderer();
134 // allow transparency to be recovered
135 transparency.setMaximum(100 - (int) ((originalTransparency = fr
136 .getTransparency()) * 100));
141 } catch (Exception ex)
143 ex.printStackTrace();
149 public String getToolTipText(MouseEvent e)
151 if (table.columnAtPoint(e.getPoint()) == 0)
154 * Tooltip for feature name only
156 return JvSwingUtils.wrapTooltip(true, MessageManager
157 .getString("label.feature_settings_click_drag"));
162 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
163 table.setFont(new Font("Verdana", Font.PLAIN, 12));
164 table.setDefaultRenderer(Color.class, new ColorRenderer());
166 table.setDefaultEditor(Color.class, new ColorEditor(this));
168 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
169 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
170 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
172 table.addMouseListener(new MouseAdapter()
175 public void mousePressed(MouseEvent evt)
177 selectedRow = table.rowAtPoint(evt.getPoint());
178 if (evt.isPopupTrigger())
180 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
181 table.getValueAt(selectedRow, 1), fr.getMinMax(),
182 evt.getX(), evt.getY());
184 else if (evt.getClickCount() == 2)
186 boolean invertSelection = evt.isAltDown();
187 boolean toggleSelection = Platform.isControlDown(evt);
188 boolean extendSelection = evt.isShiftDown();
189 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
190 invertSelection, extendSelection, toggleSelection,
191 (String) table.getValueAt(selectedRow, 0));
195 // isPopupTrigger fires on mouseReleased on Windows
197 public void mouseReleased(MouseEvent evt)
199 selectedRow = table.rowAtPoint(evt.getPoint());
200 if (evt.isPopupTrigger())
202 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
203 table.getValueAt(selectedRow, 1), fr.getMinMax(),
204 evt.getX(), evt.getY());
209 table.addMouseMotionListener(new MouseMotionAdapter()
212 public void mouseDragged(MouseEvent evt)
214 int newRow = table.rowAtPoint(evt.getPoint());
215 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
218 * reposition 'selectedRow' to 'newRow' (the dragged to location)
219 * this could be more than one row away for a very fast drag action
220 * so just swap it with adjacent rows until we get it there
222 Object[][] data = ((FeatureTableModel) table.getModel())
224 int direction = newRow < selectedRow ? -1 : 1;
225 for (int i = selectedRow; i != newRow; i += direction)
227 Object[] temp = data[i];
228 data[i] = data[i + direction];
229 data[i + direction] = temp;
231 updateFeatureRenderer(data);
233 selectedRow = newRow;
237 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
238 // MessageManager.getString("label.feature_settings_click_drag")));
239 scrollPane.setViewportView(table);
241 dassourceBrowser = new DasSourceBrowser(this);
242 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
244 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
246 fr.findAllFeatures(true); // display everything!
249 discoverAllFeatureData();
250 final PropertyChangeListener change;
251 final FeatureSettings fs = this;
252 fr.addPropertyChangeListener(change = new PropertyChangeListener()
255 public void propertyChange(PropertyChangeEvent evt)
257 if (!fs.resettingTable && !fs.handlingUpdate)
259 fs.handlingUpdate = true;
260 fs.resetTable(null); // new groups may be added with new seuqence
261 // feature types only
262 fs.handlingUpdate = false;
268 frame = new JInternalFrame();
269 frame.setContentPane(this);
270 if (Platform.isAMac())
272 Desktop.addInternalFrame(frame,
273 MessageManager.getString("label.sequence_feature_settings"),
278 Desktop.addInternalFrame(frame,
279 MessageManager.getString("label.sequence_feature_settings"),
283 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
286 public void internalFrameClosed(
287 javax.swing.event.InternalFrameEvent evt)
289 fr.removePropertyChangeListener(change);
290 dassourceBrowser.fs = null;
293 frame.setLayer(JLayeredPane.PALETTE_LAYER);
296 protected void popupSort(final int selectedRow, final String type,
297 final Object typeCol, final Map<String, float[][]> minmax, int x,
300 final FeatureColourI featureColour = (FeatureColourI) typeCol;
302 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
303 "label.settings_for_param", new String[] { type }));
304 JMenuItem scr = new JMenuItem(
305 MessageManager.getString("label.sort_by_score"));
307 final FeatureSettings me = this;
308 scr.addActionListener(new ActionListener()
312 public void actionPerformed(ActionEvent e)
314 me.af.avc.sortAlignmentByFeatureScore(Arrays
315 .asList(new String[] { type }));
319 JMenuItem dens = new JMenuItem(
320 MessageManager.getString("label.sort_by_density"));
321 dens.addActionListener(new ActionListener()
325 public void actionPerformed(ActionEvent e)
327 me.af.avc.sortAlignmentByFeatureDensity(Arrays
328 .asList(new String[] { type }));
335 final float[][] typeMinMax = minmax.get(type);
337 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
338 * this is broken at the moment and isn't that useful anyway!
339 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
342 * public void actionPerformed(ActionEvent e) {
343 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
344 * null); } else { minmax.put(type, typeMinMax); } }
350 if (typeMinMax != null && typeMinMax[0] != null)
352 // if (table.getValueAt(row, column));
353 // graduated colourschemes for those where minmax exists for the
354 // positional features
355 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
357 mxcol.setSelected(!featureColour.isSimpleColour());
359 mxcol.addActionListener(new ActionListener()
361 JColorChooser colorChooser;
364 public void actionPerformed(ActionEvent e)
366 if (e.getSource() == mxcol)
368 if (featureColour.isSimpleColour())
370 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
372 fc.addActionListener(this);
376 // bring up simple color chooser
377 colorChooser = new JColorChooser();
378 JDialog dialog = JColorChooser.createDialog(me,
379 "Select new Colour", true, // modal
380 colorChooser, this, // OK button handler
381 null); // no CANCEL button handler
382 colorChooser.setColor(featureColour.getMaxColour());
383 dialog.setVisible(true);
388 if (e.getSource() instanceof FeatureColourChooser)
390 FeatureColourChooser fc = (FeatureColourChooser) e
392 table.setValueAt(fc.getLastColour(), selectedRow, 1);
397 // probably the color chooser!
399 new FeatureColour(colorChooser.getColor()),
402 me.updateFeatureRenderer(
403 ((FeatureTableModel) table.getModel()).getData(),
412 JMenuItem selCols = new JMenuItem(
413 MessageManager.getString("label.select_columns_containing"));
414 selCols.addActionListener(new ActionListener()
417 public void actionPerformed(ActionEvent arg0)
419 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
423 JMenuItem clearCols = new JMenuItem(
424 MessageManager.getString("label.select_columns_not_containing"));
425 clearCols.addActionListener(new ActionListener()
428 public void actionPerformed(ActionEvent arg0)
430 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
434 JMenuItem hideCols = new JMenuItem(
435 MessageManager.getString("label.hide_columns_containing"));
436 hideCols.addActionListener(new ActionListener()
439 public void actionPerformed(ActionEvent arg0)
441 fr.ap.alignFrame.hideFeatureColumns(type, true);
444 JMenuItem hideOtherCols = new JMenuItem(
445 MessageManager.getString("label.hide_columns_not_containing"));
446 hideOtherCols.addActionListener(new ActionListener()
449 public void actionPerformed(ActionEvent arg0)
451 fr.ap.alignFrame.hideFeatureColumns(type, false);
457 men.add(hideOtherCols);
458 men.show(table, x, y);
462 * true when Feature Settings are updating from feature renderer
464 private boolean handlingUpdate = false;
467 * holds {featureCount, totalExtent} for each feature type
469 Map<String, float[]> typeWidth = null;
472 synchronized public void discoverAllFeatureData()
474 Set<String> allGroups = new HashSet<String>();
475 AlignmentI alignment = af.getViewport().getAlignment();
477 for (int i = 0; i < alignment.getHeight(); i++)
479 SequenceI seq = alignment.getSequenceAt(i);
480 for (String group : seq.getFeatures().getFeatureGroups(true))
482 if (group != null && !allGroups.contains(group))
484 allGroups.add(group);
485 checkGroupState(group);
496 * Synchronise gui group list and check visibility of group
499 * @return true if group is visible
501 private boolean checkGroupState(String group)
503 boolean visible = fr.checkGroupVisibility(group, true);
505 if (groupPanel == null)
507 groupPanel = new JPanel();
510 boolean alreadyAdded = false;
511 for (int g = 0; g < groupPanel.getComponentCount(); g++)
513 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
516 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
526 final String grp = group;
527 final JCheckBox check = new JCheckBox(group, visible);
528 check.setFont(new Font("Serif", Font.BOLD, 12));
529 check.addItemListener(new ItemListener()
532 public void itemStateChanged(ItemEvent evt)
534 fr.setGroupVisibility(check.getText(), check.isSelected());
535 af.alignPanel.getSeqPanel().seqCanvas.repaint();
536 if (af.alignPanel.overviewPanel != null)
538 af.alignPanel.overviewPanel.updateOverviewImage();
541 resetTable(new String[] { grp });
544 groupPanel.add(check);
548 boolean resettingTable = false;
550 synchronized void resetTable(String[] groupChanged)
556 resettingTable = true;
557 typeWidth = new Hashtable<String, float[]>();
558 // TODO: change avWidth calculation to 'per-sequence' average and use long
561 Set<String> displayableTypes = new HashSet<String>();
564 * determine which feature types may be visible depending on
565 * which groups are selected, and recompute average width data
567 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
570 SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i);
573 * get the sequence's groups for positional features
574 * and keep track of which groups are visible
576 Set<String> groups = seq.getFeatures().getFeatureGroups(true);
577 Set<String> visibleGroups = new HashSet<String>();
578 for (String group : groups)
580 if (group == null || checkGroupState(group))
582 visibleGroups.add(group);
587 * get distinct feature types for visible groups
588 * record distinct visible types, and their count and total length
590 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true,
591 visibleGroups.toArray(new String[visibleGroups.size()]));
592 for (String type : types)
594 displayableTypes.add(type);
595 float[] avWidth = typeWidth.get(type);
598 avWidth = new float[2];
599 typeWidth.put(type, avWidth);
601 // todo this could include features with a non-visible group
602 // - do we greatly care?
603 // todo should we include non-displayable features here, and only
604 // update when features are added?
605 avWidth[0] += seq.getFeatures().getFeatureCount(true, type);
606 avWidth[1] += seq.getFeatures().getTotalFeatureLength(type);
610 Object[][] data = new Object[displayableTypes.size()][3];
613 if (fr.hasRenderOrder())
617 fr.findAllFeatures(groupChanged != null); // prod to update
618 // colourschemes. but don't
620 // First add the checks in the previous render order,
621 // in case the window has been closed and reopened
623 List<String> frl = fr.getRenderOrder();
624 for (int ro = frl.size() - 1; ro > -1; ro--)
626 String type = frl.get(ro);
628 if (!displayableTypes.contains(type))
633 data[dataIndex][0] = type;
634 data[dataIndex][1] = fr.getFeatureStyle(type);
635 data[dataIndex][2] = new Boolean(af.getViewport()
636 .getFeaturesDisplayed().isVisible(type));
638 displayableTypes.remove(type);
643 * process any extra features belonging only to
644 * a group which was just selected
646 while (!displayableTypes.isEmpty())
648 String type = displayableTypes.iterator().next();
649 data[dataIndex][0] = type;
651 data[dataIndex][1] = fr.getFeatureStyle(type);
652 if (data[dataIndex][1] == null)
654 // "Colour has been updated in another view!!"
655 fr.clearRenderOrder();
659 data[dataIndex][2] = new Boolean(true);
661 displayableTypes.remove(type);
664 if (originalData == null)
666 originalData = new Object[data.length][3];
667 for (int i = 0; i < data.length; i++)
669 System.arraycopy(data[i], 0, originalData[i], 0, 3);
673 table.setModel(new FeatureTableModel(data));
674 table.getColumnModel().getColumn(0).setPreferredWidth(200);
676 if (groupPanel != null)
678 groupPanel.setLayout(new GridLayout(
679 fr.getFeatureGroupsSize() / 4 + 1, 4));
681 groupPanel.validate();
682 bigPanel.add(groupPanel, BorderLayout.NORTH);
685 updateFeatureRenderer(data, groupChanged != null);
686 resettingTable = false;
690 * reorder data based on the featureRenderers global priority list.
694 private void ensureOrder(Object[][] data)
696 boolean sort = false;
697 float[] order = new float[data.length];
698 for (int i = 0; i < order.length; i++)
700 order[i] = fr.getOrder(data[i][0].toString());
703 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
707 sort = sort || order[i - 1] > order[i];
712 jalview.util.QuickSort.sort(order, data);
718 JalviewFileChooser chooser = new JalviewFileChooser("fc",
719 "Sequence Feature Colours");
720 chooser.setFileView(new JalviewFileView());
721 chooser.setDialogTitle(MessageManager
722 .getString("label.load_feature_colours"));
723 chooser.setToolTipText(MessageManager.getString("action.load"));
725 int value = chooser.showOpenDialog(this);
727 if (value == JalviewFileChooser.APPROVE_OPTION)
729 File file = chooser.getSelectedFile();
733 InputStreamReader in = new InputStreamReader(new FileInputStream(
736 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
738 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
741 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
744 Color mincol = null, maxcol = null;
747 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
748 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
750 } catch (Exception e)
752 Cache.log.warn("Couldn't parse out graduated feature color.",
755 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
756 newcol.getMin(), newcol.getMax());
757 if (newcol.hasAutoScale())
759 gcol.setAutoScaled(newcol.getAutoScale());
761 if (newcol.hasColourByLabel())
763 gcol.setColourByLabel(newcol.getColourByLabel());
765 if (newcol.hasThreshold())
767 gcol.setThreshold(newcol.getThreshold());
769 if (newcol.getThreshType().length() > 0)
771 String ttyp = newcol.getThreshType();
772 if (ttyp.equalsIgnoreCase("ABOVE"))
774 gcol.setAboveThreshold(true);
776 if (ttyp.equalsIgnoreCase("BELOW"))
778 gcol.setBelowThreshold(true);
781 fr.setColour(name = newcol.getName(), gcol);
785 Color color = new Color(
786 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
787 fr.setColour(name = jucs.getColour(i).getName(),
788 new FeatureColour(color));
790 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
795 Object[][] data = ((FeatureTableModel) table.getModel())
798 updateFeatureRenderer(data, false);
801 } catch (Exception ex)
803 System.out.println("Error loading User Colour File\n" + ex);
810 JalviewFileChooser chooser = new JalviewFileChooser("fc",
811 "Sequence Feature Colours");
812 chooser.setFileView(new JalviewFileView());
813 chooser.setDialogTitle(MessageManager
814 .getString("label.save_feature_colours"));
815 chooser.setToolTipText(MessageManager.getString("action.save"));
817 int value = chooser.showSaveDialog(this);
819 if (value == JalviewFileChooser.APPROVE_OPTION)
821 String choice = chooser.getSelectedFile().getPath();
822 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
823 ucs.setSchemeName("Sequence Features");
826 PrintWriter out = new PrintWriter(new OutputStreamWriter(
827 new FileOutputStream(choice), "UTF-8"));
829 Set<String> fr_colours = fr.getAllFeatureColours();
830 Iterator<String> e = fr_colours.iterator();
831 float[] sortOrder = new float[fr_colours.size()];
832 String[] sortTypes = new String[fr_colours.size()];
836 sortTypes[i] = e.next();
837 sortOrder[i] = fr.getOrder(sortTypes[i]);
840 QuickSort.sort(sortOrder, sortTypes);
842 for (i = 0; i < sortTypes.length; i++)
844 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
845 col.setName(sortTypes[i]);
846 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
847 if (fcol.isSimpleColour())
849 col.setRGB(Format.getHexString(fcol.getColour()));
853 col.setRGB(Format.getHexString(fcol.getMaxColour()));
854 col.setMin(fcol.getMin());
855 col.setMax(fcol.getMax());
856 col.setMinRGB(jalview.util.Format.getHexString(fcol
858 col.setAutoScale(fcol.isAutoScaled());
859 col.setThreshold(fcol.getThreshold());
860 col.setColourByLabel(fcol.isColourByLabel());
861 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
862 .isBelowThreshold() ? "BELOW" : "NONE"));
868 } catch (Exception ex)
870 ex.printStackTrace();
875 public void invertSelection()
877 for (int i = 0; i < table.getRowCount(); i++)
879 Boolean value = (Boolean) table.getValueAt(i, 2);
881 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
885 public void orderByAvWidth()
887 if (table == null || table.getModel() == null)
891 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
892 float[] width = new float[data.length];
896 for (int i = 0; i < data.length; i++)
898 awidth = typeWidth.get(data[i][0]);
901 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
902 // weight - but have to make per
903 // sequence, too (awidth[2])
904 // if (width[i]==1) // hack to distinguish single width sequences.
916 boolean sort = false;
917 for (int i = 0; i < width.length; i++)
919 // awidth = (float[]) typeWidth.get(data[i][0]);
922 width[i] = fr.getOrder(data[i][0].toString());
925 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
930 width[i] /= max; // normalize
931 fr.setOrder(data[i][0].toString(), width[i]); // store for later
935 sort = sort || width[i - 1] > width[i];
940 jalview.util.QuickSort.sort(width, data);
941 // update global priority order
944 updateFeatureRenderer(data, false);
952 frame.setClosed(true);
953 } catch (Exception exe)
959 public void updateFeatureRenderer(Object[][] data)
961 updateFeatureRenderer(data, true);
965 * Update the priority order of features; only repaint if this changed the
966 * order of visible features
971 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
973 if (fr.setFeaturePriority(data, visibleNew))
975 af.alignPanel.paintAlignment(true);
979 int selectedRow = -1;
981 JTabbedPane tabbedPane = new JTabbedPane();
983 BorderLayout borderLayout1 = new BorderLayout();
985 BorderLayout borderLayout2 = new BorderLayout();
987 BorderLayout borderLayout3 = new BorderLayout();
989 JPanel bigPanel = new JPanel();
991 BorderLayout borderLayout4 = new BorderLayout();
993 JButton invert = new JButton();
995 JPanel buttonPanel = new JPanel();
997 JButton cancel = new JButton();
999 JButton ok = new JButton();
1001 JButton loadColours = new JButton();
1003 JButton saveColours = new JButton();
1005 JPanel dasButtonPanel = new JPanel();
1007 JButton fetchDAS = new JButton();
1009 JButton saveDAS = new JButton();
1011 JButton cancelDAS = new JButton();
1013 JButton optimizeOrder = new JButton();
1015 JButton sortByScore = new JButton();
1017 JButton sortByDens = new JButton();
1019 JButton help = new JButton();
1021 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1023 private void jbInit() throws Exception
1025 this.setLayout(borderLayout1);
1026 settingsPane.setLayout(borderLayout2);
1027 dasSettingsPane.setLayout(borderLayout3);
1028 bigPanel.setLayout(borderLayout4);
1029 invert.setFont(JvSwingUtils.getLabelFont());
1030 invert.setText(MessageManager.getString("label.invert_selection"));
1031 invert.addActionListener(new ActionListener()
1034 public void actionPerformed(ActionEvent e)
1039 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1040 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1041 optimizeOrder.addActionListener(new ActionListener()
1044 public void actionPerformed(ActionEvent e)
1049 sortByScore.setFont(JvSwingUtils.getLabelFont());
1051 .setText(MessageManager.getString("label.seq_sort_by_score"));
1052 sortByScore.addActionListener(new ActionListener()
1055 public void actionPerformed(ActionEvent e)
1057 af.avc.sortAlignmentByFeatureScore(null);
1060 sortByDens.setFont(JvSwingUtils.getLabelFont());
1061 sortByDens.setText(MessageManager
1062 .getString("label.sequence_sort_by_density"));
1063 sortByDens.addActionListener(new ActionListener()
1066 public void actionPerformed(ActionEvent e)
1068 af.avc.sortAlignmentByFeatureDensity(null);
1071 help.setFont(JvSwingUtils.getLabelFont());
1072 help.setText(MessageManager.getString("action.help"));
1073 help.addActionListener(new ActionListener()
1076 public void actionPerformed(ActionEvent e)
1080 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1081 } catch (HelpSetException e1)
1083 e1.printStackTrace();
1087 help.setFont(JvSwingUtils.getLabelFont());
1088 help.setText(MessageManager.getString("action.help"));
1089 help.addActionListener(new ActionListener()
1092 public void actionPerformed(ActionEvent e)
1096 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1097 } catch (HelpSetException e1)
1099 e1.printStackTrace();
1103 cancel.setFont(JvSwingUtils.getLabelFont());
1104 cancel.setText(MessageManager.getString("action.cancel"));
1105 cancel.addActionListener(new ActionListener()
1108 public void actionPerformed(ActionEvent e)
1110 fr.setTransparency(originalTransparency);
1111 updateFeatureRenderer(originalData);
1115 ok.setFont(JvSwingUtils.getLabelFont());
1116 ok.setText(MessageManager.getString("action.ok"));
1117 ok.addActionListener(new ActionListener()
1120 public void actionPerformed(ActionEvent e)
1125 loadColours.setFont(JvSwingUtils.getLabelFont());
1126 loadColours.setText(MessageManager.getString("label.load_colours"));
1127 loadColours.addActionListener(new ActionListener()
1130 public void actionPerformed(ActionEvent e)
1135 saveColours.setFont(JvSwingUtils.getLabelFont());
1136 saveColours.setText(MessageManager.getString("label.save_colours"));
1137 saveColours.addActionListener(new ActionListener()
1140 public void actionPerformed(ActionEvent e)
1145 transparency.addChangeListener(new ChangeListener()
1148 public void stateChanged(ChangeEvent evt)
1150 fr.setTransparency((100 - transparency.getValue()) / 100f);
1151 af.alignPanel.paintAlignment(true);
1155 transparency.setMaximum(70);
1156 transparency.setToolTipText(MessageManager
1157 .getString("label.transparency_tip"));
1158 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1159 fetchDAS.addActionListener(new ActionListener()
1162 public void actionPerformed(ActionEvent e)
1164 fetchDAS_actionPerformed(e);
1167 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1168 saveDAS.addActionListener(new ActionListener()
1171 public void actionPerformed(ActionEvent e)
1173 saveDAS_actionPerformed(e);
1176 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1177 dasSettingsPane.setBorder(null);
1178 cancelDAS.setEnabled(false);
1179 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1180 cancelDAS.addActionListener(new ActionListener()
1183 public void actionPerformed(ActionEvent e)
1185 cancelDAS_actionPerformed(e);
1188 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1189 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1191 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1193 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1194 transbuttons.add(optimizeOrder);
1195 transbuttons.add(invert);
1196 transbuttons.add(sortByScore);
1197 transbuttons.add(sortByDens);
1198 transbuttons.add(help);
1199 JPanel sliderPanel = new JPanel();
1200 sliderPanel.add(transparency);
1201 transPanel.add(transparency);
1202 transPanel.add(transbuttons);
1203 buttonPanel.add(ok);
1204 buttonPanel.add(cancel);
1205 buttonPanel.add(loadColours);
1206 buttonPanel.add(saveColours);
1207 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1208 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1209 dasButtonPanel.add(fetchDAS);
1210 dasButtonPanel.add(cancelDAS);
1211 dasButtonPanel.add(saveDAS);
1212 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1213 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1216 public void fetchDAS_actionPerformed(ActionEvent e)
1218 fetchDAS.setEnabled(false);
1219 cancelDAS.setEnabled(true);
1220 dassourceBrowser.setGuiEnabled(false);
1221 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1222 .getSelectedSources();
1223 doDasFeatureFetch(selectedSources, true, true);
1227 * get the features from selectedSources for all or the current selection
1229 * @param selectedSources
1230 * @param checkDbRefs
1231 * @param promptFetchDbRefs
1233 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1234 boolean checkDbRefs, boolean promptFetchDbRefs)
1236 SequenceI[] dataset, seqs;
1238 AlignmentViewport vp = af.getViewport();
1239 if (vp.getSelectionGroup() != null
1240 && vp.getSelectionGroup().getSize() > 0)
1242 iSize = vp.getSelectionGroup().getSize();
1243 dataset = new SequenceI[iSize];
1244 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1248 iSize = vp.getAlignment().getHeight();
1249 seqs = vp.getAlignment().getSequencesArray();
1252 dataset = new SequenceI[iSize];
1253 for (int i = 0; i < iSize; i++)
1255 dataset[i] = seqs[i].getDatasetSequence();
1258 cancelDAS.setEnabled(true);
1259 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1260 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1261 af.getViewport().setShowSequenceFeatures(true);
1262 af.showSeqFeatures.setSelected(true);
1266 * blocking call to initialise the das source browser
1268 public void initDasSources()
1270 dassourceBrowser.initDasSources();
1274 * examine the current list of das sources and return any matching the given
1275 * nicknames in sources
1278 * Vector of Strings to resolve to DAS source nicknames.
1279 * @return sources that are present in source list.
1281 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1283 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1287 * get currently selected das sources. ensure you have called initDasSources
1288 * before calling this.
1290 * @return vector of selected das source nicknames
1292 public Vector<jalviewSourceI> getSelectedSources()
1294 return dassourceBrowser.getSelectedSources();
1298 * properly initialise DAS fetcher and then initiate a new thread to fetch
1299 * features from the named sources (rather than any turned on by default)
1303 * if true then runs in same thread, otherwise passes to the Swing
1306 public void fetchDasFeatures(Vector<String> sources, boolean block)
1309 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1310 .resolveSourceNicknames(sources);
1311 if (resolved.size() == 0)
1313 resolved = dassourceBrowser.getSelectedSources();
1315 if (resolved.size() > 0)
1317 final List<jalviewSourceI> dassources = resolved;
1318 fetchDAS.setEnabled(false);
1319 // cancelDAS.setEnabled(true); doDasFetch does this.
1320 Runnable fetcher = new Runnable()
1326 doDasFeatureFetch(dassources, true, false);
1336 SwingUtilities.invokeLater(fetcher);
1341 public void saveDAS_actionPerformed(ActionEvent e)
1344 .saveProperties(jalview.bin.Cache.applicationProperties);
1347 public void complete()
1349 fetchDAS.setEnabled(true);
1350 cancelDAS.setEnabled(false);
1351 dassourceBrowser.setGuiEnabled(true);
1355 public void cancelDAS_actionPerformed(ActionEvent e)
1357 if (dasFeatureFetcher != null)
1359 dasFeatureFetcher.cancel();
1364 public void noDasSourceActive()
1368 .showInternalConfirmDialog(
1371 .getString("label.no_das_sources_selected_warn"),
1373 .getString("label.no_das_sources_selected_title"),
1374 JvOptionPane.DEFAULT_OPTION,
1375 JvOptionPane.INFORMATION_MESSAGE);
1378 // ///////////////////////////////////////////////////////////////////////
1379 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1380 // ///////////////////////////////////////////////////////////////////////
1381 class FeatureTableModel extends AbstractTableModel
1383 FeatureTableModel(Object[][] data)
1388 private String[] columnNames = {
1389 MessageManager.getString("label.feature_type"),
1390 MessageManager.getString("action.colour"),
1391 MessageManager.getString("label.display") };
1393 private Object[][] data;
1395 public Object[][] getData()
1400 public void setData(Object[][] data)
1406 public int getColumnCount()
1408 return columnNames.length;
1411 public Object[] getRow(int row)
1417 public int getRowCount()
1423 public String getColumnName(int col)
1425 return columnNames[col];
1429 public Object getValueAt(int row, int col)
1431 return data[row][col];
1435 public Class getColumnClass(int c)
1437 return getValueAt(0, c).getClass();
1441 public boolean isCellEditable(int row, int col)
1443 return col == 0 ? false : true;
1447 public void setValueAt(Object value, int row, int col)
1449 data[row][col] = value;
1450 fireTableCellUpdated(row, col);
1451 updateFeatureRenderer(data);
1456 class ColorRenderer extends JLabel implements TableCellRenderer
1458 javax.swing.border.Border unselectedBorder = null;
1460 javax.swing.border.Border selectedBorder = null;
1462 final String baseTT = "Click to edit, right/apple click for menu.";
1464 public ColorRenderer()
1466 setOpaque(true); // MUST do this for background to show up.
1467 setHorizontalTextPosition(SwingConstants.CENTER);
1468 setVerticalTextPosition(SwingConstants.CENTER);
1472 public Component getTableCellRendererComponent(JTable tbl,
1473 Object color, boolean isSelected, boolean hasFocus, int row,
1476 FeatureColourI cellColour = (FeatureColourI) color;
1477 // JLabel comp = new JLabel();
1481 // setBounds(getBounds());
1483 setToolTipText(baseTT);
1484 setBackground(tbl.getBackground());
1485 if (!cellColour.isSimpleColour())
1487 Rectangle cr = tbl.getCellRect(row, column, false);
1488 FeatureSettings.renderGraduatedColor(this, cellColour,
1489 (int) cr.getWidth(), (int) cr.getHeight());
1496 newColor = cellColour.getColour();
1497 setBackground(newColor);
1501 if (selectedBorder == null)
1503 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1504 tbl.getSelectionBackground());
1506 setBorder(selectedBorder);
1510 if (unselectedBorder == null)
1512 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1513 tbl.getBackground());
1515 setBorder(unselectedBorder);
1523 * update comp using rendering settings from gcol
1528 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1530 int w = comp.getWidth(), h = comp.getHeight();
1533 w = (int) comp.getPreferredSize().getWidth();
1534 h = (int) comp.getPreferredSize().getHeight();
1541 renderGraduatedColor(comp, gcol, w, h);
1544 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1547 boolean thr = false;
1550 if (gcol.isAboveThreshold())
1554 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1556 if (gcol.isBelowThreshold())
1560 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1562 if (gcol.isColourByLabel())
1564 tt = "Coloured by label text. " + tt;
1574 Color newColor = gcol.getMaxColour();
1575 comp.setBackground(newColor);
1576 // System.err.println("Width is " + w / 2);
1577 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1578 comp.setIcon(ficon);
1579 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1580 // + newColor.getGreen() + ", " + newColor.getBlue()
1581 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1582 // + ", " + minCol.getBlue() + ")");
1584 comp.setHorizontalAlignment(SwingConstants.CENTER);
1586 if (tt.length() > 0)
1588 if (comp.getToolTipText() == null)
1590 comp.setToolTipText(tt);
1594 comp.setToolTipText(tt + " " + comp.getToolTipText());
1600 class FeatureIcon implements Icon
1602 FeatureColourI gcol;
1606 boolean midspace = false;
1608 int width = 50, height = 20;
1610 int s1, e1; // start and end of midpoint band for thresholded symbol
1612 Color mpcolour = Color.white;
1614 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1634 public int getIconWidth()
1640 public int getIconHeight()
1646 public void paintIcon(Component c, Graphics g, int x, int y)
1649 if (gcol.isColourByLabel())
1652 g.fillRect(0, 0, width, height);
1653 // need an icon here.
1654 g.setColor(gcol.getMaxColour());
1656 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1658 // g.setFont(g.getFont().deriveFont(
1659 // AffineTransform.getScaleInstance(
1660 // width/g.getFontMetrics().stringWidth("Label"),
1661 // height/g.getFontMetrics().getHeight())));
1663 g.drawString(MessageManager.getString("label.label"), 0, 0);
1668 Color minCol = gcol.getMinColour();
1670 g.fillRect(0, 0, s1, height);
1673 g.setColor(Color.white);
1674 g.fillRect(s1, 0, e1 - s1, height);
1676 g.setColor(gcol.getMaxColour());
1677 g.fillRect(0, e1, width - e1, height);
1682 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1687 FeatureColourI currentColor;
1689 FeatureColourChooser chooser;
1695 JColorChooser colorChooser;
1699 protected static final String EDIT = "edit";
1701 int selectedRow = 0;
1703 public ColorEditor(FeatureSettings me)
1706 // Set up the editor (from the table's point of view),
1707 // which is a button.
1708 // This button brings up the color chooser dialog,
1709 // which is the editor from the user's point of view.
1710 button = new JButton();
1711 button.setActionCommand(EDIT);
1712 button.addActionListener(this);
1713 button.setBorderPainted(false);
1714 // Set up the dialog that the button brings up.
1715 colorChooser = new JColorChooser();
1716 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1717 colorChooser, this, // OK button handler
1718 null); // no CANCEL button handler
1722 * Handles events from the editor button and from the dialog's OK button.
1725 public void actionPerformed(ActionEvent e)
1728 if (EDIT.equals(e.getActionCommand()))
1730 // The user has clicked the cell, so
1731 // bring up the dialog.
1732 if (currentColor.isSimpleColour())
1734 // bring up simple color chooser
1735 button.setBackground(currentColor.getColour());
1736 colorChooser.setColor(currentColor.getColour());
1737 dialog.setVisible(true);
1741 // bring up graduated chooser.
1742 chooser = new FeatureColourChooser(me.fr, type);
1743 chooser.setRequestFocusEnabled(true);
1744 chooser.requestFocus();
1745 chooser.addActionListener(this);
1747 // Make the renderer reappear.
1748 fireEditingStopped();
1752 { // User pressed dialog's "OK" button.
1753 if (currentColor.isSimpleColour())
1755 currentColor = new FeatureColour(colorChooser.getColor());
1759 currentColor = chooser.getLastColour();
1761 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1762 fireEditingStopped();
1763 me.table.validate();
1767 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1769 public Object getCellEditorValue()
1771 return currentColor;
1774 // Implement the one method defined by TableCellEditor.
1776 public Component getTableCellEditorComponent(JTable table, Object value,
1777 boolean isSelected, int row, int column)
1779 currentColor = (FeatureColourI) value;
1780 this.selectedRow = row;
1781 type = me.table.getValueAt(row, 0).toString();
1782 button.setOpaque(true);
1783 button.setBackground(me.getBackground());
1784 if (!currentColor.isSimpleColour())
1786 JLabel btn = new JLabel();
1787 btn.setSize(button.getSize());
1788 FeatureSettings.renderGraduatedColor(btn, currentColor);
1789 button.setBackground(btn.getBackground());
1790 button.setIcon(btn.getIcon());
1791 button.setText(btn.getText());
1796 button.setIcon(null);
1797 button.setBackground(currentColor.getColour());