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.io.JalviewFileChooser;
31 import jalview.schemes.AnnotationColourGradient;
32 import jalview.schemes.GraduatedColor;
33 import jalview.util.MessageManager;
34 import jalview.ws.dbsources.das.api.jalviewSourceI;
36 import java.awt.BorderLayout;
37 import java.awt.Color;
38 import java.awt.Component;
40 import java.awt.Graphics;
41 import java.awt.GridLayout;
42 import java.awt.Rectangle;
43 import java.awt.event.ActionEvent;
44 import java.awt.event.ActionListener;
45 import java.awt.event.ItemEvent;
46 import java.awt.event.ItemListener;
47 import java.awt.event.MouseAdapter;
48 import java.awt.event.MouseEvent;
49 import java.awt.event.MouseMotionAdapter;
50 import java.beans.PropertyChangeEvent;
51 import java.beans.PropertyChangeListener;
53 import java.io.FileInputStream;
54 import java.io.FileOutputStream;
55 import java.io.InputStreamReader;
56 import java.io.OutputStreamWriter;
57 import java.io.PrintWriter;
58 import java.util.ArrayList;
59 import java.util.Hashtable;
60 import java.util.Iterator;
61 import java.util.List;
62 import java.util.Vector;
64 import javax.swing.AbstractCellEditor;
65 import javax.swing.BorderFactory;
66 import javax.swing.Icon;
67 import javax.swing.JButton;
68 import javax.swing.JCheckBox;
69 import javax.swing.JCheckBoxMenuItem;
70 import javax.swing.JColorChooser;
71 import javax.swing.JDialog;
72 import javax.swing.JInternalFrame;
73 import javax.swing.JLabel;
74 import javax.swing.JLayeredPane;
75 import javax.swing.JMenuItem;
76 import javax.swing.JOptionPane;
77 import javax.swing.JPanel;
78 import javax.swing.JPopupMenu;
79 import javax.swing.JScrollPane;
80 import javax.swing.JSlider;
81 import javax.swing.JTabbedPane;
82 import javax.swing.JTable;
83 import javax.swing.ListSelectionModel;
84 import javax.swing.SwingConstants;
85 import javax.swing.SwingUtilities;
86 import javax.swing.event.ChangeEvent;
87 import javax.swing.event.ChangeListener;
88 import javax.swing.table.AbstractTableModel;
89 import javax.swing.table.TableCellEditor;
90 import javax.swing.table.TableCellRenderer;
92 public class FeatureSettings extends JPanel
94 DasSourceBrowser dassourceBrowser;
96 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
98 JPanel settingsPane = new JPanel();
100 JPanel dasSettingsPane = new JPanel();
102 final FeatureRenderer fr;
104 public final AlignFrame af;
106 Object[][] originalData;
108 final JInternalFrame frame;
110 JScrollPane scrollPane = new JScrollPane();
116 JSlider transparency = new JSlider();
118 JPanel transPanel = new JPanel(new GridLayout(1, 2));
120 public FeatureSettings(AlignFrame af)
123 fr = af.getFeatureRenderer();
125 transparency.setMaximum(100 - (int) (fr.transparency * 100));
130 } catch (Exception ex)
132 ex.printStackTrace();
135 table = new JTable();
136 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
137 table.setFont(new Font("Verdana", Font.PLAIN, 12));
138 table.setDefaultRenderer(Color.class, new ColorRenderer());
140 table.setDefaultEditor(Color.class, new ColorEditor(this));
142 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
143 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
144 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
146 table.addMouseListener(new MouseAdapter()
148 public void mousePressed(MouseEvent evt)
150 selectedRow = table.rowAtPoint(evt.getPoint());
151 if (evt.isPopupTrigger())
153 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
154 table.getValueAt(selectedRow, 1), fr.minmax, evt.getX(),
157 else if (evt.getClickCount() == 2)
159 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
160 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
162 (String) table.getValueAt(selectedRow, 0));
166 // isPopupTrigger fires on mouseReleased on Mac
168 public void mouseReleased(MouseEvent evt)
170 selectedRow = table.rowAtPoint(evt.getPoint());
171 if (evt.isPopupTrigger())
173 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
174 table.getValueAt(selectedRow, 1), fr.minmax, evt.getX(),
180 table.addMouseMotionListener(new MouseMotionAdapter()
182 public void mouseDragged(MouseEvent evt)
184 int newRow = table.rowAtPoint(evt.getPoint());
185 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
187 Object[] temp = new Object[3];
188 temp[0] = table.getValueAt(selectedRow, 0);
189 temp[1] = table.getValueAt(selectedRow, 1);
190 temp[2] = table.getValueAt(selectedRow, 2);
192 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
193 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
194 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
196 table.setValueAt(temp[0], newRow, 0);
197 table.setValueAt(temp[1], newRow, 1);
198 table.setValueAt(temp[2], newRow, 2);
200 selectedRow = newRow;
204 table.setToolTipText(JvSwingUtils
205 .wrapTooltip(true, MessageManager.getString("label.feature_settings_click_drag")));
206 scrollPane.setViewportView(table);
208 dassourceBrowser = new DasSourceBrowser(this);
209 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
211 if (af.getViewport().featuresDisplayed == null
212 || fr.renderOrder == null)
214 fr.findAllFeatures(true); // display everything!
218 final PropertyChangeListener change;
219 final FeatureSettings fs = this;
220 fr.addPropertyChangeListener(change = new PropertyChangeListener()
222 public void propertyChange(PropertyChangeEvent evt)
224 if (!fs.resettingTable && !fs.handlingUpdate)
226 fs.handlingUpdate = true;
227 fs.resetTable(null); // new groups may be added with new seuqence
228 // feature types only
229 fs.handlingUpdate = false;
235 frame = new JInternalFrame();
236 frame.setContentPane(this);
237 if (new jalview.util.Platform().isAMac())
239 Desktop.addInternalFrame(frame,
240 MessageManager.getString("label.sequence_feature_settings"),
245 Desktop.addInternalFrame(frame,
246 MessageManager.getString("label.sequence_feature_settings"),
250 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
252 public void internalFrameClosed(
253 javax.swing.event.InternalFrameEvent evt)
255 fr.removePropertyChangeListener(change);
256 dassourceBrowser.fs = null;
259 frame.setLayer(JLayeredPane.PALETTE_LAYER);
262 protected void popupSort(final int selectedRow, final String type,
263 final Object typeCol, final Hashtable minmax, int x, int y)
265 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
266 "label.settings_for_param", new String[]
268 JMenuItem scr = new JMenuItem(
269 MessageManager.getString("label.sort_by_score"));
271 final FeatureSettings me = this;
272 scr.addActionListener(new ActionListener()
275 public void actionPerformed(ActionEvent e)
277 me.sortByScore(new String[]
282 JMenuItem dens = new JMenuItem(
283 MessageManager.getString("label.sort_by_density"));
284 dens.addActionListener(new ActionListener()
287 public void actionPerformed(ActionEvent e)
289 me.sortByDens(new String[]
297 final Object typeMinMax = minmax.get(type);
299 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
300 * this is broken at the moment and isn't that useful anyway!
301 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
304 * public void actionPerformed(ActionEvent e) {
305 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
306 * null); } else { minmax.put(type, typeMinMax); } }
312 if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
314 // if (table.getValueAt(row, column));
315 // graduated colourschemes for those where minmax exists for the
316 // positional features
317 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
319 mxcol.setSelected(!(typeCol instanceof Color));
321 mxcol.addActionListener(new ActionListener()
323 JColorChooser colorChooser;
325 public void actionPerformed(ActionEvent e)
327 if (e.getSource() == mxcol)
329 if (typeCol instanceof Color)
331 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
333 fc.addActionListener(this);
337 // bring up simple color chooser
338 colorChooser = new JColorChooser();
339 JDialog dialog = JColorChooser.createDialog(me,
340 "Select new Colour", true, // modal
341 colorChooser, this, // OK button handler
342 null); // no CANCEL button handler
343 colorChooser.setColor(((GraduatedColor) typeCol)
345 dialog.setVisible(true);
350 if (e.getSource() instanceof FeatureColourChooser)
352 FeatureColourChooser fc = (FeatureColourChooser) e
354 table.setValueAt(fc.getLastColour(), selectedRow, 1);
359 // probably the color chooser!
360 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
362 me.updateFeatureRenderer(
363 ((FeatureTableModel) table.getModel()).getData(),
372 JMenuItem selCols = new JMenuItem(
373 MessageManager.getString("label.select_columns_containing"));
374 selCols.addActionListener(new ActionListener()
378 public void actionPerformed(ActionEvent arg0)
380 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
384 JMenuItem clearCols = new JMenuItem(
385 MessageManager.getString("label.select_columns_not_containing"));
386 clearCols.addActionListener(new ActionListener()
390 public void actionPerformed(ActionEvent arg0)
392 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
398 men.show(table, x, y);
402 * true when Feature Settings are updating from feature renderer
404 private boolean handlingUpdate = false;
407 * contains a float[3] for each feature type string. created by setTableData
409 Hashtable typeWidth = null;
411 synchronized public void setTableData()
413 if (fr.featureGroups == null)
415 fr.featureGroups = new Hashtable();
417 Vector allFeatures = new Vector();
418 Vector allGroups = new Vector();
419 SequenceFeature[] tmpfeatures;
421 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
423 if (af.getViewport().getAlignment().getSequenceAt(i)
424 .getDatasetSequence().getSequenceFeatures() == null)
429 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
430 .getDatasetSequence().getSequenceFeatures();
433 while (index < tmpfeatures.length)
435 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
441 if (tmpfeatures[index].getFeatureGroup() != null)
443 group = tmpfeatures[index].featureGroup;
444 if (!allGroups.contains(group))
446 allGroups.addElement(group);
449 checkGroupState(group);
454 if (!allFeatures.contains(tmpfeatures[index].getType()))
456 allFeatures.addElement(tmpfeatures[index].getType());
470 * @return true if group has been seen before and is already added to set.
472 private boolean checkGroupState(String group)
475 if (fr.featureGroups.containsKey(group))
477 visible = ((Boolean) fr.featureGroups.get(group)).booleanValue();
481 visible = true; // new group is always made visible
484 if (groupPanel == null)
486 groupPanel = new JPanel();
489 boolean alreadyAdded = false;
490 for (int g = 0; g < groupPanel.getComponentCount(); g++)
492 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
495 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
506 fr.featureGroups.put(group, new Boolean(visible));
507 final String grp = group;
508 final JCheckBox check = new JCheckBox(group, visible);
509 check.setFont(new Font("Serif", Font.BOLD, 12));
510 check.addItemListener(new ItemListener()
512 public void itemStateChanged(ItemEvent evt)
514 fr.featureGroups.put(check.getText(),
515 new Boolean(check.isSelected()));
516 af.alignPanel.seqPanel.seqCanvas.repaint();
517 if (af.alignPanel.overviewPanel != null)
519 af.alignPanel.overviewPanel.updateOverviewImage();
522 resetTable(new String[]
526 groupPanel.add(check);
530 boolean resettingTable = false;
532 synchronized void resetTable(String[] groupChanged)
534 if (resettingTable == true)
538 resettingTable = true;
539 typeWidth = new Hashtable();
540 // TODO: change avWidth calculation to 'per-sequence' average and use long
542 float[] avWidth = null;
543 SequenceFeature[] tmpfeatures;
544 String group = null, type;
545 Vector visibleChecks = new Vector();
547 // Find out which features should be visible depending on which groups
548 // are selected / deselected
549 // and recompute average width ordering
550 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
553 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
554 .getDatasetSequence().getSequenceFeatures();
555 if (tmpfeatures == null)
561 while (index < tmpfeatures.length)
563 group = tmpfeatures[index].featureGroup;
565 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
571 if (group == null || fr.featureGroups.get(group) == null
572 || ((Boolean) fr.featureGroups.get(group)).booleanValue())
575 checkGroupState(group);
576 type = tmpfeatures[index].getType();
577 if (!visibleChecks.contains(type))
579 visibleChecks.addElement(type);
582 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
584 typeWidth.put(tmpfeatures[index].getType(),
585 avWidth = new float[3]);
589 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
592 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
594 avWidth[1] += 1 + tmpfeatures[index].getBegin()
595 - tmpfeatures[index].getEnd();
599 avWidth[1] += 1 + tmpfeatures[index].getEnd()
600 - tmpfeatures[index].getBegin();
606 int fSize = visibleChecks.size();
607 Object[][] data = new Object[fSize][3];
610 if (fr.renderOrder != null)
613 fr.findAllFeatures(groupChanged != null); // prod to update
614 // colourschemes. but don't
616 // First add the checks in the previous render order,
617 // in case the window has been closed and reopened
618 for (int ro = fr.renderOrder.length - 1; ro > -1; ro--)
620 type = fr.renderOrder[ro];
622 if (!visibleChecks.contains(type))
627 data[dataIndex][0] = type;
628 data[dataIndex][1] = fr.getFeatureStyle(type);
629 data[dataIndex][2] = new Boolean(
630 af.getViewport().featuresDisplayed.containsKey(type));
632 visibleChecks.removeElement(type);
636 fSize = visibleChecks.size();
637 for (int i = 0; i < fSize; i++)
639 // These must be extra features belonging to the group
640 // which was just selected
641 type = visibleChecks.elementAt(i).toString();
642 data[dataIndex][0] = type;
644 data[dataIndex][1] = fr.getFeatureStyle(type);
645 if (data[dataIndex][1] == null)
647 // "Colour has been updated in another view!!"
648 fr.renderOrder = null;
652 data[dataIndex][2] = new Boolean(true);
656 if (originalData == null)
658 originalData = new Object[data.length][3];
659 for (int i = 0; i < data.length; i++)
661 System.arraycopy(data[i], 0, originalData[i], 0, 3);
665 table.setModel(new FeatureTableModel(data));
666 table.getColumnModel().getColumn(0).setPreferredWidth(200);
668 if (groupPanel != null)
670 groupPanel.setLayout(new GridLayout(fr.featureGroups.size() / 4 + 1,
673 groupPanel.validate();
674 bigPanel.add(groupPanel, BorderLayout.NORTH);
677 updateFeatureRenderer(data, groupChanged != null);
678 resettingTable = false;
682 * reorder data based on the featureRenderers global priority list.
686 private void ensureOrder(Object[][] data)
688 boolean sort = false;
689 float[] order = new float[data.length];
690 for (int i = 0; i < order.length; i++)
692 order[i] = fr.getOrder(data[i][0].toString());
694 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
696 sort = sort || order[i - 1] > order[i];
699 jalview.util.QuickSort.sort(order, data);
704 JalviewFileChooser chooser = new JalviewFileChooser(
705 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
706 { "fc" }, new String[]
707 { "Sequence Feature Colours" }, "Sequence Feature Colours");
708 chooser.setFileView(new jalview.io.JalviewFileView());
709 chooser.setDialogTitle(MessageManager.getString("label.load_feature_colours"));
710 chooser.setToolTipText(MessageManager.getString("action.load"));
712 int value = chooser.showOpenDialog(this);
714 if (value == JalviewFileChooser.APPROVE_OPTION)
716 File file = chooser.getSelectedFile();
720 InputStreamReader in = new InputStreamReader(new FileInputStream(
723 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
727 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
730 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
733 Color mincol = null, maxcol = null;
736 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
737 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
739 } catch (Exception e)
741 Cache.log.warn("Couldn't parse out graduated feature color.",
744 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
745 newcol.getMin(), newcol.getMax());
746 if (newcol.hasAutoScale())
748 gcol.setAutoScaled(newcol.getAutoScale());
750 if (newcol.hasColourByLabel())
752 gcol.setColourByLabel(newcol.getColourByLabel());
754 if (newcol.hasThreshold())
756 gcol.setThresh(newcol.getThreshold());
757 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
759 if (newcol.getThreshType().length() > 0)
761 String ttyp = newcol.getThreshType();
762 if (ttyp.equalsIgnoreCase("NONE"))
764 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
766 if (ttyp.equalsIgnoreCase("ABOVE"))
768 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
770 if (ttyp.equalsIgnoreCase("BELOW"))
772 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
775 fr.setColour(name = newcol.getName(), gcol);
779 fr.setColour(name = jucs.getColour(i).getName(), new Color(
780 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
782 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
787 Object[][] data = ((FeatureTableModel) table.getModel())
790 updateFeatureRenderer(data, false);
793 } catch (Exception ex)
795 System.out.println("Error loading User Colour File\n" + ex);
802 JalviewFileChooser chooser = new JalviewFileChooser(
803 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
804 { "fc" }, new String[]
805 { "Sequence Feature Colours" }, "Sequence Feature Colours");
806 chooser.setFileView(new jalview.io.JalviewFileView());
807 chooser.setDialogTitle(MessageManager.getString("label.save_feature_colours"));
808 chooser.setToolTipText(MessageManager.getString("action.save"));
810 int value = chooser.showSaveDialog(this);
812 if (value == JalviewFileChooser.APPROVE_OPTION)
814 String choice = chooser.getSelectedFile().getPath();
815 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
816 ucs.setSchemeName("Sequence Features");
819 PrintWriter out = new PrintWriter(new OutputStreamWriter(
820 new FileOutputStream(choice), "UTF-8"));
822 Iterator e = fr.featureColours.keySet().iterator();
823 float[] sortOrder = new float[fr.featureColours.size()];
824 String[] sortTypes = new String[fr.featureColours.size()];
828 sortTypes[i] = e.next().toString();
829 sortOrder[i] = fr.getOrder(sortTypes[i]);
832 jalview.util.QuickSort.sort(sortOrder, sortTypes);
836 for (i = 0; i < sortTypes.length; i++)
838 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
839 col.setName(sortTypes[i]);
840 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
842 fcol = fr.getFeatureStyle(sortTypes[i]);
843 if (fcol instanceof GraduatedColor)
845 gcol = (GraduatedColor) fcol;
846 col.setMin(gcol.getMin());
847 col.setMax(gcol.getMax());
848 col.setMinRGB(jalview.util.Format.getHexString(gcol
850 col.setAutoScale(gcol.isAutoScale());
851 col.setThreshold(gcol.getThresh());
852 col.setColourByLabel(gcol.isColourByLabel());
853 switch (gcol.getThreshType())
855 case AnnotationColourGradient.NO_THRESHOLD:
856 col.setThreshType("NONE");
858 case AnnotationColourGradient.ABOVE_THRESHOLD:
859 col.setThreshType("ABOVE");
861 case AnnotationColourGradient.BELOW_THRESHOLD:
862 col.setThreshType("BELOW");
870 } catch (Exception ex)
872 ex.printStackTrace();
877 public void invertSelection()
879 for (int i = 0; i < table.getRowCount(); i++)
881 Boolean value = (Boolean) table.getValueAt(i, 2);
883 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
887 public void orderByAvWidth()
889 if (table == null || table.getModel() == null)
891 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
892 float[] width = new float[data.length];
896 for (int i = 0; i < data.length; i++)
898 awidth = (float[]) typeWidth.get(data[i][0]);
901 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
902 // weight - but have to make per
903 // sequence, too (awidth[2])
904 // if (width[i]==1) // hack to distinguish single width sequences.
914 boolean sort = false;
915 for (int i = 0; i < width.length; i++)
917 // awidth = (float[]) typeWidth.get(data[i][0]);
920 width[i] = fr.getOrder(data[i][0].toString());
923 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
928 width[i] /= max; // normalize
929 fr.setOrder(data[i][0].toString(), width[i]); // store for later
932 sort = sort || width[i - 1] > width[i];
935 jalview.util.QuickSort.sort(width, data);
936 // update global priority order
938 updateFeatureRenderer(data, false);
946 frame.setClosed(true);
947 } catch (Exception exe)
953 public void updateFeatureRenderer(Object[][] data)
955 updateFeatureRenderer(data, true);
958 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
960 fr.setFeaturePriority(data, visibleNew);
961 af.alignPanel.paintAlignment(true);
964 int selectedRow = -1;
966 JTabbedPane tabbedPane = new JTabbedPane();
968 BorderLayout borderLayout1 = new BorderLayout();
970 BorderLayout borderLayout2 = new BorderLayout();
972 BorderLayout borderLayout3 = new BorderLayout();
974 JPanel bigPanel = new JPanel();
976 BorderLayout borderLayout4 = new BorderLayout();
978 JButton invert = new JButton();
980 JPanel buttonPanel = new JPanel();
982 JButton cancel = new JButton();
984 JButton ok = new JButton();
986 JButton loadColours = new JButton();
988 JButton saveColours = new JButton();
990 JPanel dasButtonPanel = new JPanel();
992 JButton fetchDAS = new JButton();
994 JButton saveDAS = new JButton();
996 JButton cancelDAS = new JButton();
998 JButton optimizeOrder = new JButton();
1000 JButton sortByScore = new JButton();
1002 JButton sortByDens = new JButton();
1004 JPanel transbuttons = new JPanel(new GridLayout(4, 1));
1006 private void jbInit() throws Exception
1008 this.setLayout(borderLayout1);
1009 settingsPane.setLayout(borderLayout2);
1010 dasSettingsPane.setLayout(borderLayout3);
1011 bigPanel.setLayout(borderLayout4);
1012 invert.setFont(JvSwingUtils.getLabelFont());
1013 invert.setText(MessageManager.getString("label.invert_selection"));
1014 invert.addActionListener(new ActionListener()
1016 public void actionPerformed(ActionEvent e)
1021 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1022 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1023 optimizeOrder.addActionListener(new ActionListener()
1025 public void actionPerformed(ActionEvent e)
1030 sortByScore.setFont(JvSwingUtils.getLabelFont());
1032 .setText(MessageManager.getString("label.seq_sort_by_score"));
1033 sortByScore.addActionListener(new ActionListener()
1035 public void actionPerformed(ActionEvent e)
1040 sortByDens.setFont(JvSwingUtils.getLabelFont());
1041 sortByDens.setText(MessageManager
1042 .getString("label.sequence_sort_by_density"));
1043 sortByDens.addActionListener(new ActionListener()
1045 public void actionPerformed(ActionEvent e)
1050 cancel.setFont(JvSwingUtils.getLabelFont());
1051 cancel.setText(MessageManager.getString("action.cancel"));
1052 cancel.addActionListener(new ActionListener()
1054 public void actionPerformed(ActionEvent e)
1056 updateFeatureRenderer(originalData);
1060 ok.setFont(JvSwingUtils.getLabelFont());
1061 ok.setText(MessageManager.getString("action.ok"));
1062 ok.addActionListener(new ActionListener()
1064 public void actionPerformed(ActionEvent e)
1069 loadColours.setFont(JvSwingUtils.getLabelFont());
1070 loadColours.setText(MessageManager.getString("label.load_colours"));
1071 loadColours.addActionListener(new ActionListener()
1073 public void actionPerformed(ActionEvent e)
1078 saveColours.setFont(JvSwingUtils.getLabelFont());
1079 saveColours.setText(MessageManager.getString("label.save_colours"));
1080 saveColours.addActionListener(new ActionListener()
1082 public void actionPerformed(ActionEvent e)
1087 transparency.addChangeListener(new ChangeListener()
1089 public void stateChanged(ChangeEvent evt)
1091 fr.setTransparency((100 - transparency.getValue()) / 100f);
1092 af.alignPanel.paintAlignment(true);
1096 transparency.setMaximum(70);
1097 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1098 fetchDAS.addActionListener(new ActionListener()
1100 public void actionPerformed(ActionEvent e)
1102 fetchDAS_actionPerformed(e);
1105 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1106 saveDAS.addActionListener(new ActionListener()
1108 public void actionPerformed(ActionEvent e)
1110 saveDAS_actionPerformed(e);
1113 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1114 dasSettingsPane.setBorder(null);
1115 cancelDAS.setEnabled(false);
1116 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1117 cancelDAS.addActionListener(new ActionListener()
1119 public void actionPerformed(ActionEvent e)
1121 cancelDAS_actionPerformed(e);
1124 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1125 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1126 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1127 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1128 transbuttons.add(optimizeOrder);
1129 transbuttons.add(invert);
1130 transbuttons.add(sortByScore);
1131 transbuttons.add(sortByDens);
1132 transPanel.add(transparency);
1133 transPanel.add(transbuttons);
1134 buttonPanel.add(ok);
1135 buttonPanel.add(cancel);
1136 buttonPanel.add(loadColours);
1137 buttonPanel.add(saveColours);
1138 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1139 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1140 dasButtonPanel.add(fetchDAS);
1141 dasButtonPanel.add(cancelDAS);
1142 dasButtonPanel.add(saveDAS);
1143 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1144 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1147 protected void sortByDens(String[] typ)
1149 sortBy(typ, "Sort by Density", AlignmentSorter.FEATURE_DENSITY);
1152 protected void sortBy(String[] typ, String methodText, final String method)
1156 typ = getDisplayedFeatureTypes();
1158 String gps[] = null;
1159 gps = getDisplayedFeatureGroups();
1162 ArrayList types = new ArrayList();
1163 for (int i = 0; i < typ.length; i++)
1169 typ = new String[types.size()];
1175 ArrayList grps = new ArrayList();
1177 for (int i = 0; i < gps.length; i++)
1184 gps = new String[grps.size()];
1187 AlignmentPanel alignPanel = af.alignPanel;
1188 AlignmentI al = alignPanel.av.getAlignment();
1191 SequenceGroup sg = alignPanel.av.getSelectionGroup();
1194 start = sg.getStartRes();
1195 stop = sg.getEndRes();
1200 stop = al.getWidth();
1202 SequenceI[] oldOrder = al.getSequencesArray();
1203 AlignmentSorter.sortByFeature(typ, gps, start, stop, al, method);
1204 af.addHistoryItem(new OrderCommand(methodText, oldOrder, alignPanel.av
1206 alignPanel.paintAlignment(true);
1210 protected void sortByScore(String[] typ)
1212 sortBy(typ, "Sort by Feature Score", AlignmentSorter.FEATURE_SCORE);
1215 private String[] getDisplayedFeatureTypes()
1217 String[] typ = null;
1220 synchronized (fr.renderOrder)
1222 typ = new String[fr.renderOrder.length];
1223 System.arraycopy(fr.renderOrder, 0, typ, 0, typ.length);
1224 for (int i = 0; i < typ.length; i++)
1226 if (af.viewport.featuresDisplayed.get(typ[i]) == null)
1236 private String[] getDisplayedFeatureGroups()
1238 String[] gps = null;
1239 ArrayList<String> _gps = new ArrayList<String>();
1243 if (fr.featureGroups != null)
1245 Iterator en = fr.featureGroups.keySet().iterator();
1247 boolean valid = false;
1248 while (en.hasNext())
1250 String gp = (String) en.next();
1251 Boolean on = (Boolean) fr.featureGroups.get(gp);
1252 if (on != null && on.booleanValue())
1264 gps = new String[_gps.size()];
1272 public void fetchDAS_actionPerformed(ActionEvent e)
1274 fetchDAS.setEnabled(false);
1275 cancelDAS.setEnabled(true);
1276 dassourceBrowser.setGuiEnabled(false);
1277 Vector selectedSources = dassourceBrowser.getSelectedSources();
1278 doDasFeatureFetch(selectedSources, true, true);
1282 * get the features from selectedSources for all or the current selection
1284 * @param selectedSources
1285 * @param checkDbRefs
1286 * @param promptFetchDbRefs
1288 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1289 boolean checkDbRefs, boolean promptFetchDbRefs)
1291 SequenceI[] dataset, seqs;
1293 AlignViewport vp = af.getViewport();
1294 if (vp.getSelectionGroup() != null
1295 && vp.getSelectionGroup().getSize() > 0)
1297 iSize = vp.getSelectionGroup().getSize();
1298 dataset = new SequenceI[iSize];
1299 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1303 iSize = vp.getAlignment().getHeight();
1304 seqs = vp.getAlignment().getSequencesArray();
1307 dataset = new SequenceI[iSize];
1308 for (int i = 0; i < iSize; i++)
1310 dataset[i] = seqs[i].getDatasetSequence();
1313 cancelDAS.setEnabled(true);
1314 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1315 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1316 af.getViewport().setShowSequenceFeatures(true);
1317 af.showSeqFeatures.setSelected(true);
1321 * blocking call to initialise the das source browser
1323 public void initDasSources()
1325 dassourceBrowser.initDasSources();
1329 * examine the current list of das sources and return any matching the given
1330 * nicknames in sources
1333 * Vector of Strings to resolve to DAS source nicknames.
1334 * @return sources that are present in source list.
1336 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1338 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1342 * get currently selected das sources. ensure you have called initDasSources
1343 * before calling this.
1345 * @return vector of selected das source nicknames
1347 public Vector getSelectedSources()
1349 return dassourceBrowser.getSelectedSources();
1353 * properly initialise DAS fetcher and then initiate a new thread to fetch
1354 * features from the named sources (rather than any turned on by default)
1358 * if true then runs in same thread, otherwise passes to the Swing
1361 public void fetchDasFeatures(Vector sources, boolean block)
1364 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1365 .resolveSourceNicknames(sources);
1366 if (resolved.size() == 0)
1368 resolved = dassourceBrowser.getSelectedSources();
1370 if (resolved.size() > 0)
1372 final List<jalviewSourceI> dassources = resolved;
1373 fetchDAS.setEnabled(false);
1374 // cancelDAS.setEnabled(true); doDasFetch does this.
1375 Runnable fetcher = new Runnable()
1380 doDasFeatureFetch(dassources, true, false);
1390 SwingUtilities.invokeLater(fetcher);
1395 public void saveDAS_actionPerformed(ActionEvent e)
1398 .saveProperties(jalview.bin.Cache.applicationProperties);
1401 public void complete()
1403 fetchDAS.setEnabled(true);
1404 cancelDAS.setEnabled(false);
1405 dassourceBrowser.setGuiEnabled(true);
1409 public void cancelDAS_actionPerformed(ActionEvent e)
1411 if (dasFeatureFetcher != null)
1413 dasFeatureFetcher.cancel();
1418 public void noDasSourceActive()
1422 .showInternalConfirmDialog(
1425 .getString("label.no_das_sources_selected_warn"),
1427 .getString("label.no_das_sources_selected_title"),
1428 JOptionPane.DEFAULT_OPTION,
1429 JOptionPane.INFORMATION_MESSAGE);
1432 // ///////////////////////////////////////////////////////////////////////
1433 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1434 // ///////////////////////////////////////////////////////////////////////
1435 class FeatureTableModel extends AbstractTableModel
1437 FeatureTableModel(Object[][] data)
1442 private String[] columnNames =
1443 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1445 private Object[][] data;
1447 public Object[][] getData()
1452 public void setData(Object[][] data)
1457 public int getColumnCount()
1459 return columnNames.length;
1462 public Object[] getRow(int row)
1467 public int getRowCount()
1472 public String getColumnName(int col)
1474 return columnNames[col];
1477 public Object getValueAt(int row, int col)
1479 return data[row][col];
1482 public Class getColumnClass(int c)
1484 return getValueAt(0, c).getClass();
1487 public boolean isCellEditable(int row, int col)
1489 return col == 0 ? false : true;
1492 public void setValueAt(Object value, int row, int col)
1494 data[row][col] = value;
1495 fireTableCellUpdated(row, col);
1496 updateFeatureRenderer(data);
1501 class ColorRenderer extends JLabel implements TableCellRenderer
1503 javax.swing.border.Border unselectedBorder = null;
1505 javax.swing.border.Border selectedBorder = null;
1507 final String baseTT = "Click to edit, right/apple click for menu.";
1509 public ColorRenderer()
1511 setOpaque(true); // MUST do this for background to show up.
1512 setHorizontalTextPosition(SwingConstants.CENTER);
1513 setVerticalTextPosition(SwingConstants.CENTER);
1516 public Component getTableCellRendererComponent(JTable table,
1517 Object color, boolean isSelected, boolean hasFocus, int row,
1520 // JLabel comp = new JLabel();
1524 // setBounds(getBounds());
1526 setToolTipText(baseTT);
1527 setBackground(table.getBackground());
1528 if (color instanceof GraduatedColor)
1530 Rectangle cr = table.getCellRect(row, column, false);
1531 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1532 (int) cr.getWidth(), (int) cr.getHeight());
1539 newColor = (Color) color;
1541 setBackground(newColor);
1542 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1543 // + newColor.getGreen() + ", " + newColor.getBlue());
1547 if (selectedBorder == null)
1549 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1550 table.getSelectionBackground());
1553 setBorder(selectedBorder);
1557 if (unselectedBorder == null)
1559 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1560 table.getBackground());
1563 setBorder(unselectedBorder);
1571 * update comp using rendering settings from gcol
1576 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1578 int w = comp.getWidth(), h = comp.getHeight();
1581 w = (int) comp.getPreferredSize().getWidth();
1582 h = (int) comp.getPreferredSize().getHeight();
1589 renderGraduatedColor(comp, gcol, w, h);
1592 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1595 boolean thr = false;
1598 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1602 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1604 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1608 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1610 if (gcol.isColourByLabel())
1612 tt = "Coloured by label text. " + tt;
1622 Color newColor = gcol.getMaxColor();
1623 comp.setBackground(newColor);
1624 // System.err.println("Width is " + w / 2);
1625 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1626 comp.setIcon(ficon);
1627 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1628 // + newColor.getGreen() + ", " + newColor.getBlue()
1629 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1630 // + ", " + minCol.getBlue() + ")");
1632 comp.setHorizontalAlignment(SwingConstants.CENTER);
1634 if (tt.length() > 0)
1636 if (comp.getToolTipText() == null)
1638 comp.setToolTipText(tt);
1642 comp.setToolTipText(tt + " " + comp.getToolTipText());
1648 class FeatureIcon implements Icon
1650 GraduatedColor gcol;
1654 boolean midspace = false;
1656 int width = 50, height = 20;
1658 int s1, e1; // start and end of midpoint band for thresholded symbol
1660 Color mpcolour = Color.white;
1662 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1681 public int getIconWidth()
1686 public int getIconHeight()
1691 public void paintIcon(Component c, Graphics g, int x, int y)
1694 if (gcol.isColourByLabel())
1697 g.fillRect(0, 0, width, height);
1698 // need an icon here.
1699 g.setColor(gcol.getMaxColor());
1701 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1703 // g.setFont(g.getFont().deriveFont(
1704 // AffineTransform.getScaleInstance(
1705 // width/g.getFontMetrics().stringWidth("Label"),
1706 // height/g.getFontMetrics().getHeight())));
1708 g.drawString(MessageManager.getString("label.label"), 0, 0);
1713 Color minCol = gcol.getMinColor();
1715 g.fillRect(0, 0, s1, height);
1718 g.setColor(Color.white);
1719 g.fillRect(s1, 0, e1 - s1, height);
1721 g.setColor(gcol.getMaxColor());
1722 g.fillRect(0, e1, width - e1, height);
1727 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1732 GraduatedColor currentGColor;
1734 FeatureColourChooser chooser;
1742 JColorChooser colorChooser;
1746 protected static final String EDIT = "edit";
1748 int selectedRow = 0;
1750 public ColorEditor(FeatureSettings me)
1753 // Set up the editor (from the table's point of view),
1754 // which is a button.
1755 // This button brings up the color chooser dialog,
1756 // which is the editor from the user's point of view.
1757 button = new JButton();
1758 button.setActionCommand(EDIT);
1759 button.addActionListener(this);
1760 button.setBorderPainted(false);
1761 // Set up the dialog that the button brings up.
1762 colorChooser = new JColorChooser();
1763 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1764 colorChooser, this, // OK button handler
1765 null); // no CANCEL button handler
1769 * Handles events from the editor button and from the dialog's OK button.
1771 public void actionPerformed(ActionEvent e)
1774 if (EDIT.equals(e.getActionCommand()))
1776 // The user has clicked the cell, so
1777 // bring up the dialog.
1778 if (currentColor != null)
1780 // bring up simple color chooser
1781 button.setBackground(currentColor);
1782 colorChooser.setColor(currentColor);
1783 dialog.setVisible(true);
1787 // bring up graduated chooser.
1788 chooser = new FeatureColourChooser(me.fr, type);
1789 chooser.setRequestFocusEnabled(true);
1790 chooser.requestFocus();
1791 chooser.addActionListener(this);
1793 // Make the renderer reappear.
1794 fireEditingStopped();
1798 { // User pressed dialog's "OK" button.
1799 if (currentColor != null)
1801 currentColor = colorChooser.getColor();
1805 // class cast exceptions may be raised if the chooser created on a
1806 // non-graduated color
1807 currentGColor = (GraduatedColor) chooser.getLastColour();
1809 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1810 fireEditingStopped();
1811 me.table.validate();
1815 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1816 public Object getCellEditorValue()
1818 if (currentColor == null)
1820 return currentGColor;
1822 return currentColor;
1825 // Implement the one method defined by TableCellEditor.
1826 public Component getTableCellEditorComponent(JTable table, Object value,
1827 boolean isSelected, int row, int column)
1829 currentGColor = null;
1830 currentColor = null;
1831 this.selectedRow = row;
1832 type = me.table.getValueAt(row, 0).toString();
1833 button.setOpaque(true);
1834 button.setBackground(me.getBackground());
1835 if (value instanceof GraduatedColor)
1837 currentGColor = (GraduatedColor) value;
1838 JLabel btn = new JLabel();
1839 btn.setSize(button.getSize());
1840 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1841 button.setBackground(btn.getBackground());
1842 button.setIcon(btn.getIcon());
1843 button.setText(btn.getText());
1848 button.setIcon(null);
1849 currentColor = (Color) value;
1850 button.setBackground(currentColor);