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.ws.dbsources.das.api.jalviewSourceI;
33 import java.awt.BorderLayout;
34 import java.awt.Color;
35 import java.awt.Component;
37 import java.awt.Graphics;
38 import java.awt.GridLayout;
39 import java.awt.Rectangle;
40 import java.awt.event.ActionEvent;
41 import java.awt.event.ActionListener;
42 import java.awt.event.ItemEvent;
43 import java.awt.event.ItemListener;
44 import java.awt.event.MouseAdapter;
45 import java.awt.event.MouseEvent;
46 import java.awt.event.MouseMotionAdapter;
47 import java.beans.PropertyChangeEvent;
48 import java.beans.PropertyChangeListener;
50 import java.io.FileInputStream;
51 import java.io.FileOutputStream;
52 import java.io.InputStreamReader;
53 import java.io.OutputStreamWriter;
54 import java.io.PrintWriter;
55 import java.util.Hashtable;
56 import java.util.Iterator;
57 import java.util.List;
59 import java.util.Vector;
61 import javax.help.HelpSetException;
62 import javax.swing.AbstractCellEditor;
63 import javax.swing.BorderFactory;
64 import javax.swing.Icon;
65 import javax.swing.JButton;
66 import javax.swing.JCheckBox;
67 import javax.swing.JCheckBoxMenuItem;
68 import javax.swing.JColorChooser;
69 import javax.swing.JDialog;
70 import javax.swing.JInternalFrame;
71 import javax.swing.JLabel;
72 import javax.swing.JLayeredPane;
73 import javax.swing.JMenuItem;
74 import javax.swing.JOptionPane;
75 import javax.swing.JPanel;
76 import javax.swing.JPopupMenu;
77 import javax.swing.JScrollPane;
78 import javax.swing.JSlider;
79 import javax.swing.JTabbedPane;
80 import javax.swing.JTable;
81 import javax.swing.ListSelectionModel;
82 import javax.swing.SwingConstants;
83 import javax.swing.SwingUtilities;
84 import javax.swing.event.ChangeEvent;
85 import javax.swing.event.ChangeListener;
86 import javax.swing.table.AbstractTableModel;
87 import javax.swing.table.TableCellEditor;
88 import javax.swing.table.TableCellRenderer;
90 public class FeatureSettings extends JPanel
92 DasSourceBrowser dassourceBrowser;
94 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
96 JPanel settingsPane = new JPanel();
98 JPanel dasSettingsPane = new JPanel();
100 final FeatureRenderer fr;
102 public final AlignFrame af;
104 Object[][] originalData;
106 private float originalTransparency;
108 final JInternalFrame frame;
110 JScrollPane scrollPane = new JScrollPane();
116 JSlider transparency = new JSlider();
118 JPanel transPanel = new JPanel(new GridLayout(1, 2));
120 public FeatureSettings(AlignFrame af)
123 fr = af.getFeatureRenderer();
124 // allow transparency to be recovered
125 transparency.setMaximum(100 - (int) ((originalTransparency=fr.getTransparency()) * 100));
130 } catch (Exception ex)
132 ex.printStackTrace();
135 table = new JTable() {
137 public String getToolTipText(MouseEvent e) {
138 if (table.columnAtPoint(e.getPoint()) == 0) {
140 * Tooltip for feature name only
142 return JvSwingUtils.wrapTooltip(true,
143 MessageManager.getString("label.feature_settings_click_drag"));
148 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
149 table.setFont(new Font("Verdana", Font.PLAIN, 12));
150 table.setDefaultRenderer(Color.class, new ColorRenderer());
152 table.setDefaultEditor(Color.class, new ColorEditor(this));
154 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
155 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
156 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
158 table.addMouseListener(new MouseAdapter()
160 public void mousePressed(MouseEvent evt)
162 selectedRow = table.rowAtPoint(evt.getPoint());
163 if (SwingUtilities.isRightMouseButton(evt))
165 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
166 table.getValueAt(selectedRow, 1), fr.getMinMax(),
167 evt.getX(), evt.getY());
169 else if (evt.getClickCount() == 2)
171 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
172 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
174 (String) table.getValueAt(selectedRow, 0));
178 // isPopupTrigger fires on mouseReleased on Mac
180 public void mouseReleased(MouseEvent evt)
182 selectedRow = table.rowAtPoint(evt.getPoint());
183 if (evt.isPopupTrigger())
185 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
186 table.getValueAt(selectedRow, 1), fr.getMinMax(),
193 table.addMouseMotionListener(new MouseMotionAdapter()
195 public void mouseDragged(MouseEvent evt)
197 int newRow = table.rowAtPoint(evt.getPoint());
198 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
200 Object[] temp = new Object[3];
201 temp[0] = table.getValueAt(selectedRow, 0);
202 temp[1] = table.getValueAt(selectedRow, 1);
203 temp[2] = table.getValueAt(selectedRow, 2);
205 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
206 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
207 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
209 table.setValueAt(temp[0], newRow, 0);
210 table.setValueAt(temp[1], newRow, 1);
211 table.setValueAt(temp[2], newRow, 2);
213 selectedRow = newRow;
217 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
218 // MessageManager.getString("label.feature_settings_click_drag")));
219 scrollPane.setViewportView(table);
221 dassourceBrowser = new DasSourceBrowser(this);
222 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
224 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
226 fr.findAllFeatures(true); // display everything!
230 final PropertyChangeListener change;
231 final FeatureSettings fs = this;
232 fr.addPropertyChangeListener(change = new PropertyChangeListener()
234 public void propertyChange(PropertyChangeEvent evt)
236 if (!fs.resettingTable && !fs.handlingUpdate)
238 fs.handlingUpdate = true;
239 fs.resetTable(null); // new groups may be added with new seuqence
240 // feature types only
241 fs.handlingUpdate = false;
247 frame = new JInternalFrame();
248 frame.setContentPane(this);
249 if (new jalview.util.Platform().isAMac())
251 Desktop.addInternalFrame(frame,
252 MessageManager.getString("label.sequence_feature_settings"),
257 Desktop.addInternalFrame(frame,
258 MessageManager.getString("label.sequence_feature_settings"),
262 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
264 public void internalFrameClosed(
265 javax.swing.event.InternalFrameEvent evt)
267 fr.removePropertyChangeListener(change);
268 dassourceBrowser.fs = null;
271 frame.setLayer(JLayeredPane.PALETTE_LAYER);
274 protected void popupSort(final int selectedRow, final String type,
275 final Object typeCol, final Hashtable minmax, int x, int y)
277 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
278 "label.settings_for_param", new String[]
280 JMenuItem scr = new JMenuItem(
281 MessageManager.getString("label.sort_by_score"));
283 final FeatureSettings me = this;
284 scr.addActionListener(new ActionListener()
287 public void actionPerformed(ActionEvent e)
289 me.af.avc.sortAlignmentByFeatureScore(new String[]
294 JMenuItem dens = new JMenuItem(
295 MessageManager.getString("label.sort_by_density"));
296 dens.addActionListener(new ActionListener()
299 public void actionPerformed(ActionEvent e)
301 me.af.avc.sortAlignmentByFeatureDensity(new String[]
309 final Object typeMinMax = minmax.get(type);
311 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
312 * this is broken at the moment and isn't that useful anyway!
313 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
316 * public void actionPerformed(ActionEvent e) {
317 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
318 * null); } else { minmax.put(type, typeMinMax); } }
324 if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
326 // if (table.getValueAt(row, column));
327 // graduated colourschemes for those where minmax exists for the
328 // positional features
329 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
331 mxcol.setSelected(!(typeCol instanceof Color));
333 mxcol.addActionListener(new ActionListener()
335 JColorChooser colorChooser;
337 public void actionPerformed(ActionEvent e)
339 if (e.getSource() == mxcol)
341 if (typeCol instanceof Color)
343 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
345 fc.addActionListener(this);
349 // bring up simple color chooser
350 colorChooser = new JColorChooser();
351 JDialog dialog = JColorChooser.createDialog(me,
352 "Select new Colour", true, // modal
353 colorChooser, this, // OK button handler
354 null); // no CANCEL button handler
355 colorChooser.setColor(((GraduatedColor) typeCol)
357 dialog.setVisible(true);
362 if (e.getSource() instanceof FeatureColourChooser)
364 FeatureColourChooser fc = (FeatureColourChooser) e
366 table.setValueAt(fc.getLastColour(), selectedRow, 1);
371 // probably the color chooser!
372 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
374 me.updateFeatureRenderer(
375 ((FeatureTableModel) table.getModel()).getData(),
384 JMenuItem selCols = new JMenuItem(
385 MessageManager.getString("label.select_columns_containing"));
386 selCols.addActionListener(new ActionListener()
390 public void actionPerformed(ActionEvent arg0)
392 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
396 JMenuItem clearCols = new JMenuItem(
397 MessageManager.getString("label.select_columns_not_containing"));
398 clearCols.addActionListener(new ActionListener()
402 public void actionPerformed(ActionEvent arg0)
404 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
410 men.show(table, x, y);
414 * true when Feature Settings are updating from feature renderer
416 private boolean handlingUpdate = false;
419 * contains a float[3] for each feature type string. created by setTableData
421 Hashtable typeWidth = null;
423 synchronized public void setTableData()
425 Vector allFeatures = new Vector();
426 Vector allGroups = new Vector();
427 SequenceFeature[] tmpfeatures;
429 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
431 if (af.getViewport().getAlignment().getSequenceAt(i)
432 .getDatasetSequence().getSequenceFeatures() == null)
437 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
438 .getDatasetSequence().getSequenceFeatures();
441 while (index < tmpfeatures.length)
443 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
449 if (tmpfeatures[index].getFeatureGroup() != null)
451 group = tmpfeatures[index].featureGroup;
452 if (!allGroups.contains(group))
454 allGroups.addElement(group);
455 checkGroupState(group);
459 if (!allFeatures.contains(tmpfeatures[index].getType()))
461 allFeatures.addElement(tmpfeatures[index].getType());
473 * Synchronise gui group list and check visibility of group
476 * @return true if group is visible
478 private boolean checkGroupState(String group)
480 boolean visible = fr.checkGroupVisibility(group, true);
482 if (groupPanel == null)
484 groupPanel = new JPanel();
487 boolean alreadyAdded = false;
488 for (int g = 0; g < groupPanel.getComponentCount(); g++)
490 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
493 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
503 final String grp = group;
504 final JCheckBox check = new JCheckBox(group, visible);
505 check.setFont(new Font("Serif", Font.BOLD, 12));
506 check.addItemListener(new ItemListener()
508 public void itemStateChanged(ItemEvent evt)
510 fr.setGroupVisibility(check.getText(), check.isSelected());
511 af.alignPanel.getSeqPanel().seqCanvas.repaint();
512 if (af.alignPanel.overviewPanel != null)
514 af.alignPanel.overviewPanel.updateOverviewImage();
517 resetTable(new String[]
521 groupPanel.add(check);
525 boolean resettingTable = false;
527 synchronized void resetTable(String[] groupChanged)
529 if (resettingTable == true)
533 resettingTable = true;
534 typeWidth = new Hashtable();
535 // TODO: change avWidth calculation to 'per-sequence' average and use long
537 float[] avWidth = null;
538 SequenceFeature[] tmpfeatures;
539 String group = null, type;
540 Vector visibleChecks = new Vector();
542 // Find out which features should be visible depending on which groups
543 // are selected / deselected
544 // and recompute average width ordering
545 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
548 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
549 .getDatasetSequence().getSequenceFeatures();
550 if (tmpfeatures == null)
556 while (index < tmpfeatures.length)
558 group = tmpfeatures[index].featureGroup;
560 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
566 if (group == null || checkGroupState(group))
568 type = tmpfeatures[index].getType();
569 if (!visibleChecks.contains(type))
571 visibleChecks.addElement(type);
574 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
576 typeWidth.put(tmpfeatures[index].getType(),
577 avWidth = new float[3]);
581 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
584 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
586 avWidth[1] += 1 + tmpfeatures[index].getBegin()
587 - tmpfeatures[index].getEnd();
591 avWidth[1] += 1 + tmpfeatures[index].getEnd()
592 - tmpfeatures[index].getBegin();
598 int fSize = visibleChecks.size();
599 Object[][] data = new Object[fSize][3];
602 if (fr.hasRenderOrder())
606 fr.findAllFeatures(groupChanged != null); // prod to update
607 // colourschemes. but don't
609 // First add the checks in the previous render order,
610 // in case the window has been closed and reopened
612 List<String> frl = fr.getRenderOrder();
613 for (int ro = frl.size() - 1; ro > -1; ro--)
617 if (!visibleChecks.contains(type))
622 data[dataIndex][0] = type;
623 data[dataIndex][1] = fr.getFeatureStyle(type);
624 data[dataIndex][2] = new Boolean(af.getViewport()
625 .getFeaturesDisplayed().isVisible(type));
627 visibleChecks.removeElement(type);
631 fSize = visibleChecks.size();
632 for (int i = 0; i < fSize; i++)
634 // These must be extra features belonging to the group
635 // which was just selected
636 type = visibleChecks.elementAt(i).toString();
637 data[dataIndex][0] = type;
639 data[dataIndex][1] = fr.getFeatureStyle(type);
640 if (data[dataIndex][1] == null)
642 // "Colour has been updated in another view!!"
643 fr.clearRenderOrder();
647 data[dataIndex][2] = new Boolean(true);
651 if (originalData == null)
653 originalData = new Object[data.length][3];
654 for (int i = 0; i < data.length; i++)
656 System.arraycopy(data[i], 0, originalData[i], 0, 3);
660 table.setModel(new FeatureTableModel(data));
661 table.getColumnModel().getColumn(0).setPreferredWidth(200);
663 if (groupPanel != null)
665 groupPanel.setLayout(new GridLayout(
666 fr.getFeatureGroupsSize() / 4 + 1, 4));
668 groupPanel.validate();
669 bigPanel.add(groupPanel, BorderLayout.NORTH);
672 updateFeatureRenderer(data, groupChanged != null);
673 resettingTable = false;
677 * reorder data based on the featureRenderers global priority list.
681 private void ensureOrder(Object[][] data)
683 boolean sort = false;
684 float[] order = new float[data.length];
685 for (int i = 0; i < order.length; i++)
687 order[i] = fr.getOrder(data[i][0].toString());
690 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
694 sort = sort || order[i - 1] > order[i];
699 jalview.util.QuickSort.sort(order, data);
705 JalviewFileChooser chooser = new JalviewFileChooser(
706 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
707 { "fc" }, new String[]
708 { "Sequence Feature Colours" }, "Sequence Feature Colours");
709 chooser.setFileView(new jalview.io.JalviewFileView());
710 chooser.setDialogTitle(MessageManager.getString("label.load_feature_colours"));
711 chooser.setToolTipText(MessageManager.getString("action.load"));
713 int value = chooser.showOpenDialog(this);
715 if (value == JalviewFileChooser.APPROVE_OPTION)
717 File file = chooser.getSelectedFile();
721 InputStreamReader in = new InputStreamReader(new FileInputStream(
724 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
728 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
731 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
734 Color mincol = null, maxcol = null;
737 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
738 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
740 } catch (Exception e)
742 Cache.log.warn("Couldn't parse out graduated feature color.",
745 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
746 newcol.getMin(), newcol.getMax());
747 if (newcol.hasAutoScale())
749 gcol.setAutoScaled(newcol.getAutoScale());
751 if (newcol.hasColourByLabel())
753 gcol.setColourByLabel(newcol.getColourByLabel());
755 if (newcol.hasThreshold())
757 gcol.setThresh(newcol.getThreshold());
758 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
760 if (newcol.getThreshType().length() > 0)
762 String ttyp = newcol.getThreshType();
763 if (ttyp.equalsIgnoreCase("NONE"))
765 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
767 if (ttyp.equalsIgnoreCase("ABOVE"))
769 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
771 if (ttyp.equalsIgnoreCase("BELOW"))
773 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
776 fr.setColour(name = newcol.getName(), gcol);
780 fr.setColour(name = jucs.getColour(i).getName(), new Color(
781 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
783 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
788 Object[][] data = ((FeatureTableModel) table.getModel())
791 updateFeatureRenderer(data, false);
794 } catch (Exception ex)
796 System.out.println("Error loading User Colour File\n" + ex);
803 JalviewFileChooser chooser = new JalviewFileChooser(
804 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
805 { "fc" }, new String[]
806 { "Sequence Feature Colours" }, "Sequence Feature Colours");
807 chooser.setFileView(new jalview.io.JalviewFileView());
808 chooser.setDialogTitle(MessageManager.getString("label.save_feature_colours"));
809 chooser.setToolTipText(MessageManager.getString("action.save"));
811 int value = chooser.showSaveDialog(this);
813 if (value == JalviewFileChooser.APPROVE_OPTION)
815 String choice = chooser.getSelectedFile().getPath();
816 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
817 ucs.setSchemeName("Sequence Features");
820 PrintWriter out = new PrintWriter(new OutputStreamWriter(
821 new FileOutputStream(choice), "UTF-8"));
823 Set fr_colours = fr.getAllFeatureColours();
824 Iterator e = fr_colours.iterator();
825 float[] sortOrder = new float[fr_colours.size()];
826 String[] sortTypes = new String[fr_colours.size()];
830 sortTypes[i] = e.next().toString();
831 sortOrder[i] = fr.getOrder(sortTypes[i]);
834 jalview.util.QuickSort.sort(sortOrder, sortTypes);
838 for (i = 0; i < sortTypes.length; i++)
840 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
841 col.setName(sortTypes[i]);
842 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
844 fcol = fr.getFeatureStyle(sortTypes[i]);
845 if (fcol instanceof GraduatedColor)
847 gcol = (GraduatedColor) fcol;
848 col.setMin(gcol.getMin());
849 col.setMax(gcol.getMax());
850 col.setMinRGB(jalview.util.Format.getHexString(gcol
852 col.setAutoScale(gcol.isAutoScale());
853 col.setThreshold(gcol.getThresh());
854 col.setColourByLabel(gcol.isColourByLabel());
855 switch (gcol.getThreshType())
857 case AnnotationColourGradient.NO_THRESHOLD:
858 col.setThreshType("NONE");
860 case AnnotationColourGradient.ABOVE_THRESHOLD:
861 col.setThreshType("ABOVE");
863 case AnnotationColourGradient.BELOW_THRESHOLD:
864 col.setThreshType("BELOW");
872 } catch (Exception ex)
874 ex.printStackTrace();
879 public void invertSelection()
881 for (int i = 0; i < table.getRowCount(); i++)
883 Boolean value = (Boolean) table.getValueAt(i, 2);
885 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
889 public void orderByAvWidth()
891 if (table == null || table.getModel() == null)
895 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
896 float[] width = new float[data.length];
900 for (int i = 0; i < data.length; i++)
902 awidth = (float[]) typeWidth.get(data[i][0]);
905 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
906 // weight - but have to make per
907 // sequence, too (awidth[2])
908 // if (width[i]==1) // hack to distinguish single width sequences.
920 boolean sort = false;
921 for (int i = 0; i < width.length; i++)
923 // awidth = (float[]) typeWidth.get(data[i][0]);
926 width[i] = fr.getOrder(data[i][0].toString());
929 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
934 width[i] /= max; // normalize
935 fr.setOrder(data[i][0].toString(), width[i]); // store for later
939 sort = sort || width[i - 1] > width[i];
944 jalview.util.QuickSort.sort(width, data);
945 // update global priority order
948 updateFeatureRenderer(data, false);
956 frame.setClosed(true);
957 } catch (Exception exe)
963 public void updateFeatureRenderer(Object[][] data)
965 updateFeatureRenderer(data, true);
968 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
970 fr.setFeaturePriority(data, visibleNew);
971 af.alignPanel.paintAlignment(true);
974 int selectedRow = -1;
976 JTabbedPane tabbedPane = new JTabbedPane();
978 BorderLayout borderLayout1 = new BorderLayout();
980 BorderLayout borderLayout2 = new BorderLayout();
982 BorderLayout borderLayout3 = new BorderLayout();
984 JPanel bigPanel = new JPanel();
986 BorderLayout borderLayout4 = new BorderLayout();
988 JButton invert = new JButton();
990 JPanel buttonPanel = new JPanel();
992 JButton cancel = new JButton();
994 JButton ok = new JButton();
996 JButton loadColours = new JButton();
998 JButton saveColours = new JButton();
1000 JPanel dasButtonPanel = new JPanel();
1002 JButton fetchDAS = new JButton();
1004 JButton saveDAS = new JButton();
1006 JButton cancelDAS = new JButton();
1008 JButton optimizeOrder = new JButton();
1010 JButton sortByScore = new JButton();
1012 JButton sortByDens = new JButton();
1014 JButton help = new JButton();
1016 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1018 private void jbInit() throws Exception
1020 this.setLayout(borderLayout1);
1021 settingsPane.setLayout(borderLayout2);
1022 dasSettingsPane.setLayout(borderLayout3);
1023 bigPanel.setLayout(borderLayout4);
1024 invert.setFont(JvSwingUtils.getLabelFont());
1025 invert.setText(MessageManager.getString("label.invert_selection"));
1026 invert.addActionListener(new ActionListener()
1028 public void actionPerformed(ActionEvent e)
1033 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1034 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1035 optimizeOrder.addActionListener(new ActionListener()
1037 public void actionPerformed(ActionEvent e)
1042 sortByScore.setFont(JvSwingUtils.getLabelFont());
1044 .setText(MessageManager.getString("label.seq_sort_by_score"));
1045 sortByScore.addActionListener(new ActionListener()
1047 public void actionPerformed(ActionEvent e)
1049 af.avc.sortAlignmentByFeatureScore(null);
1052 sortByDens.setFont(JvSwingUtils.getLabelFont());
1053 sortByDens.setText(MessageManager
1054 .getString("label.sequence_sort_by_density"));
1055 sortByDens.addActionListener(new ActionListener()
1057 public void actionPerformed(ActionEvent e)
1059 af.avc.sortAlignmentByFeatureDensity(null);
1062 help.setFont(JvSwingUtils.getLabelFont());
1063 help.setText(MessageManager.getString("action.help"));
1064 help.addActionListener(new ActionListener()
1066 public void actionPerformed(ActionEvent e)
1070 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1071 } catch (HelpSetException e1)
1073 e1.printStackTrace();
1077 cancel.setFont(JvSwingUtils.getLabelFont());
1078 cancel.setText(MessageManager.getString("action.cancel"));
1079 cancel.addActionListener(new ActionListener()
1081 public void actionPerformed(ActionEvent e)
1083 fr.setTransparency(originalTransparency);
1084 updateFeatureRenderer(originalData);
1088 ok.setFont(JvSwingUtils.getLabelFont());
1089 ok.setText(MessageManager.getString("action.ok"));
1090 ok.addActionListener(new ActionListener()
1092 public void actionPerformed(ActionEvent e)
1097 loadColours.setFont(JvSwingUtils.getLabelFont());
1098 loadColours.setText(MessageManager.getString("label.load_colours"));
1099 loadColours.addActionListener(new ActionListener()
1101 public void actionPerformed(ActionEvent e)
1106 saveColours.setFont(JvSwingUtils.getLabelFont());
1107 saveColours.setText(MessageManager.getString("label.save_colours"));
1108 saveColours.addActionListener(new ActionListener()
1110 public void actionPerformed(ActionEvent e)
1115 transparency.addChangeListener(new ChangeListener()
1117 public void stateChanged(ChangeEvent evt)
1119 fr.setTransparency((100 - transparency.getValue()) / 100f);
1120 af.alignPanel.paintAlignment(true);
1124 transparency.setMaximum(70);
1125 transparency.setToolTipText(MessageManager
1126 .getString("label.transparency_tip"));
1127 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1128 fetchDAS.addActionListener(new ActionListener()
1130 public void actionPerformed(ActionEvent e)
1132 fetchDAS_actionPerformed(e);
1135 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1136 saveDAS.addActionListener(new ActionListener()
1138 public void actionPerformed(ActionEvent e)
1140 saveDAS_actionPerformed(e);
1143 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1144 dasSettingsPane.setBorder(null);
1145 cancelDAS.setEnabled(false);
1146 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1147 cancelDAS.addActionListener(new ActionListener()
1149 public void actionPerformed(ActionEvent e)
1151 cancelDAS_actionPerformed(e);
1154 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1155 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1156 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1157 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1158 transbuttons.add(optimizeOrder);
1159 transbuttons.add(invert);
1160 transbuttons.add(sortByScore);
1161 transbuttons.add(sortByDens);
1162 transbuttons.add(help);
1163 JPanel sliderPanel = new JPanel();
1164 sliderPanel.add(transparency);
1165 transPanel.add(transparency);
1166 transPanel.add(transbuttons);
1167 buttonPanel.add(ok);
1168 buttonPanel.add(cancel);
1169 buttonPanel.add(loadColours);
1170 buttonPanel.add(saveColours);
1171 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1172 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1173 dasButtonPanel.add(fetchDAS);
1174 dasButtonPanel.add(cancelDAS);
1175 dasButtonPanel.add(saveDAS);
1176 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1177 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1180 public void fetchDAS_actionPerformed(ActionEvent e)
1182 fetchDAS.setEnabled(false);
1183 cancelDAS.setEnabled(true);
1184 dassourceBrowser.setGuiEnabled(false);
1185 Vector selectedSources = dassourceBrowser.getSelectedSources();
1186 doDasFeatureFetch(selectedSources, true, true);
1190 * get the features from selectedSources for all or the current selection
1192 * @param selectedSources
1193 * @param checkDbRefs
1194 * @param promptFetchDbRefs
1196 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1197 boolean checkDbRefs, boolean promptFetchDbRefs)
1199 SequenceI[] dataset, seqs;
1201 AlignViewport vp = af.getViewport();
1202 if (vp.getSelectionGroup() != null
1203 && vp.getSelectionGroup().getSize() > 0)
1205 iSize = vp.getSelectionGroup().getSize();
1206 dataset = new SequenceI[iSize];
1207 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1211 iSize = vp.getAlignment().getHeight();
1212 seqs = vp.getAlignment().getSequencesArray();
1215 dataset = new SequenceI[iSize];
1216 for (int i = 0; i < iSize; i++)
1218 dataset[i] = seqs[i].getDatasetSequence();
1221 cancelDAS.setEnabled(true);
1222 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1223 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1224 af.getViewport().setShowSequenceFeatures(true);
1225 af.showSeqFeatures.setSelected(true);
1229 * blocking call to initialise the das source browser
1231 public void initDasSources()
1233 dassourceBrowser.initDasSources();
1237 * examine the current list of das sources and return any matching the given
1238 * nicknames in sources
1241 * Vector of Strings to resolve to DAS source nicknames.
1242 * @return sources that are present in source list.
1244 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1246 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1250 * get currently selected das sources. ensure you have called initDasSources
1251 * before calling this.
1253 * @return vector of selected das source nicknames
1255 public Vector getSelectedSources()
1257 return dassourceBrowser.getSelectedSources();
1261 * properly initialise DAS fetcher and then initiate a new thread to fetch
1262 * features from the named sources (rather than any turned on by default)
1266 * if true then runs in same thread, otherwise passes to the Swing
1269 public void fetchDasFeatures(Vector sources, boolean block)
1272 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1273 .resolveSourceNicknames(sources);
1274 if (resolved.size() == 0)
1276 resolved = dassourceBrowser.getSelectedSources();
1278 if (resolved.size() > 0)
1280 final List<jalviewSourceI> dassources = resolved;
1281 fetchDAS.setEnabled(false);
1282 // cancelDAS.setEnabled(true); doDasFetch does this.
1283 Runnable fetcher = new Runnable()
1288 doDasFeatureFetch(dassources, true, false);
1298 SwingUtilities.invokeLater(fetcher);
1303 public void saveDAS_actionPerformed(ActionEvent e)
1306 .saveProperties(jalview.bin.Cache.applicationProperties);
1309 public void complete()
1311 fetchDAS.setEnabled(true);
1312 cancelDAS.setEnabled(false);
1313 dassourceBrowser.setGuiEnabled(true);
1317 public void cancelDAS_actionPerformed(ActionEvent e)
1319 if (dasFeatureFetcher != null)
1321 dasFeatureFetcher.cancel();
1326 public void noDasSourceActive()
1330 .showInternalConfirmDialog(
1333 .getString("label.no_das_sources_selected_warn"),
1335 .getString("label.no_das_sources_selected_title"),
1336 JOptionPane.DEFAULT_OPTION,
1337 JOptionPane.INFORMATION_MESSAGE);
1340 // ///////////////////////////////////////////////////////////////////////
1341 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1342 // ///////////////////////////////////////////////////////////////////////
1343 class FeatureTableModel extends AbstractTableModel
1345 FeatureTableModel(Object[][] data)
1350 private String[] columnNames =
1351 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1353 private Object[][] data;
1355 public Object[][] getData()
1360 public void setData(Object[][] data)
1365 public int getColumnCount()
1367 return columnNames.length;
1370 public Object[] getRow(int row)
1375 public int getRowCount()
1380 public String getColumnName(int col)
1382 return columnNames[col];
1385 public Object getValueAt(int row, int col)
1387 return data[row][col];
1390 public Class getColumnClass(int c)
1392 return getValueAt(0, c).getClass();
1395 public boolean isCellEditable(int row, int col)
1397 return col == 0 ? false : true;
1400 public void setValueAt(Object value, int row, int col)
1402 data[row][col] = value;
1403 fireTableCellUpdated(row, col);
1404 updateFeatureRenderer(data);
1409 class ColorRenderer extends JLabel implements TableCellRenderer
1411 javax.swing.border.Border unselectedBorder = null;
1413 javax.swing.border.Border selectedBorder = null;
1415 final String baseTT = "Click to edit, right/apple click for menu.";
1417 public ColorRenderer()
1419 setOpaque(true); // MUST do this for background to show up.
1420 setHorizontalTextPosition(SwingConstants.CENTER);
1421 setVerticalTextPosition(SwingConstants.CENTER);
1424 public Component getTableCellRendererComponent(JTable table,
1425 Object color, boolean isSelected, boolean hasFocus, int row,
1428 // JLabel comp = new JLabel();
1432 // setBounds(getBounds());
1434 setToolTipText(baseTT);
1435 setBackground(table.getBackground());
1436 if (color instanceof GraduatedColor)
1438 Rectangle cr = table.getCellRect(row, column, false);
1439 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1440 (int) cr.getWidth(), (int) cr.getHeight());
1447 newColor = (Color) color;
1449 setBackground(newColor);
1450 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1451 // + newColor.getGreen() + ", " + newColor.getBlue());
1455 if (selectedBorder == null)
1457 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1458 table.getSelectionBackground());
1461 setBorder(selectedBorder);
1465 if (unselectedBorder == null)
1467 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1468 table.getBackground());
1471 setBorder(unselectedBorder);
1479 * update comp using rendering settings from gcol
1484 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1486 int w = comp.getWidth(), h = comp.getHeight();
1489 w = (int) comp.getPreferredSize().getWidth();
1490 h = (int) comp.getPreferredSize().getHeight();
1497 renderGraduatedColor(comp, gcol, w, h);
1500 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1503 boolean thr = false;
1506 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1510 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1512 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1516 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1518 if (gcol.isColourByLabel())
1520 tt = "Coloured by label text. " + tt;
1530 Color newColor = gcol.getMaxColor();
1531 comp.setBackground(newColor);
1532 // System.err.println("Width is " + w / 2);
1533 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1534 comp.setIcon(ficon);
1535 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1536 // + newColor.getGreen() + ", " + newColor.getBlue()
1537 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1538 // + ", " + minCol.getBlue() + ")");
1540 comp.setHorizontalAlignment(SwingConstants.CENTER);
1542 if (tt.length() > 0)
1544 if (comp.getToolTipText() == null)
1546 comp.setToolTipText(tt);
1550 comp.setToolTipText(tt + " " + comp.getToolTipText());
1556 class FeatureIcon implements Icon
1558 GraduatedColor gcol;
1562 boolean midspace = false;
1564 int width = 50, height = 20;
1566 int s1, e1; // start and end of midpoint band for thresholded symbol
1568 Color mpcolour = Color.white;
1570 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1589 public int getIconWidth()
1594 public int getIconHeight()
1599 public void paintIcon(Component c, Graphics g, int x, int y)
1602 if (gcol.isColourByLabel())
1605 g.fillRect(0, 0, width, height);
1606 // need an icon here.
1607 g.setColor(gcol.getMaxColor());
1609 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1611 // g.setFont(g.getFont().deriveFont(
1612 // AffineTransform.getScaleInstance(
1613 // width/g.getFontMetrics().stringWidth("Label"),
1614 // height/g.getFontMetrics().getHeight())));
1616 g.drawString(MessageManager.getString("label.label"), 0, 0);
1621 Color minCol = gcol.getMinColor();
1623 g.fillRect(0, 0, s1, height);
1626 g.setColor(Color.white);
1627 g.fillRect(s1, 0, e1 - s1, height);
1629 g.setColor(gcol.getMaxColor());
1630 g.fillRect(0, e1, width - e1, height);
1635 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1640 GraduatedColor currentGColor;
1642 FeatureColourChooser chooser;
1650 JColorChooser colorChooser;
1654 protected static final String EDIT = "edit";
1656 int selectedRow = 0;
1658 public ColorEditor(FeatureSettings me)
1661 // Set up the editor (from the table's point of view),
1662 // which is a button.
1663 // This button brings up the color chooser dialog,
1664 // which is the editor from the user's point of view.
1665 button = new JButton();
1666 button.setActionCommand(EDIT);
1667 button.addActionListener(this);
1668 button.setBorderPainted(false);
1669 // Set up the dialog that the button brings up.
1670 colorChooser = new JColorChooser();
1671 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1672 colorChooser, this, // OK button handler
1673 null); // no CANCEL button handler
1677 * Handles events from the editor button and from the dialog's OK button.
1679 public void actionPerformed(ActionEvent e)
1682 if (EDIT.equals(e.getActionCommand()))
1684 // The user has clicked the cell, so
1685 // bring up the dialog.
1686 if (currentColor != null)
1688 // bring up simple color chooser
1689 button.setBackground(currentColor);
1690 colorChooser.setColor(currentColor);
1691 dialog.setVisible(true);
1695 // bring up graduated chooser.
1696 chooser = new FeatureColourChooser(me.fr, type);
1697 chooser.setRequestFocusEnabled(true);
1698 chooser.requestFocus();
1699 chooser.addActionListener(this);
1701 // Make the renderer reappear.
1702 fireEditingStopped();
1706 { // User pressed dialog's "OK" button.
1707 if (currentColor != null)
1709 currentColor = colorChooser.getColor();
1713 // class cast exceptions may be raised if the chooser created on a
1714 // non-graduated color
1715 currentGColor = (GraduatedColor) chooser.getLastColour();
1717 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1718 fireEditingStopped();
1719 me.table.validate();
1723 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1724 public Object getCellEditorValue()
1726 if (currentColor == null)
1728 return currentGColor;
1730 return currentColor;
1733 // Implement the one method defined by TableCellEditor.
1734 public Component getTableCellEditorComponent(JTable table, Object value,
1735 boolean isSelected, int row, int column)
1737 currentGColor = null;
1738 currentColor = null;
1739 this.selectedRow = row;
1740 type = me.table.getValueAt(row, 0).toString();
1741 button.setOpaque(true);
1742 button.setBackground(me.getBackground());
1743 if (value instanceof GraduatedColor)
1745 currentGColor = (GraduatedColor) value;
1746 JLabel btn = new JLabel();
1747 btn.setSize(button.getSize());
1748 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1749 button.setBackground(btn.getBackground());
1750 button.setIcon(btn.getIcon());
1751 button.setText(btn.getText());
1756 button.setIcon(null);
1757 currentColor = (Color) value;
1758 button.setBackground(currentColor);