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.Arrays;
58 import java.util.Hashtable;
59 import java.util.Iterator;
60 import java.util.List;
63 import java.util.Vector;
65 import javax.help.HelpSetException;
66 import javax.swing.AbstractCellEditor;
67 import javax.swing.BorderFactory;
68 import javax.swing.Icon;
69 import javax.swing.JButton;
70 import javax.swing.JCheckBox;
71 import javax.swing.JCheckBoxMenuItem;
72 import javax.swing.JColorChooser;
73 import javax.swing.JDialog;
74 import javax.swing.JInternalFrame;
75 import javax.swing.JLabel;
76 import javax.swing.JLayeredPane;
77 import javax.swing.JMenuItem;
78 import javax.swing.JOptionPane;
79 import javax.swing.JPanel;
80 import javax.swing.JPopupMenu;
81 import javax.swing.JScrollPane;
82 import javax.swing.JSlider;
83 import javax.swing.JTabbedPane;
84 import javax.swing.JTable;
85 import javax.swing.ListSelectionModel;
86 import javax.swing.SwingConstants;
87 import javax.swing.SwingUtilities;
88 import javax.swing.event.ChangeEvent;
89 import javax.swing.event.ChangeListener;
90 import javax.swing.table.AbstractTableModel;
91 import javax.swing.table.TableCellEditor;
92 import javax.swing.table.TableCellRenderer;
94 public class FeatureSettings extends JPanel implements
95 FeatureSettingsControllerI
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 private float originalTransparency;
113 final JInternalFrame frame;
115 JScrollPane scrollPane = new JScrollPane();
121 JSlider transparency = new JSlider();
123 JPanel transPanel = new JPanel(new GridLayout(1, 2));
125 public FeatureSettings(AlignFrame af)
128 fr = af.getFeatureRenderer();
129 // allow transparency to be recovered
130 transparency.setMaximum(100 - (int) ((originalTransparency = fr
131 .getTransparency()) * 100));
136 } catch (Exception ex)
138 ex.printStackTrace();
144 public String getToolTipText(MouseEvent e)
146 if (table.columnAtPoint(e.getPoint()) == 0)
149 * Tooltip for feature name only
151 return JvSwingUtils.wrapTooltip(true, MessageManager
152 .getString("label.feature_settings_click_drag"));
157 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
158 table.setFont(new Font("Verdana", Font.PLAIN, 12));
159 table.setDefaultRenderer(Color.class, new ColorRenderer());
161 table.setDefaultEditor(Color.class, new ColorEditor(this));
163 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
164 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
165 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
167 table.addMouseListener(new MouseAdapter()
170 public void mousePressed(MouseEvent evt)
172 selectedRow = table.rowAtPoint(evt.getPoint());
173 if (evt.isPopupTrigger())
175 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
176 table.getValueAt(selectedRow, 1), fr.getMinMax(),
177 evt.getX(), evt.getY());
179 else if (evt.getClickCount() == 2)
181 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
182 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
184 (String) table.getValueAt(selectedRow, 0));
188 // isPopupTrigger fires on mouseReleased on Mac
190 public void mouseReleased(MouseEvent evt)
192 selectedRow = table.rowAtPoint(evt.getPoint());
193 if (evt.isPopupTrigger())
195 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
196 table.getValueAt(selectedRow, 1), fr.getMinMax(),
197 evt.getX(), evt.getY());
202 table.addMouseMotionListener(new MouseMotionAdapter()
205 public void mouseDragged(MouseEvent evt)
207 int newRow = table.rowAtPoint(evt.getPoint());
208 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
210 Object[][] data = ((FeatureTableModel) table.getModel())
212 Object[] temp = data[selectedRow];
213 data[selectedRow] = data[newRow];
215 updateFeatureRenderer(data);
217 selectedRow = newRow;
221 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
222 // MessageManager.getString("label.feature_settings_click_drag")));
223 scrollPane.setViewportView(table);
225 dassourceBrowser = new DasSourceBrowser(this);
226 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
228 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
230 fr.findAllFeatures(true); // display everything!
233 discoverAllFeatureData();
234 final PropertyChangeListener change;
235 final FeatureSettings fs = this;
236 fr.addPropertyChangeListener(change = new PropertyChangeListener()
239 public void propertyChange(PropertyChangeEvent evt)
241 if (!fs.resettingTable && !fs.handlingUpdate)
243 fs.handlingUpdate = true;
244 fs.resetTable(null); // new groups may be added with new seuqence
245 // feature types only
246 fs.handlingUpdate = false;
252 frame = new JInternalFrame();
253 frame.setContentPane(this);
254 if (new jalview.util.Platform().isAMac())
256 Desktop.addInternalFrame(frame,
257 MessageManager.getString("label.sequence_feature_settings"),
262 Desktop.addInternalFrame(frame,
263 MessageManager.getString("label.sequence_feature_settings"),
267 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
270 public void internalFrameClosed(
271 javax.swing.event.InternalFrameEvent evt)
273 fr.removePropertyChangeListener(change);
274 dassourceBrowser.fs = null;
277 frame.setLayer(JLayeredPane.PALETTE_LAYER);
280 protected void popupSort(final int selectedRow, final String type,
281 final Object typeCol, final Map<String, float[][]> minmax, int x,
284 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
285 "label.settings_for_param", new String[] { type }));
286 JMenuItem scr = new JMenuItem(
287 MessageManager.getString("label.sort_by_score"));
289 final FeatureSettings me = this;
290 scr.addActionListener(new ActionListener()
294 public void actionPerformed(ActionEvent e)
296 me.af.avc.sortAlignmentByFeatureScore(Arrays
297 .asList(new String[] { type }));
301 JMenuItem dens = new JMenuItem(
302 MessageManager.getString("label.sort_by_density"));
303 dens.addActionListener(new ActionListener()
307 public void actionPerformed(ActionEvent e)
309 me.af.avc.sortAlignmentByFeatureDensity(Arrays
310 .asList(new String[] { type }));
317 final float[][] typeMinMax = minmax.get(type);
319 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
320 * this is broken at the moment and isn't that useful anyway!
321 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
324 * public void actionPerformed(ActionEvent e) {
325 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
326 * null); } else { minmax.put(type, typeMinMax); } }
332 if (typeMinMax != null && typeMinMax[0] != null)
334 // if (table.getValueAt(row, column));
335 // graduated colourschemes for those where minmax exists for the
336 // positional features
337 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
339 mxcol.setSelected(!(typeCol instanceof Color));
341 mxcol.addActionListener(new ActionListener()
343 JColorChooser colorChooser;
346 public void actionPerformed(ActionEvent e)
348 if (e.getSource() == mxcol)
350 if (typeCol instanceof Color)
352 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
354 fc.addActionListener(this);
358 // bring up simple color chooser
359 colorChooser = new JColorChooser();
360 JDialog dialog = JColorChooser.createDialog(me,
361 "Select new Colour", true, // modal
362 colorChooser, this, // OK button handler
363 null); // no CANCEL button handler
364 colorChooser.setColor(((GraduatedColor) typeCol)
366 dialog.setVisible(true);
371 if (e.getSource() instanceof FeatureColourChooser)
373 FeatureColourChooser fc = (FeatureColourChooser) e
375 table.setValueAt(fc.getLastColour(), selectedRow, 1);
380 // probably the color chooser!
381 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
383 me.updateFeatureRenderer(
384 ((FeatureTableModel) table.getModel()).getData(),
393 JMenuItem selCols = new JMenuItem(
394 MessageManager.getString("label.select_columns_containing"));
395 selCols.addActionListener(new ActionListener()
399 public void actionPerformed(ActionEvent arg0)
401 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
405 JMenuItem clearCols = new JMenuItem(
406 MessageManager.getString("label.select_columns_not_containing"));
407 clearCols.addActionListener(new ActionListener()
411 public void actionPerformed(ActionEvent arg0)
413 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
419 men.show(table, x, y);
423 * true when Feature Settings are updating from feature renderer
425 private boolean handlingUpdate = false;
428 * contains a float[3] for each feature type string. created by setTableData
430 Hashtable typeWidth = null;
433 synchronized public void discoverAllFeatureData()
435 Vector allFeatures = new Vector();
436 Vector allGroups = new Vector();
437 SequenceFeature[] tmpfeatures;
439 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
441 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
442 .getSequenceFeatures();
443 if (tmpfeatures == null)
449 while (index < tmpfeatures.length)
451 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
457 if (tmpfeatures[index].getFeatureGroup() != null)
459 group = tmpfeatures[index].featureGroup;
460 if (!allGroups.contains(group))
462 allGroups.addElement(group);
463 checkGroupState(group);
467 if (!allFeatures.contains(tmpfeatures[index].getType()))
469 allFeatures.addElement(tmpfeatures[index].getType());
481 * Synchronise gui group list and check visibility of group
484 * @return true if group is visible
486 private boolean checkGroupState(String group)
488 boolean visible = fr.checkGroupVisibility(group, true);
490 if (groupPanel == null)
492 groupPanel = new JPanel();
495 boolean alreadyAdded = false;
496 for (int g = 0; g < groupPanel.getComponentCount(); g++)
498 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
501 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
511 final String grp = group;
512 final JCheckBox check = new JCheckBox(group, visible);
513 check.setFont(new Font("Serif", Font.BOLD, 12));
514 check.addItemListener(new ItemListener()
517 public void itemStateChanged(ItemEvent evt)
519 fr.setGroupVisibility(check.getText(), check.isSelected());
520 af.alignPanel.getSeqPanel().seqCanvas.repaint();
521 if (af.alignPanel.overviewPanel != null)
523 af.alignPanel.overviewPanel.updateOverviewImage();
526 resetTable(new String[] { grp });
529 groupPanel.add(check);
533 boolean resettingTable = false;
535 synchronized void resetTable(String[] groupChanged)
537 if (resettingTable == true)
541 resettingTable = true;
542 typeWidth = new Hashtable();
543 // TODO: change avWidth calculation to 'per-sequence' average and use long
545 float[] avWidth = null;
546 SequenceFeature[] tmpfeatures;
547 String group = null, type;
548 Vector visibleChecks = new Vector();
550 // Find out which features should be visible depending on which groups
551 // are selected / deselected
552 // and recompute average width ordering
553 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
556 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
557 .getSequenceFeatures();
558 if (tmpfeatures == null)
564 while (index < tmpfeatures.length)
566 group = tmpfeatures[index].featureGroup;
568 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
574 if (group == null || 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.hasRenderOrder())
614 fr.findAllFeatures(groupChanged != null); // prod to update
615 // colourschemes. but don't
617 // First add the checks in the previous render order,
618 // in case the window has been closed and reopened
620 List<String> frl = fr.getRenderOrder();
621 for (int ro = frl.size() - 1; ro > -1; ro--)
625 if (!visibleChecks.contains(type))
630 data[dataIndex][0] = type;
631 data[dataIndex][1] = fr.getFeatureStyle(type);
632 data[dataIndex][2] = new Boolean(af.getViewport()
633 .getFeaturesDisplayed().isVisible(type));
635 visibleChecks.removeElement(type);
639 fSize = visibleChecks.size();
640 for (int i = 0; i < fSize; i++)
642 // These must be extra features belonging to the group
643 // which was just selected
644 type = visibleChecks.elementAt(i).toString();
645 data[dataIndex][0] = type;
647 data[dataIndex][1] = fr.getFeatureStyle(type);
648 if (data[dataIndex][1] == null)
650 // "Colour has been updated in another view!!"
651 fr.clearRenderOrder();
655 data[dataIndex][2] = new Boolean(true);
659 if (originalData == null)
661 originalData = new Object[data.length][3];
662 for (int i = 0; i < data.length; i++)
664 System.arraycopy(data[i], 0, originalData[i], 0, 3);
668 table.setModel(new FeatureTableModel(data));
669 table.getColumnModel().getColumn(0).setPreferredWidth(200);
671 if (groupPanel != null)
673 groupPanel.setLayout(new GridLayout(
674 fr.getFeatureGroupsSize() / 4 + 1, 4));
676 groupPanel.validate();
677 bigPanel.add(groupPanel, BorderLayout.NORTH);
680 updateFeatureRenderer(data, groupChanged != null);
681 resettingTable = false;
685 * reorder data based on the featureRenderers global priority list.
689 private void ensureOrder(Object[][] data)
691 boolean sort = false;
692 float[] order = new float[data.length];
693 for (int i = 0; i < order.length; i++)
695 order[i] = fr.getOrder(data[i][0].toString());
698 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
702 sort = sort || order[i - 1] > order[i];
707 jalview.util.QuickSort.sort(order, data);
713 JalviewFileChooser chooser = new JalviewFileChooser(
714 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
715 new String[] { "fc" },
716 new String[] { "Sequence Feature Colours" },
717 "Sequence Feature Colours");
718 chooser.setFileView(new jalview.io.JalviewFileView());
719 chooser.setDialogTitle(MessageManager
720 .getString("label.load_feature_colours"));
721 chooser.setToolTipText(MessageManager.getString("action.load"));
723 int value = chooser.showOpenDialog(this);
725 if (value == JalviewFileChooser.APPROVE_OPTION)
727 File file = chooser.getSelectedFile();
731 InputStreamReader in = new InputStreamReader(new FileInputStream(
734 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
735 jucs = jucs.unmarshal(in);
737 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
740 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
743 Color mincol = null, maxcol = null;
746 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
747 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
749 } catch (Exception e)
751 Cache.log.warn("Couldn't parse out graduated feature color.",
754 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
755 newcol.getMin(), newcol.getMax());
756 if (newcol.hasAutoScale())
758 gcol.setAutoScaled(newcol.getAutoScale());
760 if (newcol.hasColourByLabel())
762 gcol.setColourByLabel(newcol.getColourByLabel());
764 if (newcol.hasThreshold())
766 gcol.setThresh(newcol.getThreshold());
767 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
769 if (newcol.getThreshType().length() > 0)
771 String ttyp = newcol.getThreshType();
772 if (ttyp.equalsIgnoreCase("NONE"))
774 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
776 if (ttyp.equalsIgnoreCase("ABOVE"))
778 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
780 if (ttyp.equalsIgnoreCase("BELOW"))
782 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
785 fr.setColour(name = newcol.getName(), gcol);
789 fr.setColour(name = jucs.getColour(i).getName(), new Color(
790 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
792 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
797 Object[][] data = ((FeatureTableModel) table.getModel())
800 updateFeatureRenderer(data, false);
803 } catch (Exception ex)
805 System.out.println("Error loading User Colour File\n" + ex);
812 JalviewFileChooser chooser = new JalviewFileChooser(
813 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
814 new String[] { "fc" },
815 new String[] { "Sequence Feature Colours" },
816 "Sequence Feature Colours");
817 chooser.setFileView(new jalview.io.JalviewFileView());
818 chooser.setDialogTitle(MessageManager
819 .getString("label.save_feature_colours"));
820 chooser.setToolTipText(MessageManager.getString("action.save"));
822 int value = chooser.showSaveDialog(this);
824 if (value == JalviewFileChooser.APPROVE_OPTION)
826 String choice = chooser.getSelectedFile().getPath();
827 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
828 ucs.setSchemeName("Sequence Features");
831 PrintWriter out = new PrintWriter(new OutputStreamWriter(
832 new FileOutputStream(choice), "UTF-8"));
834 Set fr_colours = fr.getAllFeatureColours();
835 Iterator e = fr_colours.iterator();
836 float[] sortOrder = new float[fr_colours.size()];
837 String[] sortTypes = new String[fr_colours.size()];
841 sortTypes[i] = e.next().toString();
842 sortOrder[i] = fr.getOrder(sortTypes[i]);
845 jalview.util.QuickSort.sort(sortOrder, sortTypes);
849 for (i = 0; i < sortTypes.length; i++)
851 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
852 col.setName(sortTypes[i]);
853 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
855 fcol = fr.getFeatureStyle(sortTypes[i]);
856 if (fcol instanceof GraduatedColor)
858 gcol = (GraduatedColor) fcol;
859 col.setMin(gcol.getMin());
860 col.setMax(gcol.getMax());
861 col.setMinRGB(jalview.util.Format.getHexString(gcol
863 col.setAutoScale(gcol.isAutoScale());
864 col.setThreshold(gcol.getThresh());
865 col.setColourByLabel(gcol.isColourByLabel());
866 switch (gcol.getThreshType())
868 case AnnotationColourGradient.NO_THRESHOLD:
869 col.setThreshType("NONE");
871 case AnnotationColourGradient.ABOVE_THRESHOLD:
872 col.setThreshType("ABOVE");
874 case AnnotationColourGradient.BELOW_THRESHOLD:
875 col.setThreshType("BELOW");
883 } catch (Exception ex)
885 ex.printStackTrace();
890 public void invertSelection()
892 for (int i = 0; i < table.getRowCount(); i++)
894 Boolean value = (Boolean) table.getValueAt(i, 2);
896 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
900 public void orderByAvWidth()
902 if (table == null || table.getModel() == null)
906 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
907 float[] width = new float[data.length];
911 for (int i = 0; i < data.length; i++)
913 awidth = (float[]) typeWidth.get(data[i][0]);
916 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
917 // weight - but have to make per
918 // sequence, too (awidth[2])
919 // if (width[i]==1) // hack to distinguish single width sequences.
931 boolean sort = false;
932 for (int i = 0; i < width.length; i++)
934 // awidth = (float[]) typeWidth.get(data[i][0]);
937 width[i] = fr.getOrder(data[i][0].toString());
940 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
945 width[i] /= max; // normalize
946 fr.setOrder(data[i][0].toString(), width[i]); // store for later
950 sort = sort || width[i - 1] > width[i];
955 jalview.util.QuickSort.sort(width, data);
956 // update global priority order
959 updateFeatureRenderer(data, false);
967 frame.setClosed(true);
968 } catch (Exception exe)
974 public void updateFeatureRenderer(Object[][] data)
976 updateFeatureRenderer(data, true);
980 * Update the priority order of features; only repaint if this changed the
981 * order of visible features
986 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
988 if (fr.setFeaturePriority(data, visibleNew))
990 af.alignPanel.paintAlignment(true);
994 int selectedRow = -1;
996 JTabbedPane tabbedPane = new JTabbedPane();
998 BorderLayout borderLayout1 = new BorderLayout();
1000 BorderLayout borderLayout2 = new BorderLayout();
1002 BorderLayout borderLayout3 = new BorderLayout();
1004 JPanel bigPanel = new JPanel();
1006 BorderLayout borderLayout4 = new BorderLayout();
1008 JButton invert = new JButton();
1010 JPanel buttonPanel = new JPanel();
1012 JButton cancel = new JButton();
1014 JButton ok = new JButton();
1016 JButton loadColours = new JButton();
1018 JButton saveColours = new JButton();
1020 JPanel dasButtonPanel = new JPanel();
1022 JButton fetchDAS = new JButton();
1024 JButton saveDAS = new JButton();
1026 JButton cancelDAS = new JButton();
1028 JButton optimizeOrder = new JButton();
1030 JButton sortByScore = new JButton();
1032 JButton sortByDens = new JButton();
1034 JButton help = new JButton();
1036 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1038 private void jbInit() throws Exception
1040 this.setLayout(borderLayout1);
1041 settingsPane.setLayout(borderLayout2);
1042 dasSettingsPane.setLayout(borderLayout3);
1043 bigPanel.setLayout(borderLayout4);
1044 invert.setFont(JvSwingUtils.getLabelFont());
1045 invert.setText(MessageManager.getString("label.invert_selection"));
1046 invert.addActionListener(new ActionListener()
1049 public void actionPerformed(ActionEvent e)
1054 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1055 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1056 optimizeOrder.addActionListener(new ActionListener()
1059 public void actionPerformed(ActionEvent e)
1064 sortByScore.setFont(JvSwingUtils.getLabelFont());
1066 .setText(MessageManager.getString("label.seq_sort_by_score"));
1067 sortByScore.addActionListener(new ActionListener()
1070 public void actionPerformed(ActionEvent e)
1072 af.avc.sortAlignmentByFeatureScore(null);
1075 sortByDens.setFont(JvSwingUtils.getLabelFont());
1076 sortByDens.setText(MessageManager
1077 .getString("label.sequence_sort_by_density"));
1078 sortByDens.addActionListener(new ActionListener()
1081 public void actionPerformed(ActionEvent e)
1083 af.avc.sortAlignmentByFeatureDensity(null);
1086 help.setFont(JvSwingUtils.getLabelFont());
1087 help.setText(MessageManager.getString("action.help"));
1088 help.addActionListener(new ActionListener()
1091 public void actionPerformed(ActionEvent e)
1095 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1096 } catch (HelpSetException e1)
1098 e1.printStackTrace();
1102 help.setFont(JvSwingUtils.getLabelFont());
1103 help.setText(MessageManager.getString("action.help"));
1104 help.addActionListener(new ActionListener()
1107 public void actionPerformed(ActionEvent e)
1111 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1112 } catch (HelpSetException e1)
1114 e1.printStackTrace();
1118 cancel.setFont(JvSwingUtils.getLabelFont());
1119 cancel.setText(MessageManager.getString("action.cancel"));
1120 cancel.addActionListener(new ActionListener()
1123 public void actionPerformed(ActionEvent e)
1125 fr.setTransparency(originalTransparency);
1126 updateFeatureRenderer(originalData);
1130 ok.setFont(JvSwingUtils.getLabelFont());
1131 ok.setText(MessageManager.getString("action.ok"));
1132 ok.addActionListener(new ActionListener()
1135 public void actionPerformed(ActionEvent e)
1140 loadColours.setFont(JvSwingUtils.getLabelFont());
1141 loadColours.setText(MessageManager.getString("label.load_colours"));
1142 loadColours.addActionListener(new ActionListener()
1145 public void actionPerformed(ActionEvent e)
1150 saveColours.setFont(JvSwingUtils.getLabelFont());
1151 saveColours.setText(MessageManager.getString("label.save_colours"));
1152 saveColours.addActionListener(new ActionListener()
1155 public void actionPerformed(ActionEvent e)
1160 transparency.addChangeListener(new ChangeListener()
1163 public void stateChanged(ChangeEvent evt)
1165 fr.setTransparency((100 - transparency.getValue()) / 100f);
1166 af.alignPanel.paintAlignment(true);
1170 transparency.setMaximum(70);
1171 transparency.setToolTipText(MessageManager
1172 .getString("label.transparency_tip"));
1173 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1174 fetchDAS.addActionListener(new ActionListener()
1177 public void actionPerformed(ActionEvent e)
1179 fetchDAS_actionPerformed(e);
1182 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1183 saveDAS.addActionListener(new ActionListener()
1186 public void actionPerformed(ActionEvent e)
1188 saveDAS_actionPerformed(e);
1191 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1192 dasSettingsPane.setBorder(null);
1193 cancelDAS.setEnabled(false);
1194 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1195 cancelDAS.addActionListener(new ActionListener()
1198 public void actionPerformed(ActionEvent e)
1200 cancelDAS_actionPerformed(e);
1203 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1204 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1206 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1208 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1209 transbuttons.add(optimizeOrder);
1210 transbuttons.add(invert);
1211 transbuttons.add(sortByScore);
1212 transbuttons.add(sortByDens);
1213 transbuttons.add(help);
1214 JPanel sliderPanel = new JPanel();
1215 sliderPanel.add(transparency);
1216 transPanel.add(transparency);
1217 transPanel.add(transbuttons);
1218 buttonPanel.add(ok);
1219 buttonPanel.add(cancel);
1220 buttonPanel.add(loadColours);
1221 buttonPanel.add(saveColours);
1222 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1223 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1224 dasButtonPanel.add(fetchDAS);
1225 dasButtonPanel.add(cancelDAS);
1226 dasButtonPanel.add(saveDAS);
1227 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1228 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1231 public void fetchDAS_actionPerformed(ActionEvent e)
1233 fetchDAS.setEnabled(false);
1234 cancelDAS.setEnabled(true);
1235 dassourceBrowser.setGuiEnabled(false);
1236 Vector selectedSources = dassourceBrowser.getSelectedSources();
1237 doDasFeatureFetch(selectedSources, true, true);
1241 * get the features from selectedSources for all or the current selection
1243 * @param selectedSources
1244 * @param checkDbRefs
1245 * @param promptFetchDbRefs
1247 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1248 boolean checkDbRefs, boolean promptFetchDbRefs)
1250 SequenceI[] dataset, seqs;
1252 AlignmentViewport vp = af.getViewport();
1253 if (vp.getSelectionGroup() != null
1254 && vp.getSelectionGroup().getSize() > 0)
1256 iSize = vp.getSelectionGroup().getSize();
1257 dataset = new SequenceI[iSize];
1258 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1262 iSize = vp.getAlignment().getHeight();
1263 seqs = vp.getAlignment().getSequencesArray();
1266 dataset = new SequenceI[iSize];
1267 for (int i = 0; i < iSize; i++)
1269 dataset[i] = seqs[i].getDatasetSequence();
1272 cancelDAS.setEnabled(true);
1273 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1274 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1275 af.getViewport().setShowSequenceFeatures(true);
1276 af.showSeqFeatures.setSelected(true);
1280 * blocking call to initialise the das source browser
1282 public void initDasSources()
1284 dassourceBrowser.initDasSources();
1288 * examine the current list of das sources and return any matching the given
1289 * nicknames in sources
1292 * Vector of Strings to resolve to DAS source nicknames.
1293 * @return sources that are present in source list.
1295 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1297 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1301 * get currently selected das sources. ensure you have called initDasSources
1302 * before calling this.
1304 * @return vector of selected das source nicknames
1306 public Vector getSelectedSources()
1308 return dassourceBrowser.getSelectedSources();
1312 * properly initialise DAS fetcher and then initiate a new thread to fetch
1313 * features from the named sources (rather than any turned on by default)
1317 * if true then runs in same thread, otherwise passes to the Swing
1320 public void fetchDasFeatures(Vector sources, boolean block)
1323 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1324 .resolveSourceNicknames(sources);
1325 if (resolved.size() == 0)
1327 resolved = dassourceBrowser.getSelectedSources();
1329 if (resolved.size() > 0)
1331 final List<jalviewSourceI> dassources = resolved;
1332 fetchDAS.setEnabled(false);
1333 // cancelDAS.setEnabled(true); doDasFetch does this.
1334 Runnable fetcher = new Runnable()
1340 doDasFeatureFetch(dassources, true, false);
1350 SwingUtilities.invokeLater(fetcher);
1355 public void saveDAS_actionPerformed(ActionEvent e)
1358 .saveProperties(jalview.bin.Cache.applicationProperties);
1361 public void complete()
1363 fetchDAS.setEnabled(true);
1364 cancelDAS.setEnabled(false);
1365 dassourceBrowser.setGuiEnabled(true);
1369 public void cancelDAS_actionPerformed(ActionEvent e)
1371 if (dasFeatureFetcher != null)
1373 dasFeatureFetcher.cancel();
1378 public void noDasSourceActive()
1382 .showInternalConfirmDialog(
1385 .getString("label.no_das_sources_selected_warn"),
1387 .getString("label.no_das_sources_selected_title"),
1388 JOptionPane.DEFAULT_OPTION,
1389 JOptionPane.INFORMATION_MESSAGE);
1392 // ///////////////////////////////////////////////////////////////////////
1393 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1394 // ///////////////////////////////////////////////////////////////////////
1395 class FeatureTableModel extends AbstractTableModel
1397 FeatureTableModel(Object[][] data)
1402 private String[] columnNames = {
1403 MessageManager.getString("label.feature_type"),
1404 MessageManager.getString("action.colour"),
1405 MessageManager.getString("label.display") };
1407 private Object[][] data;
1409 public Object[][] getData()
1414 public void setData(Object[][] data)
1420 public int getColumnCount()
1422 return columnNames.length;
1425 public Object[] getRow(int row)
1431 public int getRowCount()
1437 public String getColumnName(int col)
1439 return columnNames[col];
1443 public Object getValueAt(int row, int col)
1445 return data[row][col];
1449 public Class getColumnClass(int c)
1451 return getValueAt(0, c).getClass();
1455 public boolean isCellEditable(int row, int col)
1457 return col == 0 ? false : true;
1461 public void setValueAt(Object value, int row, int col)
1463 data[row][col] = value;
1464 fireTableCellUpdated(row, col);
1465 updateFeatureRenderer(data);
1470 class ColorRenderer extends JLabel implements TableCellRenderer
1472 javax.swing.border.Border unselectedBorder = null;
1474 javax.swing.border.Border selectedBorder = null;
1476 final String baseTT = "Click to edit, right/apple click for menu.";
1478 public ColorRenderer()
1480 setOpaque(true); // MUST do this for background to show up.
1481 setHorizontalTextPosition(SwingConstants.CENTER);
1482 setVerticalTextPosition(SwingConstants.CENTER);
1486 public Component getTableCellRendererComponent(JTable table,
1487 Object color, boolean isSelected, boolean hasFocus, int row,
1490 // JLabel comp = new JLabel();
1494 // setBounds(getBounds());
1496 setToolTipText(baseTT);
1497 setBackground(table.getBackground());
1498 if (color instanceof GraduatedColor)
1500 Rectangle cr = table.getCellRect(row, column, false);
1501 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1502 (int) cr.getWidth(), (int) cr.getHeight());
1509 newColor = (Color) color;
1511 setBackground(newColor);
1512 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1513 // + newColor.getGreen() + ", " + newColor.getBlue());
1517 if (selectedBorder == null)
1519 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1520 table.getSelectionBackground());
1523 setBorder(selectedBorder);
1527 if (unselectedBorder == null)
1529 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1530 table.getBackground());
1533 setBorder(unselectedBorder);
1541 * update comp using rendering settings from gcol
1546 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1548 int w = comp.getWidth(), h = comp.getHeight();
1551 w = (int) comp.getPreferredSize().getWidth();
1552 h = (int) comp.getPreferredSize().getHeight();
1559 renderGraduatedColor(comp, gcol, w, h);
1562 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1565 boolean thr = false;
1568 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1572 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1574 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1578 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1580 if (gcol.isColourByLabel())
1582 tt = "Coloured by label text. " + tt;
1590 // else if (gcol.isColourAlternately())
1592 // tt = "Coloured alternately " + tt;
1597 // tx += "Alternately";
1598 // comp.setIcon(null);
1602 Color newColor = gcol.getMaxColor();
1603 comp.setBackground(newColor);
1604 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1605 comp.setIcon(ficon);
1607 comp.setHorizontalAlignment(SwingConstants.CENTER);
1609 if (tt.length() > 0)
1611 if (comp.getToolTipText() == null)
1613 comp.setToolTipText(tt);
1617 comp.setToolTipText(tt + " " + comp.getToolTipText());
1623 class FeatureIcon implements Icon
1625 GraduatedColor gcol;
1629 boolean midspace = false;
1631 int width = 50, height = 20;
1633 int s1, e1; // start and end of midpoint band for thresholded symbol
1635 Color mpcolour = Color.white;
1637 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1644 if (midspace || gcol.isColourAlternately())
1657 public int getIconWidth()
1663 public int getIconHeight()
1669 public void paintIcon(Component c, Graphics g, int x, int y)
1672 if (gcol.isColourByLabel())
1675 g.fillRect(0, 0, width, height);
1676 // need an icon here.
1677 g.setColor(gcol.getMaxColor());
1679 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1681 // g.setFont(g.getFont().deriveFont(
1682 // AffineTransform.getScaleInstance(
1683 // width/g.getFontMetrics().stringWidth("Label"),
1684 // height/g.getFontMetrics().getHeight())));
1686 g.drawString(MessageManager.getString("label.label"), 0, 0);
1689 else if (gcol.isColourAlternately())
1691 Color minCol = gcol.getMinColor();
1693 g.fillRect(0, 0, s1, height);
1694 g.setColor(gcol.getMaxColor());
1695 g.fillRect(s1, 0, e1 - s1, height);
1697 g.fillRect(e1, 0, width - e1, height);
1701 Color minCol = gcol.getMinColor();
1703 g.fillRect(0, 0, s1, height);
1706 g.setColor(Color.white);
1707 g.fillRect(s1, 0, e1 - s1, height);
1709 g.setColor(gcol.getMaxColor());
1710 g.fillRect(e1, 0, width - e1, height);
1711 // this is wrong but works - why??
1712 // g.fillRect(0, e1, width - e1, height);
1717 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1722 GraduatedColor currentGColor;
1724 FeatureColourChooser chooser;
1732 JColorChooser colorChooser;
1736 protected static final String EDIT = "edit";
1738 int selectedRow = 0;
1740 public ColorEditor(FeatureSettings me)
1743 // Set up the editor (from the table's point of view),
1744 // which is a button.
1745 // This button brings up the color chooser dialog,
1746 // which is the editor from the user's point of view.
1747 button = new JButton();
1748 button.setActionCommand(EDIT);
1749 button.addActionListener(this);
1750 button.setBorderPainted(false);
1751 // Set up the dialog that the button brings up.
1752 colorChooser = new JColorChooser();
1753 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1754 colorChooser, this, // OK button handler
1755 null); // no CANCEL button handler
1759 * Handles events from the editor button and from the dialog's OK button.
1762 public void actionPerformed(ActionEvent e)
1765 if (EDIT.equals(e.getActionCommand()))
1767 // The user has clicked the cell, so
1768 // bring up the dialog.
1769 if (currentColor != null)
1771 // bring up simple color chooser
1772 button.setBackground(currentColor);
1773 colorChooser.setColor(currentColor);
1774 dialog.setVisible(true);
1778 // bring up graduated chooser.
1779 chooser = new FeatureColourChooser(me.fr, type);
1780 chooser.setRequestFocusEnabled(true);
1781 chooser.requestFocus();
1782 chooser.addActionListener(this);
1784 // Make the renderer reappear.
1785 fireEditingStopped();
1789 { // User pressed dialog's "OK" button.
1790 if (currentColor != null)
1792 currentColor = colorChooser.getColor();
1796 // class cast exceptions may be raised if the chooser created on a
1797 // non-graduated color
1798 currentGColor = (GraduatedColor) chooser.getLastColour();
1800 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1801 fireEditingStopped();
1802 me.table.validate();
1806 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1808 public Object getCellEditorValue()
1810 if (currentColor == null)
1812 return currentGColor;
1814 return currentColor;
1817 // Implement the one method defined by TableCellEditor.
1819 public Component getTableCellEditorComponent(JTable table, Object value,
1820 boolean isSelected, int row, int column)
1822 currentGColor = null;
1823 currentColor = null;
1824 this.selectedRow = row;
1825 type = me.table.getValueAt(row, 0).toString();
1826 button.setOpaque(true);
1827 button.setBackground(me.getBackground());
1828 if (value instanceof GraduatedColor)
1830 currentGColor = (GraduatedColor) value;
1831 JLabel btn = new JLabel();
1832 btn.setSize(button.getSize());
1833 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1834 button.setBackground(btn.getBackground());
1835 button.setIcon(btn.getIcon());
1836 button.setText(btn.getText());
1841 button.setIcon(null);
1842 currentColor = (Color) value;
1843 button.setBackground(currentColor);