2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ 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.api.FeatureSettingsControllerI;
24 import jalview.bin.Cache;
25 import jalview.datamodel.SequenceFeature;
26 import jalview.datamodel.SequenceI;
27 import jalview.gui.Help.HelpId;
28 import jalview.io.JalviewFileChooser;
29 import jalview.schemes.AnnotationColourGradient;
30 import jalview.schemes.GraduatedColor;
31 import jalview.util.MessageManager;
32 import jalview.viewmodel.AlignmentViewport;
33 import jalview.ws.dbsources.das.api.jalviewSourceI;
35 import java.awt.BorderLayout;
36 import java.awt.Color;
37 import java.awt.Component;
39 import java.awt.Graphics;
40 import java.awt.GridLayout;
41 import java.awt.Rectangle;
42 import java.awt.event.ActionEvent;
43 import java.awt.event.ActionListener;
44 import java.awt.event.ItemEvent;
45 import java.awt.event.ItemListener;
46 import java.awt.event.MouseAdapter;
47 import java.awt.event.MouseEvent;
48 import java.awt.event.MouseMotionAdapter;
49 import java.beans.PropertyChangeEvent;
50 import java.beans.PropertyChangeListener;
52 import java.io.FileInputStream;
53 import java.io.FileOutputStream;
54 import java.io.InputStreamReader;
55 import java.io.OutputStreamWriter;
56 import java.io.PrintWriter;
57 import java.util.Hashtable;
58 import java.util.Iterator;
59 import java.util.List;
61 import java.util.Vector;
63 import javax.help.HelpSetException;
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 implements
93 FeatureSettingsControllerI
95 DasSourceBrowser dassourceBrowser;
97 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
99 JPanel settingsPane = new JPanel();
101 JPanel dasSettingsPane = new JPanel();
103 final FeatureRenderer fr;
105 public final AlignFrame af;
107 Object[][] originalData;
109 private float originalTransparency;
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();
127 // allow transparency to be recovered
128 transparency.setMaximum(100 - (int) ((originalTransparency=fr.getTransparency()) * 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.getMinMax(),
170 evt.getX(), evt.getY());
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.getMinMax(),
196 table.addMouseMotionListener(new MouseMotionAdapter()
198 public void mouseDragged(MouseEvent evt)
200 int newRow = table.rowAtPoint(evt.getPoint());
201 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
203 Object[] temp = new Object[3];
204 temp[0] = table.getValueAt(selectedRow, 0);
205 temp[1] = table.getValueAt(selectedRow, 1);
206 temp[2] = table.getValueAt(selectedRow, 2);
208 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
209 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
210 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
212 table.setValueAt(temp[0], newRow, 0);
213 table.setValueAt(temp[1], newRow, 1);
214 table.setValueAt(temp[2], newRow, 2);
216 selectedRow = newRow;
220 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
221 // MessageManager.getString("label.feature_settings_click_drag")));
222 scrollPane.setViewportView(table);
224 dassourceBrowser = new DasSourceBrowser(this);
225 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
227 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
229 fr.findAllFeatures(true); // display everything!
232 discoverAllFeatureData();
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.af.avc.sortAlignmentByFeatureScore(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.af.avc.sortAlignmentByFeatureDensity(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;
427 synchronized public void discoverAllFeatureData()
429 Vector allFeatures = new Vector();
430 Vector allGroups = new Vector();
431 SequenceFeature[] tmpfeatures;
433 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
435 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
436 .getSequenceFeatures();
437 if (tmpfeatures == null)
443 while (index < tmpfeatures.length)
445 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
451 if (tmpfeatures[index].getFeatureGroup() != null)
453 group = tmpfeatures[index].featureGroup;
454 if (!allGroups.contains(group))
456 allGroups.addElement(group);
457 checkGroupState(group);
461 if (!allFeatures.contains(tmpfeatures[index].getType()))
463 allFeatures.addElement(tmpfeatures[index].getType());
475 * Synchronise gui group list and check visibility of group
478 * @return true if group is visible
480 private boolean checkGroupState(String group)
482 boolean visible = fr.checkGroupVisibility(group, true);
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);
505 final String grp = group;
506 final JCheckBox check = new JCheckBox(group, visible);
507 check.setFont(new Font("Serif", Font.BOLD, 12));
508 check.addItemListener(new ItemListener()
510 public void itemStateChanged(ItemEvent evt)
512 fr.setGroupVisibility(check.getText(), check.isSelected());
513 af.alignPanel.getSeqPanel().seqCanvas.repaint();
514 if (af.alignPanel.overviewPanel != null)
516 af.alignPanel.overviewPanel.updateOverviewImage();
519 resetTable(new String[]
523 groupPanel.add(check);
527 boolean resettingTable = false;
529 synchronized void resetTable(String[] groupChanged)
531 if (resettingTable == true)
535 resettingTable = true;
536 typeWidth = new Hashtable();
537 // TODO: change avWidth calculation to 'per-sequence' average and use long
539 float[] avWidth = null;
540 SequenceFeature[] tmpfeatures;
541 String group = null, type;
542 Vector visibleChecks = new Vector();
544 // Find out which features should be visible depending on which groups
545 // are selected / deselected
546 // and recompute average width ordering
547 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
550 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
551 .getSequenceFeatures();
552 if (tmpfeatures == null)
558 while (index < tmpfeatures.length)
560 group = tmpfeatures[index].featureGroup;
562 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
568 if (group == null || checkGroupState(group))
570 type = tmpfeatures[index].getType();
571 if (!visibleChecks.contains(type))
573 visibleChecks.addElement(type);
576 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
578 typeWidth.put(tmpfeatures[index].getType(),
579 avWidth = new float[3]);
583 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
586 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
588 avWidth[1] += 1 + tmpfeatures[index].getBegin()
589 - tmpfeatures[index].getEnd();
593 avWidth[1] += 1 + tmpfeatures[index].getEnd()
594 - tmpfeatures[index].getBegin();
600 int fSize = visibleChecks.size();
601 Object[][] data = new Object[fSize][3];
604 if (fr.hasRenderOrder())
608 fr.findAllFeatures(groupChanged != null); // prod to update
609 // colourschemes. but don't
611 // First add the checks in the previous render order,
612 // in case the window has been closed and reopened
614 List<String> frl = fr.getRenderOrder();
615 for (int ro = frl.size() - 1; ro > -1; ro--)
619 if (!visibleChecks.contains(type))
624 data[dataIndex][0] = type;
625 data[dataIndex][1] = fr.getFeatureStyle(type);
626 data[dataIndex][2] = new Boolean(af.getViewport()
627 .getFeaturesDisplayed().isVisible(type));
629 visibleChecks.removeElement(type);
633 fSize = visibleChecks.size();
634 for (int i = 0; i < fSize; i++)
636 // These must be extra features belonging to the group
637 // which was just selected
638 type = visibleChecks.elementAt(i).toString();
639 data[dataIndex][0] = type;
641 data[dataIndex][1] = fr.getFeatureStyle(type);
642 if (data[dataIndex][1] == null)
644 // "Colour has been updated in another view!!"
645 fr.clearRenderOrder();
649 data[dataIndex][2] = new Boolean(true);
653 if (originalData == null)
655 originalData = new Object[data.length][3];
656 for (int i = 0; i < data.length; i++)
658 System.arraycopy(data[i], 0, originalData[i], 0, 3);
662 table.setModel(new FeatureTableModel(data));
663 table.getColumnModel().getColumn(0).setPreferredWidth(200);
665 if (groupPanel != null)
667 groupPanel.setLayout(new GridLayout(
668 fr.getFeatureGroupsSize() / 4 + 1, 4));
670 groupPanel.validate();
671 bigPanel.add(groupPanel, BorderLayout.NORTH);
674 updateFeatureRenderer(data, groupChanged != null);
675 resettingTable = false;
679 * reorder data based on the featureRenderers global priority list.
683 private void ensureOrder(Object[][] data)
685 boolean sort = false;
686 float[] order = new float[data.length];
687 for (int i = 0; i < order.length; i++)
689 order[i] = fr.getOrder(data[i][0].toString());
692 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
696 sort = sort || order[i - 1] > order[i];
701 jalview.util.QuickSort.sort(order, data);
707 JalviewFileChooser chooser = new JalviewFileChooser(
708 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
709 { "fc" }, new String[]
710 { "Sequence Feature Colours" }, "Sequence Feature Colours");
711 chooser.setFileView(new jalview.io.JalviewFileView());
712 chooser.setDialogTitle(MessageManager.getString("label.load_feature_colours"));
713 chooser.setToolTipText(MessageManager.getString("action.load"));
715 int value = chooser.showOpenDialog(this);
717 if (value == JalviewFileChooser.APPROVE_OPTION)
719 File file = chooser.getSelectedFile();
723 InputStreamReader in = new InputStreamReader(new FileInputStream(
726 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
730 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
733 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
736 Color mincol = null, maxcol = null;
739 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
740 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
742 } catch (Exception e)
744 Cache.log.warn("Couldn't parse out graduated feature color.",
747 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
748 newcol.getMin(), newcol.getMax());
749 if (newcol.hasAutoScale())
751 gcol.setAutoScaled(newcol.getAutoScale());
753 if (newcol.hasColourByLabel())
755 gcol.setColourByLabel(newcol.getColourByLabel());
757 if (newcol.hasThreshold())
759 gcol.setThresh(newcol.getThreshold());
760 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
762 if (newcol.getThreshType().length() > 0)
764 String ttyp = newcol.getThreshType();
765 if (ttyp.equalsIgnoreCase("NONE"))
767 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
769 if (ttyp.equalsIgnoreCase("ABOVE"))
771 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
773 if (ttyp.equalsIgnoreCase("BELOW"))
775 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
778 fr.setColour(name = newcol.getName(), gcol);
782 fr.setColour(name = jucs.getColour(i).getName(), new Color(
783 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
785 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
790 Object[][] data = ((FeatureTableModel) table.getModel())
793 updateFeatureRenderer(data, false);
796 } catch (Exception ex)
798 System.out.println("Error loading User Colour File\n" + ex);
805 JalviewFileChooser chooser = new JalviewFileChooser(
806 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
807 { "fc" }, new String[]
808 { "Sequence Feature Colours" }, "Sequence Feature Colours");
809 chooser.setFileView(new jalview.io.JalviewFileView());
810 chooser.setDialogTitle(MessageManager.getString("label.save_feature_colours"));
811 chooser.setToolTipText(MessageManager.getString("action.save"));
813 int value = chooser.showSaveDialog(this);
815 if (value == JalviewFileChooser.APPROVE_OPTION)
817 String choice = chooser.getSelectedFile().getPath();
818 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
819 ucs.setSchemeName("Sequence Features");
822 PrintWriter out = new PrintWriter(new OutputStreamWriter(
823 new FileOutputStream(choice), "UTF-8"));
825 Set fr_colours = fr.getAllFeatureColours();
826 Iterator e = fr_colours.iterator();
827 float[] sortOrder = new float[fr_colours.size()];
828 String[] sortTypes = new String[fr_colours.size()];
832 sortTypes[i] = e.next().toString();
833 sortOrder[i] = fr.getOrder(sortTypes[i]);
836 jalview.util.QuickSort.sort(sortOrder, sortTypes);
840 for (i = 0; i < sortTypes.length; i++)
842 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
843 col.setName(sortTypes[i]);
844 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
846 fcol = fr.getFeatureStyle(sortTypes[i]);
847 if (fcol instanceof GraduatedColor)
849 gcol = (GraduatedColor) fcol;
850 col.setMin(gcol.getMin());
851 col.setMax(gcol.getMax());
852 col.setMinRGB(jalview.util.Format.getHexString(gcol
854 col.setAutoScale(gcol.isAutoScale());
855 col.setThreshold(gcol.getThresh());
856 col.setColourByLabel(gcol.isColourByLabel());
857 switch (gcol.getThreshType())
859 case AnnotationColourGradient.NO_THRESHOLD:
860 col.setThreshType("NONE");
862 case AnnotationColourGradient.ABOVE_THRESHOLD:
863 col.setThreshType("ABOVE");
865 case AnnotationColourGradient.BELOW_THRESHOLD:
866 col.setThreshType("BELOW");
874 } catch (Exception ex)
876 ex.printStackTrace();
881 public void invertSelection()
883 for (int i = 0; i < table.getRowCount(); i++)
885 Boolean value = (Boolean) table.getValueAt(i, 2);
887 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
891 public void orderByAvWidth()
893 if (table == null || table.getModel() == null)
897 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
898 float[] width = new float[data.length];
902 for (int i = 0; i < data.length; i++)
904 awidth = (float[]) typeWidth.get(data[i][0]);
907 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
908 // weight - but have to make per
909 // sequence, too (awidth[2])
910 // if (width[i]==1) // hack to distinguish single width sequences.
922 boolean sort = false;
923 for (int i = 0; i < width.length; i++)
925 // awidth = (float[]) typeWidth.get(data[i][0]);
928 width[i] = fr.getOrder(data[i][0].toString());
931 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
936 width[i] /= max; // normalize
937 fr.setOrder(data[i][0].toString(), width[i]); // store for later
941 sort = sort || width[i - 1] > width[i];
946 jalview.util.QuickSort.sort(width, data);
947 // update global priority order
950 updateFeatureRenderer(data, false);
958 frame.setClosed(true);
959 } catch (Exception exe)
965 public void updateFeatureRenderer(Object[][] data)
967 updateFeatureRenderer(data, true);
970 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
972 fr.setFeaturePriority(data, visibleNew);
973 af.alignPanel.paintAlignment(true);
976 int selectedRow = -1;
978 JTabbedPane tabbedPane = new JTabbedPane();
980 BorderLayout borderLayout1 = new BorderLayout();
982 BorderLayout borderLayout2 = new BorderLayout();
984 BorderLayout borderLayout3 = new BorderLayout();
986 JPanel bigPanel = new JPanel();
988 BorderLayout borderLayout4 = new BorderLayout();
990 JButton invert = new JButton();
992 JPanel buttonPanel = new JPanel();
994 JButton cancel = new JButton();
996 JButton ok = new JButton();
998 JButton loadColours = new JButton();
1000 JButton saveColours = new JButton();
1002 JPanel dasButtonPanel = new JPanel();
1004 JButton fetchDAS = new JButton();
1006 JButton saveDAS = new JButton();
1008 JButton cancelDAS = new JButton();
1010 JButton optimizeOrder = new JButton();
1012 JButton sortByScore = new JButton();
1014 JButton sortByDens = new JButton();
1016 JButton help = new JButton();
1018 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1020 private void jbInit() throws Exception
1022 this.setLayout(borderLayout1);
1023 settingsPane.setLayout(borderLayout2);
1024 dasSettingsPane.setLayout(borderLayout3);
1025 bigPanel.setLayout(borderLayout4);
1026 invert.setFont(JvSwingUtils.getLabelFont());
1027 invert.setText(MessageManager.getString("label.invert_selection"));
1028 invert.addActionListener(new ActionListener()
1030 public void actionPerformed(ActionEvent e)
1035 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1036 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1037 optimizeOrder.addActionListener(new ActionListener()
1039 public void actionPerformed(ActionEvent e)
1044 sortByScore.setFont(JvSwingUtils.getLabelFont());
1046 .setText(MessageManager.getString("label.seq_sort_by_score"));
1047 sortByScore.addActionListener(new ActionListener()
1049 public void actionPerformed(ActionEvent e)
1051 af.avc.sortAlignmentByFeatureScore(null);
1054 sortByDens.setFont(JvSwingUtils.getLabelFont());
1055 sortByDens.setText(MessageManager
1056 .getString("label.sequence_sort_by_density"));
1057 sortByDens.addActionListener(new ActionListener()
1059 public void actionPerformed(ActionEvent e)
1061 af.avc.sortAlignmentByFeatureDensity(null);
1064 help.setFont(JvSwingUtils.getLabelFont());
1065 help.setText(MessageManager.getString("action.help"));
1066 help.addActionListener(new ActionListener()
1068 public void actionPerformed(ActionEvent e)
1072 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1073 } catch (HelpSetException e1)
1075 e1.printStackTrace();
1079 help.setFont(JvSwingUtils.getLabelFont());
1080 help.setText(MessageManager.getString("action.help"));
1081 help.addActionListener(new ActionListener()
1083 public void actionPerformed(ActionEvent e)
1087 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1088 } catch (HelpSetException e1)
1090 e1.printStackTrace();
1094 cancel.setFont(JvSwingUtils.getLabelFont());
1095 cancel.setText(MessageManager.getString("action.cancel"));
1096 cancel.addActionListener(new ActionListener()
1098 public void actionPerformed(ActionEvent e)
1100 fr.setTransparency(originalTransparency);
1101 updateFeatureRenderer(originalData);
1105 ok.setFont(JvSwingUtils.getLabelFont());
1106 ok.setText(MessageManager.getString("action.ok"));
1107 ok.addActionListener(new ActionListener()
1109 public void actionPerformed(ActionEvent e)
1114 loadColours.setFont(JvSwingUtils.getLabelFont());
1115 loadColours.setText(MessageManager.getString("label.load_colours"));
1116 loadColours.addActionListener(new ActionListener()
1118 public void actionPerformed(ActionEvent e)
1123 saveColours.setFont(JvSwingUtils.getLabelFont());
1124 saveColours.setText(MessageManager.getString("label.save_colours"));
1125 saveColours.addActionListener(new ActionListener()
1127 public void actionPerformed(ActionEvent e)
1132 transparency.addChangeListener(new ChangeListener()
1134 public void stateChanged(ChangeEvent evt)
1136 fr.setTransparency((100 - transparency.getValue()) / 100f);
1137 af.alignPanel.paintAlignment(true);
1141 transparency.setMaximum(70);
1142 transparency.setToolTipText(MessageManager
1143 .getString("label.transparency_tip"));
1144 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1145 fetchDAS.addActionListener(new ActionListener()
1147 public void actionPerformed(ActionEvent e)
1149 fetchDAS_actionPerformed(e);
1152 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1153 saveDAS.addActionListener(new ActionListener()
1155 public void actionPerformed(ActionEvent e)
1157 saveDAS_actionPerformed(e);
1160 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1161 dasSettingsPane.setBorder(null);
1162 cancelDAS.setEnabled(false);
1163 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1164 cancelDAS.addActionListener(new ActionListener()
1166 public void actionPerformed(ActionEvent e)
1168 cancelDAS_actionPerformed(e);
1171 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1172 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1173 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1174 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1175 transbuttons.add(optimizeOrder);
1176 transbuttons.add(invert);
1177 transbuttons.add(sortByScore);
1178 transbuttons.add(sortByDens);
1179 transbuttons.add(help);
1180 JPanel sliderPanel = new JPanel();
1181 sliderPanel.add(transparency);
1182 transPanel.add(transparency);
1183 transPanel.add(transbuttons);
1184 buttonPanel.add(ok);
1185 buttonPanel.add(cancel);
1186 buttonPanel.add(loadColours);
1187 buttonPanel.add(saveColours);
1188 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1189 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1190 dasButtonPanel.add(fetchDAS);
1191 dasButtonPanel.add(cancelDAS);
1192 dasButtonPanel.add(saveDAS);
1193 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1194 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1197 public void fetchDAS_actionPerformed(ActionEvent e)
1199 fetchDAS.setEnabled(false);
1200 cancelDAS.setEnabled(true);
1201 dassourceBrowser.setGuiEnabled(false);
1202 Vector selectedSources = dassourceBrowser.getSelectedSources();
1203 doDasFeatureFetch(selectedSources, true, true);
1207 * get the features from selectedSources for all or the current selection
1209 * @param selectedSources
1210 * @param checkDbRefs
1211 * @param promptFetchDbRefs
1213 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1214 boolean checkDbRefs, boolean promptFetchDbRefs)
1216 SequenceI[] dataset, seqs;
1218 AlignmentViewport vp = af.getViewport();
1219 if (vp.getSelectionGroup() != null
1220 && vp.getSelectionGroup().getSize() > 0)
1222 iSize = vp.getSelectionGroup().getSize();
1223 dataset = new SequenceI[iSize];
1224 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1228 iSize = vp.getAlignment().getHeight();
1229 seqs = vp.getAlignment().getSequencesArray();
1232 dataset = new SequenceI[iSize];
1233 for (int i = 0; i < iSize; i++)
1235 dataset[i] = seqs[i].getDatasetSequence();
1238 cancelDAS.setEnabled(true);
1239 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1240 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1241 af.getViewport().setShowSequenceFeatures(true);
1242 af.showSeqFeatures.setSelected(true);
1246 * blocking call to initialise the das source browser
1248 public void initDasSources()
1250 dassourceBrowser.initDasSources();
1254 * examine the current list of das sources and return any matching the given
1255 * nicknames in sources
1258 * Vector of Strings to resolve to DAS source nicknames.
1259 * @return sources that are present in source list.
1261 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1263 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1267 * get currently selected das sources. ensure you have called initDasSources
1268 * before calling this.
1270 * @return vector of selected das source nicknames
1272 public Vector getSelectedSources()
1274 return dassourceBrowser.getSelectedSources();
1278 * properly initialise DAS fetcher and then initiate a new thread to fetch
1279 * features from the named sources (rather than any turned on by default)
1283 * if true then runs in same thread, otherwise passes to the Swing
1286 public void fetchDasFeatures(Vector sources, boolean block)
1289 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1290 .resolveSourceNicknames(sources);
1291 if (resolved.size() == 0)
1293 resolved = dassourceBrowser.getSelectedSources();
1295 if (resolved.size() > 0)
1297 final List<jalviewSourceI> dassources = resolved;
1298 fetchDAS.setEnabled(false);
1299 // cancelDAS.setEnabled(true); doDasFetch does this.
1300 Runnable fetcher = new Runnable()
1305 doDasFeatureFetch(dassources, true, false);
1315 SwingUtilities.invokeLater(fetcher);
1320 public void saveDAS_actionPerformed(ActionEvent e)
1323 .saveProperties(jalview.bin.Cache.applicationProperties);
1326 public void complete()
1328 fetchDAS.setEnabled(true);
1329 cancelDAS.setEnabled(false);
1330 dassourceBrowser.setGuiEnabled(true);
1334 public void cancelDAS_actionPerformed(ActionEvent e)
1336 if (dasFeatureFetcher != null)
1338 dasFeatureFetcher.cancel();
1343 public void noDasSourceActive()
1347 .showInternalConfirmDialog(
1350 .getString("label.no_das_sources_selected_warn"),
1352 .getString("label.no_das_sources_selected_title"),
1353 JOptionPane.DEFAULT_OPTION,
1354 JOptionPane.INFORMATION_MESSAGE);
1357 // ///////////////////////////////////////////////////////////////////////
1358 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1359 // ///////////////////////////////////////////////////////////////////////
1360 class FeatureTableModel extends AbstractTableModel
1362 FeatureTableModel(Object[][] data)
1367 private String[] columnNames =
1368 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1370 private Object[][] data;
1372 public Object[][] getData()
1377 public void setData(Object[][] data)
1382 public int getColumnCount()
1384 return columnNames.length;
1387 public Object[] getRow(int row)
1392 public int getRowCount()
1397 public String getColumnName(int col)
1399 return columnNames[col];
1402 public Object getValueAt(int row, int col)
1404 return data[row][col];
1407 public Class getColumnClass(int c)
1409 return getValueAt(0, c).getClass();
1412 public boolean isCellEditable(int row, int col)
1414 return col == 0 ? false : true;
1417 public void setValueAt(Object value, int row, int col)
1419 data[row][col] = value;
1420 fireTableCellUpdated(row, col);
1421 updateFeatureRenderer(data);
1426 class ColorRenderer extends JLabel implements TableCellRenderer
1428 javax.swing.border.Border unselectedBorder = null;
1430 javax.swing.border.Border selectedBorder = null;
1432 final String baseTT = "Click to edit, right/apple click for menu.";
1434 public ColorRenderer()
1436 setOpaque(true); // MUST do this for background to show up.
1437 setHorizontalTextPosition(SwingConstants.CENTER);
1438 setVerticalTextPosition(SwingConstants.CENTER);
1441 public Component getTableCellRendererComponent(JTable table,
1442 Object color, boolean isSelected, boolean hasFocus, int row,
1445 // JLabel comp = new JLabel();
1449 // setBounds(getBounds());
1451 setToolTipText(baseTT);
1452 setBackground(table.getBackground());
1453 if (color instanceof GraduatedColor)
1455 Rectangle cr = table.getCellRect(row, column, false);
1456 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1457 (int) cr.getWidth(), (int) cr.getHeight());
1464 newColor = (Color) color;
1466 setBackground(newColor);
1467 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1468 // + newColor.getGreen() + ", " + newColor.getBlue());
1472 if (selectedBorder == null)
1474 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1475 table.getSelectionBackground());
1478 setBorder(selectedBorder);
1482 if (unselectedBorder == null)
1484 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1485 table.getBackground());
1488 setBorder(unselectedBorder);
1496 * update comp using rendering settings from gcol
1501 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1503 int w = comp.getWidth(), h = comp.getHeight();
1506 w = (int) comp.getPreferredSize().getWidth();
1507 h = (int) comp.getPreferredSize().getHeight();
1514 renderGraduatedColor(comp, gcol, w, h);
1517 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1520 boolean thr = false;
1523 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1527 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1529 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1533 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1535 if (gcol.isColourByLabel())
1537 tt = "Coloured by label text. " + tt;
1547 Color newColor = gcol.getMaxColor();
1548 comp.setBackground(newColor);
1549 // System.err.println("Width is " + w / 2);
1550 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1551 comp.setIcon(ficon);
1552 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1553 // + newColor.getGreen() + ", " + newColor.getBlue()
1554 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1555 // + ", " + minCol.getBlue() + ")");
1557 comp.setHorizontalAlignment(SwingConstants.CENTER);
1559 if (tt.length() > 0)
1561 if (comp.getToolTipText() == null)
1563 comp.setToolTipText(tt);
1567 comp.setToolTipText(tt + " " + comp.getToolTipText());
1573 class FeatureIcon implements Icon
1575 GraduatedColor gcol;
1579 boolean midspace = false;
1581 int width = 50, height = 20;
1583 int s1, e1; // start and end of midpoint band for thresholded symbol
1585 Color mpcolour = Color.white;
1587 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1606 public int getIconWidth()
1611 public int getIconHeight()
1616 public void paintIcon(Component c, Graphics g, int x, int y)
1619 if (gcol.isColourByLabel())
1622 g.fillRect(0, 0, width, height);
1623 // need an icon here.
1624 g.setColor(gcol.getMaxColor());
1626 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1628 // g.setFont(g.getFont().deriveFont(
1629 // AffineTransform.getScaleInstance(
1630 // width/g.getFontMetrics().stringWidth("Label"),
1631 // height/g.getFontMetrics().getHeight())));
1633 g.drawString(MessageManager.getString("label.label"), 0, 0);
1638 Color minCol = gcol.getMinColor();
1640 g.fillRect(0, 0, s1, height);
1643 g.setColor(Color.white);
1644 g.fillRect(s1, 0, e1 - s1, height);
1646 g.setColor(gcol.getMaxColor());
1647 g.fillRect(0, e1, width - e1, height);
1652 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1657 GraduatedColor currentGColor;
1659 FeatureColourChooser chooser;
1667 JColorChooser colorChooser;
1671 protected static final String EDIT = "edit";
1673 int selectedRow = 0;
1675 public ColorEditor(FeatureSettings me)
1678 // Set up the editor (from the table's point of view),
1679 // which is a button.
1680 // This button brings up the color chooser dialog,
1681 // which is the editor from the user's point of view.
1682 button = new JButton();
1683 button.setActionCommand(EDIT);
1684 button.addActionListener(this);
1685 button.setBorderPainted(false);
1686 // Set up the dialog that the button brings up.
1687 colorChooser = new JColorChooser();
1688 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1689 colorChooser, this, // OK button handler
1690 null); // no CANCEL button handler
1694 * Handles events from the editor button and from the dialog's OK button.
1696 public void actionPerformed(ActionEvent e)
1699 if (EDIT.equals(e.getActionCommand()))
1701 // The user has clicked the cell, so
1702 // bring up the dialog.
1703 if (currentColor != null)
1705 // bring up simple color chooser
1706 button.setBackground(currentColor);
1707 colorChooser.setColor(currentColor);
1708 dialog.setVisible(true);
1712 // bring up graduated chooser.
1713 chooser = new FeatureColourChooser(me.fr, type);
1714 chooser.setRequestFocusEnabled(true);
1715 chooser.requestFocus();
1716 chooser.addActionListener(this);
1718 // Make the renderer reappear.
1719 fireEditingStopped();
1723 { // User pressed dialog's "OK" button.
1724 if (currentColor != null)
1726 currentColor = colorChooser.getColor();
1730 // class cast exceptions may be raised if the chooser created on a
1731 // non-graduated color
1732 currentGColor = (GraduatedColor) chooser.getLastColour();
1734 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1735 fireEditingStopped();
1736 me.table.validate();
1740 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1741 public Object getCellEditorValue()
1743 if (currentColor == null)
1745 return currentGColor;
1747 return currentColor;
1750 // Implement the one method defined by TableCellEditor.
1751 public Component getTableCellEditorComponent(JTable table, Object value,
1752 boolean isSelected, int row, int column)
1754 currentGColor = null;
1755 currentColor = null;
1756 this.selectedRow = row;
1757 type = me.table.getValueAt(row, 0).toString();
1758 button.setOpaque(true);
1759 button.setBackground(me.getBackground());
1760 if (value instanceof GraduatedColor)
1762 currentGColor = (GraduatedColor) value;
1763 JLabel btn = new JLabel();
1764 btn.setSize(button.getSize());
1765 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1766 button.setBackground(btn.getBackground());
1767 button.setIcon(btn.getIcon());
1768 button.setText(btn.getText());
1773 button.setIcon(null);
1774 currentColor = (Color) value;
1775 button.setBackground(currentColor);