2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 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.bin.Cache;
24 import jalview.datamodel.SequenceFeature;
25 import jalview.datamodel.SequenceI;
26 import jalview.io.JalviewFileChooser;
27 import jalview.schemes.AnnotationColourGradient;
28 import jalview.schemes.GraduatedColor;
29 import jalview.util.MessageManager;
30 import jalview.ws.dbsources.das.api.jalviewSourceI;
32 import java.awt.BorderLayout;
33 import java.awt.Color;
34 import java.awt.Component;
36 import java.awt.Graphics;
37 import java.awt.GridLayout;
38 import java.awt.Rectangle;
39 import java.awt.event.ActionEvent;
40 import java.awt.event.ActionListener;
41 import java.awt.event.ItemEvent;
42 import java.awt.event.ItemListener;
43 import java.awt.event.MouseAdapter;
44 import java.awt.event.MouseEvent;
45 import java.awt.event.MouseMotionAdapter;
46 import java.beans.PropertyChangeEvent;
47 import java.beans.PropertyChangeListener;
49 import java.io.FileInputStream;
50 import java.io.FileOutputStream;
51 import java.io.InputStreamReader;
52 import java.io.OutputStreamWriter;
53 import java.io.PrintWriter;
54 import java.util.Hashtable;
55 import java.util.Iterator;
56 import java.util.List;
58 import java.util.Vector;
60 import javax.swing.AbstractCellEditor;
61 import javax.swing.BorderFactory;
62 import javax.swing.Icon;
63 import javax.swing.JButton;
64 import javax.swing.JCheckBox;
65 import javax.swing.JCheckBoxMenuItem;
66 import javax.swing.JColorChooser;
67 import javax.swing.JDialog;
68 import javax.swing.JInternalFrame;
69 import javax.swing.JLabel;
70 import javax.swing.JLayeredPane;
71 import javax.swing.JMenuItem;
72 import javax.swing.JOptionPane;
73 import javax.swing.JPanel;
74 import javax.swing.JPopupMenu;
75 import javax.swing.JScrollPane;
76 import javax.swing.JSlider;
77 import javax.swing.JTabbedPane;
78 import javax.swing.JTable;
79 import javax.swing.ListSelectionModel;
80 import javax.swing.SwingConstants;
81 import javax.swing.SwingUtilities;
82 import javax.swing.event.ChangeEvent;
83 import javax.swing.event.ChangeListener;
84 import javax.swing.table.AbstractTableModel;
85 import javax.swing.table.TableCellEditor;
86 import javax.swing.table.TableCellRenderer;
88 public class FeatureSettings extends JPanel
90 DasSourceBrowser dassourceBrowser;
92 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
94 JPanel settingsPane = new JPanel();
96 JPanel dasSettingsPane = new JPanel();
98 final FeatureRenderer fr;
100 public final AlignFrame af;
102 Object[][] originalData;
104 private float originalTransparency;
106 final JInternalFrame frame;
108 JScrollPane scrollPane = new JScrollPane();
114 JSlider transparency = new JSlider();
116 JPanel transPanel = new JPanel(new GridLayout(1, 2));
118 public FeatureSettings(AlignFrame af)
121 fr = af.getFeatureRenderer();
122 // allow transparency to be recovered
123 transparency.setMaximum(100 - (int) ((originalTransparency=fr.getTransparency()) * 100));
128 } catch (Exception ex)
130 ex.printStackTrace();
133 table = new JTable();
134 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
135 table.setFont(new Font("Verdana", Font.PLAIN, 12));
136 table.setDefaultRenderer(Color.class, new ColorRenderer());
138 table.setDefaultEditor(Color.class, new ColorEditor(this));
140 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
141 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
142 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
144 table.addMouseListener(new MouseAdapter()
146 public void mousePressed(MouseEvent evt)
148 selectedRow = table.rowAtPoint(evt.getPoint());
149 if (SwingUtilities.isRightMouseButton(evt))
151 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
152 table.getValueAt(selectedRow, 1), fr.getMinMax(),
153 evt.getX(), evt.getY());
155 else if (evt.getClickCount() == 2)
157 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
158 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
160 (String) table.getValueAt(selectedRow, 0));
164 // isPopupTrigger fires on mouseReleased on Mac
166 public void mouseReleased(MouseEvent evt)
168 selectedRow = table.rowAtPoint(evt.getPoint());
169 if (evt.isPopupTrigger())
171 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
172 table.getValueAt(selectedRow, 1), fr.getMinMax(),
179 table.addMouseMotionListener(new MouseMotionAdapter()
181 public void mouseDragged(MouseEvent evt)
183 int newRow = table.rowAtPoint(evt.getPoint());
184 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
186 Object[] temp = new Object[3];
187 temp[0] = table.getValueAt(selectedRow, 0);
188 temp[1] = table.getValueAt(selectedRow, 1);
189 temp[2] = table.getValueAt(selectedRow, 2);
191 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
192 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
193 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
195 table.setValueAt(temp[0], newRow, 0);
196 table.setValueAt(temp[1], newRow, 1);
197 table.setValueAt(temp[2], newRow, 2);
199 selectedRow = newRow;
203 table.setToolTipText(JvSwingUtils
204 .wrapTooltip(true, MessageManager.getString("label.feature_settings_click_drag")));
205 scrollPane.setViewportView(table);
207 dassourceBrowser = new DasSourceBrowser(this);
208 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
210 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
212 fr.findAllFeatures(true); // display everything!
216 final PropertyChangeListener change;
217 final FeatureSettings fs = this;
218 fr.addPropertyChangeListener(change = new PropertyChangeListener()
220 public void propertyChange(PropertyChangeEvent evt)
222 if (!fs.resettingTable && !fs.handlingUpdate)
224 fs.handlingUpdate = true;
225 fs.resetTable(null); // new groups may be added with new seuqence
226 // feature types only
227 fs.handlingUpdate = false;
233 frame = new JInternalFrame();
234 frame.setContentPane(this);
235 if (new jalview.util.Platform().isAMac())
237 Desktop.addInternalFrame(frame,
238 MessageManager.getString("label.sequence_feature_settings"),
243 Desktop.addInternalFrame(frame,
244 MessageManager.getString("label.sequence_feature_settings"),
248 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
250 public void internalFrameClosed(
251 javax.swing.event.InternalFrameEvent evt)
253 fr.removePropertyChangeListener(change);
254 dassourceBrowser.fs = null;
257 frame.setLayer(JLayeredPane.PALETTE_LAYER);
260 protected void popupSort(final int selectedRow, final String type,
261 final Object typeCol, final Hashtable minmax, int x, int y)
263 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
264 "label.settings_for_param", new String[]
266 JMenuItem scr = new JMenuItem(
267 MessageManager.getString("label.sort_by_score"));
269 final FeatureSettings me = this;
270 scr.addActionListener(new ActionListener()
273 public void actionPerformed(ActionEvent e)
275 me.af.avc.sortAlignmentByFeatureScore(new String[]
280 JMenuItem dens = new JMenuItem(
281 MessageManager.getString("label.sort_by_density"));
282 dens.addActionListener(new ActionListener()
285 public void actionPerformed(ActionEvent e)
287 me.af.avc.sortAlignmentByFeatureDensity(new String[]
295 final Object typeMinMax = minmax.get(type);
297 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
298 * this is broken at the moment and isn't that useful anyway!
299 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
302 * public void actionPerformed(ActionEvent e) {
303 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
304 * null); } else { minmax.put(type, typeMinMax); } }
310 if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
312 // if (table.getValueAt(row, column));
313 // graduated colourschemes for those where minmax exists for the
314 // positional features
315 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
317 mxcol.setSelected(!(typeCol instanceof Color));
319 mxcol.addActionListener(new ActionListener()
321 JColorChooser colorChooser;
323 public void actionPerformed(ActionEvent e)
325 if (e.getSource() == mxcol)
327 if (typeCol instanceof Color)
329 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
331 fc.addActionListener(this);
335 // bring up simple color chooser
336 colorChooser = new JColorChooser();
337 JDialog dialog = JColorChooser.createDialog(me,
338 "Select new Colour", true, // modal
339 colorChooser, this, // OK button handler
340 null); // no CANCEL button handler
341 colorChooser.setColor(((GraduatedColor) typeCol)
343 dialog.setVisible(true);
348 if (e.getSource() instanceof FeatureColourChooser)
350 FeatureColourChooser fc = (FeatureColourChooser) e
352 table.setValueAt(fc.getLastColour(), selectedRow, 1);
357 // probably the color chooser!
358 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
360 me.updateFeatureRenderer(
361 ((FeatureTableModel) table.getModel()).getData(),
370 JMenuItem selCols = new JMenuItem(
371 MessageManager.getString("label.select_columns_containing"));
372 selCols.addActionListener(new ActionListener()
376 public void actionPerformed(ActionEvent arg0)
378 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
382 JMenuItem clearCols = new JMenuItem(
383 MessageManager.getString("label.select_columns_not_containing"));
384 clearCols.addActionListener(new ActionListener()
388 public void actionPerformed(ActionEvent arg0)
390 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
396 men.show(table, x, y);
400 * true when Feature Settings are updating from feature renderer
402 private boolean handlingUpdate = false;
405 * contains a float[3] for each feature type string. created by setTableData
407 Hashtable typeWidth = null;
409 synchronized public void setTableData()
411 Vector allFeatures = new Vector();
412 Vector allGroups = new Vector();
413 SequenceFeature[] tmpfeatures;
415 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
417 if (af.getViewport().getAlignment().getSequenceAt(i)
418 .getDatasetSequence().getSequenceFeatures() == null)
423 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
424 .getDatasetSequence().getSequenceFeatures();
427 while (index < tmpfeatures.length)
429 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
435 if (tmpfeatures[index].getFeatureGroup() != null)
437 group = tmpfeatures[index].featureGroup;
438 if (!allGroups.contains(group))
440 allGroups.addElement(group);
441 checkGroupState(group);
445 if (!allFeatures.contains(tmpfeatures[index].getType()))
447 allFeatures.addElement(tmpfeatures[index].getType());
459 * Synchronise gui group list and check visibility of group
462 * @return true if group is visible
464 private boolean checkGroupState(String group)
466 boolean visible = fr.checkGroupVisibility(group, true);
468 if (groupPanel == null)
470 groupPanel = new JPanel();
473 boolean alreadyAdded = false;
474 for (int g = 0; g < groupPanel.getComponentCount(); g++)
476 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
479 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
489 final String grp = group;
490 final JCheckBox check = new JCheckBox(group, visible);
491 check.setFont(new Font("Serif", Font.BOLD, 12));
492 check.addItemListener(new ItemListener()
494 public void itemStateChanged(ItemEvent evt)
496 fr.setGroupVisibility(check.getText(), check.isSelected());
497 af.alignPanel.seqPanel.seqCanvas.repaint();
498 if (af.alignPanel.overviewPanel != null)
500 af.alignPanel.overviewPanel.updateOverviewImage();
503 resetTable(new String[]
507 groupPanel.add(check);
511 boolean resettingTable = false;
513 synchronized void resetTable(String[] groupChanged)
515 if (resettingTable == true)
519 resettingTable = true;
520 typeWidth = new Hashtable();
521 // TODO: change avWidth calculation to 'per-sequence' average and use long
523 float[] avWidth = null;
524 SequenceFeature[] tmpfeatures;
525 String group = null, type;
526 Vector visibleChecks = new Vector();
528 // Find out which features should be visible depending on which groups
529 // are selected / deselected
530 // and recompute average width ordering
531 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
534 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
535 .getDatasetSequence().getSequenceFeatures();
536 if (tmpfeatures == null)
542 while (index < tmpfeatures.length)
544 group = tmpfeatures[index].featureGroup;
546 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
552 if (group == null || checkGroupState(group))
554 type = tmpfeatures[index].getType();
555 if (!visibleChecks.contains(type))
557 visibleChecks.addElement(type);
560 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
562 typeWidth.put(tmpfeatures[index].getType(),
563 avWidth = new float[3]);
567 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
570 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
572 avWidth[1] += 1 + tmpfeatures[index].getBegin()
573 - tmpfeatures[index].getEnd();
577 avWidth[1] += 1 + tmpfeatures[index].getEnd()
578 - tmpfeatures[index].getBegin();
584 int fSize = visibleChecks.size();
585 Object[][] data = new Object[fSize][3];
588 if (fr.hasRenderOrder())
592 fr.findAllFeatures(groupChanged != null); // prod to update
593 // colourschemes. but don't
595 // First add the checks in the previous render order,
596 // in case the window has been closed and reopened
598 List<String> frl = fr.getRenderOrder();
599 for (int ro = frl.size() - 1; ro > -1; ro--)
603 if (!visibleChecks.contains(type))
608 data[dataIndex][0] = type;
609 data[dataIndex][1] = fr.getFeatureStyle(type);
610 data[dataIndex][2] = new Boolean(af.getViewport()
611 .getFeaturesDisplayed().isVisible(type));
613 visibleChecks.removeElement(type);
617 fSize = visibleChecks.size();
618 for (int i = 0; i < fSize; i++)
620 // These must be extra features belonging to the group
621 // which was just selected
622 type = visibleChecks.elementAt(i).toString();
623 data[dataIndex][0] = type;
625 data[dataIndex][1] = fr.getFeatureStyle(type);
626 if (data[dataIndex][1] == null)
628 // "Colour has been updated in another view!!"
629 fr.clearRenderOrder();
633 data[dataIndex][2] = new Boolean(true);
637 if (originalData == null)
639 originalData = new Object[data.length][3];
640 for (int i = 0; i < data.length; i++)
642 System.arraycopy(data[i], 0, originalData[i], 0, 3);
646 table.setModel(new FeatureTableModel(data));
647 table.getColumnModel().getColumn(0).setPreferredWidth(200);
649 if (groupPanel != null)
651 groupPanel.setLayout(new GridLayout(
652 fr.getFeatureGroupsSize() / 4 + 1, 4));
654 groupPanel.validate();
655 bigPanel.add(groupPanel, BorderLayout.NORTH);
658 updateFeatureRenderer(data, groupChanged != null);
659 resettingTable = false;
663 * reorder data based on the featureRenderers global priority list.
667 private void ensureOrder(Object[][] data)
669 boolean sort = false;
670 float[] order = new float[data.length];
671 for (int i = 0; i < order.length; i++)
673 order[i] = fr.getOrder(data[i][0].toString());
676 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
680 sort = sort || order[i - 1] > order[i];
685 jalview.util.QuickSort.sort(order, data);
691 JalviewFileChooser chooser = new JalviewFileChooser(
692 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
693 { "fc" }, new String[]
694 { "Sequence Feature Colours" }, "Sequence Feature Colours");
695 chooser.setFileView(new jalview.io.JalviewFileView());
696 chooser.setDialogTitle(MessageManager.getString("label.load_feature_colours"));
697 chooser.setToolTipText(MessageManager.getString("action.load"));
699 int value = chooser.showOpenDialog(this);
701 if (value == JalviewFileChooser.APPROVE_OPTION)
703 File file = chooser.getSelectedFile();
707 InputStreamReader in = new InputStreamReader(new FileInputStream(
710 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
714 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
717 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
720 Color mincol = null, maxcol = null;
723 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
724 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
726 } catch (Exception e)
728 Cache.log.warn("Couldn't parse out graduated feature color.",
731 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
732 newcol.getMin(), newcol.getMax());
733 if (newcol.hasAutoScale())
735 gcol.setAutoScaled(newcol.getAutoScale());
737 if (newcol.hasColourByLabel())
739 gcol.setColourByLabel(newcol.getColourByLabel());
741 if (newcol.hasThreshold())
743 gcol.setThresh(newcol.getThreshold());
744 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
746 if (newcol.getThreshType().length() > 0)
748 String ttyp = newcol.getThreshType();
749 if (ttyp.equalsIgnoreCase("NONE"))
751 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
753 if (ttyp.equalsIgnoreCase("ABOVE"))
755 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
757 if (ttyp.equalsIgnoreCase("BELOW"))
759 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
762 fr.setColour(name = newcol.getName(), gcol);
766 fr.setColour(name = jucs.getColour(i).getName(), new Color(
767 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
769 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
774 Object[][] data = ((FeatureTableModel) table.getModel())
777 updateFeatureRenderer(data, false);
780 } catch (Exception ex)
782 System.out.println("Error loading User Colour File\n" + ex);
789 JalviewFileChooser chooser = new JalviewFileChooser(
790 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
791 { "fc" }, new String[]
792 { "Sequence Feature Colours" }, "Sequence Feature Colours");
793 chooser.setFileView(new jalview.io.JalviewFileView());
794 chooser.setDialogTitle(MessageManager.getString("label.save_feature_colours"));
795 chooser.setToolTipText(MessageManager.getString("action.save"));
797 int value = chooser.showSaveDialog(this);
799 if (value == JalviewFileChooser.APPROVE_OPTION)
801 String choice = chooser.getSelectedFile().getPath();
802 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
803 ucs.setSchemeName("Sequence Features");
806 PrintWriter out = new PrintWriter(new OutputStreamWriter(
807 new FileOutputStream(choice), "UTF-8"));
809 Set fr_colours = fr.getAllFeatureColours();
810 Iterator e = fr_colours.iterator();
811 float[] sortOrder = new float[fr_colours.size()];
812 String[] sortTypes = new String[fr_colours.size()];
816 sortTypes[i] = e.next().toString();
817 sortOrder[i] = fr.getOrder(sortTypes[i]);
820 jalview.util.QuickSort.sort(sortOrder, sortTypes);
824 for (i = 0; i < sortTypes.length; i++)
826 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
827 col.setName(sortTypes[i]);
828 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
830 fcol = fr.getFeatureStyle(sortTypes[i]);
831 if (fcol instanceof GraduatedColor)
833 gcol = (GraduatedColor) fcol;
834 col.setMin(gcol.getMin());
835 col.setMax(gcol.getMax());
836 col.setMinRGB(jalview.util.Format.getHexString(gcol
838 col.setAutoScale(gcol.isAutoScale());
839 col.setThreshold(gcol.getThresh());
840 col.setColourByLabel(gcol.isColourByLabel());
841 switch (gcol.getThreshType())
843 case AnnotationColourGradient.NO_THRESHOLD:
844 col.setThreshType("NONE");
846 case AnnotationColourGradient.ABOVE_THRESHOLD:
847 col.setThreshType("ABOVE");
849 case AnnotationColourGradient.BELOW_THRESHOLD:
850 col.setThreshType("BELOW");
858 } catch (Exception ex)
860 ex.printStackTrace();
865 public void invertSelection()
867 for (int i = 0; i < table.getRowCount(); i++)
869 Boolean value = (Boolean) table.getValueAt(i, 2);
871 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
875 public void orderByAvWidth()
877 if (table == null || table.getModel() == null)
881 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
882 float[] width = new float[data.length];
886 for (int i = 0; i < data.length; i++)
888 awidth = (float[]) typeWidth.get(data[i][0]);
891 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
892 // weight - but have to make per
893 // sequence, too (awidth[2])
894 // if (width[i]==1) // hack to distinguish single width sequences.
906 boolean sort = false;
907 for (int i = 0; i < width.length; i++)
909 // awidth = (float[]) typeWidth.get(data[i][0]);
912 width[i] = fr.getOrder(data[i][0].toString());
915 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
920 width[i] /= max; // normalize
921 fr.setOrder(data[i][0].toString(), width[i]); // store for later
925 sort = sort || width[i - 1] > width[i];
930 jalview.util.QuickSort.sort(width, data);
931 // update global priority order
934 updateFeatureRenderer(data, false);
942 frame.setClosed(true);
943 } catch (Exception exe)
949 public void updateFeatureRenderer(Object[][] data)
951 updateFeatureRenderer(data, true);
954 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
956 fr.setFeaturePriority(data, visibleNew);
957 af.alignPanel.paintAlignment(true);
960 int selectedRow = -1;
962 JTabbedPane tabbedPane = new JTabbedPane();
964 BorderLayout borderLayout1 = new BorderLayout();
966 BorderLayout borderLayout2 = new BorderLayout();
968 BorderLayout borderLayout3 = new BorderLayout();
970 JPanel bigPanel = new JPanel();
972 BorderLayout borderLayout4 = new BorderLayout();
974 JButton invert = new JButton();
976 JPanel buttonPanel = new JPanel();
978 JButton cancel = new JButton();
980 JButton ok = new JButton();
982 JButton loadColours = new JButton();
984 JButton saveColours = new JButton();
986 JPanel dasButtonPanel = new JPanel();
988 JButton fetchDAS = new JButton();
990 JButton saveDAS = new JButton();
992 JButton cancelDAS = new JButton();
994 JButton optimizeOrder = new JButton();
996 JButton sortByScore = new JButton();
998 JButton sortByDens = new JButton();
1000 JPanel transbuttons = new JPanel(new GridLayout(4, 1));
1002 private void jbInit() throws Exception
1004 this.setLayout(borderLayout1);
1005 settingsPane.setLayout(borderLayout2);
1006 dasSettingsPane.setLayout(borderLayout3);
1007 bigPanel.setLayout(borderLayout4);
1008 invert.setFont(JvSwingUtils.getLabelFont());
1009 invert.setText(MessageManager.getString("label.invert_selection"));
1010 invert.addActionListener(new ActionListener()
1012 public void actionPerformed(ActionEvent e)
1017 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1018 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1019 optimizeOrder.addActionListener(new ActionListener()
1021 public void actionPerformed(ActionEvent e)
1026 sortByScore.setFont(JvSwingUtils.getLabelFont());
1028 .setText(MessageManager.getString("label.seq_sort_by_score"));
1029 sortByScore.addActionListener(new ActionListener()
1031 public void actionPerformed(ActionEvent e)
1033 af.avc.sortAlignmentByFeatureScore(null);
1036 sortByDens.setFont(JvSwingUtils.getLabelFont());
1037 sortByDens.setText(MessageManager
1038 .getString("label.sequence_sort_by_density"));
1039 sortByDens.addActionListener(new ActionListener()
1041 public void actionPerformed(ActionEvent e)
1043 af.avc.sortAlignmentByFeatureDensity(null);
1046 cancel.setFont(JvSwingUtils.getLabelFont());
1047 cancel.setText(MessageManager.getString("action.cancel"));
1048 cancel.addActionListener(new ActionListener()
1050 public void actionPerformed(ActionEvent e)
1052 fr.setTransparency(originalTransparency);
1053 updateFeatureRenderer(originalData);
1057 ok.setFont(JvSwingUtils.getLabelFont());
1058 ok.setText(MessageManager.getString("action.ok"));
1059 ok.addActionListener(new ActionListener()
1061 public void actionPerformed(ActionEvent e)
1066 loadColours.setFont(JvSwingUtils.getLabelFont());
1067 loadColours.setText(MessageManager.getString("label.load_colours"));
1068 loadColours.addActionListener(new ActionListener()
1070 public void actionPerformed(ActionEvent e)
1075 saveColours.setFont(JvSwingUtils.getLabelFont());
1076 saveColours.setText(MessageManager.getString("label.save_colours"));
1077 saveColours.addActionListener(new ActionListener()
1079 public void actionPerformed(ActionEvent e)
1084 transparency.addChangeListener(new ChangeListener()
1086 public void stateChanged(ChangeEvent evt)
1088 fr.setTransparency((100 - transparency.getValue()) / 100f);
1089 af.alignPanel.paintAlignment(true);
1093 transparency.setMaximum(70);
1094 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1095 fetchDAS.addActionListener(new ActionListener()
1097 public void actionPerformed(ActionEvent e)
1099 fetchDAS_actionPerformed(e);
1102 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1103 saveDAS.addActionListener(new ActionListener()
1105 public void actionPerformed(ActionEvent e)
1107 saveDAS_actionPerformed(e);
1110 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1111 dasSettingsPane.setBorder(null);
1112 cancelDAS.setEnabled(false);
1113 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1114 cancelDAS.addActionListener(new ActionListener()
1116 public void actionPerformed(ActionEvent e)
1118 cancelDAS_actionPerformed(e);
1121 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1122 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1123 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1124 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1125 transbuttons.add(optimizeOrder);
1126 transbuttons.add(invert);
1127 transbuttons.add(sortByScore);
1128 transbuttons.add(sortByDens);
1129 transPanel.add(transparency);
1130 transPanel.add(transbuttons);
1131 buttonPanel.add(ok);
1132 buttonPanel.add(cancel);
1133 buttonPanel.add(loadColours);
1134 buttonPanel.add(saveColours);
1135 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1136 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1137 dasButtonPanel.add(fetchDAS);
1138 dasButtonPanel.add(cancelDAS);
1139 dasButtonPanel.add(saveDAS);
1140 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1141 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1144 public void fetchDAS_actionPerformed(ActionEvent e)
1146 fetchDAS.setEnabled(false);
1147 cancelDAS.setEnabled(true);
1148 dassourceBrowser.setGuiEnabled(false);
1149 Vector selectedSources = dassourceBrowser.getSelectedSources();
1150 doDasFeatureFetch(selectedSources, true, true);
1154 * get the features from selectedSources for all or the current selection
1156 * @param selectedSources
1157 * @param checkDbRefs
1158 * @param promptFetchDbRefs
1160 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1161 boolean checkDbRefs, boolean promptFetchDbRefs)
1163 SequenceI[] dataset, seqs;
1165 AlignViewport vp = af.getViewport();
1166 if (vp.getSelectionGroup() != null
1167 && vp.getSelectionGroup().getSize() > 0)
1169 iSize = vp.getSelectionGroup().getSize();
1170 dataset = new SequenceI[iSize];
1171 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1175 iSize = vp.getAlignment().getHeight();
1176 seqs = vp.getAlignment().getSequencesArray();
1179 dataset = new SequenceI[iSize];
1180 for (int i = 0; i < iSize; i++)
1182 dataset[i] = seqs[i].getDatasetSequence();
1185 cancelDAS.setEnabled(true);
1186 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1187 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1188 af.getViewport().setShowSequenceFeatures(true);
1189 af.showSeqFeatures.setSelected(true);
1193 * blocking call to initialise the das source browser
1195 public void initDasSources()
1197 dassourceBrowser.initDasSources();
1201 * examine the current list of das sources and return any matching the given
1202 * nicknames in sources
1205 * Vector of Strings to resolve to DAS source nicknames.
1206 * @return sources that are present in source list.
1208 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1210 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1214 * get currently selected das sources. ensure you have called initDasSources
1215 * before calling this.
1217 * @return vector of selected das source nicknames
1219 public Vector getSelectedSources()
1221 return dassourceBrowser.getSelectedSources();
1225 * properly initialise DAS fetcher and then initiate a new thread to fetch
1226 * features from the named sources (rather than any turned on by default)
1230 * if true then runs in same thread, otherwise passes to the Swing
1233 public void fetchDasFeatures(Vector sources, boolean block)
1236 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1237 .resolveSourceNicknames(sources);
1238 if (resolved.size() == 0)
1240 resolved = dassourceBrowser.getSelectedSources();
1242 if (resolved.size() > 0)
1244 final List<jalviewSourceI> dassources = resolved;
1245 fetchDAS.setEnabled(false);
1246 // cancelDAS.setEnabled(true); doDasFetch does this.
1247 Runnable fetcher = new Runnable()
1252 doDasFeatureFetch(dassources, true, false);
1262 SwingUtilities.invokeLater(fetcher);
1267 public void saveDAS_actionPerformed(ActionEvent e)
1270 .saveProperties(jalview.bin.Cache.applicationProperties);
1273 public void complete()
1275 fetchDAS.setEnabled(true);
1276 cancelDAS.setEnabled(false);
1277 dassourceBrowser.setGuiEnabled(true);
1281 public void cancelDAS_actionPerformed(ActionEvent e)
1283 if (dasFeatureFetcher != null)
1285 dasFeatureFetcher.cancel();
1290 public void noDasSourceActive()
1294 .showInternalConfirmDialog(
1297 .getString("label.no_das_sources_selected_warn"),
1299 .getString("label.no_das_sources_selected_title"),
1300 JOptionPane.DEFAULT_OPTION,
1301 JOptionPane.INFORMATION_MESSAGE);
1304 // ///////////////////////////////////////////////////////////////////////
1305 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1306 // ///////////////////////////////////////////////////////////////////////
1307 class FeatureTableModel extends AbstractTableModel
1309 FeatureTableModel(Object[][] data)
1314 private String[] columnNames =
1315 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1317 private Object[][] data;
1319 public Object[][] getData()
1324 public void setData(Object[][] data)
1329 public int getColumnCount()
1331 return columnNames.length;
1334 public Object[] getRow(int row)
1339 public int getRowCount()
1344 public String getColumnName(int col)
1346 return columnNames[col];
1349 public Object getValueAt(int row, int col)
1351 return data[row][col];
1354 public Class getColumnClass(int c)
1356 return getValueAt(0, c).getClass();
1359 public boolean isCellEditable(int row, int col)
1361 return col == 0 ? false : true;
1364 public void setValueAt(Object value, int row, int col)
1366 data[row][col] = value;
1367 fireTableCellUpdated(row, col);
1368 updateFeatureRenderer(data);
1373 class ColorRenderer extends JLabel implements TableCellRenderer
1375 javax.swing.border.Border unselectedBorder = null;
1377 javax.swing.border.Border selectedBorder = null;
1379 final String baseTT = "Click to edit, right/apple click for menu.";
1381 public ColorRenderer()
1383 setOpaque(true); // MUST do this for background to show up.
1384 setHorizontalTextPosition(SwingConstants.CENTER);
1385 setVerticalTextPosition(SwingConstants.CENTER);
1388 public Component getTableCellRendererComponent(JTable table,
1389 Object color, boolean isSelected, boolean hasFocus, int row,
1392 // JLabel comp = new JLabel();
1396 // setBounds(getBounds());
1398 setToolTipText(baseTT);
1399 setBackground(table.getBackground());
1400 if (color instanceof GraduatedColor)
1402 Rectangle cr = table.getCellRect(row, column, false);
1403 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1404 (int) cr.getWidth(), (int) cr.getHeight());
1411 newColor = (Color) color;
1413 setBackground(newColor);
1414 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1415 // + newColor.getGreen() + ", " + newColor.getBlue());
1419 if (selectedBorder == null)
1421 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1422 table.getSelectionBackground());
1425 setBorder(selectedBorder);
1429 if (unselectedBorder == null)
1431 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1432 table.getBackground());
1435 setBorder(unselectedBorder);
1443 * update comp using rendering settings from gcol
1448 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1450 int w = comp.getWidth(), h = comp.getHeight();
1453 w = (int) comp.getPreferredSize().getWidth();
1454 h = (int) comp.getPreferredSize().getHeight();
1461 renderGraduatedColor(comp, gcol, w, h);
1464 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1467 boolean thr = false;
1470 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1474 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1476 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1480 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1482 if (gcol.isColourByLabel())
1484 tt = "Coloured by label text. " + tt;
1494 Color newColor = gcol.getMaxColor();
1495 comp.setBackground(newColor);
1496 // System.err.println("Width is " + w / 2);
1497 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1498 comp.setIcon(ficon);
1499 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1500 // + newColor.getGreen() + ", " + newColor.getBlue()
1501 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1502 // + ", " + minCol.getBlue() + ")");
1504 comp.setHorizontalAlignment(SwingConstants.CENTER);
1506 if (tt.length() > 0)
1508 if (comp.getToolTipText() == null)
1510 comp.setToolTipText(tt);
1514 comp.setToolTipText(tt + " " + comp.getToolTipText());
1520 class FeatureIcon implements Icon
1522 GraduatedColor gcol;
1526 boolean midspace = false;
1528 int width = 50, height = 20;
1530 int s1, e1; // start and end of midpoint band for thresholded symbol
1532 Color mpcolour = Color.white;
1534 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1553 public int getIconWidth()
1558 public int getIconHeight()
1563 public void paintIcon(Component c, Graphics g, int x, int y)
1566 if (gcol.isColourByLabel())
1569 g.fillRect(0, 0, width, height);
1570 // need an icon here.
1571 g.setColor(gcol.getMaxColor());
1573 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1575 // g.setFont(g.getFont().deriveFont(
1576 // AffineTransform.getScaleInstance(
1577 // width/g.getFontMetrics().stringWidth("Label"),
1578 // height/g.getFontMetrics().getHeight())));
1580 g.drawString(MessageManager.getString("label.label"), 0, 0);
1585 Color minCol = gcol.getMinColor();
1587 g.fillRect(0, 0, s1, height);
1590 g.setColor(Color.white);
1591 g.fillRect(s1, 0, e1 - s1, height);
1593 g.setColor(gcol.getMaxColor());
1594 g.fillRect(0, e1, width - e1, height);
1599 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1604 GraduatedColor currentGColor;
1606 FeatureColourChooser chooser;
1614 JColorChooser colorChooser;
1618 protected static final String EDIT = "edit";
1620 int selectedRow = 0;
1622 public ColorEditor(FeatureSettings me)
1625 // Set up the editor (from the table's point of view),
1626 // which is a button.
1627 // This button brings up the color chooser dialog,
1628 // which is the editor from the user's point of view.
1629 button = new JButton();
1630 button.setActionCommand(EDIT);
1631 button.addActionListener(this);
1632 button.setBorderPainted(false);
1633 // Set up the dialog that the button brings up.
1634 colorChooser = new JColorChooser();
1635 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1636 colorChooser, this, // OK button handler
1637 null); // no CANCEL button handler
1641 * Handles events from the editor button and from the dialog's OK button.
1643 public void actionPerformed(ActionEvent e)
1646 if (EDIT.equals(e.getActionCommand()))
1648 // The user has clicked the cell, so
1649 // bring up the dialog.
1650 if (currentColor != null)
1652 // bring up simple color chooser
1653 button.setBackground(currentColor);
1654 colorChooser.setColor(currentColor);
1655 dialog.setVisible(true);
1659 // bring up graduated chooser.
1660 chooser = new FeatureColourChooser(me.fr, type);
1661 chooser.setRequestFocusEnabled(true);
1662 chooser.requestFocus();
1663 chooser.addActionListener(this);
1665 // Make the renderer reappear.
1666 fireEditingStopped();
1670 { // User pressed dialog's "OK" button.
1671 if (currentColor != null)
1673 currentColor = colorChooser.getColor();
1677 // class cast exceptions may be raised if the chooser created on a
1678 // non-graduated color
1679 currentGColor = (GraduatedColor) chooser.getLastColour();
1681 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1682 fireEditingStopped();
1683 me.table.validate();
1687 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1688 public Object getCellEditorValue()
1690 if (currentColor == null)
1692 return currentGColor;
1694 return currentColor;
1697 // Implement the one method defined by TableCellEditor.
1698 public Component getTableCellEditorComponent(JTable table, Object value,
1699 boolean isSelected, int row, int column)
1701 currentGColor = null;
1702 currentColor = null;
1703 this.selectedRow = row;
1704 type = me.table.getValueAt(row, 0).toString();
1705 button.setOpaque(true);
1706 button.setBackground(me.getBackground());
1707 if (value instanceof GraduatedColor)
1709 currentGColor = (GraduatedColor) value;
1710 JLabel btn = new JLabel();
1711 btn.setSize(button.getSize());
1712 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1713 button.setBackground(btn.getBackground());
1714 button.setIcon(btn.getIcon());
1715 button.setText(btn.getText());
1720 button.setIcon(null);
1721 currentColor = (Color) value;
1722 button.setBackground(currentColor);