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 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
432 .getSequenceFeatures();
433 if (tmpfeatures == null)
439 while (index < tmpfeatures.length)
441 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
447 if (tmpfeatures[index].getFeatureGroup() != null)
449 group = tmpfeatures[index].featureGroup;
450 if (!allGroups.contains(group))
452 allGroups.addElement(group);
453 checkGroupState(group);
457 if (!allFeatures.contains(tmpfeatures[index].getType()))
459 allFeatures.addElement(tmpfeatures[index].getType());
471 * Synchronise gui group list and check visibility of group
474 * @return true if group is visible
476 private boolean checkGroupState(String group)
478 boolean visible = fr.checkGroupVisibility(group, true);
480 if (groupPanel == null)
482 groupPanel = new JPanel();
485 boolean alreadyAdded = false;
486 for (int g = 0; g < groupPanel.getComponentCount(); g++)
488 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
491 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
501 final String grp = group;
502 final JCheckBox check = new JCheckBox(group, visible);
503 check.setFont(new Font("Serif", Font.BOLD, 12));
504 check.addItemListener(new ItemListener()
506 public void itemStateChanged(ItemEvent evt)
508 fr.setGroupVisibility(check.getText(), check.isSelected());
509 af.alignPanel.getSeqPanel().seqCanvas.repaint();
510 if (af.alignPanel.overviewPanel != null)
512 af.alignPanel.overviewPanel.updateOverviewImage();
515 resetTable(new String[]
519 groupPanel.add(check);
523 boolean resettingTable = false;
525 synchronized void resetTable(String[] groupChanged)
527 if (resettingTable == true)
531 resettingTable = true;
532 typeWidth = new Hashtable();
533 // TODO: change avWidth calculation to 'per-sequence' average and use long
535 float[] avWidth = null;
536 SequenceFeature[] tmpfeatures;
537 String group = null, type;
538 Vector visibleChecks = new Vector();
540 // Find out which features should be visible depending on which groups
541 // are selected / deselected
542 // and recompute average width ordering
543 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
546 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
547 .getSequenceFeatures();
548 if (tmpfeatures == null)
554 while (index < tmpfeatures.length)
556 group = tmpfeatures[index].featureGroup;
558 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
564 if (group == null || checkGroupState(group))
566 type = tmpfeatures[index].getType();
567 if (!visibleChecks.contains(type))
569 visibleChecks.addElement(type);
572 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
574 typeWidth.put(tmpfeatures[index].getType(),
575 avWidth = new float[3]);
579 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
582 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
584 avWidth[1] += 1 + tmpfeatures[index].getBegin()
585 - tmpfeatures[index].getEnd();
589 avWidth[1] += 1 + tmpfeatures[index].getEnd()
590 - tmpfeatures[index].getBegin();
596 int fSize = visibleChecks.size();
597 Object[][] data = new Object[fSize][3];
600 if (fr.hasRenderOrder())
604 fr.findAllFeatures(groupChanged != null); // prod to update
605 // colourschemes. but don't
607 // First add the checks in the previous render order,
608 // in case the window has been closed and reopened
610 List<String> frl = fr.getRenderOrder();
611 for (int ro = frl.size() - 1; ro > -1; ro--)
615 if (!visibleChecks.contains(type))
620 data[dataIndex][0] = type;
621 data[dataIndex][1] = fr.getFeatureStyle(type);
622 data[dataIndex][2] = new Boolean(af.getViewport()
623 .getFeaturesDisplayed().isVisible(type));
625 visibleChecks.removeElement(type);
629 fSize = visibleChecks.size();
630 for (int i = 0; i < fSize; i++)
632 // These must be extra features belonging to the group
633 // which was just selected
634 type = visibleChecks.elementAt(i).toString();
635 data[dataIndex][0] = type;
637 data[dataIndex][1] = fr.getFeatureStyle(type);
638 if (data[dataIndex][1] == null)
640 // "Colour has been updated in another view!!"
641 fr.clearRenderOrder();
645 data[dataIndex][2] = new Boolean(true);
649 if (originalData == null)
651 originalData = new Object[data.length][3];
652 for (int i = 0; i < data.length; i++)
654 System.arraycopy(data[i], 0, originalData[i], 0, 3);
658 table.setModel(new FeatureTableModel(data));
659 table.getColumnModel().getColumn(0).setPreferredWidth(200);
661 if (groupPanel != null)
663 groupPanel.setLayout(new GridLayout(
664 fr.getFeatureGroupsSize() / 4 + 1, 4));
666 groupPanel.validate();
667 bigPanel.add(groupPanel, BorderLayout.NORTH);
670 updateFeatureRenderer(data, groupChanged != null);
671 resettingTable = false;
675 * reorder data based on the featureRenderers global priority list.
679 private void ensureOrder(Object[][] data)
681 boolean sort = false;
682 float[] order = new float[data.length];
683 for (int i = 0; i < order.length; i++)
685 order[i] = fr.getOrder(data[i][0].toString());
688 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
692 sort = sort || order[i - 1] > order[i];
697 jalview.util.QuickSort.sort(order, data);
703 JalviewFileChooser chooser = new JalviewFileChooser(
704 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
705 { "fc" }, new String[]
706 { "Sequence Feature Colours" }, "Sequence Feature Colours");
707 chooser.setFileView(new jalview.io.JalviewFileView());
708 chooser.setDialogTitle(MessageManager.getString("label.load_feature_colours"));
709 chooser.setToolTipText(MessageManager.getString("action.load"));
711 int value = chooser.showOpenDialog(this);
713 if (value == JalviewFileChooser.APPROVE_OPTION)
715 File file = chooser.getSelectedFile();
719 InputStreamReader in = new InputStreamReader(new FileInputStream(
722 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
726 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
729 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
732 Color mincol = null, maxcol = null;
735 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
736 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
738 } catch (Exception e)
740 Cache.log.warn("Couldn't parse out graduated feature color.",
743 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
744 newcol.getMin(), newcol.getMax());
745 if (newcol.hasAutoScale())
747 gcol.setAutoScaled(newcol.getAutoScale());
749 if (newcol.hasColourByLabel())
751 gcol.setColourByLabel(newcol.getColourByLabel());
753 if (newcol.hasThreshold())
755 gcol.setThresh(newcol.getThreshold());
756 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
758 if (newcol.getThreshType().length() > 0)
760 String ttyp = newcol.getThreshType();
761 if (ttyp.equalsIgnoreCase("NONE"))
763 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
765 if (ttyp.equalsIgnoreCase("ABOVE"))
767 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
769 if (ttyp.equalsIgnoreCase("BELOW"))
771 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
774 fr.setColour(name = newcol.getName(), gcol);
778 fr.setColour(name = jucs.getColour(i).getName(), new Color(
779 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
781 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
786 Object[][] data = ((FeatureTableModel) table.getModel())
789 updateFeatureRenderer(data, false);
792 } catch (Exception ex)
794 System.out.println("Error loading User Colour File\n" + ex);
801 JalviewFileChooser chooser = new JalviewFileChooser(
802 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
803 { "fc" }, new String[]
804 { "Sequence Feature Colours" }, "Sequence Feature Colours");
805 chooser.setFileView(new jalview.io.JalviewFileView());
806 chooser.setDialogTitle(MessageManager.getString("label.save_feature_colours"));
807 chooser.setToolTipText(MessageManager.getString("action.save"));
809 int value = chooser.showSaveDialog(this);
811 if (value == JalviewFileChooser.APPROVE_OPTION)
813 String choice = chooser.getSelectedFile().getPath();
814 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
815 ucs.setSchemeName("Sequence Features");
818 PrintWriter out = new PrintWriter(new OutputStreamWriter(
819 new FileOutputStream(choice), "UTF-8"));
821 Set fr_colours = fr.getAllFeatureColours();
822 Iterator e = fr_colours.iterator();
823 float[] sortOrder = new float[fr_colours.size()];
824 String[] sortTypes = new String[fr_colours.size()];
828 sortTypes[i] = e.next().toString();
829 sortOrder[i] = fr.getOrder(sortTypes[i]);
832 jalview.util.QuickSort.sort(sortOrder, sortTypes);
836 for (i = 0; i < sortTypes.length; i++)
838 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
839 col.setName(sortTypes[i]);
840 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
842 fcol = fr.getFeatureStyle(sortTypes[i]);
843 if (fcol instanceof GraduatedColor)
845 gcol = (GraduatedColor) fcol;
846 col.setMin(gcol.getMin());
847 col.setMax(gcol.getMax());
848 col.setMinRGB(jalview.util.Format.getHexString(gcol
850 col.setAutoScale(gcol.isAutoScale());
851 col.setThreshold(gcol.getThresh());
852 col.setColourByLabel(gcol.isColourByLabel());
853 switch (gcol.getThreshType())
855 case AnnotationColourGradient.NO_THRESHOLD:
856 col.setThreshType("NONE");
858 case AnnotationColourGradient.ABOVE_THRESHOLD:
859 col.setThreshType("ABOVE");
861 case AnnotationColourGradient.BELOW_THRESHOLD:
862 col.setThreshType("BELOW");
870 } catch (Exception ex)
872 ex.printStackTrace();
877 public void invertSelection()
879 for (int i = 0; i < table.getRowCount(); i++)
881 Boolean value = (Boolean) table.getValueAt(i, 2);
883 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
887 public void orderByAvWidth()
889 if (table == null || table.getModel() == null)
893 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
894 float[] width = new float[data.length];
898 for (int i = 0; i < data.length; i++)
900 awidth = (float[]) typeWidth.get(data[i][0]);
903 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
904 // weight - but have to make per
905 // sequence, too (awidth[2])
906 // if (width[i]==1) // hack to distinguish single width sequences.
918 boolean sort = false;
919 for (int i = 0; i < width.length; i++)
921 // awidth = (float[]) typeWidth.get(data[i][0]);
924 width[i] = fr.getOrder(data[i][0].toString());
927 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
932 width[i] /= max; // normalize
933 fr.setOrder(data[i][0].toString(), width[i]); // store for later
937 sort = sort || width[i - 1] > width[i];
942 jalview.util.QuickSort.sort(width, data);
943 // update global priority order
946 updateFeatureRenderer(data, false);
954 frame.setClosed(true);
955 } catch (Exception exe)
961 public void updateFeatureRenderer(Object[][] data)
963 updateFeatureRenderer(data, true);
966 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
968 fr.setFeaturePriority(data, visibleNew);
969 af.alignPanel.paintAlignment(true);
972 int selectedRow = -1;
974 JTabbedPane tabbedPane = new JTabbedPane();
976 BorderLayout borderLayout1 = new BorderLayout();
978 BorderLayout borderLayout2 = new BorderLayout();
980 BorderLayout borderLayout3 = new BorderLayout();
982 JPanel bigPanel = new JPanel();
984 BorderLayout borderLayout4 = new BorderLayout();
986 JButton invert = new JButton();
988 JPanel buttonPanel = new JPanel();
990 JButton cancel = new JButton();
992 JButton ok = new JButton();
994 JButton loadColours = new JButton();
996 JButton saveColours = new JButton();
998 JPanel dasButtonPanel = new JPanel();
1000 JButton fetchDAS = new JButton();
1002 JButton saveDAS = new JButton();
1004 JButton cancelDAS = new JButton();
1006 JButton optimizeOrder = new JButton();
1008 JButton sortByScore = new JButton();
1010 JButton sortByDens = new JButton();
1012 JButton help = new JButton();
1014 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1016 private void jbInit() throws Exception
1018 this.setLayout(borderLayout1);
1019 settingsPane.setLayout(borderLayout2);
1020 dasSettingsPane.setLayout(borderLayout3);
1021 bigPanel.setLayout(borderLayout4);
1022 invert.setFont(JvSwingUtils.getLabelFont());
1023 invert.setText(MessageManager.getString("label.invert_selection"));
1024 invert.addActionListener(new ActionListener()
1026 public void actionPerformed(ActionEvent e)
1031 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1032 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1033 optimizeOrder.addActionListener(new ActionListener()
1035 public void actionPerformed(ActionEvent e)
1040 sortByScore.setFont(JvSwingUtils.getLabelFont());
1042 .setText(MessageManager.getString("label.seq_sort_by_score"));
1043 sortByScore.addActionListener(new ActionListener()
1045 public void actionPerformed(ActionEvent e)
1047 af.avc.sortAlignmentByFeatureScore(null);
1050 sortByDens.setFont(JvSwingUtils.getLabelFont());
1051 sortByDens.setText(MessageManager
1052 .getString("label.sequence_sort_by_density"));
1053 sortByDens.addActionListener(new ActionListener()
1055 public void actionPerformed(ActionEvent e)
1057 af.avc.sortAlignmentByFeatureDensity(null);
1060 help.setFont(JvSwingUtils.getLabelFont());
1061 help.setText(MessageManager.getString("action.help"));
1062 help.addActionListener(new ActionListener()
1064 public void actionPerformed(ActionEvent e)
1068 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1069 } catch (HelpSetException e1)
1071 e1.printStackTrace();
1075 help.setFont(JvSwingUtils.getLabelFont());
1076 help.setText(MessageManager.getString("action.help"));
1077 help.addActionListener(new ActionListener()
1079 public void actionPerformed(ActionEvent e)
1083 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1084 } catch (HelpSetException e1)
1086 e1.printStackTrace();
1090 cancel.setFont(JvSwingUtils.getLabelFont());
1091 cancel.setText(MessageManager.getString("action.cancel"));
1092 cancel.addActionListener(new ActionListener()
1094 public void actionPerformed(ActionEvent e)
1096 fr.setTransparency(originalTransparency);
1097 updateFeatureRenderer(originalData);
1101 ok.setFont(JvSwingUtils.getLabelFont());
1102 ok.setText(MessageManager.getString("action.ok"));
1103 ok.addActionListener(new ActionListener()
1105 public void actionPerformed(ActionEvent e)
1110 loadColours.setFont(JvSwingUtils.getLabelFont());
1111 loadColours.setText(MessageManager.getString("label.load_colours"));
1112 loadColours.addActionListener(new ActionListener()
1114 public void actionPerformed(ActionEvent e)
1119 saveColours.setFont(JvSwingUtils.getLabelFont());
1120 saveColours.setText(MessageManager.getString("label.save_colours"));
1121 saveColours.addActionListener(new ActionListener()
1123 public void actionPerformed(ActionEvent e)
1128 transparency.addChangeListener(new ChangeListener()
1130 public void stateChanged(ChangeEvent evt)
1132 fr.setTransparency((100 - transparency.getValue()) / 100f);
1133 af.alignPanel.paintAlignment(true);
1137 transparency.setMaximum(70);
1138 transparency.setToolTipText(MessageManager
1139 .getString("label.transparency_tip"));
1140 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1141 fetchDAS.addActionListener(new ActionListener()
1143 public void actionPerformed(ActionEvent e)
1145 fetchDAS_actionPerformed(e);
1148 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1149 saveDAS.addActionListener(new ActionListener()
1151 public void actionPerformed(ActionEvent e)
1153 saveDAS_actionPerformed(e);
1156 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1157 dasSettingsPane.setBorder(null);
1158 cancelDAS.setEnabled(false);
1159 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1160 cancelDAS.addActionListener(new ActionListener()
1162 public void actionPerformed(ActionEvent e)
1164 cancelDAS_actionPerformed(e);
1167 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1168 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1169 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1170 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1171 transbuttons.add(optimizeOrder);
1172 transbuttons.add(invert);
1173 transbuttons.add(sortByScore);
1174 transbuttons.add(sortByDens);
1175 transbuttons.add(help);
1176 JPanel sliderPanel = new JPanel();
1177 sliderPanel.add(transparency);
1178 transPanel.add(transparency);
1179 transPanel.add(transbuttons);
1180 buttonPanel.add(ok);
1181 buttonPanel.add(cancel);
1182 buttonPanel.add(loadColours);
1183 buttonPanel.add(saveColours);
1184 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1185 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1186 dasButtonPanel.add(fetchDAS);
1187 dasButtonPanel.add(cancelDAS);
1188 dasButtonPanel.add(saveDAS);
1189 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1190 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1193 public void fetchDAS_actionPerformed(ActionEvent e)
1195 fetchDAS.setEnabled(false);
1196 cancelDAS.setEnabled(true);
1197 dassourceBrowser.setGuiEnabled(false);
1198 Vector selectedSources = dassourceBrowser.getSelectedSources();
1199 doDasFeatureFetch(selectedSources, true, true);
1203 * get the features from selectedSources for all or the current selection
1205 * @param selectedSources
1206 * @param checkDbRefs
1207 * @param promptFetchDbRefs
1209 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1210 boolean checkDbRefs, boolean promptFetchDbRefs)
1212 SequenceI[] dataset, seqs;
1214 AlignViewport vp = af.getViewport();
1215 if (vp.getSelectionGroup() != null
1216 && vp.getSelectionGroup().getSize() > 0)
1218 iSize = vp.getSelectionGroup().getSize();
1219 dataset = new SequenceI[iSize];
1220 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1224 iSize = vp.getAlignment().getHeight();
1225 seqs = vp.getAlignment().getSequencesArray();
1228 dataset = new SequenceI[iSize];
1229 for (int i = 0; i < iSize; i++)
1231 dataset[i] = seqs[i].getDatasetSequence();
1234 cancelDAS.setEnabled(true);
1235 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1236 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1237 af.getViewport().setShowSequenceFeatures(true);
1238 af.showSeqFeatures.setSelected(true);
1242 * blocking call to initialise the das source browser
1244 public void initDasSources()
1246 dassourceBrowser.initDasSources();
1250 * examine the current list of das sources and return any matching the given
1251 * nicknames in sources
1254 * Vector of Strings to resolve to DAS source nicknames.
1255 * @return sources that are present in source list.
1257 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1259 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1263 * get currently selected das sources. ensure you have called initDasSources
1264 * before calling this.
1266 * @return vector of selected das source nicknames
1268 public Vector getSelectedSources()
1270 return dassourceBrowser.getSelectedSources();
1274 * properly initialise DAS fetcher and then initiate a new thread to fetch
1275 * features from the named sources (rather than any turned on by default)
1279 * if true then runs in same thread, otherwise passes to the Swing
1282 public void fetchDasFeatures(Vector sources, boolean block)
1285 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1286 .resolveSourceNicknames(sources);
1287 if (resolved.size() == 0)
1289 resolved = dassourceBrowser.getSelectedSources();
1291 if (resolved.size() > 0)
1293 final List<jalviewSourceI> dassources = resolved;
1294 fetchDAS.setEnabled(false);
1295 // cancelDAS.setEnabled(true); doDasFetch does this.
1296 Runnable fetcher = new Runnable()
1301 doDasFeatureFetch(dassources, true, false);
1311 SwingUtilities.invokeLater(fetcher);
1316 public void saveDAS_actionPerformed(ActionEvent e)
1319 .saveProperties(jalview.bin.Cache.applicationProperties);
1322 public void complete()
1324 fetchDAS.setEnabled(true);
1325 cancelDAS.setEnabled(false);
1326 dassourceBrowser.setGuiEnabled(true);
1330 public void cancelDAS_actionPerformed(ActionEvent e)
1332 if (dasFeatureFetcher != null)
1334 dasFeatureFetcher.cancel();
1339 public void noDasSourceActive()
1343 .showInternalConfirmDialog(
1346 .getString("label.no_das_sources_selected_warn"),
1348 .getString("label.no_das_sources_selected_title"),
1349 JOptionPane.DEFAULT_OPTION,
1350 JOptionPane.INFORMATION_MESSAGE);
1353 // ///////////////////////////////////////////////////////////////////////
1354 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1355 // ///////////////////////////////////////////////////////////////////////
1356 class FeatureTableModel extends AbstractTableModel
1358 FeatureTableModel(Object[][] data)
1363 private String[] columnNames =
1364 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1366 private Object[][] data;
1368 public Object[][] getData()
1373 public void setData(Object[][] data)
1378 public int getColumnCount()
1380 return columnNames.length;
1383 public Object[] getRow(int row)
1388 public int getRowCount()
1393 public String getColumnName(int col)
1395 return columnNames[col];
1398 public Object getValueAt(int row, int col)
1400 return data[row][col];
1403 public Class getColumnClass(int c)
1405 return getValueAt(0, c).getClass();
1408 public boolean isCellEditable(int row, int col)
1410 return col == 0 ? false : true;
1413 public void setValueAt(Object value, int row, int col)
1415 data[row][col] = value;
1416 fireTableCellUpdated(row, col);
1417 updateFeatureRenderer(data);
1422 class ColorRenderer extends JLabel implements TableCellRenderer
1424 javax.swing.border.Border unselectedBorder = null;
1426 javax.swing.border.Border selectedBorder = null;
1428 final String baseTT = "Click to edit, right/apple click for menu.";
1430 public ColorRenderer()
1432 setOpaque(true); // MUST do this for background to show up.
1433 setHorizontalTextPosition(SwingConstants.CENTER);
1434 setVerticalTextPosition(SwingConstants.CENTER);
1437 public Component getTableCellRendererComponent(JTable table,
1438 Object color, boolean isSelected, boolean hasFocus, int row,
1441 // JLabel comp = new JLabel();
1445 // setBounds(getBounds());
1447 setToolTipText(baseTT);
1448 setBackground(table.getBackground());
1449 if (color instanceof GraduatedColor)
1451 Rectangle cr = table.getCellRect(row, column, false);
1452 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1453 (int) cr.getWidth(), (int) cr.getHeight());
1460 newColor = (Color) color;
1462 setBackground(newColor);
1463 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1464 // + newColor.getGreen() + ", " + newColor.getBlue());
1468 if (selectedBorder == null)
1470 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1471 table.getSelectionBackground());
1474 setBorder(selectedBorder);
1478 if (unselectedBorder == null)
1480 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1481 table.getBackground());
1484 setBorder(unselectedBorder);
1492 * update comp using rendering settings from gcol
1497 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1499 int w = comp.getWidth(), h = comp.getHeight();
1502 w = (int) comp.getPreferredSize().getWidth();
1503 h = (int) comp.getPreferredSize().getHeight();
1510 renderGraduatedColor(comp, gcol, w, h);
1513 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1516 boolean thr = false;
1519 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1523 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1525 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1529 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1531 if (gcol.isColourByLabel())
1533 tt = "Coloured by label text. " + tt;
1543 Color newColor = gcol.getMaxColor();
1544 comp.setBackground(newColor);
1545 // System.err.println("Width is " + w / 2);
1546 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1547 comp.setIcon(ficon);
1548 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1549 // + newColor.getGreen() + ", " + newColor.getBlue()
1550 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1551 // + ", " + minCol.getBlue() + ")");
1553 comp.setHorizontalAlignment(SwingConstants.CENTER);
1555 if (tt.length() > 0)
1557 if (comp.getToolTipText() == null)
1559 comp.setToolTipText(tt);
1563 comp.setToolTipText(tt + " " + comp.getToolTipText());
1569 class FeatureIcon implements Icon
1571 GraduatedColor gcol;
1575 boolean midspace = false;
1577 int width = 50, height = 20;
1579 int s1, e1; // start and end of midpoint band for thresholded symbol
1581 Color mpcolour = Color.white;
1583 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1602 public int getIconWidth()
1607 public int getIconHeight()
1612 public void paintIcon(Component c, Graphics g, int x, int y)
1615 if (gcol.isColourByLabel())
1618 g.fillRect(0, 0, width, height);
1619 // need an icon here.
1620 g.setColor(gcol.getMaxColor());
1622 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1624 // g.setFont(g.getFont().deriveFont(
1625 // AffineTransform.getScaleInstance(
1626 // width/g.getFontMetrics().stringWidth("Label"),
1627 // height/g.getFontMetrics().getHeight())));
1629 g.drawString(MessageManager.getString("label.label"), 0, 0);
1634 Color minCol = gcol.getMinColor();
1636 g.fillRect(0, 0, s1, height);
1639 g.setColor(Color.white);
1640 g.fillRect(s1, 0, e1 - s1, height);
1642 g.setColor(gcol.getMaxColor());
1643 g.fillRect(0, e1, width - e1, height);
1648 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1653 GraduatedColor currentGColor;
1655 FeatureColourChooser chooser;
1663 JColorChooser colorChooser;
1667 protected static final String EDIT = "edit";
1669 int selectedRow = 0;
1671 public ColorEditor(FeatureSettings me)
1674 // Set up the editor (from the table's point of view),
1675 // which is a button.
1676 // This button brings up the color chooser dialog,
1677 // which is the editor from the user's point of view.
1678 button = new JButton();
1679 button.setActionCommand(EDIT);
1680 button.addActionListener(this);
1681 button.setBorderPainted(false);
1682 // Set up the dialog that the button brings up.
1683 colorChooser = new JColorChooser();
1684 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1685 colorChooser, this, // OK button handler
1686 null); // no CANCEL button handler
1690 * Handles events from the editor button and from the dialog's OK button.
1692 public void actionPerformed(ActionEvent e)
1695 if (EDIT.equals(e.getActionCommand()))
1697 // The user has clicked the cell, so
1698 // bring up the dialog.
1699 if (currentColor != null)
1701 // bring up simple color chooser
1702 button.setBackground(currentColor);
1703 colorChooser.setColor(currentColor);
1704 dialog.setVisible(true);
1708 // bring up graduated chooser.
1709 chooser = new FeatureColourChooser(me.fr, type);
1710 chooser.setRequestFocusEnabled(true);
1711 chooser.requestFocus();
1712 chooser.addActionListener(this);
1714 // Make the renderer reappear.
1715 fireEditingStopped();
1719 { // User pressed dialog's "OK" button.
1720 if (currentColor != null)
1722 currentColor = colorChooser.getColor();
1726 // class cast exceptions may be raised if the chooser created on a
1727 // non-graduated color
1728 currentGColor = (GraduatedColor) chooser.getLastColour();
1730 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1731 fireEditingStopped();
1732 me.table.validate();
1736 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1737 public Object getCellEditorValue()
1739 if (currentColor == null)
1741 return currentGColor;
1743 return currentColor;
1746 // Implement the one method defined by TableCellEditor.
1747 public Component getTableCellEditorComponent(JTable table, Object value,
1748 boolean isSelected, int row, int column)
1750 currentGColor = null;
1751 currentColor = null;
1752 this.selectedRow = row;
1753 type = me.table.getValueAt(row, 0).toString();
1754 button.setOpaque(true);
1755 button.setBackground(me.getBackground());
1756 if (value instanceof GraduatedColor)
1758 currentGColor = (GraduatedColor) value;
1759 JLabel btn = new JLabel();
1760 btn.setSize(button.getSize());
1761 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1762 button.setBackground(btn.getBackground());
1763 button.setIcon(btn.getIcon());
1764 button.setText(btn.getText());
1769 button.setIcon(null);
1770 currentColor = (Color) value;
1771 button.setBackground(currentColor);