2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.bin.Cache;
24 import jalview.datamodel.SequenceFeature;
25 import jalview.datamodel.SequenceI;
26 import jalview.gui.Help.HelpId;
27 import jalview.io.JalviewFileChooser;
28 import jalview.schemes.AnnotationColourGradient;
29 import jalview.schemes.GraduatedColor;
30 import jalview.util.MessageManager;
31 import jalview.viewmodel.AlignmentViewport;
32 import jalview.ws.dbsources.das.api.jalviewSourceI;
34 import java.awt.BorderLayout;
35 import java.awt.Color;
36 import java.awt.Component;
38 import java.awt.Graphics;
39 import java.awt.GridLayout;
40 import java.awt.Rectangle;
41 import java.awt.event.ActionEvent;
42 import java.awt.event.ActionListener;
43 import java.awt.event.ItemEvent;
44 import java.awt.event.ItemListener;
45 import java.awt.event.MouseAdapter;
46 import java.awt.event.MouseEvent;
47 import java.awt.event.MouseMotionAdapter;
48 import java.beans.PropertyChangeEvent;
49 import java.beans.PropertyChangeListener;
51 import java.io.FileInputStream;
52 import java.io.FileOutputStream;
53 import java.io.InputStreamReader;
54 import java.io.OutputStreamWriter;
55 import java.io.PrintWriter;
56 import java.util.Hashtable;
57 import java.util.Iterator;
58 import java.util.List;
60 import java.util.Vector;
62 import javax.help.HelpSetException;
63 import javax.swing.AbstractCellEditor;
64 import javax.swing.BorderFactory;
65 import javax.swing.Icon;
66 import javax.swing.JButton;
67 import javax.swing.JCheckBox;
68 import javax.swing.JCheckBoxMenuItem;
69 import javax.swing.JColorChooser;
70 import javax.swing.JDialog;
71 import javax.swing.JInternalFrame;
72 import javax.swing.JLabel;
73 import javax.swing.JLayeredPane;
74 import javax.swing.JMenuItem;
75 import javax.swing.JOptionPane;
76 import javax.swing.JPanel;
77 import javax.swing.JPopupMenu;
78 import javax.swing.JScrollPane;
79 import javax.swing.JSlider;
80 import javax.swing.JTabbedPane;
81 import javax.swing.JTable;
82 import javax.swing.ListSelectionModel;
83 import javax.swing.SwingConstants;
84 import javax.swing.SwingUtilities;
85 import javax.swing.event.ChangeEvent;
86 import javax.swing.event.ChangeListener;
87 import javax.swing.table.AbstractTableModel;
88 import javax.swing.table.TableCellEditor;
89 import javax.swing.table.TableCellRenderer;
91 public class FeatureSettings extends JPanel
93 DasSourceBrowser dassourceBrowser;
95 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
97 JPanel settingsPane = new JPanel();
99 JPanel dasSettingsPane = new JPanel();
101 final FeatureRenderer fr;
103 public final AlignFrame af;
105 Object[][] originalData;
107 private float originalTransparency;
109 final JInternalFrame frame;
111 JScrollPane scrollPane = new JScrollPane();
117 JSlider transparency = new JSlider();
119 JPanel transPanel = new JPanel(new GridLayout(1, 2));
121 public FeatureSettings(AlignFrame af)
124 fr = af.getFeatureRenderer();
125 // allow transparency to be recovered
126 transparency.setMaximum(100 - (int) ((originalTransparency=fr.getTransparency()) * 100));
131 } catch (Exception ex)
133 ex.printStackTrace();
136 table = new JTable() {
138 public String getToolTipText(MouseEvent e) {
139 if (table.columnAtPoint(e.getPoint()) == 0) {
141 * Tooltip for feature name only
143 return JvSwingUtils.wrapTooltip(true,
144 MessageManager.getString("label.feature_settings_click_drag"));
149 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
150 table.setFont(new Font("Verdana", Font.PLAIN, 12));
151 table.setDefaultRenderer(Color.class, new ColorRenderer());
153 table.setDefaultEditor(Color.class, new ColorEditor(this));
155 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
156 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
157 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
159 table.addMouseListener(new MouseAdapter()
161 public void mousePressed(MouseEvent evt)
163 selectedRow = table.rowAtPoint(evt.getPoint());
164 if (SwingUtilities.isRightMouseButton(evt))
166 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
167 table.getValueAt(selectedRow, 1), fr.getMinMax(),
168 evt.getX(), evt.getY());
170 else if (evt.getClickCount() == 2)
172 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
173 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
175 (String) table.getValueAt(selectedRow, 0));
179 // isPopupTrigger fires on mouseReleased on Mac
181 public void mouseReleased(MouseEvent evt)
183 selectedRow = table.rowAtPoint(evt.getPoint());
184 if (evt.isPopupTrigger())
186 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
187 table.getValueAt(selectedRow, 1), fr.getMinMax(),
194 table.addMouseMotionListener(new MouseMotionAdapter()
196 public void mouseDragged(MouseEvent evt)
198 int newRow = table.rowAtPoint(evt.getPoint());
199 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
201 Object[] temp = new Object[3];
202 temp[0] = table.getValueAt(selectedRow, 0);
203 temp[1] = table.getValueAt(selectedRow, 1);
204 temp[2] = table.getValueAt(selectedRow, 2);
206 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
207 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
208 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
210 table.setValueAt(temp[0], newRow, 0);
211 table.setValueAt(temp[1], newRow, 1);
212 table.setValueAt(temp[2], newRow, 2);
214 selectedRow = newRow;
218 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
219 // MessageManager.getString("label.feature_settings_click_drag")));
220 scrollPane.setViewportView(table);
222 dassourceBrowser = new DasSourceBrowser(this);
223 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
225 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
227 fr.findAllFeatures(true); // display everything!
231 final PropertyChangeListener change;
232 final FeatureSettings fs = this;
233 fr.addPropertyChangeListener(change = new PropertyChangeListener()
235 public void propertyChange(PropertyChangeEvent evt)
237 if (!fs.resettingTable && !fs.handlingUpdate)
239 fs.handlingUpdate = true;
240 fs.resetTable(null); // new groups may be added with new seuqence
241 // feature types only
242 fs.handlingUpdate = false;
248 frame = new JInternalFrame();
249 frame.setContentPane(this);
250 if (new jalview.util.Platform().isAMac())
252 Desktop.addInternalFrame(frame,
253 MessageManager.getString("label.sequence_feature_settings"),
258 Desktop.addInternalFrame(frame,
259 MessageManager.getString("label.sequence_feature_settings"),
263 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
265 public void internalFrameClosed(
266 javax.swing.event.InternalFrameEvent evt)
268 fr.removePropertyChangeListener(change);
269 dassourceBrowser.fs = null;
272 frame.setLayer(JLayeredPane.PALETTE_LAYER);
275 protected void popupSort(final int selectedRow, final String type,
276 final Object typeCol, final Hashtable minmax, int x, int y)
278 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
279 "label.settings_for_param", new String[]
281 JMenuItem scr = new JMenuItem(
282 MessageManager.getString("label.sort_by_score"));
284 final FeatureSettings me = this;
285 scr.addActionListener(new ActionListener()
288 public void actionPerformed(ActionEvent e)
290 me.af.avc.sortAlignmentByFeatureScore(new String[]
295 JMenuItem dens = new JMenuItem(
296 MessageManager.getString("label.sort_by_density"));
297 dens.addActionListener(new ActionListener()
300 public void actionPerformed(ActionEvent e)
302 me.af.avc.sortAlignmentByFeatureDensity(new String[]
310 final Object typeMinMax = minmax.get(type);
312 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
313 * this is broken at the moment and isn't that useful anyway!
314 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
317 * public void actionPerformed(ActionEvent e) {
318 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
319 * null); } else { minmax.put(type, typeMinMax); } }
325 if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
327 // if (table.getValueAt(row, column));
328 // graduated colourschemes for those where minmax exists for the
329 // positional features
330 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
332 mxcol.setSelected(!(typeCol instanceof Color));
334 mxcol.addActionListener(new ActionListener()
336 JColorChooser colorChooser;
338 public void actionPerformed(ActionEvent e)
340 if (e.getSource() == mxcol)
342 if (typeCol instanceof Color)
344 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
346 fc.addActionListener(this);
350 // bring up simple color chooser
351 colorChooser = new JColorChooser();
352 JDialog dialog = JColorChooser.createDialog(me,
353 "Select new Colour", true, // modal
354 colorChooser, this, // OK button handler
355 null); // no CANCEL button handler
356 colorChooser.setColor(((GraduatedColor) typeCol)
358 dialog.setVisible(true);
363 if (e.getSource() instanceof FeatureColourChooser)
365 FeatureColourChooser fc = (FeatureColourChooser) e
367 table.setValueAt(fc.getLastColour(), selectedRow, 1);
372 // probably the color chooser!
373 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
375 me.updateFeatureRenderer(
376 ((FeatureTableModel) table.getModel()).getData(),
385 JMenuItem selCols = new JMenuItem(
386 MessageManager.getString("label.select_columns_containing"));
387 selCols.addActionListener(new ActionListener()
391 public void actionPerformed(ActionEvent arg0)
393 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
397 JMenuItem clearCols = new JMenuItem(
398 MessageManager.getString("label.select_columns_not_containing"));
399 clearCols.addActionListener(new ActionListener()
403 public void actionPerformed(ActionEvent arg0)
405 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
411 men.show(table, x, y);
415 * true when Feature Settings are updating from feature renderer
417 private boolean handlingUpdate = false;
420 * contains a float[3] for each feature type string. created by setTableData
422 Hashtable typeWidth = null;
424 synchronized public void setTableData()
426 Vector allFeatures = new Vector();
427 Vector allGroups = new Vector();
428 SequenceFeature[] tmpfeatures;
430 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
432 if (af.getViewport().getAlignment().getSequenceAt(i)
433 .getDatasetSequence().getSequenceFeatures() == null)
438 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
439 .getDatasetSequence().getSequenceFeatures();
442 while (index < tmpfeatures.length)
444 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
450 if (tmpfeatures[index].getFeatureGroup() != null)
452 group = tmpfeatures[index].featureGroup;
453 if (!allGroups.contains(group))
455 allGroups.addElement(group);
456 checkGroupState(group);
460 if (!allFeatures.contains(tmpfeatures[index].getType()))
462 allFeatures.addElement(tmpfeatures[index].getType());
474 * Synchronise gui group list and check visibility of group
477 * @return true if group is visible
479 private boolean checkGroupState(String group)
481 boolean visible = fr.checkGroupVisibility(group, true);
483 if (groupPanel == null)
485 groupPanel = new JPanel();
488 boolean alreadyAdded = false;
489 for (int g = 0; g < groupPanel.getComponentCount(); g++)
491 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
494 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
504 final String grp = group;
505 final JCheckBox check = new JCheckBox(group, visible);
506 check.setFont(new Font("Serif", Font.BOLD, 12));
507 check.addItemListener(new ItemListener()
509 public void itemStateChanged(ItemEvent evt)
511 fr.setGroupVisibility(check.getText(), check.isSelected());
512 af.alignPanel.getSeqPanel().seqCanvas.repaint();
513 if (af.alignPanel.overviewPanel != null)
515 af.alignPanel.overviewPanel.updateOverviewImage();
518 resetTable(new String[]
522 groupPanel.add(check);
526 boolean resettingTable = false;
528 synchronized void resetTable(String[] groupChanged)
530 if (resettingTable == true)
534 resettingTable = true;
535 typeWidth = new Hashtable();
536 // TODO: change avWidth calculation to 'per-sequence' average and use long
538 float[] avWidth = null;
539 SequenceFeature[] tmpfeatures;
540 String group = null, type;
541 Vector visibleChecks = new Vector();
543 // Find out which features should be visible depending on which groups
544 // are selected / deselected
545 // and recompute average width ordering
546 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
549 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
550 .getDatasetSequence().getSequenceFeatures();
551 if (tmpfeatures == null)
557 while (index < tmpfeatures.length)
559 group = tmpfeatures[index].featureGroup;
561 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
567 if (group == null || checkGroupState(group))
569 type = tmpfeatures[index].getType();
570 if (!visibleChecks.contains(type))
572 visibleChecks.addElement(type);
575 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
577 typeWidth.put(tmpfeatures[index].getType(),
578 avWidth = new float[3]);
582 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
585 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
587 avWidth[1] += 1 + tmpfeatures[index].getBegin()
588 - tmpfeatures[index].getEnd();
592 avWidth[1] += 1 + tmpfeatures[index].getEnd()
593 - tmpfeatures[index].getBegin();
599 int fSize = visibleChecks.size();
600 Object[][] data = new Object[fSize][3];
603 if (fr.hasRenderOrder())
607 fr.findAllFeatures(groupChanged != null); // prod to update
608 // colourschemes. but don't
610 // First add the checks in the previous render order,
611 // in case the window has been closed and reopened
613 List<String> frl = fr.getRenderOrder();
614 for (int ro = frl.size() - 1; ro > -1; ro--)
618 if (!visibleChecks.contains(type))
623 data[dataIndex][0] = type;
624 data[dataIndex][1] = fr.getFeatureStyle(type);
625 data[dataIndex][2] = new Boolean(af.getViewport()
626 .getFeaturesDisplayed().isVisible(type));
628 visibleChecks.removeElement(type);
632 fSize = visibleChecks.size();
633 for (int i = 0; i < fSize; i++)
635 // These must be extra features belonging to the group
636 // which was just selected
637 type = visibleChecks.elementAt(i).toString();
638 data[dataIndex][0] = type;
640 data[dataIndex][1] = fr.getFeatureStyle(type);
641 if (data[dataIndex][1] == null)
643 // "Colour has been updated in another view!!"
644 fr.clearRenderOrder();
648 data[dataIndex][2] = new Boolean(true);
652 if (originalData == null)
654 originalData = new Object[data.length][3];
655 for (int i = 0; i < data.length; i++)
657 System.arraycopy(data[i], 0, originalData[i], 0, 3);
661 table.setModel(new FeatureTableModel(data));
662 table.getColumnModel().getColumn(0).setPreferredWidth(200);
664 if (groupPanel != null)
666 groupPanel.setLayout(new GridLayout(
667 fr.getFeatureGroupsSize() / 4 + 1, 4));
669 groupPanel.validate();
670 bigPanel.add(groupPanel, BorderLayout.NORTH);
673 updateFeatureRenderer(data, groupChanged != null);
674 resettingTable = false;
678 * reorder data based on the featureRenderers global priority list.
682 private void ensureOrder(Object[][] data)
684 boolean sort = false;
685 float[] order = new float[data.length];
686 for (int i = 0; i < order.length; i++)
688 order[i] = fr.getOrder(data[i][0].toString());
691 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
695 sort = sort || order[i - 1] > order[i];
700 jalview.util.QuickSort.sort(order, data);
706 JalviewFileChooser chooser = new JalviewFileChooser(
707 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
708 { "fc" }, new String[]
709 { "Sequence Feature Colours" }, "Sequence Feature Colours");
710 chooser.setFileView(new jalview.io.JalviewFileView());
711 chooser.setDialogTitle(MessageManager.getString("label.load_feature_colours"));
712 chooser.setToolTipText(MessageManager.getString("action.load"));
714 int value = chooser.showOpenDialog(this);
716 if (value == JalviewFileChooser.APPROVE_OPTION)
718 File file = chooser.getSelectedFile();
722 InputStreamReader in = new InputStreamReader(new FileInputStream(
725 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
729 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
732 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
735 Color mincol = null, maxcol = null;
738 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
739 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
741 } catch (Exception e)
743 Cache.log.warn("Couldn't parse out graduated feature color.",
746 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
747 newcol.getMin(), newcol.getMax());
748 if (newcol.hasAutoScale())
750 gcol.setAutoScaled(newcol.getAutoScale());
752 if (newcol.hasColourByLabel())
754 gcol.setColourByLabel(newcol.getColourByLabel());
756 if (newcol.hasThreshold())
758 gcol.setThresh(newcol.getThreshold());
759 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
761 if (newcol.getThreshType().length() > 0)
763 String ttyp = newcol.getThreshType();
764 if (ttyp.equalsIgnoreCase("NONE"))
766 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
768 if (ttyp.equalsIgnoreCase("ABOVE"))
770 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
772 if (ttyp.equalsIgnoreCase("BELOW"))
774 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
777 fr.setColour(name = newcol.getName(), gcol);
781 fr.setColour(name = jucs.getColour(i).getName(), new Color(
782 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
784 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
789 Object[][] data = ((FeatureTableModel) table.getModel())
792 updateFeatureRenderer(data, false);
795 } catch (Exception ex)
797 System.out.println("Error loading User Colour File\n" + ex);
804 JalviewFileChooser chooser = new JalviewFileChooser(
805 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
806 { "fc" }, new String[]
807 { "Sequence Feature Colours" }, "Sequence Feature Colours");
808 chooser.setFileView(new jalview.io.JalviewFileView());
809 chooser.setDialogTitle(MessageManager.getString("label.save_feature_colours"));
810 chooser.setToolTipText(MessageManager.getString("action.save"));
812 int value = chooser.showSaveDialog(this);
814 if (value == JalviewFileChooser.APPROVE_OPTION)
816 String choice = chooser.getSelectedFile().getPath();
817 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
818 ucs.setSchemeName("Sequence Features");
821 PrintWriter out = new PrintWriter(new OutputStreamWriter(
822 new FileOutputStream(choice), "UTF-8"));
824 Set fr_colours = fr.getAllFeatureColours();
825 Iterator e = fr_colours.iterator();
826 float[] sortOrder = new float[fr_colours.size()];
827 String[] sortTypes = new String[fr_colours.size()];
831 sortTypes[i] = e.next().toString();
832 sortOrder[i] = fr.getOrder(sortTypes[i]);
835 jalview.util.QuickSort.sort(sortOrder, sortTypes);
839 for (i = 0; i < sortTypes.length; i++)
841 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
842 col.setName(sortTypes[i]);
843 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
845 fcol = fr.getFeatureStyle(sortTypes[i]);
846 if (fcol instanceof GraduatedColor)
848 gcol = (GraduatedColor) fcol;
849 col.setMin(gcol.getMin());
850 col.setMax(gcol.getMax());
851 col.setMinRGB(jalview.util.Format.getHexString(gcol
853 col.setAutoScale(gcol.isAutoScale());
854 col.setThreshold(gcol.getThresh());
855 col.setColourByLabel(gcol.isColourByLabel());
856 switch (gcol.getThreshType())
858 case AnnotationColourGradient.NO_THRESHOLD:
859 col.setThreshType("NONE");
861 case AnnotationColourGradient.ABOVE_THRESHOLD:
862 col.setThreshType("ABOVE");
864 case AnnotationColourGradient.BELOW_THRESHOLD:
865 col.setThreshType("BELOW");
873 } catch (Exception ex)
875 ex.printStackTrace();
880 public void invertSelection()
882 for (int i = 0; i < table.getRowCount(); i++)
884 Boolean value = (Boolean) table.getValueAt(i, 2);
886 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
890 public void orderByAvWidth()
892 if (table == null || table.getModel() == null)
896 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
897 float[] width = new float[data.length];
901 for (int i = 0; i < data.length; i++)
903 awidth = (float[]) typeWidth.get(data[i][0]);
906 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
907 // weight - but have to make per
908 // sequence, too (awidth[2])
909 // if (width[i]==1) // hack to distinguish single width sequences.
921 boolean sort = false;
922 for (int i = 0; i < width.length; i++)
924 // awidth = (float[]) typeWidth.get(data[i][0]);
927 width[i] = fr.getOrder(data[i][0].toString());
930 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
935 width[i] /= max; // normalize
936 fr.setOrder(data[i][0].toString(), width[i]); // store for later
940 sort = sort || width[i - 1] > width[i];
945 jalview.util.QuickSort.sort(width, data);
946 // update global priority order
949 updateFeatureRenderer(data, false);
957 frame.setClosed(true);
958 } catch (Exception exe)
964 public void updateFeatureRenderer(Object[][] data)
966 updateFeatureRenderer(data, true);
969 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
971 fr.setFeaturePriority(data, visibleNew);
972 af.alignPanel.paintAlignment(true);
975 int selectedRow = -1;
977 JTabbedPane tabbedPane = new JTabbedPane();
979 BorderLayout borderLayout1 = new BorderLayout();
981 BorderLayout borderLayout2 = new BorderLayout();
983 BorderLayout borderLayout3 = new BorderLayout();
985 JPanel bigPanel = new JPanel();
987 BorderLayout borderLayout4 = new BorderLayout();
989 JButton invert = new JButton();
991 JPanel buttonPanel = new JPanel();
993 JButton cancel = new JButton();
995 JButton ok = new JButton();
997 JButton loadColours = new JButton();
999 JButton saveColours = new JButton();
1001 JPanel dasButtonPanel = new JPanel();
1003 JButton fetchDAS = new JButton();
1005 JButton saveDAS = new JButton();
1007 JButton cancelDAS = new JButton();
1009 JButton optimizeOrder = new JButton();
1011 JButton sortByScore = new JButton();
1013 JButton sortByDens = new JButton();
1015 JButton help = new JButton();
1017 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1019 private void jbInit() throws Exception
1021 this.setLayout(borderLayout1);
1022 settingsPane.setLayout(borderLayout2);
1023 dasSettingsPane.setLayout(borderLayout3);
1024 bigPanel.setLayout(borderLayout4);
1025 invert.setFont(JvSwingUtils.getLabelFont());
1026 invert.setText(MessageManager.getString("label.invert_selection"));
1027 invert.addActionListener(new ActionListener()
1029 public void actionPerformed(ActionEvent e)
1034 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1035 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1036 optimizeOrder.addActionListener(new ActionListener()
1038 public void actionPerformed(ActionEvent e)
1043 sortByScore.setFont(JvSwingUtils.getLabelFont());
1045 .setText(MessageManager.getString("label.seq_sort_by_score"));
1046 sortByScore.addActionListener(new ActionListener()
1048 public void actionPerformed(ActionEvent e)
1050 af.avc.sortAlignmentByFeatureScore(null);
1053 sortByDens.setFont(JvSwingUtils.getLabelFont());
1054 sortByDens.setText(MessageManager
1055 .getString("label.sequence_sort_by_density"));
1056 sortByDens.addActionListener(new ActionListener()
1058 public void actionPerformed(ActionEvent e)
1060 af.avc.sortAlignmentByFeatureDensity(null);
1063 help.setFont(JvSwingUtils.getLabelFont());
1064 help.setText(MessageManager.getString("action.help"));
1065 help.addActionListener(new ActionListener()
1067 public void actionPerformed(ActionEvent e)
1071 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1072 } catch (HelpSetException e1)
1074 e1.printStackTrace();
1078 help.setFont(JvSwingUtils.getLabelFont());
1079 help.setText(MessageManager.getString("action.help"));
1080 help.addActionListener(new ActionListener()
1082 public void actionPerformed(ActionEvent e)
1086 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1087 } catch (HelpSetException e1)
1089 e1.printStackTrace();
1093 cancel.setFont(JvSwingUtils.getLabelFont());
1094 cancel.setText(MessageManager.getString("action.cancel"));
1095 cancel.addActionListener(new ActionListener()
1097 public void actionPerformed(ActionEvent e)
1099 fr.setTransparency(originalTransparency);
1100 updateFeatureRenderer(originalData);
1104 ok.setFont(JvSwingUtils.getLabelFont());
1105 ok.setText(MessageManager.getString("action.ok"));
1106 ok.addActionListener(new ActionListener()
1108 public void actionPerformed(ActionEvent e)
1113 loadColours.setFont(JvSwingUtils.getLabelFont());
1114 loadColours.setText(MessageManager.getString("label.load_colours"));
1115 loadColours.addActionListener(new ActionListener()
1117 public void actionPerformed(ActionEvent e)
1122 saveColours.setFont(JvSwingUtils.getLabelFont());
1123 saveColours.setText(MessageManager.getString("label.save_colours"));
1124 saveColours.addActionListener(new ActionListener()
1126 public void actionPerformed(ActionEvent e)
1131 transparency.addChangeListener(new ChangeListener()
1133 public void stateChanged(ChangeEvent evt)
1135 fr.setTransparency((100 - transparency.getValue()) / 100f);
1136 af.alignPanel.paintAlignment(true);
1140 transparency.setMaximum(70);
1141 transparency.setToolTipText(MessageManager
1142 .getString("label.transparency_tip"));
1143 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1144 fetchDAS.addActionListener(new ActionListener()
1146 public void actionPerformed(ActionEvent e)
1148 fetchDAS_actionPerformed(e);
1151 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1152 saveDAS.addActionListener(new ActionListener()
1154 public void actionPerformed(ActionEvent e)
1156 saveDAS_actionPerformed(e);
1159 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1160 dasSettingsPane.setBorder(null);
1161 cancelDAS.setEnabled(false);
1162 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1163 cancelDAS.addActionListener(new ActionListener()
1165 public void actionPerformed(ActionEvent e)
1167 cancelDAS_actionPerformed(e);
1170 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1171 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1172 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1173 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1174 transbuttons.add(optimizeOrder);
1175 transbuttons.add(invert);
1176 transbuttons.add(sortByScore);
1177 transbuttons.add(sortByDens);
1178 transbuttons.add(help);
1179 JPanel sliderPanel = new JPanel();
1180 sliderPanel.add(transparency);
1181 transPanel.add(transparency);
1182 transPanel.add(transbuttons);
1183 buttonPanel.add(ok);
1184 buttonPanel.add(cancel);
1185 buttonPanel.add(loadColours);
1186 buttonPanel.add(saveColours);
1187 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1188 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1189 dasButtonPanel.add(fetchDAS);
1190 dasButtonPanel.add(cancelDAS);
1191 dasButtonPanel.add(saveDAS);
1192 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1193 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1196 public void fetchDAS_actionPerformed(ActionEvent e)
1198 fetchDAS.setEnabled(false);
1199 cancelDAS.setEnabled(true);
1200 dassourceBrowser.setGuiEnabled(false);
1201 Vector selectedSources = dassourceBrowser.getSelectedSources();
1202 doDasFeatureFetch(selectedSources, true, true);
1206 * get the features from selectedSources for all or the current selection
1208 * @param selectedSources
1209 * @param checkDbRefs
1210 * @param promptFetchDbRefs
1212 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1213 boolean checkDbRefs, boolean promptFetchDbRefs)
1215 SequenceI[] dataset, seqs;
1217 AlignmentViewport vp = af.getViewport();
1218 if (vp.getSelectionGroup() != null
1219 && vp.getSelectionGroup().getSize() > 0)
1221 iSize = vp.getSelectionGroup().getSize();
1222 dataset = new SequenceI[iSize];
1223 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1227 iSize = vp.getAlignment().getHeight();
1228 seqs = vp.getAlignment().getSequencesArray();
1231 dataset = new SequenceI[iSize];
1232 for (int i = 0; i < iSize; i++)
1234 dataset[i] = seqs[i].getDatasetSequence();
1237 cancelDAS.setEnabled(true);
1238 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1239 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1240 af.getViewport().setShowSequenceFeatures(true);
1241 af.showSeqFeatures.setSelected(true);
1245 * blocking call to initialise the das source browser
1247 public void initDasSources()
1249 dassourceBrowser.initDasSources();
1253 * examine the current list of das sources and return any matching the given
1254 * nicknames in sources
1257 * Vector of Strings to resolve to DAS source nicknames.
1258 * @return sources that are present in source list.
1260 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1262 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1266 * get currently selected das sources. ensure you have called initDasSources
1267 * before calling this.
1269 * @return vector of selected das source nicknames
1271 public Vector getSelectedSources()
1273 return dassourceBrowser.getSelectedSources();
1277 * properly initialise DAS fetcher and then initiate a new thread to fetch
1278 * features from the named sources (rather than any turned on by default)
1282 * if true then runs in same thread, otherwise passes to the Swing
1285 public void fetchDasFeatures(Vector sources, boolean block)
1288 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1289 .resolveSourceNicknames(sources);
1290 if (resolved.size() == 0)
1292 resolved = dassourceBrowser.getSelectedSources();
1294 if (resolved.size() > 0)
1296 final List<jalviewSourceI> dassources = resolved;
1297 fetchDAS.setEnabled(false);
1298 // cancelDAS.setEnabled(true); doDasFetch does this.
1299 Runnable fetcher = new Runnable()
1304 doDasFeatureFetch(dassources, true, false);
1314 SwingUtilities.invokeLater(fetcher);
1319 public void saveDAS_actionPerformed(ActionEvent e)
1322 .saveProperties(jalview.bin.Cache.applicationProperties);
1325 public void complete()
1327 fetchDAS.setEnabled(true);
1328 cancelDAS.setEnabled(false);
1329 dassourceBrowser.setGuiEnabled(true);
1333 public void cancelDAS_actionPerformed(ActionEvent e)
1335 if (dasFeatureFetcher != null)
1337 dasFeatureFetcher.cancel();
1342 public void noDasSourceActive()
1346 .showInternalConfirmDialog(
1349 .getString("label.no_das_sources_selected_warn"),
1351 .getString("label.no_das_sources_selected_title"),
1352 JOptionPane.DEFAULT_OPTION,
1353 JOptionPane.INFORMATION_MESSAGE);
1356 // ///////////////////////////////////////////////////////////////////////
1357 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1358 // ///////////////////////////////////////////////////////////////////////
1359 class FeatureTableModel extends AbstractTableModel
1361 FeatureTableModel(Object[][] data)
1366 private String[] columnNames =
1367 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1369 private Object[][] data;
1371 public Object[][] getData()
1376 public void setData(Object[][] data)
1381 public int getColumnCount()
1383 return columnNames.length;
1386 public Object[] getRow(int row)
1391 public int getRowCount()
1396 public String getColumnName(int col)
1398 return columnNames[col];
1401 public Object getValueAt(int row, int col)
1403 return data[row][col];
1406 public Class getColumnClass(int c)
1408 return getValueAt(0, c).getClass();
1411 public boolean isCellEditable(int row, int col)
1413 return col == 0 ? false : true;
1416 public void setValueAt(Object value, int row, int col)
1418 data[row][col] = value;
1419 fireTableCellUpdated(row, col);
1420 updateFeatureRenderer(data);
1425 class ColorRenderer extends JLabel implements TableCellRenderer
1427 javax.swing.border.Border unselectedBorder = null;
1429 javax.swing.border.Border selectedBorder = null;
1431 final String baseTT = "Click to edit, right/apple click for menu.";
1433 public ColorRenderer()
1435 setOpaque(true); // MUST do this for background to show up.
1436 setHorizontalTextPosition(SwingConstants.CENTER);
1437 setVerticalTextPosition(SwingConstants.CENTER);
1440 public Component getTableCellRendererComponent(JTable table,
1441 Object color, boolean isSelected, boolean hasFocus, int row,
1444 // JLabel comp = new JLabel();
1448 // setBounds(getBounds());
1450 setToolTipText(baseTT);
1451 setBackground(table.getBackground());
1452 if (color instanceof GraduatedColor)
1454 Rectangle cr = table.getCellRect(row, column, false);
1455 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1456 (int) cr.getWidth(), (int) cr.getHeight());
1463 newColor = (Color) color;
1465 setBackground(newColor);
1466 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1467 // + newColor.getGreen() + ", " + newColor.getBlue());
1471 if (selectedBorder == null)
1473 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1474 table.getSelectionBackground());
1477 setBorder(selectedBorder);
1481 if (unselectedBorder == null)
1483 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1484 table.getBackground());
1487 setBorder(unselectedBorder);
1495 * update comp using rendering settings from gcol
1500 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1502 int w = comp.getWidth(), h = comp.getHeight();
1505 w = (int) comp.getPreferredSize().getWidth();
1506 h = (int) comp.getPreferredSize().getHeight();
1513 renderGraduatedColor(comp, gcol, w, h);
1516 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1519 boolean thr = false;
1522 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1526 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1528 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1532 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1534 if (gcol.isColourByLabel())
1536 tt = "Coloured by label text. " + tt;
1546 Color newColor = gcol.getMaxColor();
1547 comp.setBackground(newColor);
1548 // System.err.println("Width is " + w / 2);
1549 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1550 comp.setIcon(ficon);
1551 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1552 // + newColor.getGreen() + ", " + newColor.getBlue()
1553 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1554 // + ", " + minCol.getBlue() + ")");
1556 comp.setHorizontalAlignment(SwingConstants.CENTER);
1558 if (tt.length() > 0)
1560 if (comp.getToolTipText() == null)
1562 comp.setToolTipText(tt);
1566 comp.setToolTipText(tt + " " + comp.getToolTipText());
1572 class FeatureIcon implements Icon
1574 GraduatedColor gcol;
1578 boolean midspace = false;
1580 int width = 50, height = 20;
1582 int s1, e1; // start and end of midpoint band for thresholded symbol
1584 Color mpcolour = Color.white;
1586 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1605 public int getIconWidth()
1610 public int getIconHeight()
1615 public void paintIcon(Component c, Graphics g, int x, int y)
1618 if (gcol.isColourByLabel())
1621 g.fillRect(0, 0, width, height);
1622 // need an icon here.
1623 g.setColor(gcol.getMaxColor());
1625 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1627 // g.setFont(g.getFont().deriveFont(
1628 // AffineTransform.getScaleInstance(
1629 // width/g.getFontMetrics().stringWidth("Label"),
1630 // height/g.getFontMetrics().getHeight())));
1632 g.drawString(MessageManager.getString("label.label"), 0, 0);
1637 Color minCol = gcol.getMinColor();
1639 g.fillRect(0, 0, s1, height);
1642 g.setColor(Color.white);
1643 g.fillRect(s1, 0, e1 - s1, height);
1645 g.setColor(gcol.getMaxColor());
1646 g.fillRect(0, e1, width - e1, height);
1651 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1656 GraduatedColor currentGColor;
1658 FeatureColourChooser chooser;
1666 JColorChooser colorChooser;
1670 protected static final String EDIT = "edit";
1672 int selectedRow = 0;
1674 public ColorEditor(FeatureSettings me)
1677 // Set up the editor (from the table's point of view),
1678 // which is a button.
1679 // This button brings up the color chooser dialog,
1680 // which is the editor from the user's point of view.
1681 button = new JButton();
1682 button.setActionCommand(EDIT);
1683 button.addActionListener(this);
1684 button.setBorderPainted(false);
1685 // Set up the dialog that the button brings up.
1686 colorChooser = new JColorChooser();
1687 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1688 colorChooser, this, // OK button handler
1689 null); // no CANCEL button handler
1693 * Handles events from the editor button and from the dialog's OK button.
1695 public void actionPerformed(ActionEvent e)
1698 if (EDIT.equals(e.getActionCommand()))
1700 // The user has clicked the cell, so
1701 // bring up the dialog.
1702 if (currentColor != null)
1704 // bring up simple color chooser
1705 button.setBackground(currentColor);
1706 colorChooser.setColor(currentColor);
1707 dialog.setVisible(true);
1711 // bring up graduated chooser.
1712 chooser = new FeatureColourChooser(me.fr, type);
1713 chooser.setRequestFocusEnabled(true);
1714 chooser.requestFocus();
1715 chooser.addActionListener(this);
1717 // Make the renderer reappear.
1718 fireEditingStopped();
1722 { // User pressed dialog's "OK" button.
1723 if (currentColor != null)
1725 currentColor = colorChooser.getColor();
1729 // class cast exceptions may be raised if the chooser created on a
1730 // non-graduated color
1731 currentGColor = (GraduatedColor) chooser.getLastColour();
1733 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1734 fireEditingStopped();
1735 me.table.validate();
1739 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1740 public Object getCellEditorValue()
1742 if (currentColor == null)
1744 return currentGColor;
1746 return currentColor;
1749 // Implement the one method defined by TableCellEditor.
1750 public Component getTableCellEditorComponent(JTable table, Object value,
1751 boolean isSelected, int row, int column)
1753 currentGColor = null;
1754 currentColor = null;
1755 this.selectedRow = row;
1756 type = me.table.getValueAt(row, 0).toString();
1757 button.setOpaque(true);
1758 button.setBackground(me.getBackground());
1759 if (value instanceof GraduatedColor)
1761 currentGColor = (GraduatedColor) value;
1762 JLabel btn = new JLabel();
1763 btn.setSize(button.getSize());
1764 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1765 button.setBackground(btn.getBackground());
1766 button.setIcon(btn.getIcon());
1767 button.setText(btn.getText());
1772 button.setIcon(null);
1773 currentColor = (Color) value;
1774 button.setBackground(currentColor);