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 help.setFont(JvSwingUtils.getLabelFont());
1078 help.setText(MessageManager.getString("action.help"));
1079 help.addActionListener(new ActionListener()
1081 public void actionPerformed(ActionEvent e)
1085 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1086 } catch (HelpSetException e1)
1088 e1.printStackTrace();
1092 cancel.setFont(JvSwingUtils.getLabelFont());
1093 cancel.setText(MessageManager.getString("action.cancel"));
1094 cancel.addActionListener(new ActionListener()
1096 public void actionPerformed(ActionEvent e)
1098 fr.setTransparency(originalTransparency);
1099 updateFeatureRenderer(originalData);
1103 ok.setFont(JvSwingUtils.getLabelFont());
1104 ok.setText(MessageManager.getString("action.ok"));
1105 ok.addActionListener(new ActionListener()
1107 public void actionPerformed(ActionEvent e)
1112 loadColours.setFont(JvSwingUtils.getLabelFont());
1113 loadColours.setText(MessageManager.getString("label.load_colours"));
1114 loadColours.addActionListener(new ActionListener()
1116 public void actionPerformed(ActionEvent e)
1121 saveColours.setFont(JvSwingUtils.getLabelFont());
1122 saveColours.setText(MessageManager.getString("label.save_colours"));
1123 saveColours.addActionListener(new ActionListener()
1125 public void actionPerformed(ActionEvent e)
1130 transparency.addChangeListener(new ChangeListener()
1132 public void stateChanged(ChangeEvent evt)
1134 fr.setTransparency((100 - transparency.getValue()) / 100f);
1135 af.alignPanel.paintAlignment(true);
1139 transparency.setMaximum(70);
1140 transparency.setToolTipText(MessageManager
1141 .getString("label.transparency_tip"));
1142 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1143 fetchDAS.addActionListener(new ActionListener()
1145 public void actionPerformed(ActionEvent e)
1147 fetchDAS_actionPerformed(e);
1150 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1151 saveDAS.addActionListener(new ActionListener()
1153 public void actionPerformed(ActionEvent e)
1155 saveDAS_actionPerformed(e);
1158 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1159 dasSettingsPane.setBorder(null);
1160 cancelDAS.setEnabled(false);
1161 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1162 cancelDAS.addActionListener(new ActionListener()
1164 public void actionPerformed(ActionEvent e)
1166 cancelDAS_actionPerformed(e);
1169 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1170 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1171 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1172 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1173 transbuttons.add(optimizeOrder);
1174 transbuttons.add(invert);
1175 transbuttons.add(sortByScore);
1176 transbuttons.add(sortByDens);
1177 transbuttons.add(help);
1178 JPanel sliderPanel = new JPanel();
1179 sliderPanel.add(transparency);
1180 transPanel.add(transparency);
1181 transPanel.add(transbuttons);
1182 buttonPanel.add(ok);
1183 buttonPanel.add(cancel);
1184 buttonPanel.add(loadColours);
1185 buttonPanel.add(saveColours);
1186 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1187 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1188 dasButtonPanel.add(fetchDAS);
1189 dasButtonPanel.add(cancelDAS);
1190 dasButtonPanel.add(saveDAS);
1191 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1192 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1195 public void fetchDAS_actionPerformed(ActionEvent e)
1197 fetchDAS.setEnabled(false);
1198 cancelDAS.setEnabled(true);
1199 dassourceBrowser.setGuiEnabled(false);
1200 Vector selectedSources = dassourceBrowser.getSelectedSources();
1201 doDasFeatureFetch(selectedSources, true, true);
1205 * get the features from selectedSources for all or the current selection
1207 * @param selectedSources
1208 * @param checkDbRefs
1209 * @param promptFetchDbRefs
1211 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1212 boolean checkDbRefs, boolean promptFetchDbRefs)
1214 SequenceI[] dataset, seqs;
1216 AlignViewport vp = af.getViewport();
1217 if (vp.getSelectionGroup() != null
1218 && vp.getSelectionGroup().getSize() > 0)
1220 iSize = vp.getSelectionGroup().getSize();
1221 dataset = new SequenceI[iSize];
1222 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1226 iSize = vp.getAlignment().getHeight();
1227 seqs = vp.getAlignment().getSequencesArray();
1230 dataset = new SequenceI[iSize];
1231 for (int i = 0; i < iSize; i++)
1233 dataset[i] = seqs[i].getDatasetSequence();
1236 cancelDAS.setEnabled(true);
1237 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1238 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1239 af.getViewport().setShowSequenceFeatures(true);
1240 af.showSeqFeatures.setSelected(true);
1244 * blocking call to initialise the das source browser
1246 public void initDasSources()
1248 dassourceBrowser.initDasSources();
1252 * examine the current list of das sources and return any matching the given
1253 * nicknames in sources
1256 * Vector of Strings to resolve to DAS source nicknames.
1257 * @return sources that are present in source list.
1259 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1261 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1265 * get currently selected das sources. ensure you have called initDasSources
1266 * before calling this.
1268 * @return vector of selected das source nicknames
1270 public Vector getSelectedSources()
1272 return dassourceBrowser.getSelectedSources();
1276 * properly initialise DAS fetcher and then initiate a new thread to fetch
1277 * features from the named sources (rather than any turned on by default)
1281 * if true then runs in same thread, otherwise passes to the Swing
1284 public void fetchDasFeatures(Vector sources, boolean block)
1287 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1288 .resolveSourceNicknames(sources);
1289 if (resolved.size() == 0)
1291 resolved = dassourceBrowser.getSelectedSources();
1293 if (resolved.size() > 0)
1295 final List<jalviewSourceI> dassources = resolved;
1296 fetchDAS.setEnabled(false);
1297 // cancelDAS.setEnabled(true); doDasFetch does this.
1298 Runnable fetcher = new Runnable()
1303 doDasFeatureFetch(dassources, true, false);
1313 SwingUtilities.invokeLater(fetcher);
1318 public void saveDAS_actionPerformed(ActionEvent e)
1321 .saveProperties(jalview.bin.Cache.applicationProperties);
1324 public void complete()
1326 fetchDAS.setEnabled(true);
1327 cancelDAS.setEnabled(false);
1328 dassourceBrowser.setGuiEnabled(true);
1332 public void cancelDAS_actionPerformed(ActionEvent e)
1334 if (dasFeatureFetcher != null)
1336 dasFeatureFetcher.cancel();
1341 public void noDasSourceActive()
1345 .showInternalConfirmDialog(
1348 .getString("label.no_das_sources_selected_warn"),
1350 .getString("label.no_das_sources_selected_title"),
1351 JOptionPane.DEFAULT_OPTION,
1352 JOptionPane.INFORMATION_MESSAGE);
1355 // ///////////////////////////////////////////////////////////////////////
1356 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1357 // ///////////////////////////////////////////////////////////////////////
1358 class FeatureTableModel extends AbstractTableModel
1360 FeatureTableModel(Object[][] data)
1365 private String[] columnNames =
1366 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1368 private Object[][] data;
1370 public Object[][] getData()
1375 public void setData(Object[][] data)
1380 public int getColumnCount()
1382 return columnNames.length;
1385 public Object[] getRow(int row)
1390 public int getRowCount()
1395 public String getColumnName(int col)
1397 return columnNames[col];
1400 public Object getValueAt(int row, int col)
1402 return data[row][col];
1405 public Class getColumnClass(int c)
1407 return getValueAt(0, c).getClass();
1410 public boolean isCellEditable(int row, int col)
1412 return col == 0 ? false : true;
1415 public void setValueAt(Object value, int row, int col)
1417 data[row][col] = value;
1418 fireTableCellUpdated(row, col);
1419 updateFeatureRenderer(data);
1424 class ColorRenderer extends JLabel implements TableCellRenderer
1426 javax.swing.border.Border unselectedBorder = null;
1428 javax.swing.border.Border selectedBorder = null;
1430 final String baseTT = "Click to edit, right/apple click for menu.";
1432 public ColorRenderer()
1434 setOpaque(true); // MUST do this for background to show up.
1435 setHorizontalTextPosition(SwingConstants.CENTER);
1436 setVerticalTextPosition(SwingConstants.CENTER);
1439 public Component getTableCellRendererComponent(JTable table,
1440 Object color, boolean isSelected, boolean hasFocus, int row,
1443 // JLabel comp = new JLabel();
1447 // setBounds(getBounds());
1449 setToolTipText(baseTT);
1450 setBackground(table.getBackground());
1451 if (color instanceof GraduatedColor)
1453 Rectangle cr = table.getCellRect(row, column, false);
1454 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1455 (int) cr.getWidth(), (int) cr.getHeight());
1462 newColor = (Color) color;
1464 setBackground(newColor);
1465 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1466 // + newColor.getGreen() + ", " + newColor.getBlue());
1470 if (selectedBorder == null)
1472 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1473 table.getSelectionBackground());
1476 setBorder(selectedBorder);
1480 if (unselectedBorder == null)
1482 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1483 table.getBackground());
1486 setBorder(unselectedBorder);
1494 * update comp using rendering settings from gcol
1499 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1501 int w = comp.getWidth(), h = comp.getHeight();
1504 w = (int) comp.getPreferredSize().getWidth();
1505 h = (int) comp.getPreferredSize().getHeight();
1512 renderGraduatedColor(comp, gcol, w, h);
1515 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1518 boolean thr = false;
1521 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1525 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1527 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1531 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1533 if (gcol.isColourByLabel())
1535 tt = "Coloured by label text. " + tt;
1545 Color newColor = gcol.getMaxColor();
1546 comp.setBackground(newColor);
1547 // System.err.println("Width is " + w / 2);
1548 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1549 comp.setIcon(ficon);
1550 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1551 // + newColor.getGreen() + ", " + newColor.getBlue()
1552 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1553 // + ", " + minCol.getBlue() + ")");
1555 comp.setHorizontalAlignment(SwingConstants.CENTER);
1557 if (tt.length() > 0)
1559 if (comp.getToolTipText() == null)
1561 comp.setToolTipText(tt);
1565 comp.setToolTipText(tt + " " + comp.getToolTipText());
1571 class FeatureIcon implements Icon
1573 GraduatedColor gcol;
1577 boolean midspace = false;
1579 int width = 50, height = 20;
1581 int s1, e1; // start and end of midpoint band for thresholded symbol
1583 Color mpcolour = Color.white;
1585 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1604 public int getIconWidth()
1609 public int getIconHeight()
1614 public void paintIcon(Component c, Graphics g, int x, int y)
1617 if (gcol.isColourByLabel())
1620 g.fillRect(0, 0, width, height);
1621 // need an icon here.
1622 g.setColor(gcol.getMaxColor());
1624 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1626 // g.setFont(g.getFont().deriveFont(
1627 // AffineTransform.getScaleInstance(
1628 // width/g.getFontMetrics().stringWidth("Label"),
1629 // height/g.getFontMetrics().getHeight())));
1631 g.drawString(MessageManager.getString("label.label"), 0, 0);
1636 Color minCol = gcol.getMinColor();
1638 g.fillRect(0, 0, s1, height);
1641 g.setColor(Color.white);
1642 g.fillRect(s1, 0, e1 - s1, height);
1644 g.setColor(gcol.getMaxColor());
1645 g.fillRect(0, e1, width - e1, height);
1650 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1655 GraduatedColor currentGColor;
1657 FeatureColourChooser chooser;
1665 JColorChooser colorChooser;
1669 protected static final String EDIT = "edit";
1671 int selectedRow = 0;
1673 public ColorEditor(FeatureSettings me)
1676 // Set up the editor (from the table's point of view),
1677 // which is a button.
1678 // This button brings up the color chooser dialog,
1679 // which is the editor from the user's point of view.
1680 button = new JButton();
1681 button.setActionCommand(EDIT);
1682 button.addActionListener(this);
1683 button.setBorderPainted(false);
1684 // Set up the dialog that the button brings up.
1685 colorChooser = new JColorChooser();
1686 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1687 colorChooser, this, // OK button handler
1688 null); // no CANCEL button handler
1692 * Handles events from the editor button and from the dialog's OK button.
1694 public void actionPerformed(ActionEvent e)
1697 if (EDIT.equals(e.getActionCommand()))
1699 // The user has clicked the cell, so
1700 // bring up the dialog.
1701 if (currentColor != null)
1703 // bring up simple color chooser
1704 button.setBackground(currentColor);
1705 colorChooser.setColor(currentColor);
1706 dialog.setVisible(true);
1710 // bring up graduated chooser.
1711 chooser = new FeatureColourChooser(me.fr, type);
1712 chooser.setRequestFocusEnabled(true);
1713 chooser.requestFocus();
1714 chooser.addActionListener(this);
1716 // Make the renderer reappear.
1717 fireEditingStopped();
1721 { // User pressed dialog's "OK" button.
1722 if (currentColor != null)
1724 currentColor = colorChooser.getColor();
1728 // class cast exceptions may be raised if the chooser created on a
1729 // non-graduated color
1730 currentGColor = (GraduatedColor) chooser.getLastColour();
1732 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1733 fireEditingStopped();
1734 me.table.validate();
1738 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1739 public Object getCellEditorValue()
1741 if (currentColor == null)
1743 return currentGColor;
1745 return currentColor;
1748 // Implement the one method defined by TableCellEditor.
1749 public Component getTableCellEditorComponent(JTable table, Object value,
1750 boolean isSelected, int row, int column)
1752 currentGColor = null;
1753 currentColor = null;
1754 this.selectedRow = row;
1755 type = me.table.getValueAt(row, 0).toString();
1756 button.setOpaque(true);
1757 button.setBackground(me.getBackground());
1758 if (value instanceof GraduatedColor)
1760 currentGColor = (GraduatedColor) value;
1761 JLabel btn = new JLabel();
1762 btn.setSize(button.getSize());
1763 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1764 button.setBackground(btn.getBackground());
1765 button.setIcon(btn.getIcon());
1766 button.setText(btn.getText());
1771 button.setIcon(null);
1772 currentColor = (Color) value;
1773 button.setBackground(currentColor);