2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
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 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
17 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import java.util.List;
25 import java.awt.event.*;
26 import java.beans.PropertyChangeEvent;
27 import java.beans.PropertyChangeListener;
30 import javax.swing.event.*;
31 import javax.swing.table.*;
33 import jalview.analysis.AlignmentSorter;
34 import jalview.bin.Cache;
35 import jalview.commands.OrderCommand;
36 import jalview.datamodel.*;
38 import jalview.schemes.AnnotationColourGradient;
39 import jalview.schemes.GraduatedColor;
40 import jalview.util.MessageManager;
41 import jalview.ws.dbsources.das.api.jalviewSourceI;
43 public class FeatureSettings extends JPanel
45 DasSourceBrowser dassourceBrowser;
47 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
49 JPanel settingsPane = new JPanel();
51 JPanel dasSettingsPane = new JPanel();
53 final FeatureRenderer fr;
55 public final AlignFrame af;
57 Object[][] originalData;
59 final JInternalFrame frame;
61 JScrollPane scrollPane = new JScrollPane();
67 JSlider transparency = new JSlider();
69 JPanel transPanel = new JPanel(new GridLayout(1, 2));
71 public FeatureSettings(AlignFrame af)
74 fr = af.getFeatureRenderer();
76 transparency.setMaximum(100 - (int) (fr.transparency * 100));
81 } catch (Exception ex)
87 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
88 table.setFont(new Font("Verdana", Font.PLAIN, 12));
89 table.setDefaultRenderer(Color.class, new ColorRenderer());
91 table.setDefaultEditor(Color.class, new ColorEditor(this));
93 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
94 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
95 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
97 table.addMouseListener(new MouseAdapter()
99 public void mousePressed(MouseEvent evt)
101 selectedRow = table.rowAtPoint(evt.getPoint());
102 if (evt.isPopupTrigger())
104 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
105 table.getValueAt(selectedRow, 1), fr.minmax, evt.getX(),
108 else if (evt.getClickCount() == 2)
110 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
112 (String) table.getValueAt(selectedRow, 0));
117 table.addMouseMotionListener(new MouseMotionAdapter()
119 public void mouseDragged(MouseEvent evt)
121 int newRow = table.rowAtPoint(evt.getPoint());
122 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
124 Object[] temp = new Object[3];
125 temp[0] = table.getValueAt(selectedRow, 0);
126 temp[1] = table.getValueAt(selectedRow, 1);
127 temp[2] = table.getValueAt(selectedRow, 2);
129 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
130 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
131 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
133 table.setValueAt(temp[0], newRow, 0);
134 table.setValueAt(temp[1], newRow, 1);
135 table.setValueAt(temp[2], newRow, 2);
137 selectedRow = newRow;
142 scrollPane.setViewportView(table);
144 dassourceBrowser = new DasSourceBrowser(this);
145 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
147 if (af.getViewport().featuresDisplayed == null
148 || fr.renderOrder == null)
150 fr.findAllFeatures(true); // display everything!
154 final PropertyChangeListener change;
155 final FeatureSettings fs = this;
156 fr.addPropertyChangeListener(change = new PropertyChangeListener()
158 public void propertyChange(PropertyChangeEvent evt)
160 if (!fs.resettingTable && !fs.handlingUpdate)
162 fs.handlingUpdate = true;
163 fs.resetTable(null); // new groups may be added with new seuqence
164 // feature types only
165 fs.handlingUpdate = false;
171 frame = new JInternalFrame();
172 frame.setContentPane(this);
173 if (new jalview.util.Platform().isAMac())
175 Desktop.addInternalFrame(frame, MessageManager.getString("label.sequence_feature_settings"), 475, 480);
179 Desktop.addInternalFrame(frame, MessageManager.getString("label.sequence_feature_settings"), 400, 450);
182 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
184 public void internalFrameClosed(
185 javax.swing.event.InternalFrameEvent evt)
187 fr.removePropertyChangeListener(change);
188 dassourceBrowser.fs = null;
191 frame.setLayer(JLayeredPane.PALETTE_LAYER);
194 protected void popupSort(final int selectedRow, final String type,
195 final Object typeCol, final Hashtable minmax, int x, int y)
197 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage("label.settings_for_param", new String[]{type}));
198 JMenuItem scr = new JMenuItem(MessageManager.getString("label.sort_by_score"));
200 final FeatureSettings me = this;
201 scr.addActionListener(new ActionListener()
204 public void actionPerformed(ActionEvent e)
206 me.sortByScore(new String[]
211 JMenuItem dens = new JMenuItem(MessageManager.getString("label.sort_by_density"));
212 dens.addActionListener(new ActionListener()
215 public void actionPerformed(ActionEvent e)
217 me.sortByDens(new String[]
225 final Object typeMinMax = minmax.get(type);
227 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
228 * this is broken at the moment and isn't that useful anyway!
229 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
232 * public void actionPerformed(ActionEvent e) {
233 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
234 * null); } else { minmax.put(type, typeMinMax); } }
240 if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
242 // if (table.getValueAt(row, column));
243 // graduated colourschemes for those where minmax exists for the
244 // positional features
245 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
247 mxcol.setSelected(!(typeCol instanceof Color));
249 mxcol.addActionListener(new ActionListener()
251 JColorChooser colorChooser;
253 public void actionPerformed(ActionEvent e)
255 if (e.getSource() == mxcol)
257 if (typeCol instanceof Color)
259 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
261 fc.addActionListener(this);
265 // bring up simple color chooser
266 colorChooser = new JColorChooser();
267 JDialog dialog = JColorChooser.createDialog(me,
268 "Select new Colour", true, // modal
269 colorChooser, this, // OK button handler
270 null); // no CANCEL button handler
271 colorChooser.setColor(((GraduatedColor) typeCol)
273 dialog.setVisible(true);
278 if (e.getSource() instanceof FeatureColourChooser)
280 FeatureColourChooser fc = (FeatureColourChooser) e
282 table.setValueAt(fc.getLastColour(), selectedRow, 1);
287 // probably the color chooser!
288 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
290 me.updateFeatureRenderer(
291 ((FeatureTableModel) table.getModel()).getData(),
300 JMenuItem selCols = new JMenuItem(MessageManager.getString("label.select_columns_containing"));
301 selCols.addActionListener(new ActionListener()
305 public void actionPerformed(ActionEvent arg0)
307 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, type);
310 JMenuItem clearCols = new JMenuItem(MessageManager.getString("label.select_columns_not_containing"));
311 clearCols.addActionListener(new ActionListener()
315 public void actionPerformed(ActionEvent arg0)
317 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, type);
322 men.show(table, x, y);
326 * true when Feature Settings are updating from feature renderer
328 private boolean handlingUpdate = false;
331 * contains a float[3] for each feature type string. created by setTableData
333 Hashtable typeWidth = null;
335 synchronized public void setTableData()
337 if (fr.featureGroups == null)
339 fr.featureGroups = new Hashtable();
341 Vector allFeatures = new Vector();
342 Vector allGroups = new Vector();
343 SequenceFeature[] tmpfeatures;
345 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
347 if (af.getViewport().getAlignment().getSequenceAt(i)
348 .getDatasetSequence().getSequenceFeatures() == null)
353 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
354 .getDatasetSequence().getSequenceFeatures();
357 while (index < tmpfeatures.length)
359 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
365 if (tmpfeatures[index].getFeatureGroup() != null)
367 group = tmpfeatures[index].featureGroup;
368 if (!allGroups.contains(group))
370 allGroups.addElement(group);
373 checkGroupState(group);
378 if (!allFeatures.contains(tmpfeatures[index].getType()))
380 allFeatures.addElement(tmpfeatures[index].getType());
394 * @return true if group has been seen before and is already added to set.
396 private boolean checkGroupState(String group)
399 if (fr.featureGroups.containsKey(group))
401 visible = ((Boolean) fr.featureGroups.get(group)).booleanValue();
405 visible = true; // new group is always made visible
408 if (groupPanel == null)
410 groupPanel = new JPanel();
413 boolean alreadyAdded = false;
414 for (int g = 0; g < groupPanel.getComponentCount(); g++)
416 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
419 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
430 fr.featureGroups.put(group, new Boolean(visible));
431 final String grp = group;
432 final JCheckBox check = new JCheckBox(group, visible);
433 check.setFont(new Font("Serif", Font.BOLD, 12));
434 check.addItemListener(new ItemListener()
436 public void itemStateChanged(ItemEvent evt)
438 fr.featureGroups.put(check.getText(),
439 new Boolean(check.isSelected()));
440 af.alignPanel.seqPanel.seqCanvas.repaint();
441 if (af.alignPanel.overviewPanel != null)
443 af.alignPanel.overviewPanel.updateOverviewImage();
446 resetTable(new String[]
450 groupPanel.add(check);
454 boolean resettingTable = false;
456 synchronized void resetTable(String[] groupChanged)
458 if (resettingTable == true)
462 resettingTable = true;
463 typeWidth = new Hashtable();
464 // TODO: change avWidth calculation to 'per-sequence' average and use long
466 float[] avWidth = null;
467 SequenceFeature[] tmpfeatures;
468 String group = null, type;
469 Vector visibleChecks = new Vector();
471 // Find out which features should be visible depending on which groups
472 // are selected / deselected
473 // and recompute average width ordering
474 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
477 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
478 .getDatasetSequence().getSequenceFeatures();
479 if (tmpfeatures == null)
485 while (index < tmpfeatures.length)
487 group = tmpfeatures[index].featureGroup;
489 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
495 if (group == null || fr.featureGroups.get(group) == null
496 || ((Boolean) fr.featureGroups.get(group)).booleanValue())
499 checkGroupState(group);
500 type = tmpfeatures[index].getType();
501 if (!visibleChecks.contains(type))
503 visibleChecks.addElement(type);
506 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
508 typeWidth.put(tmpfeatures[index].getType(),
509 avWidth = new float[3]);
513 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
516 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
518 avWidth[1] += 1 + tmpfeatures[index].getBegin()
519 - tmpfeatures[index].getEnd();
523 avWidth[1] += 1 + tmpfeatures[index].getEnd()
524 - tmpfeatures[index].getBegin();
530 int fSize = visibleChecks.size();
531 Object[][] data = new Object[fSize][3];
534 if (fr.renderOrder != null)
537 fr.findAllFeatures(groupChanged != null); // prod to update
538 // colourschemes. but don't
540 // First add the checks in the previous render order,
541 // in case the window has been closed and reopened
542 for (int ro = fr.renderOrder.length - 1; ro > -1; ro--)
544 type = fr.renderOrder[ro];
546 if (!visibleChecks.contains(type))
551 data[dataIndex][0] = type;
552 data[dataIndex][1] = fr.getFeatureStyle(type);
553 data[dataIndex][2] = new Boolean(
554 af.getViewport().featuresDisplayed.containsKey(type));
556 visibleChecks.removeElement(type);
560 fSize = visibleChecks.size();
561 for (int i = 0; i < fSize; i++)
563 // These must be extra features belonging to the group
564 // which was just selected
565 type = visibleChecks.elementAt(i).toString();
566 data[dataIndex][0] = type;
568 data[dataIndex][1] = fr.getFeatureStyle(type);
569 if (data[dataIndex][1] == null)
571 // "Colour has been updated in another view!!"
572 fr.renderOrder = null;
576 data[dataIndex][2] = new Boolean(true);
580 if (originalData == null)
582 originalData = new Object[data.length][3];
583 for (int i = 0; i < data.length; i++)
585 System.arraycopy(data[i], 0, originalData[i], 0, 3);
589 table.setModel(new FeatureTableModel(data));
590 table.getColumnModel().getColumn(0).setPreferredWidth(200);
592 if (groupPanel != null)
594 groupPanel.setLayout(new GridLayout(fr.featureGroups.size() / 4 + 1,
597 groupPanel.validate();
598 bigPanel.add(groupPanel, BorderLayout.NORTH);
601 updateFeatureRenderer(data, groupChanged != null);
602 resettingTable = false;
606 * reorder data based on the featureRenderers global priority list.
610 private void ensureOrder(Object[][] data)
612 boolean sort = false;
613 float[] order = new float[data.length];
614 for (int i = 0; i < order.length; i++)
616 order[i] = fr.getOrder(data[i][0].toString());
618 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
620 sort = sort || order[i - 1] > order[i];
623 jalview.util.QuickSort.sort(order, data);
628 JalviewFileChooser chooser = new JalviewFileChooser(
629 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
630 { "fc" }, new String[]
631 { "Sequence Feature Colours" }, "Sequence Feature Colours");
632 chooser.setFileView(new jalview.io.JalviewFileView());
633 chooser.setDialogTitle("Load Feature Colours");
634 chooser.setToolTipText(MessageManager.getString("action.load"));
636 int value = chooser.showOpenDialog(this);
638 if (value == JalviewFileChooser.APPROVE_OPTION)
640 File file = chooser.getSelectedFile();
644 InputStreamReader in = new InputStreamReader(new FileInputStream(
647 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
648 jucs = (jalview.schemabinding.version2.JalviewUserColours) jucs
651 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
654 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
657 Color mincol = null, maxcol = null;
660 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
661 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
663 } catch (Exception e)
665 Cache.log.warn("Couldn't parse out graduated feature color.",
668 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
669 newcol.getMin(), newcol.getMax());
670 if (newcol.hasAutoScale())
672 gcol.setAutoScaled(newcol.getAutoScale());
674 if (newcol.hasColourByLabel())
676 gcol.setColourByLabel(newcol.getColourByLabel());
678 if (newcol.hasThreshold())
680 gcol.setThresh(newcol.getThreshold());
681 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
683 if (newcol.getThreshType().length() > 0)
685 String ttyp = newcol.getThreshType();
686 if (ttyp.equalsIgnoreCase("NONE"))
688 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
690 if (ttyp.equalsIgnoreCase("ABOVE"))
692 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
694 if (ttyp.equalsIgnoreCase("BELOW"))
696 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
699 fr.setColour(name = newcol.getName(), gcol);
703 fr.setColour(name = jucs.getColour(i).getName(), new Color(
704 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
706 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
711 Object[][] data = ((FeatureTableModel) table.getModel())
714 updateFeatureRenderer(data, false);
717 } catch (Exception ex)
719 System.out.println("Error loading User Colour File\n" + ex);
726 JalviewFileChooser chooser = new JalviewFileChooser(
727 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
728 { "fc" }, new String[]
729 { "Sequence Feature Colours" }, "Sequence Feature Colours");
730 chooser.setFileView(new jalview.io.JalviewFileView());
731 chooser.setDialogTitle("Save Feature Colour Scheme");
732 chooser.setToolTipText(MessageManager.getString("action.save"));
734 int value = chooser.showSaveDialog(this);
736 if (value == JalviewFileChooser.APPROVE_OPTION)
738 String choice = chooser.getSelectedFile().getPath();
739 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
740 ucs.setSchemeName("Sequence Features");
743 PrintWriter out = new PrintWriter(new OutputStreamWriter(
744 new FileOutputStream(choice), "UTF-8"));
746 Iterator e = fr.featureColours.keySet().iterator();
747 float[] sortOrder = new float[fr.featureColours.size()];
748 String[] sortTypes = new String[fr.featureColours.size()];
752 sortTypes[i] = e.next().toString();
753 sortOrder[i] = fr.getOrder(sortTypes[i]);
756 jalview.util.QuickSort.sort(sortOrder, sortTypes);
760 for (i = 0; i < sortTypes.length; i++)
762 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
763 col.setName(sortTypes[i]);
764 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
766 fcol = fr.getFeatureStyle(sortTypes[i]);
767 if (fcol instanceof GraduatedColor)
769 gcol = (GraduatedColor) fcol;
770 col.setMin(gcol.getMin());
771 col.setMax(gcol.getMax());
772 col.setMinRGB(jalview.util.Format.getHexString(gcol
774 col.setAutoScale(gcol.isAutoScale());
775 col.setThreshold(gcol.getThresh());
776 col.setColourByLabel(gcol.isColourByLabel());
777 switch (gcol.getThreshType())
779 case AnnotationColourGradient.NO_THRESHOLD:
780 col.setThreshType("NONE");
782 case AnnotationColourGradient.ABOVE_THRESHOLD:
783 col.setThreshType("ABOVE");
785 case AnnotationColourGradient.BELOW_THRESHOLD:
786 col.setThreshType("BELOW");
794 } catch (Exception ex)
796 ex.printStackTrace();
801 public void invertSelection()
803 for (int i = 0; i < table.getRowCount(); i++)
805 Boolean value = (Boolean) table.getValueAt(i, 2);
807 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
811 public void orderByAvWidth()
813 if (table == null || table.getModel() == null)
815 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
816 float[] width = new float[data.length];
820 for (int i = 0; i < data.length; i++)
822 awidth = (float[]) typeWidth.get(data[i][0]);
825 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
826 // weight - but have to make per
827 // sequence, too (awidth[2])
828 // if (width[i]==1) // hack to distinguish single width sequences.
838 boolean sort = false;
839 for (int i = 0; i < width.length; i++)
841 // awidth = (float[]) typeWidth.get(data[i][0]);
844 width[i] = fr.getOrder(data[i][0].toString());
847 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
852 width[i] /= max; // normalize
853 fr.setOrder(data[i][0].toString(), width[i]); // store for later
856 sort = sort || width[i - 1] > width[i];
859 jalview.util.QuickSort.sort(width, data);
860 // update global priority order
862 updateFeatureRenderer(data, false);
870 frame.setClosed(true);
871 } catch (Exception exe)
877 public void updateFeatureRenderer(Object[][] data)
879 updateFeatureRenderer(data, true);
882 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
884 fr.setFeaturePriority(data, visibleNew);
885 af.alignPanel.paintAlignment(true);
888 int selectedRow = -1;
890 JTabbedPane tabbedPane = new JTabbedPane();
892 BorderLayout borderLayout1 = new BorderLayout();
894 BorderLayout borderLayout2 = new BorderLayout();
896 BorderLayout borderLayout3 = new BorderLayout();
898 JPanel bigPanel = new JPanel();
900 BorderLayout borderLayout4 = new BorderLayout();
902 JButton invert = new JButton();
904 JPanel buttonPanel = new JPanel();
906 JButton cancel = new JButton();
908 JButton ok = new JButton();
910 JButton loadColours = new JButton();
912 JButton saveColours = new JButton();
914 JPanel dasButtonPanel = new JPanel();
916 JButton fetchDAS = new JButton();
918 JButton saveDAS = new JButton();
920 JButton cancelDAS = new JButton();
922 JButton optimizeOrder = new JButton();
924 JButton sortByScore = new JButton();
926 JButton sortByDens = new JButton();
928 JPanel transbuttons = new JPanel(new GridLayout(4, 1));
930 private void jbInit() throws Exception
932 this.setLayout(borderLayout1);
933 settingsPane.setLayout(borderLayout2);
934 dasSettingsPane.setLayout(borderLayout3);
935 bigPanel.setLayout(borderLayout4);
936 invert.setFont(JvSwingUtils.getLabelFont());
937 invert.setText(MessageManager.getString("label.invert_selection"));
938 invert.addActionListener(new ActionListener()
940 public void actionPerformed(ActionEvent e)
945 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
946 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
947 optimizeOrder.addActionListener(new ActionListener()
949 public void actionPerformed(ActionEvent e)
954 sortByScore.setFont(JvSwingUtils.getLabelFont());
955 sortByScore.setText(MessageManager.getString("label.seq_sort_by_score"));
956 sortByScore.addActionListener(new ActionListener()
958 public void actionPerformed(ActionEvent e)
963 sortByDens.setFont(JvSwingUtils.getLabelFont());
964 sortByDens.setText(MessageManager.getString("label.sequence_sort_by_density"));
965 sortByDens.addActionListener(new ActionListener()
967 public void actionPerformed(ActionEvent e)
972 cancel.setFont(JvSwingUtils.getLabelFont());
973 cancel.setText(MessageManager.getString("action.cancel"));
974 cancel.addActionListener(new ActionListener()
976 public void actionPerformed(ActionEvent e)
978 updateFeatureRenderer(originalData);
982 ok.setFont(JvSwingUtils.getLabelFont());
983 ok.setText(MessageManager.getString("action.ok"));
984 ok.addActionListener(new ActionListener()
986 public void actionPerformed(ActionEvent e)
991 loadColours.setFont(JvSwingUtils.getLabelFont());
992 loadColours.setText(MessageManager.getString("label.load_colours"));
993 loadColours.addActionListener(new ActionListener()
995 public void actionPerformed(ActionEvent e)
1000 saveColours.setFont(JvSwingUtils.getLabelFont());
1001 saveColours.setText(MessageManager.getString("label.save_colours"));
1002 saveColours.addActionListener(new ActionListener()
1004 public void actionPerformed(ActionEvent e)
1009 transparency.addChangeListener(new ChangeListener()
1011 public void stateChanged(ChangeEvent evt)
1013 fr.setTransparency((float) (100 - transparency.getValue()) / 100f);
1014 af.alignPanel.paintAlignment(true);
1018 transparency.setMaximum(70);
1019 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1020 fetchDAS.addActionListener(new ActionListener()
1022 public void actionPerformed(ActionEvent e)
1024 fetchDAS_actionPerformed(e);
1027 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1028 saveDAS.addActionListener(new ActionListener()
1030 public void actionPerformed(ActionEvent e)
1032 saveDAS_actionPerformed(e);
1035 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1036 dasSettingsPane.setBorder(null);
1037 cancelDAS.setEnabled(false);
1038 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1039 cancelDAS.addActionListener(new ActionListener()
1041 public void actionPerformed(ActionEvent e)
1043 cancelDAS_actionPerformed(e);
1046 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1047 tabbedPane.addTab("Feature Settings", settingsPane);
1048 tabbedPane.addTab("DAS Settings", dasSettingsPane);
1049 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1050 transbuttons.add(optimizeOrder);
1051 transbuttons.add(invert);
1052 transbuttons.add(sortByScore);
1053 transbuttons.add(sortByDens);
1054 transPanel.add(transparency);
1055 transPanel.add(transbuttons);
1056 buttonPanel.add(ok);
1057 buttonPanel.add(cancel);
1058 buttonPanel.add(loadColours);
1059 buttonPanel.add(saveColours);
1060 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1061 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1062 dasButtonPanel.add(fetchDAS);
1063 dasButtonPanel.add(cancelDAS);
1064 dasButtonPanel.add(saveDAS);
1065 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1066 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1069 protected void sortByDens(String[] typ)
1071 sortBy(typ, "Sort by Density", AlignmentSorter.FEATURE_DENSITY);
1074 protected void sortBy(String[] typ, String methodText, final String method)
1078 typ = getDisplayedFeatureTypes();
1080 String gps[] = null;
1081 gps = getDisplayedFeatureGroups();
1084 ArrayList types = new ArrayList();
1085 for (int i = 0; i < typ.length; i++)
1091 typ = new String[types.size()];
1097 ArrayList grps = new ArrayList();
1099 for (int i = 0; i < gps.length; i++)
1106 gps = new String[grps.size()];
1109 AlignmentPanel alignPanel = af.alignPanel;
1110 AlignmentI al = alignPanel.av.getAlignment();
1113 SequenceGroup sg = alignPanel.av.getSelectionGroup();
1116 start = sg.getStartRes();
1117 stop = sg.getEndRes();
1122 stop = al.getWidth();
1124 SequenceI[] oldOrder = al.getSequencesArray();
1125 AlignmentSorter.sortByFeature(typ, gps, start, stop, al, method);
1126 af.addHistoryItem(new OrderCommand(methodText, oldOrder, alignPanel.av
1128 alignPanel.paintAlignment(true);
1132 protected void sortByScore(String[] typ)
1134 sortBy(typ, "Sort by Feature Score", AlignmentSorter.FEATURE_SCORE);
1137 private String[] getDisplayedFeatureTypes()
1139 String[] typ = null;
1142 synchronized (fr.renderOrder)
1144 typ = new String[fr.renderOrder.length];
1145 System.arraycopy(fr.renderOrder, 0, typ, 0, typ.length);
1146 for (int i = 0; i < typ.length; i++)
1148 if (af.viewport.featuresDisplayed.get(typ[i]) == null)
1158 private String[] getDisplayedFeatureGroups()
1160 String[] gps = null;
1161 ArrayList<String> _gps = new ArrayList<String>();
1165 if (fr.featureGroups != null)
1167 Iterator en = fr.featureGroups.keySet().iterator();
1169 boolean valid = false;
1170 while (en.hasNext())
1172 String gp = (String) en.next();
1173 Boolean on = (Boolean) fr.featureGroups.get(gp);
1174 if (on != null && on.booleanValue())
1184 gps = new String[_gps.size()];
1192 public void fetchDAS_actionPerformed(ActionEvent e)
1194 fetchDAS.setEnabled(false);
1195 cancelDAS.setEnabled(true);
1196 dassourceBrowser.setGuiEnabled(false);
1197 Vector selectedSources = dassourceBrowser.getSelectedSources();
1198 doDasFeatureFetch(selectedSources, true, true);
1202 * get the features from selectedSources for all or the current selection
1204 * @param selectedSources
1205 * @param checkDbRefs
1206 * @param promptFetchDbRefs
1208 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1209 boolean checkDbRefs, boolean promptFetchDbRefs)
1211 SequenceI[] dataset, seqs;
1213 AlignViewport vp = af.getViewport();
1214 if (vp.getSelectionGroup() != null
1215 && vp.getSelectionGroup().getSize() > 0)
1217 iSize = vp.getSelectionGroup().getSize();
1218 dataset = new SequenceI[iSize];
1219 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1223 iSize = vp.getAlignment().getHeight();
1224 seqs = vp.getAlignment().getSequencesArray();
1227 dataset = new SequenceI[iSize];
1228 for (int i = 0; i < iSize; i++)
1230 dataset[i] = seqs[i].getDatasetSequence();
1233 cancelDAS.setEnabled(true);
1234 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1235 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1236 af.getViewport().setShowSequenceFeatures(true);
1237 af.showSeqFeatures.setSelected(true);
1241 * blocking call to initialise the das source browser
1243 public void initDasSources()
1245 dassourceBrowser.initDasSources();
1249 * examine the current list of das sources and return any matching the given
1250 * nicknames in sources
1253 * Vector of Strings to resolve to DAS source nicknames.
1254 * @return sources that are present in source list.
1256 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1258 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1262 * get currently selected das sources. ensure you have called initDasSources
1263 * before calling this.
1265 * @return vector of selected das source nicknames
1267 public Vector getSelectedSources()
1269 return dassourceBrowser.getSelectedSources();
1273 * properly initialise DAS fetcher and then initiate a new thread to fetch
1274 * features from the named sources (rather than any turned on by default)
1278 * if true then runs in same thread, otherwise passes to the Swing
1281 public void fetchDasFeatures(Vector sources, boolean block)
1284 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1285 .resolveSourceNicknames(sources);
1286 if (resolved.size() == 0)
1288 resolved = dassourceBrowser.getSelectedSources();
1290 if (resolved.size() > 0)
1292 final List<jalviewSourceI> dassources = resolved;
1293 fetchDAS.setEnabled(false);
1294 // cancelDAS.setEnabled(true); doDasFetch does this.
1295 Runnable fetcher = new Runnable()
1300 doDasFeatureFetch(dassources, true, false);
1310 SwingUtilities.invokeLater(fetcher);
1315 public void saveDAS_actionPerformed(ActionEvent e)
1318 .saveProperties(jalview.bin.Cache.applicationProperties);
1321 public void complete()
1323 fetchDAS.setEnabled(true);
1324 cancelDAS.setEnabled(false);
1325 dassourceBrowser.setGuiEnabled(true);
1329 public void cancelDAS_actionPerformed(ActionEvent e)
1331 if (dasFeatureFetcher != null)
1333 dasFeatureFetcher.cancel();
1338 public void noDasSourceActive()
1341 JOptionPane.showInternalConfirmDialog(Desktop.desktop,
1342 MessageManager.getString("label.no_das_sources_selected_warn"),
1343 MessageManager.getString("label.no_das_sources_selected_title"), JOptionPane.DEFAULT_OPTION,
1344 JOptionPane.INFORMATION_MESSAGE);
1347 // ///////////////////////////////////////////////////////////////////////
1348 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1349 // ///////////////////////////////////////////////////////////////////////
1350 class FeatureTableModel extends AbstractTableModel
1352 FeatureTableModel(Object[][] data)
1357 private String[] columnNames =
1358 { "Feature Type", "Colour", "Display" };
1360 private Object[][] data;
1362 public Object[][] getData()
1367 public void setData(Object[][] data)
1372 public int getColumnCount()
1374 return columnNames.length;
1377 public Object[] getRow(int row)
1382 public int getRowCount()
1387 public String getColumnName(int col)
1389 return columnNames[col];
1392 public Object getValueAt(int row, int col)
1394 return data[row][col];
1397 public Class getColumnClass(int c)
1399 return getValueAt(0, c).getClass();
1402 public boolean isCellEditable(int row, int col)
1404 return col == 0 ? false : true;
1407 public void setValueAt(Object value, int row, int col)
1409 data[row][col] = value;
1410 fireTableCellUpdated(row, col);
1411 updateFeatureRenderer(data);
1416 class ColorRenderer extends JLabel implements TableCellRenderer
1418 javax.swing.border.Border unselectedBorder = null;
1420 javax.swing.border.Border selectedBorder = null;
1422 final String baseTT = "Click to edit, right/apple click for menu.";
1424 public ColorRenderer()
1426 setOpaque(true); // MUST do this for background to show up.
1427 setHorizontalTextPosition(SwingConstants.CENTER);
1428 setVerticalTextPosition(SwingConstants.CENTER);
1431 public Component getTableCellRendererComponent(JTable table,
1432 Object color, boolean isSelected, boolean hasFocus, int row,
1435 // JLabel comp = new JLabel();
1439 // setBounds(getBounds());
1441 setToolTipText(baseTT);
1442 setBackground(table.getBackground());
1443 if (color instanceof GraduatedColor)
1445 Rectangle cr = table.getCellRect(row, column, false);
1446 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1447 (int) cr.getWidth(), (int) cr.getHeight());
1454 newColor = (Color) color;
1456 setBackground(newColor);
1457 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1458 // + newColor.getGreen() + ", " + newColor.getBlue());
1462 if (selectedBorder == null)
1464 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1465 table.getSelectionBackground());
1468 setBorder(selectedBorder);
1472 if (unselectedBorder == null)
1474 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1475 table.getBackground());
1478 setBorder(unselectedBorder);
1486 * update comp using rendering settings from gcol
1491 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1493 int w = comp.getWidth(), h = comp.getHeight();
1496 w = (int) comp.getPreferredSize().getWidth();
1497 h = (int) comp.getPreferredSize().getHeight();
1504 renderGraduatedColor(comp, gcol, w, h);
1507 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1510 boolean thr = false;
1513 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1517 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1519 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1523 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1525 if (gcol.isColourByLabel())
1527 tt = "Coloured by label text. " + tt;
1537 Color newColor = gcol.getMaxColor();
1538 comp.setBackground(newColor);
1539 // System.err.println("Width is " + w / 2);
1540 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1541 comp.setIcon(ficon);
1542 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1543 // + newColor.getGreen() + ", " + newColor.getBlue()
1544 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1545 // + ", " + minCol.getBlue() + ")");
1547 comp.setHorizontalAlignment(SwingConstants.CENTER);
1549 if (tt.length() > 0)
1551 if (comp.getToolTipText() == null)
1553 comp.setToolTipText(tt);
1557 comp.setToolTipText(tt + " " + comp.getToolTipText());
1563 class FeatureIcon implements Icon
1565 GraduatedColor gcol;
1569 boolean midspace = false;
1571 int width = 50, height = 20;
1573 int s1, e1; // start and end of midpoint band for thresholded symbol
1575 Color mpcolour = Color.white;
1577 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1596 public int getIconWidth()
1601 public int getIconHeight()
1606 public void paintIcon(Component c, Graphics g, int x, int y)
1609 if (gcol.isColourByLabel())
1612 g.fillRect(0, 0, width, height);
1613 // need an icon here.
1614 g.setColor(gcol.getMaxColor());
1616 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1618 // g.setFont(g.getFont().deriveFont(
1619 // AffineTransform.getScaleInstance(
1620 // width/g.getFontMetrics().stringWidth("Label"),
1621 // height/g.getFontMetrics().getHeight())));
1623 g.drawString(MessageManager.getString("label.label"), 0, 0);
1628 Color minCol = gcol.getMinColor();
1630 g.fillRect(0, 0, s1, height);
1633 g.setColor(Color.white);
1634 g.fillRect(s1, 0, e1 - s1, height);
1636 g.setColor(gcol.getMaxColor());
1637 g.fillRect(0, e1, width - e1, height);
1642 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1647 GraduatedColor currentGColor;
1649 FeatureColourChooser chooser;
1657 JColorChooser colorChooser;
1661 protected static final String EDIT = "edit";
1663 int selectedRow = 0;
1665 public ColorEditor(FeatureSettings me)
1668 // Set up the editor (from the table's point of view),
1669 // which is a button.
1670 // This button brings up the color chooser dialog,
1671 // which is the editor from the user's point of view.
1672 button = new JButton();
1673 button.setActionCommand(EDIT);
1674 button.addActionListener(this);
1675 button.setBorderPainted(false);
1676 // Set up the dialog that the button brings up.
1677 colorChooser = new JColorChooser();
1678 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1679 colorChooser, this, // OK button handler
1680 null); // no CANCEL button handler
1684 * Handles events from the editor button and from the dialog's OK button.
1686 public void actionPerformed(ActionEvent e)
1689 if (EDIT.equals(e.getActionCommand()))
1691 // The user has clicked the cell, so
1692 // bring up the dialog.
1693 if (currentColor != null)
1695 // bring up simple color chooser
1696 button.setBackground(currentColor);
1697 colorChooser.setColor(currentColor);
1698 dialog.setVisible(true);
1702 // bring up graduated chooser.
1703 chooser = new FeatureColourChooser(me.fr, type);
1704 chooser.setRequestFocusEnabled(true);
1705 chooser.requestFocus();
1706 chooser.addActionListener(this);
1708 // Make the renderer reappear.
1709 fireEditingStopped();
1713 { // User pressed dialog's "OK" button.
1714 if (currentColor != null)
1716 currentColor = colorChooser.getColor();
1720 // class cast exceptions may be raised if the chooser created on a
1721 // non-graduated color
1722 currentGColor = (GraduatedColor) chooser.getLastColour();
1724 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1725 fireEditingStopped();
1726 me.table.validate();
1730 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1731 public Object getCellEditorValue()
1733 if (currentColor == null)
1735 return currentGColor;
1737 return currentColor;
1740 // Implement the one method defined by TableCellEditor.
1741 public Component getTableCellEditorComponent(JTable table, Object value,
1742 boolean isSelected, int row, int column)
1744 currentGColor = null;
1745 currentColor = null;
1746 this.selectedRow = row;
1747 type = me.table.getValueAt(row, 0).toString();
1748 button.setOpaque(true);
1749 button.setBackground(me.getBackground());
1750 if (value instanceof GraduatedColor)
1752 currentGColor = (GraduatedColor) value;
1753 JLabel btn = new JLabel();
1754 btn.setSize(button.getSize());
1755 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1756 button.setBackground(btn.getBackground());
1757 button.setIcon(btn.getIcon());
1758 button.setText(btn.getText());
1763 button.setIcon(null);
1764 currentColor = (Color) value;
1765 button.setBackground(currentColor);