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.viewmodel.AlignmentViewport;
36 import jalview.ws.dbsources.das.api.jalviewSourceI;
38 import java.awt.BorderLayout;
39 import java.awt.Color;
40 import java.awt.Component;
42 import java.awt.Graphics;
43 import java.awt.GridLayout;
44 import java.awt.Rectangle;
45 import java.awt.event.ActionEvent;
46 import java.awt.event.ActionListener;
47 import java.awt.event.ItemEvent;
48 import java.awt.event.ItemListener;
49 import java.awt.event.MouseAdapter;
50 import java.awt.event.MouseEvent;
51 import java.awt.event.MouseMotionAdapter;
52 import java.beans.PropertyChangeEvent;
53 import java.beans.PropertyChangeListener;
55 import java.io.FileInputStream;
56 import java.io.FileOutputStream;
57 import java.io.InputStreamReader;
58 import java.io.OutputStreamWriter;
59 import java.io.PrintWriter;
60 import java.util.ArrayList;
61 import java.util.Hashtable;
62 import java.util.Iterator;
63 import java.util.List;
64 import java.util.Vector;
66 import javax.help.HelpSetException;
67 import javax.swing.AbstractCellEditor;
68 import javax.swing.BorderFactory;
69 import javax.swing.Icon;
70 import javax.swing.JButton;
71 import javax.swing.JCheckBox;
72 import javax.swing.JCheckBoxMenuItem;
73 import javax.swing.JColorChooser;
74 import javax.swing.JDialog;
75 import javax.swing.JInternalFrame;
76 import javax.swing.JLabel;
77 import javax.swing.JLayeredPane;
78 import javax.swing.JMenuItem;
79 import javax.swing.JOptionPane;
80 import javax.swing.JPanel;
81 import javax.swing.JPopupMenu;
82 import javax.swing.JScrollPane;
83 import javax.swing.JSlider;
84 import javax.swing.JTabbedPane;
85 import javax.swing.JTable;
86 import javax.swing.ListSelectionModel;
87 import javax.swing.SwingConstants;
88 import javax.swing.SwingUtilities;
89 import javax.swing.event.ChangeEvent;
90 import javax.swing.event.ChangeListener;
91 import javax.swing.table.AbstractTableModel;
92 import javax.swing.table.TableCellEditor;
93 import javax.swing.table.TableCellRenderer;
95 public class FeatureSettings extends JPanel
97 DasSourceBrowser dassourceBrowser;
99 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
101 JPanel settingsPane = new JPanel();
103 JPanel dasSettingsPane = new JPanel();
105 final FeatureRenderer fr;
107 public final AlignFrame af;
109 Object[][] originalData;
111 final JInternalFrame frame;
113 JScrollPane scrollPane = new JScrollPane();
119 JSlider transparency = new JSlider();
121 JPanel transPanel = new JPanel(new GridLayout(1, 2));
123 public FeatureSettings(AlignFrame af)
126 fr = af.getFeatureRenderer();
128 transparency.setMaximum(100 - (int) (fr.transparency * 100));
133 } catch (Exception ex)
135 ex.printStackTrace();
138 table = new JTable() {
140 public String getToolTipText(MouseEvent e) {
141 if (table.columnAtPoint(e.getPoint()) == 0) {
143 * Tooltip for feature name only
145 return JvSwingUtils.wrapTooltip(true,
146 MessageManager.getString("label.feature_settings_click_drag"));
151 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
152 table.setFont(new Font("Verdana", Font.PLAIN, 12));
153 table.setDefaultRenderer(Color.class, new ColorRenderer());
155 table.setDefaultEditor(Color.class, new ColorEditor(this));
157 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
158 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
159 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
161 table.addMouseListener(new MouseAdapter()
163 public void mousePressed(MouseEvent evt)
165 selectedRow = table.rowAtPoint(evt.getPoint());
166 if (SwingUtilities.isRightMouseButton(evt))
168 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
169 table.getValueAt(selectedRow, 1), fr.minmax, evt.getX(),
172 else if (evt.getClickCount() == 2)
174 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
175 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
177 (String) table.getValueAt(selectedRow, 0));
181 // isPopupTrigger fires on mouseReleased on Mac
183 public void mouseReleased(MouseEvent evt)
185 selectedRow = table.rowAtPoint(evt.getPoint());
186 if (evt.isPopupTrigger())
188 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
189 table.getValueAt(selectedRow, 1), fr.minmax, evt.getX(),
195 table.addMouseMotionListener(new MouseMotionAdapter()
197 public void mouseDragged(MouseEvent evt)
199 int newRow = table.rowAtPoint(evt.getPoint());
200 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
202 Object[] temp = new Object[3];
203 temp[0] = table.getValueAt(selectedRow, 0);
204 temp[1] = table.getValueAt(selectedRow, 1);
205 temp[2] = table.getValueAt(selectedRow, 2);
207 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
208 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
209 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
211 table.setValueAt(temp[0], newRow, 0);
212 table.setValueAt(temp[1], newRow, 1);
213 table.setValueAt(temp[2], newRow, 2);
215 selectedRow = newRow;
219 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
220 // MessageManager.getString("label.feature_settings_click_drag")));
221 scrollPane.setViewportView(table);
223 dassourceBrowser = new DasSourceBrowser(this);
224 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
226 if (af.getViewport().featuresDisplayed == null
227 || fr.renderOrder == null)
229 fr.findAllFeatures(true); // display everything!
233 final PropertyChangeListener change;
234 final FeatureSettings fs = this;
235 fr.addPropertyChangeListener(change = new PropertyChangeListener()
237 public void propertyChange(PropertyChangeEvent evt)
239 if (!fs.resettingTable && !fs.handlingUpdate)
241 fs.handlingUpdate = true;
242 fs.resetTable(null); // new groups may be added with new seuqence
243 // feature types only
244 fs.handlingUpdate = false;
250 frame = new JInternalFrame();
251 frame.setContentPane(this);
252 if (new jalview.util.Platform().isAMac())
254 Desktop.addInternalFrame(frame,
255 MessageManager.getString("label.sequence_feature_settings"),
260 Desktop.addInternalFrame(frame,
261 MessageManager.getString("label.sequence_feature_settings"),
265 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
267 public void internalFrameClosed(
268 javax.swing.event.InternalFrameEvent evt)
270 fr.removePropertyChangeListener(change);
271 dassourceBrowser.fs = null;
274 frame.setLayer(JLayeredPane.PALETTE_LAYER);
277 protected void popupSort(final int selectedRow, final String type,
278 final Object typeCol, final Hashtable minmax, int x, int y)
280 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
281 "label.settings_for_param", new String[]
283 JMenuItem scr = new JMenuItem(
284 MessageManager.getString("label.sort_by_score"));
286 final FeatureSettings me = this;
287 scr.addActionListener(new ActionListener()
290 public void actionPerformed(ActionEvent e)
292 me.sortByScore(new String[]
297 JMenuItem dens = new JMenuItem(
298 MessageManager.getString("label.sort_by_density"));
299 dens.addActionListener(new ActionListener()
302 public void actionPerformed(ActionEvent e)
304 me.sortByDens(new String[]
312 final Object typeMinMax = minmax.get(type);
314 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
315 * this is broken at the moment and isn't that useful anyway!
316 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
319 * public void actionPerformed(ActionEvent e) {
320 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
321 * null); } else { minmax.put(type, typeMinMax); } }
327 if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
329 // if (table.getValueAt(row, column));
330 // graduated colourschemes for those where minmax exists for the
331 // positional features
332 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
334 mxcol.setSelected(!(typeCol instanceof Color));
336 mxcol.addActionListener(new ActionListener()
338 JColorChooser colorChooser;
340 public void actionPerformed(ActionEvent e)
342 if (e.getSource() == mxcol)
344 if (typeCol instanceof Color)
346 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
348 fc.addActionListener(this);
352 // bring up simple color chooser
353 colorChooser = new JColorChooser();
354 JDialog dialog = JColorChooser.createDialog(me,
355 "Select new Colour", true, // modal
356 colorChooser, this, // OK button handler
357 null); // no CANCEL button handler
358 colorChooser.setColor(((GraduatedColor) typeCol)
360 dialog.setVisible(true);
365 if (e.getSource() instanceof FeatureColourChooser)
367 FeatureColourChooser fc = (FeatureColourChooser) e
369 table.setValueAt(fc.getLastColour(), selectedRow, 1);
374 // probably the color chooser!
375 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
377 me.updateFeatureRenderer(
378 ((FeatureTableModel) table.getModel()).getData(),
387 JMenuItem selCols = new JMenuItem(
388 MessageManager.getString("label.select_columns_containing"));
389 selCols.addActionListener(new ActionListener()
393 public void actionPerformed(ActionEvent arg0)
395 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
399 JMenuItem clearCols = new JMenuItem(
400 MessageManager.getString("label.select_columns_not_containing"));
401 clearCols.addActionListener(new ActionListener()
405 public void actionPerformed(ActionEvent arg0)
407 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
413 men.show(table, x, y);
417 * true when Feature Settings are updating from feature renderer
419 private boolean handlingUpdate = false;
422 * contains a float[3] for each feature type string. created by setTableData
424 Hashtable typeWidth = null;
426 synchronized public void setTableData()
428 if (fr.featureGroups == null)
430 fr.featureGroups = new Hashtable();
432 Vector allFeatures = new Vector();
433 Vector allGroups = new Vector();
434 SequenceFeature[] tmpfeatures;
436 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
438 if (af.getViewport().getAlignment().getSequenceAt(i)
439 .getDatasetSequence().getSequenceFeatures() == null)
444 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
445 .getDatasetSequence().getSequenceFeatures();
448 while (index < tmpfeatures.length)
450 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
456 if (tmpfeatures[index].getFeatureGroup() != null)
458 group = tmpfeatures[index].featureGroup;
459 if (!allGroups.contains(group))
461 allGroups.addElement(group);
464 checkGroupState(group);
469 if (!allFeatures.contains(tmpfeatures[index].getType()))
471 allFeatures.addElement(tmpfeatures[index].getType());
485 * @return true if group has been seen before and is already added to set.
487 private boolean checkGroupState(String group)
490 if (fr.featureGroups.containsKey(group))
492 visible = ((Boolean) fr.featureGroups.get(group)).booleanValue();
496 visible = true; // new group is always made visible
499 if (groupPanel == null)
501 groupPanel = new JPanel();
504 boolean alreadyAdded = false;
505 for (int g = 0; g < groupPanel.getComponentCount(); g++)
507 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
510 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
521 fr.featureGroups.put(group, new Boolean(visible));
522 final String grp = group;
523 final JCheckBox check = new JCheckBox(group, visible);
524 check.setFont(new Font("Serif", Font.BOLD, 12));
525 check.addItemListener(new ItemListener()
527 public void itemStateChanged(ItemEvent evt)
529 fr.featureGroups.put(check.getText(),
530 new Boolean(check.isSelected()));
531 af.alignPanel.seqPanel.seqCanvas.repaint();
532 if (af.alignPanel.overviewPanel != null)
534 af.alignPanel.overviewPanel.updateOverviewImage();
537 resetTable(new String[]
541 groupPanel.add(check);
545 boolean resettingTable = false;
547 synchronized void resetTable(String[] groupChanged)
549 if (resettingTable == true)
553 resettingTable = true;
554 typeWidth = new Hashtable();
555 // TODO: change avWidth calculation to 'per-sequence' average and use long
557 float[] avWidth = null;
558 SequenceFeature[] tmpfeatures;
559 String group = null, type;
560 Vector visibleChecks = new Vector();
562 // Find out which features should be visible depending on which groups
563 // are selected / deselected
564 // and recompute average width ordering
565 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
568 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
569 .getDatasetSequence().getSequenceFeatures();
570 if (tmpfeatures == null)
576 while (index < tmpfeatures.length)
578 group = tmpfeatures[index].featureGroup;
580 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
586 if (group == null || fr.featureGroups.get(group) == null
587 || ((Boolean) fr.featureGroups.get(group)).booleanValue())
591 checkGroupState(group);
593 type = tmpfeatures[index].getType();
594 if (!visibleChecks.contains(type))
596 visibleChecks.addElement(type);
599 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
601 typeWidth.put(tmpfeatures[index].getType(),
602 avWidth = new float[3]);
606 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
609 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
611 avWidth[1] += 1 + tmpfeatures[index].getBegin()
612 - tmpfeatures[index].getEnd();
616 avWidth[1] += 1 + tmpfeatures[index].getEnd()
617 - tmpfeatures[index].getBegin();
623 int fSize = visibleChecks.size();
624 Object[][] data = new Object[fSize][3];
627 if (fr.renderOrder != null)
631 fr.findAllFeatures(groupChanged != null); // prod to update
633 // colourschemes. but don't
635 // First add the checks in the previous render order,
636 // in case the window has been closed and reopened
637 for (int ro = fr.renderOrder.length - 1; ro > -1; ro--)
639 type = fr.renderOrder[ro];
641 if (!visibleChecks.contains(type))
646 data[dataIndex][0] = type;
647 data[dataIndex][1] = fr.getFeatureStyle(type);
648 data[dataIndex][2] = new Boolean(
649 af.getViewport().featuresDisplayed.containsKey(type));
651 visibleChecks.removeElement(type);
655 fSize = visibleChecks.size();
656 for (int i = 0; i < fSize; i++)
658 // These must be extra features belonging to the group
659 // which was just selected
660 type = visibleChecks.elementAt(i).toString();
661 data[dataIndex][0] = type;
663 data[dataIndex][1] = fr.getFeatureStyle(type);
664 if (data[dataIndex][1] == null)
666 // "Colour has been updated in another view!!"
667 fr.renderOrder = null;
671 data[dataIndex][2] = new Boolean(true);
675 if (originalData == null)
677 originalData = new Object[data.length][3];
678 for (int i = 0; i < data.length; i++)
680 System.arraycopy(data[i], 0, originalData[i], 0, 3);
684 table.setModel(new FeatureTableModel(data));
685 table.getColumnModel().getColumn(0).setPreferredWidth(200);
687 if (groupPanel != null)
689 groupPanel.setLayout(new GridLayout(fr.featureGroups.size() / 4 + 1,
692 groupPanel.validate();
693 bigPanel.add(groupPanel, BorderLayout.NORTH);
696 updateFeatureRenderer(data, groupChanged != null);
697 resettingTable = false;
701 * reorder data based on the featureRenderers global priority list.
705 private void ensureOrder(Object[][] data)
707 boolean sort = false;
708 float[] order = new float[data.length];
709 for (int i = 0; i < order.length; i++)
711 order[i] = fr.getOrder(data[i][0].toString());
714 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
718 sort = sort || order[i - 1] > order[i];
723 jalview.util.QuickSort.sort(order, data);
729 JalviewFileChooser chooser = new JalviewFileChooser(
730 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
731 { "fc" }, new String[]
732 { "Sequence Feature Colours" }, "Sequence Feature Colours");
733 chooser.setFileView(new jalview.io.JalviewFileView());
734 chooser.setDialogTitle(MessageManager.getString("label.load_feature_colours"));
735 chooser.setToolTipText(MessageManager.getString("action.load"));
737 int value = chooser.showOpenDialog(this);
739 if (value == JalviewFileChooser.APPROVE_OPTION)
741 File file = chooser.getSelectedFile();
745 InputStreamReader in = new InputStreamReader(new FileInputStream(
748 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
752 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
755 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
758 Color mincol = null, maxcol = null;
761 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
762 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
764 } catch (Exception e)
766 Cache.log.warn("Couldn't parse out graduated feature color.",
769 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
770 newcol.getMin(), newcol.getMax());
771 if (newcol.hasAutoScale())
773 gcol.setAutoScaled(newcol.getAutoScale());
775 if (newcol.hasColourByLabel())
777 gcol.setColourByLabel(newcol.getColourByLabel());
779 if (newcol.hasThreshold())
781 gcol.setThresh(newcol.getThreshold());
782 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
784 if (newcol.getThreshType().length() > 0)
786 String ttyp = newcol.getThreshType();
787 if (ttyp.equalsIgnoreCase("NONE"))
789 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
791 if (ttyp.equalsIgnoreCase("ABOVE"))
793 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
795 if (ttyp.equalsIgnoreCase("BELOW"))
797 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
800 fr.setColour(name = newcol.getName(), gcol);
804 fr.setColour(name = jucs.getColour(i).getName(), new Color(
805 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
807 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
812 Object[][] data = ((FeatureTableModel) table.getModel())
815 updateFeatureRenderer(data, false);
818 } catch (Exception ex)
820 System.out.println("Error loading User Colour File\n" + ex);
827 JalviewFileChooser chooser = new JalviewFileChooser(
828 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
829 { "fc" }, new String[]
830 { "Sequence Feature Colours" }, "Sequence Feature Colours");
831 chooser.setFileView(new jalview.io.JalviewFileView());
832 chooser.setDialogTitle(MessageManager.getString("label.save_feature_colours"));
833 chooser.setToolTipText(MessageManager.getString("action.save"));
835 int value = chooser.showSaveDialog(this);
837 if (value == JalviewFileChooser.APPROVE_OPTION)
839 String choice = chooser.getSelectedFile().getPath();
840 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
841 ucs.setSchemeName("Sequence Features");
844 PrintWriter out = new PrintWriter(new OutputStreamWriter(
845 new FileOutputStream(choice), "UTF-8"));
847 Iterator e = fr.featureColours.keySet().iterator();
848 float[] sortOrder = new float[fr.featureColours.size()];
849 String[] sortTypes = new String[fr.featureColours.size()];
853 sortTypes[i] = e.next().toString();
854 sortOrder[i] = fr.getOrder(sortTypes[i]);
857 jalview.util.QuickSort.sort(sortOrder, sortTypes);
861 for (i = 0; i < sortTypes.length; i++)
863 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
864 col.setName(sortTypes[i]);
865 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
867 fcol = fr.getFeatureStyle(sortTypes[i]);
868 if (fcol instanceof GraduatedColor)
870 gcol = (GraduatedColor) fcol;
871 col.setMin(gcol.getMin());
872 col.setMax(gcol.getMax());
873 col.setMinRGB(jalview.util.Format.getHexString(gcol
875 col.setAutoScale(gcol.isAutoScale());
876 col.setThreshold(gcol.getThresh());
877 col.setColourByLabel(gcol.isColourByLabel());
878 switch (gcol.getThreshType())
880 case AnnotationColourGradient.NO_THRESHOLD:
881 col.setThreshType("NONE");
883 case AnnotationColourGradient.ABOVE_THRESHOLD:
884 col.setThreshType("ABOVE");
886 case AnnotationColourGradient.BELOW_THRESHOLD:
887 col.setThreshType("BELOW");
895 } catch (Exception ex)
897 ex.printStackTrace();
902 public void invertSelection()
904 for (int i = 0; i < table.getRowCount(); i++)
906 Boolean value = (Boolean) table.getValueAt(i, 2);
908 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
912 public void orderByAvWidth()
914 if (table == null || table.getModel() == null)
918 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
919 float[] width = new float[data.length];
923 for (int i = 0; i < data.length; i++)
925 awidth = (float[]) typeWidth.get(data[i][0]);
928 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
929 // weight - but have to make per
930 // sequence, too (awidth[2])
931 // if (width[i]==1) // hack to distinguish single width sequences.
943 boolean sort = false;
944 for (int i = 0; i < width.length; i++)
946 // awidth = (float[]) typeWidth.get(data[i][0]);
949 width[i] = fr.getOrder(data[i][0].toString());
952 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
957 width[i] /= max; // normalize
958 fr.setOrder(data[i][0].toString(), width[i]); // store for later
962 sort = sort || width[i - 1] > width[i];
967 jalview.util.QuickSort.sort(width, data);
968 // update global priority order
971 updateFeatureRenderer(data, false);
979 frame.setClosed(true);
980 } catch (Exception exe)
986 public void updateFeatureRenderer(Object[][] data)
988 updateFeatureRenderer(data, true);
991 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
993 fr.setFeaturePriority(data, visibleNew);
994 af.alignPanel.paintAlignment(true);
997 int selectedRow = -1;
999 JTabbedPane tabbedPane = new JTabbedPane();
1001 BorderLayout borderLayout1 = new BorderLayout();
1003 BorderLayout borderLayout2 = new BorderLayout();
1005 BorderLayout borderLayout3 = new BorderLayout();
1007 JPanel bigPanel = new JPanel();
1009 BorderLayout borderLayout4 = new BorderLayout();
1011 JButton invert = new JButton();
1013 JPanel buttonPanel = new JPanel();
1015 JButton cancel = new JButton();
1017 JButton ok = new JButton();
1019 JButton loadColours = new JButton();
1021 JButton saveColours = new JButton();
1023 JPanel dasButtonPanel = new JPanel();
1025 JButton fetchDAS = new JButton();
1027 JButton saveDAS = new JButton();
1029 JButton cancelDAS = new JButton();
1031 JButton optimizeOrder = new JButton();
1033 JButton sortByScore = new JButton();
1035 JButton sortByDens = new JButton();
1037 JButton help = new JButton();
1039 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1041 private void jbInit() throws Exception
1043 this.setLayout(borderLayout1);
1044 settingsPane.setLayout(borderLayout2);
1045 dasSettingsPane.setLayout(borderLayout3);
1046 bigPanel.setLayout(borderLayout4);
1047 invert.setFont(JvSwingUtils.getLabelFont());
1048 invert.setText(MessageManager.getString("label.invert_selection"));
1049 invert.addActionListener(new ActionListener()
1051 public void actionPerformed(ActionEvent e)
1056 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1057 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1058 optimizeOrder.addActionListener(new ActionListener()
1060 public void actionPerformed(ActionEvent e)
1065 sortByScore.setFont(JvSwingUtils.getLabelFont());
1067 .setText(MessageManager.getString("label.seq_sort_by_score"));
1068 sortByScore.addActionListener(new ActionListener()
1070 public void actionPerformed(ActionEvent e)
1075 sortByDens.setFont(JvSwingUtils.getLabelFont());
1076 sortByDens.setText(MessageManager
1077 .getString("label.sequence_sort_by_density"));
1078 sortByDens.addActionListener(new ActionListener()
1080 public void actionPerformed(ActionEvent e)
1085 help.setFont(JvSwingUtils.getLabelFont());
1086 help.setText(MessageManager.getString("action.help"));
1087 help.addActionListener(new ActionListener()
1089 public void actionPerformed(ActionEvent e)
1093 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1094 } catch (HelpSetException e1)
1096 e1.printStackTrace();
1100 cancel.setFont(JvSwingUtils.getLabelFont());
1101 cancel.setText(MessageManager.getString("action.cancel"));
1102 cancel.addActionListener(new ActionListener()
1104 public void actionPerformed(ActionEvent e)
1106 updateFeatureRenderer(originalData);
1110 ok.setFont(JvSwingUtils.getLabelFont());
1111 ok.setText(MessageManager.getString("action.ok"));
1112 ok.addActionListener(new ActionListener()
1114 public void actionPerformed(ActionEvent e)
1119 loadColours.setFont(JvSwingUtils.getLabelFont());
1120 loadColours.setText(MessageManager.getString("label.load_colours"));
1121 loadColours.addActionListener(new ActionListener()
1123 public void actionPerformed(ActionEvent e)
1128 saveColours.setFont(JvSwingUtils.getLabelFont());
1129 saveColours.setText(MessageManager.getString("label.save_colours"));
1130 saveColours.addActionListener(new ActionListener()
1132 public void actionPerformed(ActionEvent e)
1137 transparency.addChangeListener(new ChangeListener()
1139 public void stateChanged(ChangeEvent evt)
1141 fr.setTransparency((100 - transparency.getValue()) / 100f);
1142 af.alignPanel.paintAlignment(true);
1146 transparency.setMaximum(70);
1147 transparency.setToolTipText(MessageManager
1148 .getString("label.transparency_tip"));
1149 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1150 fetchDAS.addActionListener(new ActionListener()
1152 public void actionPerformed(ActionEvent e)
1154 fetchDAS_actionPerformed(e);
1157 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1158 saveDAS.addActionListener(new ActionListener()
1160 public void actionPerformed(ActionEvent e)
1162 saveDAS_actionPerformed(e);
1165 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1166 dasSettingsPane.setBorder(null);
1167 cancelDAS.setEnabled(false);
1168 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1169 cancelDAS.addActionListener(new ActionListener()
1171 public void actionPerformed(ActionEvent e)
1173 cancelDAS_actionPerformed(e);
1176 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1177 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1178 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1179 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1180 transbuttons.add(optimizeOrder);
1181 transbuttons.add(invert);
1182 transbuttons.add(sortByScore);
1183 transbuttons.add(sortByDens);
1184 transbuttons.add(help);
1185 JPanel sliderPanel = new JPanel();
1186 sliderPanel.add(transparency);
1187 transPanel.add(transparency);
1188 transPanel.add(transbuttons);
1189 buttonPanel.add(ok);
1190 buttonPanel.add(cancel);
1191 buttonPanel.add(loadColours);
1192 buttonPanel.add(saveColours);
1193 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1194 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1195 dasButtonPanel.add(fetchDAS);
1196 dasButtonPanel.add(cancelDAS);
1197 dasButtonPanel.add(saveDAS);
1198 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1199 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1202 protected void sortByDens(String[] typ)
1204 sortBy(typ, "Sort by Density", AlignmentSorter.FEATURE_DENSITY);
1207 protected void sortBy(String[] typ, String methodText, final String method)
1211 typ = getDisplayedFeatureTypes();
1213 String gps[] = null;
1214 gps = getDisplayedFeatureGroups();
1217 ArrayList types = new ArrayList();
1218 for (int i = 0; i < typ.length; i++)
1224 typ = new String[types.size()];
1230 ArrayList grps = new ArrayList();
1232 for (int i = 0; i < gps.length; i++)
1239 gps = new String[grps.size()];
1242 AlignmentPanel alignPanel = af.alignPanel;
1243 AlignmentI al = alignPanel.av.getAlignment();
1246 SequenceGroup sg = alignPanel.av.getSelectionGroup();
1249 start = sg.getStartRes();
1250 stop = sg.getEndRes();
1255 stop = al.getWidth();
1257 SequenceI[] oldOrder = al.getSequencesArray();
1258 AlignmentSorter.sortByFeature(typ, gps, start, stop, al, method);
1259 af.addHistoryItem(new OrderCommand(methodText, oldOrder, alignPanel.av
1261 alignPanel.paintAlignment(true);
1265 protected void sortByScore(String[] typ)
1267 sortBy(typ, "Sort by Feature Score", AlignmentSorter.FEATURE_SCORE);
1270 private String[] getDisplayedFeatureTypes()
1272 String[] typ = null;
1275 synchronized (fr.renderOrder)
1277 typ = new String[fr.renderOrder.length];
1278 System.arraycopy(fr.renderOrder, 0, typ, 0, typ.length);
1279 for (int i = 0; i < typ.length; i++)
1281 if (af.viewport.featuresDisplayed.get(typ[i]) == null)
1291 private String[] getDisplayedFeatureGroups()
1293 String[] gps = null;
1294 ArrayList<String> _gps = new ArrayList<String>();
1298 if (fr.featureGroups != null)
1300 Iterator en = fr.featureGroups.keySet().iterator();
1302 boolean valid = false;
1303 while (en.hasNext())
1305 String gp = (String) en.next();
1306 Boolean on = (Boolean) fr.featureGroups.get(gp);
1307 if (on != null && on.booleanValue())
1319 gps = new String[_gps.size()];
1327 public void fetchDAS_actionPerformed(ActionEvent e)
1329 fetchDAS.setEnabled(false);
1330 cancelDAS.setEnabled(true);
1331 dassourceBrowser.setGuiEnabled(false);
1332 Vector selectedSources = dassourceBrowser.getSelectedSources();
1333 doDasFeatureFetch(selectedSources, true, true);
1337 * get the features from selectedSources for all or the current selection
1339 * @param selectedSources
1340 * @param checkDbRefs
1341 * @param promptFetchDbRefs
1343 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1344 boolean checkDbRefs, boolean promptFetchDbRefs)
1346 SequenceI[] dataset, seqs;
1348 AlignmentViewport vp = af.getViewport();
1349 if (vp.getSelectionGroup() != null
1350 && vp.getSelectionGroup().getSize() > 0)
1352 iSize = vp.getSelectionGroup().getSize();
1353 dataset = new SequenceI[iSize];
1354 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1358 iSize = vp.getAlignment().getHeight();
1359 seqs = vp.getAlignment().getSequencesArray();
1362 dataset = new SequenceI[iSize];
1363 for (int i = 0; i < iSize; i++)
1365 dataset[i] = seqs[i].getDatasetSequence();
1368 cancelDAS.setEnabled(true);
1369 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1370 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1371 af.getViewport().setShowSequenceFeatures(true);
1372 af.showSeqFeatures.setSelected(true);
1376 * blocking call to initialise the das source browser
1378 public void initDasSources()
1380 dassourceBrowser.initDasSources();
1384 * examine the current list of das sources and return any matching the given
1385 * nicknames in sources
1388 * Vector of Strings to resolve to DAS source nicknames.
1389 * @return sources that are present in source list.
1391 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1393 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1397 * get currently selected das sources. ensure you have called initDasSources
1398 * before calling this.
1400 * @return vector of selected das source nicknames
1402 public Vector getSelectedSources()
1404 return dassourceBrowser.getSelectedSources();
1408 * properly initialise DAS fetcher and then initiate a new thread to fetch
1409 * features from the named sources (rather than any turned on by default)
1413 * if true then runs in same thread, otherwise passes to the Swing
1416 public void fetchDasFeatures(Vector sources, boolean block)
1419 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1420 .resolveSourceNicknames(sources);
1421 if (resolved.size() == 0)
1423 resolved = dassourceBrowser.getSelectedSources();
1425 if (resolved.size() > 0)
1427 final List<jalviewSourceI> dassources = resolved;
1428 fetchDAS.setEnabled(false);
1429 // cancelDAS.setEnabled(true); doDasFetch does this.
1430 Runnable fetcher = new Runnable()
1435 doDasFeatureFetch(dassources, true, false);
1445 SwingUtilities.invokeLater(fetcher);
1450 public void saveDAS_actionPerformed(ActionEvent e)
1453 .saveProperties(jalview.bin.Cache.applicationProperties);
1456 public void complete()
1458 fetchDAS.setEnabled(true);
1459 cancelDAS.setEnabled(false);
1460 dassourceBrowser.setGuiEnabled(true);
1464 public void cancelDAS_actionPerformed(ActionEvent e)
1466 if (dasFeatureFetcher != null)
1468 dasFeatureFetcher.cancel();
1473 public void noDasSourceActive()
1477 .showInternalConfirmDialog(
1480 .getString("label.no_das_sources_selected_warn"),
1482 .getString("label.no_das_sources_selected_title"),
1483 JOptionPane.DEFAULT_OPTION,
1484 JOptionPane.INFORMATION_MESSAGE);
1487 // ///////////////////////////////////////////////////////////////////////
1488 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1489 // ///////////////////////////////////////////////////////////////////////
1490 class FeatureTableModel extends AbstractTableModel
1492 FeatureTableModel(Object[][] data)
1497 private String[] columnNames =
1498 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1500 private Object[][] data;
1502 public Object[][] getData()
1507 public void setData(Object[][] data)
1512 public int getColumnCount()
1514 return columnNames.length;
1517 public Object[] getRow(int row)
1522 public int getRowCount()
1527 public String getColumnName(int col)
1529 return columnNames[col];
1532 public Object getValueAt(int row, int col)
1534 return data[row][col];
1537 public Class getColumnClass(int c)
1539 return getValueAt(0, c).getClass();
1542 public boolean isCellEditable(int row, int col)
1544 return col == 0 ? false : true;
1547 public void setValueAt(Object value, int row, int col)
1549 data[row][col] = value;
1550 fireTableCellUpdated(row, col);
1551 updateFeatureRenderer(data);
1556 class ColorRenderer extends JLabel implements TableCellRenderer
1558 javax.swing.border.Border unselectedBorder = null;
1560 javax.swing.border.Border selectedBorder = null;
1562 final String baseTT = "Click to edit, right/apple click for menu.";
1564 public ColorRenderer()
1566 setOpaque(true); // MUST do this for background to show up.
1567 setHorizontalTextPosition(SwingConstants.CENTER);
1568 setVerticalTextPosition(SwingConstants.CENTER);
1571 public Component getTableCellRendererComponent(JTable table,
1572 Object color, boolean isSelected, boolean hasFocus, int row,
1575 // JLabel comp = new JLabel();
1579 // setBounds(getBounds());
1581 setToolTipText(baseTT);
1582 setBackground(table.getBackground());
1583 if (color instanceof GraduatedColor)
1585 Rectangle cr = table.getCellRect(row, column, false);
1586 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1587 (int) cr.getWidth(), (int) cr.getHeight());
1594 newColor = (Color) color;
1596 setBackground(newColor);
1597 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1598 // + newColor.getGreen() + ", " + newColor.getBlue());
1602 if (selectedBorder == null)
1604 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1605 table.getSelectionBackground());
1608 setBorder(selectedBorder);
1612 if (unselectedBorder == null)
1614 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1615 table.getBackground());
1618 setBorder(unselectedBorder);
1626 * update comp using rendering settings from gcol
1631 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1633 int w = comp.getWidth(), h = comp.getHeight();
1636 w = (int) comp.getPreferredSize().getWidth();
1637 h = (int) comp.getPreferredSize().getHeight();
1644 renderGraduatedColor(comp, gcol, w, h);
1647 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1650 boolean thr = false;
1653 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1657 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1659 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1663 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1665 if (gcol.isColourByLabel())
1667 tt = "Coloured by label text. " + tt;
1677 Color newColor = gcol.getMaxColor();
1678 comp.setBackground(newColor);
1679 // System.err.println("Width is " + w / 2);
1680 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1681 comp.setIcon(ficon);
1682 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1683 // + newColor.getGreen() + ", " + newColor.getBlue()
1684 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1685 // + ", " + minCol.getBlue() + ")");
1687 comp.setHorizontalAlignment(SwingConstants.CENTER);
1689 if (tt.length() > 0)
1691 if (comp.getToolTipText() == null)
1693 comp.setToolTipText(tt);
1697 comp.setToolTipText(tt + " " + comp.getToolTipText());
1703 class FeatureIcon implements Icon
1705 GraduatedColor gcol;
1709 boolean midspace = false;
1711 int width = 50, height = 20;
1713 int s1, e1; // start and end of midpoint band for thresholded symbol
1715 Color mpcolour = Color.white;
1717 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1736 public int getIconWidth()
1741 public int getIconHeight()
1746 public void paintIcon(Component c, Graphics g, int x, int y)
1749 if (gcol.isColourByLabel())
1752 g.fillRect(0, 0, width, height);
1753 // need an icon here.
1754 g.setColor(gcol.getMaxColor());
1756 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1758 // g.setFont(g.getFont().deriveFont(
1759 // AffineTransform.getScaleInstance(
1760 // width/g.getFontMetrics().stringWidth("Label"),
1761 // height/g.getFontMetrics().getHeight())));
1763 g.drawString(MessageManager.getString("label.label"), 0, 0);
1768 Color minCol = gcol.getMinColor();
1770 g.fillRect(0, 0, s1, height);
1773 g.setColor(Color.white);
1774 g.fillRect(s1, 0, e1 - s1, height);
1776 g.setColor(gcol.getMaxColor());
1777 g.fillRect(0, e1, width - e1, height);
1782 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1787 GraduatedColor currentGColor;
1789 FeatureColourChooser chooser;
1797 JColorChooser colorChooser;
1801 protected static final String EDIT = "edit";
1803 int selectedRow = 0;
1805 public ColorEditor(FeatureSettings me)
1808 // Set up the editor (from the table's point of view),
1809 // which is a button.
1810 // This button brings up the color chooser dialog,
1811 // which is the editor from the user's point of view.
1812 button = new JButton();
1813 button.setActionCommand(EDIT);
1814 button.addActionListener(this);
1815 button.setBorderPainted(false);
1816 // Set up the dialog that the button brings up.
1817 colorChooser = new JColorChooser();
1818 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1819 colorChooser, this, // OK button handler
1820 null); // no CANCEL button handler
1824 * Handles events from the editor button and from the dialog's OK button.
1826 public void actionPerformed(ActionEvent e)
1829 if (EDIT.equals(e.getActionCommand()))
1831 // The user has clicked the cell, so
1832 // bring up the dialog.
1833 if (currentColor != null)
1835 // bring up simple color chooser
1836 button.setBackground(currentColor);
1837 colorChooser.setColor(currentColor);
1838 dialog.setVisible(true);
1842 // bring up graduated chooser.
1843 chooser = new FeatureColourChooser(me.fr, type);
1844 chooser.setRequestFocusEnabled(true);
1845 chooser.requestFocus();
1846 chooser.addActionListener(this);
1848 // Make the renderer reappear.
1849 fireEditingStopped();
1853 { // User pressed dialog's "OK" button.
1854 if (currentColor != null)
1856 currentColor = colorChooser.getColor();
1860 // class cast exceptions may be raised if the chooser created on a
1861 // non-graduated color
1862 currentGColor = (GraduatedColor) chooser.getLastColour();
1864 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1865 fireEditingStopped();
1866 me.table.validate();
1870 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1871 public Object getCellEditorValue()
1873 if (currentColor == null)
1875 return currentGColor;
1877 return currentColor;
1880 // Implement the one method defined by TableCellEditor.
1881 public Component getTableCellEditorComponent(JTable table, Object value,
1882 boolean isSelected, int row, int column)
1884 currentGColor = null;
1885 currentColor = null;
1886 this.selectedRow = row;
1887 type = me.table.getValueAt(row, 0).toString();
1888 button.setOpaque(true);
1889 button.setBackground(me.getBackground());
1890 if (value instanceof GraduatedColor)
1892 currentGColor = (GraduatedColor) value;
1893 JLabel btn = new JLabel();
1894 btn.setSize(button.getSize());
1895 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1896 button.setBackground(btn.getBackground());
1897 button.setIcon(btn.getIcon());
1898 button.setText(btn.getText());
1903 button.setIcon(null);
1904 currentColor = (Color) value;
1905 button.setBackground(currentColor);