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.analysis.AlignmentSorter;
24 import jalview.bin.Cache;
25 import jalview.commands.OrderCommand;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.SequenceFeature;
28 import jalview.datamodel.SequenceGroup;
29 import jalview.datamodel.SequenceI;
30 import jalview.gui.Help.HelpId;
31 import jalview.io.JalviewFileChooser;
32 import jalview.schemes.AnnotationColourGradient;
33 import jalview.schemes.GraduatedColor;
34 import jalview.util.MessageManager;
35 import jalview.ws.dbsources.das.api.jalviewSourceI;
37 import java.awt.BorderLayout;
38 import java.awt.Color;
39 import java.awt.Component;
41 import java.awt.Graphics;
42 import java.awt.GridLayout;
43 import java.awt.Rectangle;
44 import java.awt.event.ActionEvent;
45 import java.awt.event.ActionListener;
46 import java.awt.event.ItemEvent;
47 import java.awt.event.ItemListener;
48 import java.awt.event.MouseAdapter;
49 import java.awt.event.MouseEvent;
50 import java.awt.event.MouseMotionAdapter;
51 import java.beans.PropertyChangeEvent;
52 import java.beans.PropertyChangeListener;
54 import java.io.FileInputStream;
55 import java.io.FileOutputStream;
56 import java.io.InputStreamReader;
57 import java.io.OutputStreamWriter;
58 import java.io.PrintWriter;
59 import java.util.ArrayList;
60 import java.util.Hashtable;
61 import java.util.Iterator;
62 import java.util.List;
63 import java.util.Vector;
65 import javax.help.HelpSetException;
66 import javax.swing.AbstractCellEditor;
67 import javax.swing.BorderFactory;
68 import javax.swing.Icon;
69 import javax.swing.JButton;
70 import javax.swing.JCheckBox;
71 import javax.swing.JCheckBoxMenuItem;
72 import javax.swing.JColorChooser;
73 import javax.swing.JDialog;
74 import javax.swing.JInternalFrame;
75 import javax.swing.JLabel;
76 import javax.swing.JLayeredPane;
77 import javax.swing.JMenuItem;
78 import javax.swing.JOptionPane;
79 import javax.swing.JPanel;
80 import javax.swing.JPopupMenu;
81 import javax.swing.JScrollPane;
82 import javax.swing.JSlider;
83 import javax.swing.JTabbedPane;
84 import javax.swing.JTable;
85 import javax.swing.ListSelectionModel;
86 import javax.swing.SwingConstants;
87 import javax.swing.SwingUtilities;
88 import javax.swing.event.ChangeEvent;
89 import javax.swing.event.ChangeListener;
90 import javax.swing.table.AbstractTableModel;
91 import javax.swing.table.TableCellEditor;
92 import javax.swing.table.TableCellRenderer;
94 public class FeatureSettings extends JPanel
96 DasSourceBrowser dassourceBrowser;
98 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
100 JPanel settingsPane = new JPanel();
102 JPanel dasSettingsPane = new JPanel();
104 final FeatureRenderer fr;
106 public final AlignFrame af;
108 Object[][] originalData;
110 final JInternalFrame frame;
112 JScrollPane scrollPane = new JScrollPane();
118 JSlider transparency = new JSlider();
120 JPanel transPanel = new JPanel(new GridLayout(1, 2));
122 public FeatureSettings(AlignFrame af)
125 fr = af.getFeatureRenderer();
127 transparency.setMaximum(100 - (int) (fr.transparency * 100));
132 } catch (Exception ex)
134 ex.printStackTrace();
137 table = new JTable() {
139 public String getToolTipText(MouseEvent e) {
140 if (table.columnAtPoint(e.getPoint()) == 0) {
142 * Tooltip for feature name only
144 return JvSwingUtils.wrapTooltip(true,
145 MessageManager.getString("label.feature_settings_click_drag"));
150 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
151 table.setFont(new Font("Verdana", Font.PLAIN, 12));
152 table.setDefaultRenderer(Color.class, new ColorRenderer());
154 table.setDefaultEditor(Color.class, new ColorEditor(this));
156 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
157 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
158 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
160 table.addMouseListener(new MouseAdapter()
162 public void mousePressed(MouseEvent evt)
164 selectedRow = table.rowAtPoint(evt.getPoint());
165 if (SwingUtilities.isRightMouseButton(evt))
167 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
168 table.getValueAt(selectedRow, 1), fr.minmax, evt.getX(),
171 else if (evt.getClickCount() == 2)
173 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
174 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
176 (String) table.getValueAt(selectedRow, 0));
180 // isPopupTrigger fires on mouseReleased on Mac
182 public void mouseReleased(MouseEvent evt)
184 selectedRow = table.rowAtPoint(evt.getPoint());
185 if (evt.isPopupTrigger())
187 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
188 table.getValueAt(selectedRow, 1), fr.minmax, evt.getX(),
194 table.addMouseMotionListener(new MouseMotionAdapter()
196 public void mouseDragged(MouseEvent evt)
198 int newRow = table.rowAtPoint(evt.getPoint());
199 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
201 Object[] temp = new Object[3];
202 temp[0] = table.getValueAt(selectedRow, 0);
203 temp[1] = table.getValueAt(selectedRow, 1);
204 temp[2] = table.getValueAt(selectedRow, 2);
206 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
207 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
208 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
210 table.setValueAt(temp[0], newRow, 0);
211 table.setValueAt(temp[1], newRow, 1);
212 table.setValueAt(temp[2], newRow, 2);
214 selectedRow = newRow;
218 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
219 // MessageManager.getString("label.feature_settings_click_drag")));
220 scrollPane.setViewportView(table);
222 dassourceBrowser = new DasSourceBrowser(this);
223 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
225 if (af.getViewport().featuresDisplayed == null
226 || fr.renderOrder == null)
228 fr.findAllFeatures(true); // display everything!
232 final PropertyChangeListener change;
233 final FeatureSettings fs = this;
234 fr.addPropertyChangeListener(change = new PropertyChangeListener()
236 public void propertyChange(PropertyChangeEvent evt)
238 if (!fs.resettingTable && !fs.handlingUpdate)
240 fs.handlingUpdate = true;
241 fs.resetTable(null); // new groups may be added with new seuqence
242 // feature types only
243 fs.handlingUpdate = false;
249 frame = new JInternalFrame();
250 frame.setContentPane(this);
251 if (new jalview.util.Platform().isAMac())
253 Desktop.addInternalFrame(frame,
254 MessageManager.getString("label.sequence_feature_settings"),
259 Desktop.addInternalFrame(frame,
260 MessageManager.getString("label.sequence_feature_settings"),
264 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
266 public void internalFrameClosed(
267 javax.swing.event.InternalFrameEvent evt)
269 fr.removePropertyChangeListener(change);
270 dassourceBrowser.fs = null;
273 frame.setLayer(JLayeredPane.PALETTE_LAYER);
276 protected void popupSort(final int selectedRow, final String type,
277 final Object typeCol, final Hashtable minmax, int x, int y)
279 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
280 "label.settings_for_param", new String[]
282 JMenuItem scr = new JMenuItem(
283 MessageManager.getString("label.sort_by_score"));
285 final FeatureSettings me = this;
286 scr.addActionListener(new ActionListener()
289 public void actionPerformed(ActionEvent e)
291 me.sortByScore(new String[]
296 JMenuItem dens = new JMenuItem(
297 MessageManager.getString("label.sort_by_density"));
298 dens.addActionListener(new ActionListener()
301 public void actionPerformed(ActionEvent e)
303 me.sortByDens(new String[]
311 final Object typeMinMax = minmax.get(type);
313 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
314 * this is broken at the moment and isn't that useful anyway!
315 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
318 * public void actionPerformed(ActionEvent e) {
319 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
320 * null); } else { minmax.put(type, typeMinMax); } }
326 if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
328 // if (table.getValueAt(row, column));
329 // graduated colourschemes for those where minmax exists for the
330 // positional features
331 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
333 mxcol.setSelected(!(typeCol instanceof Color));
335 mxcol.addActionListener(new ActionListener()
337 JColorChooser colorChooser;
339 public void actionPerformed(ActionEvent e)
341 if (e.getSource() == mxcol)
343 if (typeCol instanceof Color)
345 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
347 fc.addActionListener(this);
351 // bring up simple color chooser
352 colorChooser = new JColorChooser();
353 JDialog dialog = JColorChooser.createDialog(me,
354 "Select new Colour", true, // modal
355 colorChooser, this, // OK button handler
356 null); // no CANCEL button handler
357 colorChooser.setColor(((GraduatedColor) typeCol)
359 dialog.setVisible(true);
364 if (e.getSource() instanceof FeatureColourChooser)
366 FeatureColourChooser fc = (FeatureColourChooser) e
368 table.setValueAt(fc.getLastColour(), selectedRow, 1);
373 // probably the color chooser!
374 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
376 me.updateFeatureRenderer(
377 ((FeatureTableModel) table.getModel()).getData(),
386 JMenuItem selCols = new JMenuItem(
387 MessageManager.getString("label.select_columns_containing"));
388 selCols.addActionListener(new ActionListener()
392 public void actionPerformed(ActionEvent arg0)
394 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
398 JMenuItem clearCols = new JMenuItem(
399 MessageManager.getString("label.select_columns_not_containing"));
400 clearCols.addActionListener(new ActionListener()
404 public void actionPerformed(ActionEvent arg0)
406 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
412 men.show(table, x, y);
416 * true when Feature Settings are updating from feature renderer
418 private boolean handlingUpdate = false;
421 * contains a float[3] for each feature type string. created by setTableData
423 Hashtable typeWidth = null;
425 synchronized public void setTableData()
427 if (fr.featureGroups == null)
429 fr.featureGroups = new Hashtable();
431 Vector allFeatures = new Vector();
432 Vector allGroups = new Vector();
433 SequenceFeature[] tmpfeatures;
435 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
437 if (af.getViewport().getAlignment().getSequenceAt(i)
438 .getDatasetSequence().getSequenceFeatures() == null)
443 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
444 .getDatasetSequence().getSequenceFeatures();
447 while (index < tmpfeatures.length)
449 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
455 if (tmpfeatures[index].getFeatureGroup() != null)
457 group = tmpfeatures[index].featureGroup;
458 if (!allGroups.contains(group))
460 allGroups.addElement(group);
463 checkGroupState(group);
468 if (!allFeatures.contains(tmpfeatures[index].getType()))
470 allFeatures.addElement(tmpfeatures[index].getType());
484 * @return true if group has been seen before and is already added to set.
486 private boolean checkGroupState(String group)
489 if (fr.featureGroups.containsKey(group))
491 visible = ((Boolean) fr.featureGroups.get(group)).booleanValue();
495 visible = true; // new group is always made visible
498 if (groupPanel == null)
500 groupPanel = new JPanel();
503 boolean alreadyAdded = false;
504 for (int g = 0; g < groupPanel.getComponentCount(); g++)
506 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
509 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
520 fr.featureGroups.put(group, new Boolean(visible));
521 final String grp = group;
522 final JCheckBox check = new JCheckBox(group, visible);
523 check.setFont(new Font("Serif", Font.BOLD, 12));
524 check.addItemListener(new ItemListener()
526 public void itemStateChanged(ItemEvent evt)
528 fr.featureGroups.put(check.getText(),
529 new Boolean(check.isSelected()));
530 af.alignPanel.seqPanel.seqCanvas.repaint();
531 if (af.alignPanel.overviewPanel != null)
533 af.alignPanel.overviewPanel.updateOverviewImage();
536 resetTable(new String[]
540 groupPanel.add(check);
544 boolean resettingTable = false;
546 synchronized void resetTable(String[] groupChanged)
548 if (resettingTable == true)
552 resettingTable = true;
553 typeWidth = new Hashtable();
554 // TODO: change avWidth calculation to 'per-sequence' average and use long
556 float[] avWidth = null;
557 SequenceFeature[] tmpfeatures;
558 String group = null, type;
559 Vector visibleChecks = new Vector();
561 // Find out which features should be visible depending on which groups
562 // are selected / deselected
563 // and recompute average width ordering
564 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
567 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
568 .getDatasetSequence().getSequenceFeatures();
569 if (tmpfeatures == null)
575 while (index < tmpfeatures.length)
577 group = tmpfeatures[index].featureGroup;
579 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
585 if (group == null || fr.featureGroups.get(group) == null
586 || ((Boolean) fr.featureGroups.get(group)).booleanValue())
590 checkGroupState(group);
592 type = tmpfeatures[index].getType();
593 if (!visibleChecks.contains(type))
595 visibleChecks.addElement(type);
598 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
600 typeWidth.put(tmpfeatures[index].getType(),
601 avWidth = new float[3]);
605 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
608 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
610 avWidth[1] += 1 + tmpfeatures[index].getBegin()
611 - tmpfeatures[index].getEnd();
615 avWidth[1] += 1 + tmpfeatures[index].getEnd()
616 - tmpfeatures[index].getBegin();
622 int fSize = visibleChecks.size();
623 Object[][] data = new Object[fSize][3];
626 if (fr.renderOrder != null)
630 fr.findAllFeatures(groupChanged != null); // prod to update
632 // colourschemes. but don't
634 // First add the checks in the previous render order,
635 // in case the window has been closed and reopened
636 for (int ro = fr.renderOrder.length - 1; ro > -1; ro--)
638 type = fr.renderOrder[ro];
640 if (!visibleChecks.contains(type))
645 data[dataIndex][0] = type;
646 data[dataIndex][1] = fr.getFeatureStyle(type);
647 data[dataIndex][2] = new Boolean(
648 af.getViewport().featuresDisplayed.containsKey(type));
650 visibleChecks.removeElement(type);
654 fSize = visibleChecks.size();
655 for (int i = 0; i < fSize; i++)
657 // These must be extra features belonging to the group
658 // which was just selected
659 type = visibleChecks.elementAt(i).toString();
660 data[dataIndex][0] = type;
662 data[dataIndex][1] = fr.getFeatureStyle(type);
663 if (data[dataIndex][1] == null)
665 // "Colour has been updated in another view!!"
666 fr.renderOrder = null;
670 data[dataIndex][2] = new Boolean(true);
674 if (originalData == null)
676 originalData = new Object[data.length][3];
677 for (int i = 0; i < data.length; i++)
679 System.arraycopy(data[i], 0, originalData[i], 0, 3);
683 table.setModel(new FeatureTableModel(data));
684 table.getColumnModel().getColumn(0).setPreferredWidth(200);
686 if (groupPanel != null)
688 groupPanel.setLayout(new GridLayout(fr.featureGroups.size() / 4 + 1,
691 groupPanel.validate();
692 bigPanel.add(groupPanel, BorderLayout.NORTH);
695 updateFeatureRenderer(data, groupChanged != null);
696 resettingTable = false;
700 * reorder data based on the featureRenderers global priority list.
704 private void ensureOrder(Object[][] data)
706 boolean sort = false;
707 float[] order = new float[data.length];
708 for (int i = 0; i < order.length; i++)
710 order[i] = fr.getOrder(data[i][0].toString());
713 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
717 sort = sort || order[i - 1] > order[i];
722 jalview.util.QuickSort.sort(order, data);
728 JalviewFileChooser chooser = new JalviewFileChooser(
729 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
730 { "fc" }, new String[]
731 { "Sequence Feature Colours" }, "Sequence Feature Colours");
732 chooser.setFileView(new jalview.io.JalviewFileView());
733 chooser.setDialogTitle(MessageManager.getString("label.load_feature_colours"));
734 chooser.setToolTipText(MessageManager.getString("action.load"));
736 int value = chooser.showOpenDialog(this);
738 if (value == JalviewFileChooser.APPROVE_OPTION)
740 File file = chooser.getSelectedFile();
744 InputStreamReader in = new InputStreamReader(new FileInputStream(
747 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
751 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
754 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
757 Color mincol = null, maxcol = null;
760 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
761 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
763 } catch (Exception e)
765 Cache.log.warn("Couldn't parse out graduated feature color.",
768 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
769 newcol.getMin(), newcol.getMax());
770 if (newcol.hasAutoScale())
772 gcol.setAutoScaled(newcol.getAutoScale());
774 if (newcol.hasColourByLabel())
776 gcol.setColourByLabel(newcol.getColourByLabel());
778 if (newcol.hasThreshold())
780 gcol.setThresh(newcol.getThreshold());
781 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
783 if (newcol.getThreshType().length() > 0)
785 String ttyp = newcol.getThreshType();
786 if (ttyp.equalsIgnoreCase("NONE"))
788 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
790 if (ttyp.equalsIgnoreCase("ABOVE"))
792 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
794 if (ttyp.equalsIgnoreCase("BELOW"))
796 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
799 fr.setColour(name = newcol.getName(), gcol);
803 fr.setColour(name = jucs.getColour(i).getName(), new Color(
804 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
806 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
811 Object[][] data = ((FeatureTableModel) table.getModel())
814 updateFeatureRenderer(data, false);
817 } catch (Exception ex)
819 System.out.println("Error loading User Colour File\n" + ex);
826 JalviewFileChooser chooser = new JalviewFileChooser(
827 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
828 { "fc" }, new String[]
829 { "Sequence Feature Colours" }, "Sequence Feature Colours");
830 chooser.setFileView(new jalview.io.JalviewFileView());
831 chooser.setDialogTitle(MessageManager.getString("label.save_feature_colours"));
832 chooser.setToolTipText(MessageManager.getString("action.save"));
834 int value = chooser.showSaveDialog(this);
836 if (value == JalviewFileChooser.APPROVE_OPTION)
838 String choice = chooser.getSelectedFile().getPath();
839 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
840 ucs.setSchemeName("Sequence Features");
843 PrintWriter out = new PrintWriter(new OutputStreamWriter(
844 new FileOutputStream(choice), "UTF-8"));
846 Iterator e = fr.featureColours.keySet().iterator();
847 float[] sortOrder = new float[fr.featureColours.size()];
848 String[] sortTypes = new String[fr.featureColours.size()];
852 sortTypes[i] = e.next().toString();
853 sortOrder[i] = fr.getOrder(sortTypes[i]);
856 jalview.util.QuickSort.sort(sortOrder, sortTypes);
860 for (i = 0; i < sortTypes.length; i++)
862 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
863 col.setName(sortTypes[i]);
864 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
866 fcol = fr.getFeatureStyle(sortTypes[i]);
867 if (fcol instanceof GraduatedColor)
869 gcol = (GraduatedColor) fcol;
870 col.setMin(gcol.getMin());
871 col.setMax(gcol.getMax());
872 col.setMinRGB(jalview.util.Format.getHexString(gcol
874 col.setAutoScale(gcol.isAutoScale());
875 col.setThreshold(gcol.getThresh());
876 col.setColourByLabel(gcol.isColourByLabel());
877 switch (gcol.getThreshType())
879 case AnnotationColourGradient.NO_THRESHOLD:
880 col.setThreshType("NONE");
882 case AnnotationColourGradient.ABOVE_THRESHOLD:
883 col.setThreshType("ABOVE");
885 case AnnotationColourGradient.BELOW_THRESHOLD:
886 col.setThreshType("BELOW");
894 } catch (Exception ex)
896 ex.printStackTrace();
901 public void invertSelection()
903 for (int i = 0; i < table.getRowCount(); i++)
905 Boolean value = (Boolean) table.getValueAt(i, 2);
907 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
911 public void orderByAvWidth()
913 if (table == null || table.getModel() == null)
917 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
918 float[] width = new float[data.length];
922 for (int i = 0; i < data.length; i++)
924 awidth = (float[]) typeWidth.get(data[i][0]);
927 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
928 // weight - but have to make per
929 // sequence, too (awidth[2])
930 // if (width[i]==1) // hack to distinguish single width sequences.
942 boolean sort = false;
943 for (int i = 0; i < width.length; i++)
945 // awidth = (float[]) typeWidth.get(data[i][0]);
948 width[i] = fr.getOrder(data[i][0].toString());
951 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
956 width[i] /= max; // normalize
957 fr.setOrder(data[i][0].toString(), width[i]); // store for later
961 sort = sort || width[i - 1] > width[i];
966 jalview.util.QuickSort.sort(width, data);
967 // update global priority order
970 updateFeatureRenderer(data, false);
978 frame.setClosed(true);
979 } catch (Exception exe)
985 public void updateFeatureRenderer(Object[][] data)
987 updateFeatureRenderer(data, true);
990 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
992 fr.setFeaturePriority(data, visibleNew);
993 af.alignPanel.paintAlignment(true);
996 int selectedRow = -1;
998 JTabbedPane tabbedPane = new JTabbedPane();
1000 BorderLayout borderLayout1 = new BorderLayout();
1002 BorderLayout borderLayout2 = new BorderLayout();
1004 BorderLayout borderLayout3 = new BorderLayout();
1006 JPanel bigPanel = new JPanel();
1008 BorderLayout borderLayout4 = new BorderLayout();
1010 JButton invert = new JButton();
1012 JPanel buttonPanel = new JPanel();
1014 JButton cancel = new JButton();
1016 JButton ok = new JButton();
1018 JButton loadColours = new JButton();
1020 JButton saveColours = new JButton();
1022 JPanel dasButtonPanel = new JPanel();
1024 JButton fetchDAS = new JButton();
1026 JButton saveDAS = new JButton();
1028 JButton cancelDAS = new JButton();
1030 JButton optimizeOrder = new JButton();
1032 JButton sortByScore = new JButton();
1034 JButton sortByDens = new JButton();
1036 JButton help = new JButton();
1038 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1040 private void jbInit() throws Exception
1042 this.setLayout(borderLayout1);
1043 settingsPane.setLayout(borderLayout2);
1044 dasSettingsPane.setLayout(borderLayout3);
1045 bigPanel.setLayout(borderLayout4);
1046 invert.setFont(JvSwingUtils.getLabelFont());
1047 invert.setText(MessageManager.getString("label.invert_selection"));
1048 invert.addActionListener(new ActionListener()
1050 public void actionPerformed(ActionEvent e)
1055 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1056 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1057 optimizeOrder.addActionListener(new ActionListener()
1059 public void actionPerformed(ActionEvent e)
1064 sortByScore.setFont(JvSwingUtils.getLabelFont());
1066 .setText(MessageManager.getString("label.seq_sort_by_score"));
1067 sortByScore.addActionListener(new ActionListener()
1069 public void actionPerformed(ActionEvent e)
1074 sortByDens.setFont(JvSwingUtils.getLabelFont());
1075 sortByDens.setText(MessageManager
1076 .getString("label.sequence_sort_by_density"));
1077 sortByDens.addActionListener(new ActionListener()
1079 public void actionPerformed(ActionEvent e)
1084 help.setFont(JvSwingUtils.getLabelFont());
1085 help.setText(MessageManager.getString("action.help"));
1086 help.addActionListener(new ActionListener()
1088 public void actionPerformed(ActionEvent e)
1092 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1093 } catch (HelpSetException e1)
1095 e1.printStackTrace();
1099 cancel.setFont(JvSwingUtils.getLabelFont());
1100 cancel.setText(MessageManager.getString("action.cancel"));
1101 cancel.addActionListener(new ActionListener()
1103 public void actionPerformed(ActionEvent e)
1105 updateFeatureRenderer(originalData);
1109 ok.setFont(JvSwingUtils.getLabelFont());
1110 ok.setText(MessageManager.getString("action.ok"));
1111 ok.addActionListener(new ActionListener()
1113 public void actionPerformed(ActionEvent e)
1118 loadColours.setFont(JvSwingUtils.getLabelFont());
1119 loadColours.setText(MessageManager.getString("label.load_colours"));
1120 loadColours.addActionListener(new ActionListener()
1122 public void actionPerformed(ActionEvent e)
1127 saveColours.setFont(JvSwingUtils.getLabelFont());
1128 saveColours.setText(MessageManager.getString("label.save_colours"));
1129 saveColours.addActionListener(new ActionListener()
1131 public void actionPerformed(ActionEvent e)
1136 transparency.addChangeListener(new ChangeListener()
1138 public void stateChanged(ChangeEvent evt)
1140 fr.setTransparency((100 - transparency.getValue()) / 100f);
1141 af.alignPanel.paintAlignment(true);
1145 transparency.setMaximum(70);
1146 transparency.setToolTipText(MessageManager
1147 .getString("label.transparency_tip"));
1148 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1149 fetchDAS.addActionListener(new ActionListener()
1151 public void actionPerformed(ActionEvent e)
1153 fetchDAS_actionPerformed(e);
1156 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1157 saveDAS.addActionListener(new ActionListener()
1159 public void actionPerformed(ActionEvent e)
1161 saveDAS_actionPerformed(e);
1164 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1165 dasSettingsPane.setBorder(null);
1166 cancelDAS.setEnabled(false);
1167 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1168 cancelDAS.addActionListener(new ActionListener()
1170 public void actionPerformed(ActionEvent e)
1172 cancelDAS_actionPerformed(e);
1175 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1176 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1177 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1178 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1179 transbuttons.add(optimizeOrder);
1180 transbuttons.add(invert);
1181 transbuttons.add(sortByScore);
1182 transbuttons.add(sortByDens);
1183 transbuttons.add(help);
1184 JPanel sliderPanel = new JPanel();
1185 sliderPanel.add(transparency);
1186 transPanel.add(transparency);
1187 transPanel.add(transbuttons);
1188 buttonPanel.add(ok);
1189 buttonPanel.add(cancel);
1190 buttonPanel.add(loadColours);
1191 buttonPanel.add(saveColours);
1192 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1193 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1194 dasButtonPanel.add(fetchDAS);
1195 dasButtonPanel.add(cancelDAS);
1196 dasButtonPanel.add(saveDAS);
1197 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1198 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1201 protected void sortByDens(String[] typ)
1203 sortBy(typ, "Sort by Density", AlignmentSorter.FEATURE_DENSITY);
1206 protected void sortBy(String[] typ, String methodText, final String method)
1210 typ = getDisplayedFeatureTypes();
1212 String gps[] = null;
1213 gps = getDisplayedFeatureGroups();
1216 ArrayList types = new ArrayList();
1217 for (int i = 0; i < typ.length; i++)
1223 typ = new String[types.size()];
1229 ArrayList grps = new ArrayList();
1231 for (int i = 0; i < gps.length; i++)
1238 gps = new String[grps.size()];
1241 AlignmentPanel alignPanel = af.alignPanel;
1242 AlignmentI al = alignPanel.av.getAlignment();
1245 SequenceGroup sg = alignPanel.av.getSelectionGroup();
1248 start = sg.getStartRes();
1249 stop = sg.getEndRes();
1254 stop = al.getWidth();
1256 SequenceI[] oldOrder = al.getSequencesArray();
1257 AlignmentSorter.sortByFeature(typ, gps, start, stop, al, method);
1258 af.addHistoryItem(new OrderCommand(methodText, oldOrder, alignPanel.av
1260 alignPanel.paintAlignment(true);
1264 protected void sortByScore(String[] typ)
1266 sortBy(typ, "Sort by Feature Score", AlignmentSorter.FEATURE_SCORE);
1269 private String[] getDisplayedFeatureTypes()
1271 String[] typ = null;
1274 synchronized (fr.renderOrder)
1276 typ = new String[fr.renderOrder.length];
1277 System.arraycopy(fr.renderOrder, 0, typ, 0, typ.length);
1278 for (int i = 0; i < typ.length; i++)
1280 if (af.viewport.featuresDisplayed.get(typ[i]) == null)
1290 private String[] getDisplayedFeatureGroups()
1292 String[] gps = null;
1293 ArrayList<String> _gps = new ArrayList<String>();
1297 if (fr.featureGroups != null)
1299 Iterator en = fr.featureGroups.keySet().iterator();
1301 boolean valid = false;
1302 while (en.hasNext())
1304 String gp = (String) en.next();
1305 Boolean on = (Boolean) fr.featureGroups.get(gp);
1306 if (on != null && on.booleanValue())
1318 gps = new String[_gps.size()];
1326 public void fetchDAS_actionPerformed(ActionEvent e)
1328 fetchDAS.setEnabled(false);
1329 cancelDAS.setEnabled(true);
1330 dassourceBrowser.setGuiEnabled(false);
1331 Vector selectedSources = dassourceBrowser.getSelectedSources();
1332 doDasFeatureFetch(selectedSources, true, true);
1336 * get the features from selectedSources for all or the current selection
1338 * @param selectedSources
1339 * @param checkDbRefs
1340 * @param promptFetchDbRefs
1342 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1343 boolean checkDbRefs, boolean promptFetchDbRefs)
1345 SequenceI[] dataset, seqs;
1347 AlignViewport vp = af.getViewport();
1348 if (vp.getSelectionGroup() != null
1349 && vp.getSelectionGroup().getSize() > 0)
1351 iSize = vp.getSelectionGroup().getSize();
1352 dataset = new SequenceI[iSize];
1353 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1357 iSize = vp.getAlignment().getHeight();
1358 seqs = vp.getAlignment().getSequencesArray();
1361 dataset = new SequenceI[iSize];
1362 for (int i = 0; i < iSize; i++)
1364 dataset[i] = seqs[i].getDatasetSequence();
1367 cancelDAS.setEnabled(true);
1368 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1369 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1370 af.getViewport().setShowSequenceFeatures(true);
1371 af.showSeqFeatures.setSelected(true);
1375 * blocking call to initialise the das source browser
1377 public void initDasSources()
1379 dassourceBrowser.initDasSources();
1383 * examine the current list of das sources and return any matching the given
1384 * nicknames in sources
1387 * Vector of Strings to resolve to DAS source nicknames.
1388 * @return sources that are present in source list.
1390 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1392 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1396 * get currently selected das sources. ensure you have called initDasSources
1397 * before calling this.
1399 * @return vector of selected das source nicknames
1401 public Vector getSelectedSources()
1403 return dassourceBrowser.getSelectedSources();
1407 * properly initialise DAS fetcher and then initiate a new thread to fetch
1408 * features from the named sources (rather than any turned on by default)
1412 * if true then runs in same thread, otherwise passes to the Swing
1415 public void fetchDasFeatures(Vector sources, boolean block)
1418 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1419 .resolveSourceNicknames(sources);
1420 if (resolved.size() == 0)
1422 resolved = dassourceBrowser.getSelectedSources();
1424 if (resolved.size() > 0)
1426 final List<jalviewSourceI> dassources = resolved;
1427 fetchDAS.setEnabled(false);
1428 // cancelDAS.setEnabled(true); doDasFetch does this.
1429 Runnable fetcher = new Runnable()
1434 doDasFeatureFetch(dassources, true, false);
1444 SwingUtilities.invokeLater(fetcher);
1449 public void saveDAS_actionPerformed(ActionEvent e)
1452 .saveProperties(jalview.bin.Cache.applicationProperties);
1455 public void complete()
1457 fetchDAS.setEnabled(true);
1458 cancelDAS.setEnabled(false);
1459 dassourceBrowser.setGuiEnabled(true);
1463 public void cancelDAS_actionPerformed(ActionEvent e)
1465 if (dasFeatureFetcher != null)
1467 dasFeatureFetcher.cancel();
1472 public void noDasSourceActive()
1476 .showInternalConfirmDialog(
1479 .getString("label.no_das_sources_selected_warn"),
1481 .getString("label.no_das_sources_selected_title"),
1482 JOptionPane.DEFAULT_OPTION,
1483 JOptionPane.INFORMATION_MESSAGE);
1486 // ///////////////////////////////////////////////////////////////////////
1487 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1488 // ///////////////////////////////////////////////////////////////////////
1489 class FeatureTableModel extends AbstractTableModel
1491 FeatureTableModel(Object[][] data)
1496 private String[] columnNames =
1497 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1499 private Object[][] data;
1501 public Object[][] getData()
1506 public void setData(Object[][] data)
1511 public int getColumnCount()
1513 return columnNames.length;
1516 public Object[] getRow(int row)
1521 public int getRowCount()
1526 public String getColumnName(int col)
1528 return columnNames[col];
1531 public Object getValueAt(int row, int col)
1533 return data[row][col];
1536 public Class getColumnClass(int c)
1538 return getValueAt(0, c).getClass();
1541 public boolean isCellEditable(int row, int col)
1543 return col == 0 ? false : true;
1546 public void setValueAt(Object value, int row, int col)
1548 data[row][col] = value;
1549 fireTableCellUpdated(row, col);
1550 updateFeatureRenderer(data);
1555 class ColorRenderer extends JLabel implements TableCellRenderer
1557 javax.swing.border.Border unselectedBorder = null;
1559 javax.swing.border.Border selectedBorder = null;
1561 final String baseTT = "Click to edit, right/apple click for menu.";
1563 public ColorRenderer()
1565 setOpaque(true); // MUST do this for background to show up.
1566 setHorizontalTextPosition(SwingConstants.CENTER);
1567 setVerticalTextPosition(SwingConstants.CENTER);
1570 public Component getTableCellRendererComponent(JTable table,
1571 Object color, boolean isSelected, boolean hasFocus, int row,
1574 // JLabel comp = new JLabel();
1578 // setBounds(getBounds());
1580 setToolTipText(baseTT);
1581 setBackground(table.getBackground());
1582 if (color instanceof GraduatedColor)
1584 Rectangle cr = table.getCellRect(row, column, false);
1585 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1586 (int) cr.getWidth(), (int) cr.getHeight());
1593 newColor = (Color) color;
1595 setBackground(newColor);
1596 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1597 // + newColor.getGreen() + ", " + newColor.getBlue());
1601 if (selectedBorder == null)
1603 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1604 table.getSelectionBackground());
1607 setBorder(selectedBorder);
1611 if (unselectedBorder == null)
1613 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1614 table.getBackground());
1617 setBorder(unselectedBorder);
1625 * update comp using rendering settings from gcol
1630 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1632 int w = comp.getWidth(), h = comp.getHeight();
1635 w = (int) comp.getPreferredSize().getWidth();
1636 h = (int) comp.getPreferredSize().getHeight();
1643 renderGraduatedColor(comp, gcol, w, h);
1646 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1649 boolean thr = false;
1652 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1656 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1658 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1662 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1664 if (gcol.isColourByLabel())
1666 tt = "Coloured by label text. " + tt;
1676 Color newColor = gcol.getMaxColor();
1677 comp.setBackground(newColor);
1678 // System.err.println("Width is " + w / 2);
1679 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1680 comp.setIcon(ficon);
1681 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1682 // + newColor.getGreen() + ", " + newColor.getBlue()
1683 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1684 // + ", " + minCol.getBlue() + ")");
1686 comp.setHorizontalAlignment(SwingConstants.CENTER);
1688 if (tt.length() > 0)
1690 if (comp.getToolTipText() == null)
1692 comp.setToolTipText(tt);
1696 comp.setToolTipText(tt + " " + comp.getToolTipText());
1702 class FeatureIcon implements Icon
1704 GraduatedColor gcol;
1708 boolean midspace = false;
1710 int width = 50, height = 20;
1712 int s1, e1; // start and end of midpoint band for thresholded symbol
1714 Color mpcolour = Color.white;
1716 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1735 public int getIconWidth()
1740 public int getIconHeight()
1745 public void paintIcon(Component c, Graphics g, int x, int y)
1748 if (gcol.isColourByLabel())
1751 g.fillRect(0, 0, width, height);
1752 // need an icon here.
1753 g.setColor(gcol.getMaxColor());
1755 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1757 // g.setFont(g.getFont().deriveFont(
1758 // AffineTransform.getScaleInstance(
1759 // width/g.getFontMetrics().stringWidth("Label"),
1760 // height/g.getFontMetrics().getHeight())));
1762 g.drawString(MessageManager.getString("label.label"), 0, 0);
1767 Color minCol = gcol.getMinColor();
1769 g.fillRect(0, 0, s1, height);
1772 g.setColor(Color.white);
1773 g.fillRect(s1, 0, e1 - s1, height);
1775 g.setColor(gcol.getMaxColor());
1776 g.fillRect(0, e1, width - e1, height);
1781 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1786 GraduatedColor currentGColor;
1788 FeatureColourChooser chooser;
1796 JColorChooser colorChooser;
1800 protected static final String EDIT = "edit";
1802 int selectedRow = 0;
1804 public ColorEditor(FeatureSettings me)
1807 // Set up the editor (from the table's point of view),
1808 // which is a button.
1809 // This button brings up the color chooser dialog,
1810 // which is the editor from the user's point of view.
1811 button = new JButton();
1812 button.setActionCommand(EDIT);
1813 button.addActionListener(this);
1814 button.setBorderPainted(false);
1815 // Set up the dialog that the button brings up.
1816 colorChooser = new JColorChooser();
1817 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1818 colorChooser, this, // OK button handler
1819 null); // no CANCEL button handler
1823 * Handles events from the editor button and from the dialog's OK button.
1825 public void actionPerformed(ActionEvent e)
1828 if (EDIT.equals(e.getActionCommand()))
1830 // The user has clicked the cell, so
1831 // bring up the dialog.
1832 if (currentColor != null)
1834 // bring up simple color chooser
1835 button.setBackground(currentColor);
1836 colorChooser.setColor(currentColor);
1837 dialog.setVisible(true);
1841 // bring up graduated chooser.
1842 chooser = new FeatureColourChooser(me.fr, type);
1843 chooser.setRequestFocusEnabled(true);
1844 chooser.requestFocus();
1845 chooser.addActionListener(this);
1847 // Make the renderer reappear.
1848 fireEditingStopped();
1852 { // User pressed dialog's "OK" button.
1853 if (currentColor != null)
1855 currentColor = colorChooser.getColor();
1859 // class cast exceptions may be raised if the chooser created on a
1860 // non-graduated color
1861 currentGColor = (GraduatedColor) chooser.getLastColour();
1863 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1864 fireEditingStopped();
1865 me.table.validate();
1869 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1870 public Object getCellEditorValue()
1872 if (currentColor == null)
1874 return currentGColor;
1876 return currentColor;
1879 // Implement the one method defined by TableCellEditor.
1880 public Component getTableCellEditorComponent(JTable table, Object value,
1881 boolean isSelected, int row, int column)
1883 currentGColor = null;
1884 currentColor = null;
1885 this.selectedRow = row;
1886 type = me.table.getValueAt(row, 0).toString();
1887 button.setOpaque(true);
1888 button.setBackground(me.getBackground());
1889 if (value instanceof GraduatedColor)
1891 currentGColor = (GraduatedColor) value;
1892 JLabel btn = new JLabel();
1893 btn.setSize(button.getSize());
1894 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1895 button.setBackground(btn.getBackground());
1896 button.setIcon(btn.getIcon());
1897 button.setText(btn.getText());
1902 button.setIcon(null);
1903 currentColor = (Color) value;
1904 button.setBackground(currentColor);