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;
1592 Color newColor = gcol.getMaxColor();
1593 comp.setBackground(newColor);
1594 // System.err.println("Width is " + w / 2);
1595 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1596 comp.setIcon(ficon);
1597 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1598 // + newColor.getGreen() + ", " + newColor.getBlue()
1599 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1600 // + ", " + minCol.getBlue() + ")");
1602 comp.setHorizontalAlignment(SwingConstants.CENTER);
1604 if (tt.length() > 0)
1606 if (comp.getToolTipText() == null)
1608 comp.setToolTipText(tt);
1612 comp.setToolTipText(tt + " " + comp.getToolTipText());
1618 class FeatureIcon implements Icon
1620 GraduatedColor gcol;
1624 boolean midspace = false;
1626 int width = 50, height = 20;
1628 int s1, e1; // start and end of midpoint band for thresholded symbol
1630 Color mpcolour = Color.white;
1632 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1652 public int getIconWidth()
1658 public int getIconHeight()
1664 public void paintIcon(Component c, Graphics g, int x, int y)
1667 if (gcol.isColourByLabel())
1670 g.fillRect(0, 0, width, height);
1671 // need an icon here.
1672 g.setColor(gcol.getMaxColor());
1674 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1676 // g.setFont(g.getFont().deriveFont(
1677 // AffineTransform.getScaleInstance(
1678 // width/g.getFontMetrics().stringWidth("Label"),
1679 // height/g.getFontMetrics().getHeight())));
1681 g.drawString(MessageManager.getString("label.label"), 0, 0);
1686 Color minCol = gcol.getMinColor();
1688 g.fillRect(0, 0, s1, height);
1691 g.setColor(Color.white);
1692 g.fillRect(s1, 0, e1 - s1, height);
1694 g.setColor(gcol.getMaxColor());
1695 g.fillRect(0, e1, width - e1, height);
1700 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1705 GraduatedColor currentGColor;
1707 FeatureColourChooser chooser;
1715 JColorChooser colorChooser;
1719 protected static final String EDIT = "edit";
1721 int selectedRow = 0;
1723 public ColorEditor(FeatureSettings me)
1726 // Set up the editor (from the table's point of view),
1727 // which is a button.
1728 // This button brings up the color chooser dialog,
1729 // which is the editor from the user's point of view.
1730 button = new JButton();
1731 button.setActionCommand(EDIT);
1732 button.addActionListener(this);
1733 button.setBorderPainted(false);
1734 // Set up the dialog that the button brings up.
1735 colorChooser = new JColorChooser();
1736 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1737 colorChooser, this, // OK button handler
1738 null); // no CANCEL button handler
1742 * Handles events from the editor button and from the dialog's OK button.
1745 public void actionPerformed(ActionEvent e)
1748 if (EDIT.equals(e.getActionCommand()))
1750 // The user has clicked the cell, so
1751 // bring up the dialog.
1752 if (currentColor != null)
1754 // bring up simple color chooser
1755 button.setBackground(currentColor);
1756 colorChooser.setColor(currentColor);
1757 dialog.setVisible(true);
1761 // bring up graduated chooser.
1762 chooser = new FeatureColourChooser(me.fr, type);
1763 chooser.setRequestFocusEnabled(true);
1764 chooser.requestFocus();
1765 chooser.addActionListener(this);
1767 // Make the renderer reappear.
1768 fireEditingStopped();
1772 { // User pressed dialog's "OK" button.
1773 if (currentColor != null)
1775 currentColor = colorChooser.getColor();
1779 // class cast exceptions may be raised if the chooser created on a
1780 // non-graduated color
1781 currentGColor = (GraduatedColor) chooser.getLastColour();
1783 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1784 fireEditingStopped();
1785 me.table.validate();
1789 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1791 public Object getCellEditorValue()
1793 if (currentColor == null)
1795 return currentGColor;
1797 return currentColor;
1800 // Implement the one method defined by TableCellEditor.
1802 public Component getTableCellEditorComponent(JTable table, Object value,
1803 boolean isSelected, int row, int column)
1805 currentGColor = null;
1806 currentColor = null;
1807 this.selectedRow = row;
1808 type = me.table.getValueAt(row, 0).toString();
1809 button.setOpaque(true);
1810 button.setBackground(me.getBackground());
1811 if (value instanceof GraduatedColor)
1813 currentGColor = (GraduatedColor) value;
1814 JLabel btn = new JLabel();
1815 btn.setSize(button.getSize());
1816 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1817 button.setBackground(btn.getBackground());
1818 button.setIcon(btn.getIcon());
1819 button.setText(btn.getText());
1824 button.setIcon(null);
1825 currentColor = (Color) value;
1826 button.setBackground(currentColor);