2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.FeatureColourI;
24 import jalview.api.FeatureSettingsControllerI;
25 import jalview.bin.Cache;
26 import jalview.datamodel.SequenceFeature;
27 import jalview.datamodel.SequenceI;
28 import jalview.gui.Help.HelpId;
29 import jalview.io.JalviewFileChooser;
30 import jalview.schemabinding.version2.JalviewUserColours;
31 import jalview.schemes.FeatureColour;
32 import jalview.util.Format;
33 import jalview.util.MessageManager;
34 import jalview.util.Platform;
35 import jalview.util.QuickSort;
36 import jalview.viewmodel.AlignmentViewport;
37 import jalview.ws.dbsources.das.api.jalviewSourceI;
39 import java.awt.BorderLayout;
40 import java.awt.Color;
41 import java.awt.Component;
43 import java.awt.Graphics;
44 import java.awt.GridLayout;
45 import java.awt.Rectangle;
46 import java.awt.event.ActionEvent;
47 import java.awt.event.ActionListener;
48 import java.awt.event.ItemEvent;
49 import java.awt.event.ItemListener;
50 import java.awt.event.MouseAdapter;
51 import java.awt.event.MouseEvent;
52 import java.awt.event.MouseMotionAdapter;
53 import java.beans.PropertyChangeEvent;
54 import java.beans.PropertyChangeListener;
56 import java.io.FileInputStream;
57 import java.io.FileOutputStream;
58 import java.io.InputStreamReader;
59 import java.io.OutputStreamWriter;
60 import java.io.PrintWriter;
61 import java.util.Hashtable;
62 import java.util.Iterator;
63 import java.util.List;
66 import java.util.Vector;
68 import javax.help.HelpSetException;
69 import javax.swing.AbstractCellEditor;
70 import javax.swing.BorderFactory;
71 import javax.swing.Icon;
72 import javax.swing.JButton;
73 import javax.swing.JCheckBox;
74 import javax.swing.JCheckBoxMenuItem;
75 import javax.swing.JColorChooser;
76 import javax.swing.JDialog;
77 import javax.swing.JInternalFrame;
78 import javax.swing.JLabel;
79 import javax.swing.JLayeredPane;
80 import javax.swing.JMenuItem;
81 import javax.swing.JOptionPane;
82 import javax.swing.JPanel;
83 import javax.swing.JPopupMenu;
84 import javax.swing.JScrollPane;
85 import javax.swing.JSlider;
86 import javax.swing.JTabbedPane;
87 import javax.swing.JTable;
88 import javax.swing.ListSelectionModel;
89 import javax.swing.SwingConstants;
90 import javax.swing.SwingUtilities;
91 import javax.swing.event.ChangeEvent;
92 import javax.swing.event.ChangeListener;
93 import javax.swing.table.AbstractTableModel;
94 import javax.swing.table.TableCellEditor;
95 import javax.swing.table.TableCellRenderer;
97 public class FeatureSettings extends JPanel implements
98 FeatureSettingsControllerI
100 DasSourceBrowser dassourceBrowser;
102 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
104 JPanel settingsPane = new JPanel();
106 JPanel dasSettingsPane = new JPanel();
108 final FeatureRenderer fr;
110 public final AlignFrame af;
112 Object[][] originalData;
114 private float originalTransparency;
116 final JInternalFrame frame;
118 JScrollPane scrollPane = new JScrollPane();
124 JSlider transparency = new JSlider();
126 JPanel transPanel = new JPanel(new GridLayout(1, 2));
128 public FeatureSettings(AlignFrame af)
131 fr = af.getFeatureRenderer();
132 // allow transparency to be recovered
133 transparency.setMaximum(100 - (int) ((originalTransparency = fr
134 .getTransparency()) * 100));
139 } catch (Exception ex)
141 ex.printStackTrace();
147 public String getToolTipText(MouseEvent e)
149 if (table.columnAtPoint(e.getPoint()) == 0)
152 * Tooltip for feature name only
154 return JvSwingUtils.wrapTooltip(true, MessageManager
155 .getString("label.feature_settings_click_drag"));
160 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
161 table.setFont(new Font("Verdana", Font.PLAIN, 12));
162 table.setDefaultRenderer(Color.class, new ColorRenderer());
164 table.setDefaultEditor(Color.class, new ColorEditor(this));
166 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
167 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
168 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
170 table.addMouseListener(new MouseAdapter()
173 public void mousePressed(MouseEvent evt)
175 selectedRow = table.rowAtPoint(evt.getPoint());
176 if (SwingUtilities.isRightMouseButton(evt))
178 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
179 table.getValueAt(selectedRow, 1), fr.getMinMax(),
180 evt.getX(), evt.getY());
182 else if (evt.getClickCount() == 2)
184 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
185 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
187 (String) table.getValueAt(selectedRow, 0));
191 // isPopupTrigger fires on mouseReleased on Mac
193 public void mouseReleased(MouseEvent evt)
195 selectedRow = table.rowAtPoint(evt.getPoint());
196 if (evt.isPopupTrigger())
198 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
199 table.getValueAt(selectedRow, 1), fr.getMinMax(),
200 evt.getX(), evt.getY());
205 table.addMouseMotionListener(new MouseMotionAdapter()
208 public void mouseDragged(MouseEvent evt)
210 int newRow = table.rowAtPoint(evt.getPoint());
211 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
213 Object[] temp = new Object[3];
214 temp[0] = table.getValueAt(selectedRow, 0);
215 temp[1] = table.getValueAt(selectedRow, 1);
216 temp[2] = table.getValueAt(selectedRow, 2);
218 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
219 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
220 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
222 table.setValueAt(temp[0], newRow, 0);
223 table.setValueAt(temp[1], newRow, 1);
224 table.setValueAt(temp[2], newRow, 2);
226 selectedRow = newRow;
230 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
231 // MessageManager.getString("label.feature_settings_click_drag")));
232 scrollPane.setViewportView(table);
234 dassourceBrowser = new DasSourceBrowser(this);
235 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
237 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
239 fr.findAllFeatures(true); // display everything!
242 discoverAllFeatureData();
243 final PropertyChangeListener change;
244 final FeatureSettings fs = this;
245 fr.addPropertyChangeListener(change = new PropertyChangeListener()
248 public void propertyChange(PropertyChangeEvent evt)
250 if (!fs.resettingTable && !fs.handlingUpdate)
252 fs.handlingUpdate = true;
253 fs.resetTable(null); // new groups may be added with new seuqence
254 // feature types only
255 fs.handlingUpdate = false;
261 frame = new JInternalFrame();
262 frame.setContentPane(this);
263 if (Platform.isAMac())
265 Desktop.addInternalFrame(frame,
266 MessageManager.getString("label.sequence_feature_settings"),
271 Desktop.addInternalFrame(frame,
272 MessageManager.getString("label.sequence_feature_settings"),
276 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
279 public void internalFrameClosed(
280 javax.swing.event.InternalFrameEvent evt)
282 fr.removePropertyChangeListener(change);
283 dassourceBrowser.fs = null;
286 frame.setLayer(JLayeredPane.PALETTE_LAYER);
289 protected void popupSort(final int row, final String type,
290 final Object typeCol, final Map<String, float[][]> minmax, int x,
293 final FeatureColourI featureColour = (FeatureColourI) typeCol;
295 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
296 "label.settings_for_param", new String[] { type }));
297 JMenuItem scr = new JMenuItem(
298 MessageManager.getString("label.sort_by_score"));
300 final FeatureSettings me = this;
301 scr.addActionListener(new ActionListener()
305 public void actionPerformed(ActionEvent e)
307 me.af.avc.sortAlignmentByFeatureScore(new String[] { type });
311 JMenuItem dens = new JMenuItem(
312 MessageManager.getString("label.sort_by_density"));
313 dens.addActionListener(new ActionListener()
317 public void actionPerformed(ActionEvent e)
319 me.af.avc.sortAlignmentByFeatureDensity(new String[] { type });
326 final float[][] typeMinMax = minmax.get(type);
328 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
329 * this is broken at the moment and isn't that useful anyway!
330 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
333 * public void actionPerformed(ActionEvent e) {
334 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
335 * null); } else { minmax.put(type, typeMinMax); } }
341 if (typeMinMax != null && typeMinMax[0] != null)
343 // if (table.getValueAt(row, column));
344 // graduated colourschemes for those where minmax exists for the
345 // positional features
346 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
348 mxcol.setSelected(!featureColour.isSimpleColour());
350 mxcol.addActionListener(new ActionListener()
352 JColorChooser colorChooser;
355 public void actionPerformed(ActionEvent e)
357 if (e.getSource() == mxcol)
359 if (featureColour.isSimpleColour())
361 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
363 fc.addActionListener(this);
367 // bring up simple color chooser
368 colorChooser = new JColorChooser();
369 JDialog dialog = JColorChooser.createDialog(me,
370 "Select new Colour", true, // modal
371 colorChooser, this, // OK button handler
372 null); // no CANCEL button handler
373 colorChooser.setColor(featureColour.getMaxColour());
374 dialog.setVisible(true);
379 if (e.getSource() instanceof FeatureColourChooser)
381 FeatureColourChooser fc = (FeatureColourChooser) e
383 table.setValueAt(fc.getLastColour(), row, 1);
388 // probably the color chooser!
389 table.setValueAt(colorChooser.getColor(), row, 1);
391 me.updateFeatureRenderer(
392 ((FeatureTableModel) table.getModel()).getData(),
401 JMenuItem selCols = new JMenuItem(
402 MessageManager.getString("label.select_columns_containing"));
403 selCols.addActionListener(new ActionListener()
407 public void actionPerformed(ActionEvent arg0)
409 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
413 JMenuItem clearCols = new JMenuItem(
414 MessageManager.getString("label.select_columns_not_containing"));
415 clearCols.addActionListener(new ActionListener()
419 public void actionPerformed(ActionEvent arg0)
421 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
427 men.show(table, x, y);
431 * true when Feature Settings are updating from feature renderer
433 private boolean handlingUpdate = false;
436 * contains a float[3] for each feature type string. created by setTableData
438 Map<String, float[]> typeWidth = null;
441 synchronized public void discoverAllFeatureData()
443 Vector<String> allFeatures = new Vector<String>();
444 Vector<String> allGroups = new Vector<String>();
445 SequenceFeature[] tmpfeatures;
447 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
449 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
450 .getSequenceFeatures();
451 if (tmpfeatures == null)
457 while (index < tmpfeatures.length)
459 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
465 if (tmpfeatures[index].getFeatureGroup() != null)
467 group = tmpfeatures[index].featureGroup;
468 if (!allGroups.contains(group))
470 allGroups.addElement(group);
471 checkGroupState(group);
475 if (!allFeatures.contains(tmpfeatures[index].getType()))
477 allFeatures.addElement(tmpfeatures[index].getType());
489 * Synchronise gui group list and check visibility of group
492 * @return true if group is visible
494 private boolean checkGroupState(String group)
496 boolean visible = fr.checkGroupVisibility(group, true);
498 if (groupPanel == null)
500 groupPanel = new JPanel();
503 boolean alreadyAdded = false;
504 for (int g = 0; g < groupPanel.getComponentCount(); g++)
506 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
509 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
519 final String grp = group;
520 final JCheckBox check = new JCheckBox(group, visible);
521 check.setFont(new Font("Serif", Font.BOLD, 12));
522 check.addItemListener(new ItemListener()
525 public void itemStateChanged(ItemEvent evt)
527 fr.setGroupVisibility(check.getText(), check.isSelected());
528 af.alignPanel.getSeqPanel().seqCanvas.repaint();
529 if (af.alignPanel.overviewPanel != null)
531 af.alignPanel.overviewPanel.updateOverviewImage();
534 resetTable(new String[] { grp });
537 groupPanel.add(check);
541 boolean resettingTable = false;
543 synchronized void resetTable(String[] groupChanged)
545 if (resettingTable == true)
549 resettingTable = true;
550 typeWidth = new Hashtable<String, float[]>();
551 // TODO: change avWidth calculation to 'per-sequence' average and use long
553 float[] avWidth = null;
554 SequenceFeature[] tmpfeatures;
555 String group = null, type;
556 Vector<String> visibleChecks = new Vector<String>();
558 // Find out which features should be visible depending on which groups
559 // are selected / deselected
560 // and recompute average width ordering
561 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
564 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
565 .getSequenceFeatures();
566 if (tmpfeatures == null)
572 while (index < tmpfeatures.length)
574 group = tmpfeatures[index].featureGroup;
576 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
582 if (group == null || checkGroupState(group))
584 type = tmpfeatures[index].getType();
585 if (!visibleChecks.contains(type))
587 visibleChecks.addElement(type);
590 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
592 typeWidth.put(tmpfeatures[index].getType(),
593 avWidth = new float[3]);
597 avWidth = typeWidth.get(tmpfeatures[index].getType());
600 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
602 avWidth[1] += 1 + tmpfeatures[index].getBegin()
603 - tmpfeatures[index].getEnd();
607 avWidth[1] += 1 + tmpfeatures[index].getEnd()
608 - tmpfeatures[index].getBegin();
614 int fSize = visibleChecks.size();
615 Object[][] data = new Object[fSize][3];
618 if (fr.hasRenderOrder())
622 fr.findAllFeatures(groupChanged != null); // prod to update
623 // colourschemes. but don't
625 // First add the checks in the previous render order,
626 // in case the window has been closed and reopened
628 List<String> frl = fr.getRenderOrder();
629 for (int ro = frl.size() - 1; ro > -1; ro--)
633 if (!visibleChecks.contains(type))
638 data[dataIndex][0] = type;
639 data[dataIndex][1] = fr.getFeatureStyle(type);
640 data[dataIndex][2] = new Boolean(af.getViewport()
641 .getFeaturesDisplayed().isVisible(type));
643 visibleChecks.removeElement(type);
647 fSize = visibleChecks.size();
648 for (int i = 0; i < fSize; i++)
650 // These must be extra features belonging to the group
651 // which was just selected
652 type = visibleChecks.elementAt(i).toString();
653 data[dataIndex][0] = type;
655 data[dataIndex][1] = fr.getFeatureStyle(type);
656 if (data[dataIndex][1] == null)
658 // "Colour has been updated in another view!!"
659 fr.clearRenderOrder();
663 data[dataIndex][2] = new Boolean(true);
667 if (originalData == null)
669 originalData = new Object[data.length][3];
670 for (int i = 0; i < data.length; i++)
672 System.arraycopy(data[i], 0, originalData[i], 0, 3);
676 table.setModel(new FeatureTableModel(data));
677 table.getColumnModel().getColumn(0).setPreferredWidth(200);
679 if (groupPanel != null)
681 groupPanel.setLayout(new GridLayout(
682 fr.getFeatureGroupsSize() / 4 + 1, 4));
684 groupPanel.validate();
685 bigPanel.add(groupPanel, BorderLayout.NORTH);
688 updateFeatureRenderer(data, groupChanged != null);
689 resettingTable = false;
693 * reorder data based on the featureRenderers global priority list.
697 private void ensureOrder(Object[][] data)
699 boolean sort = false;
700 float[] order = new float[data.length];
701 for (int i = 0; i < order.length; i++)
703 order[i] = fr.getOrder(data[i][0].toString());
706 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
710 sort = sort || order[i - 1] > order[i];
715 jalview.util.QuickSort.sort(order, data);
721 JalviewFileChooser chooser = new JalviewFileChooser(
722 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
723 new String[] { "fc" },
724 new String[] { "Sequence Feature Colours" },
725 "Sequence Feature Colours");
726 chooser.setFileView(new jalview.io.JalviewFileView());
727 chooser.setDialogTitle(MessageManager
728 .getString("label.load_feature_colours"));
729 chooser.setToolTipText(MessageManager.getString("action.load"));
731 int value = chooser.showOpenDialog(this);
733 if (value == JalviewFileChooser.APPROVE_OPTION)
735 File file = chooser.getSelectedFile();
739 InputStreamReader in = new InputStreamReader(new FileInputStream(
742 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
744 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
747 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
750 Color mincol = null, maxcol = null;
753 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
754 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
756 } catch (Exception e)
758 Cache.log.warn("Couldn't parse out graduated feature color.",
761 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
762 newcol.getMin(), newcol.getMax());
763 if (newcol.hasAutoScale())
765 gcol.setAutoScaled(newcol.getAutoScale());
767 if (newcol.hasColourByLabel())
769 gcol.setColourByLabel(newcol.getColourByLabel());
771 if (newcol.hasThreshold())
773 gcol.setThreshold(newcol.getThreshold());
775 if (newcol.getThreshType().length() > 0)
777 String ttyp = newcol.getThreshType();
778 if (ttyp.equalsIgnoreCase("ABOVE"))
780 gcol.setAboveThreshold(true);
782 if (ttyp.equalsIgnoreCase("BELOW"))
784 gcol.setBelowThreshold(true);
787 fr.setColour(name = newcol.getName(), gcol);
791 Color color = new Color(
792 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
793 fr.setColour(name = jucs.getColour(i).getName(),
794 new FeatureColour(color));
796 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
801 Object[][] data = ((FeatureTableModel) table.getModel())
804 updateFeatureRenderer(data, false);
807 } catch (Exception ex)
809 System.out.println("Error loading User Colour File\n" + ex);
816 JalviewFileChooser chooser = new JalviewFileChooser(
817 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
818 new String[] { "fc" },
819 new String[] { "Sequence Feature Colours" },
820 "Sequence Feature Colours");
821 chooser.setFileView(new jalview.io.JalviewFileView());
822 chooser.setDialogTitle(MessageManager
823 .getString("label.save_feature_colours"));
824 chooser.setToolTipText(MessageManager.getString("action.save"));
826 int value = chooser.showSaveDialog(this);
828 if (value == JalviewFileChooser.APPROVE_OPTION)
830 String choice = chooser.getSelectedFile().getPath();
831 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
832 ucs.setSchemeName("Sequence Features");
835 PrintWriter out = new PrintWriter(new OutputStreamWriter(
836 new FileOutputStream(choice), "UTF-8"));
838 Set<String> fr_colours = fr.getAllFeatureColours();
839 Iterator<String> e = fr_colours.iterator();
840 float[] sortOrder = new float[fr_colours.size()];
841 String[] sortTypes = new String[fr_colours.size()];
845 sortTypes[i] = e.next();
846 sortOrder[i] = fr.getOrder(sortTypes[i]);
849 QuickSort.sort(sortOrder, sortTypes);
851 for (i = 0; i < sortTypes.length; i++)
853 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
854 col.setName(sortTypes[i]);
855 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
856 if (fcol.isSimpleColour())
858 col.setRGB(Format.getHexString(fcol.getColour()));
862 col.setRGB(Format.getHexString(fcol.getMaxColour()));
863 col.setMin(fcol.getMin());
864 col.setMax(fcol.getMax());
865 col.setMinRGB(jalview.util.Format.getHexString(fcol
867 col.setAutoScale(fcol.isAutoScaled());
868 col.setThreshold(fcol.getThreshold());
869 col.setColourByLabel(fcol.isColourByLabel());
870 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
871 .isBelowThreshold() ? "BELOW" : "NONE"));
877 } catch (Exception ex)
879 ex.printStackTrace();
884 public void invertSelection()
886 for (int i = 0; i < table.getRowCount(); i++)
888 Boolean value = (Boolean) table.getValueAt(i, 2);
890 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
894 public void orderByAvWidth()
896 if (table == null || table.getModel() == null)
900 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
901 float[] width = new float[data.length];
905 for (int i = 0; i < data.length; i++)
907 awidth = typeWidth.get(data[i][0]);
910 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
911 // weight - but have to make per
912 // sequence, too (awidth[2])
913 // if (width[i]==1) // hack to distinguish single width sequences.
925 boolean sort = false;
926 for (int i = 0; i < width.length; i++)
928 // awidth = (float[]) typeWidth.get(data[i][0]);
931 width[i] = fr.getOrder(data[i][0].toString());
934 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
939 width[i] /= max; // normalize
940 fr.setOrder(data[i][0].toString(), width[i]); // store for later
944 sort = sort || width[i - 1] > width[i];
949 jalview.util.QuickSort.sort(width, data);
950 // update global priority order
953 updateFeatureRenderer(data, false);
961 frame.setClosed(true);
962 } catch (Exception exe)
968 public void updateFeatureRenderer(Object[][] data)
970 updateFeatureRenderer(data, true);
973 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
975 fr.setFeaturePriority(data, visibleNew);
976 af.alignPanel.paintAlignment(true);
979 int selectedRow = -1;
981 JTabbedPane tabbedPane = new JTabbedPane();
983 BorderLayout borderLayout1 = new BorderLayout();
985 BorderLayout borderLayout2 = new BorderLayout();
987 BorderLayout borderLayout3 = new BorderLayout();
989 JPanel bigPanel = new JPanel();
991 BorderLayout borderLayout4 = new BorderLayout();
993 JButton invert = new JButton();
995 JPanel buttonPanel = new JPanel();
997 JButton cancel = new JButton();
999 JButton ok = new JButton();
1001 JButton loadColours = new JButton();
1003 JButton saveColours = new JButton();
1005 JPanel dasButtonPanel = new JPanel();
1007 JButton fetchDAS = new JButton();
1009 JButton saveDAS = new JButton();
1011 JButton cancelDAS = new JButton();
1013 JButton optimizeOrder = new JButton();
1015 JButton sortByScore = new JButton();
1017 JButton sortByDens = new JButton();
1019 JButton help = new JButton();
1021 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1023 private void jbInit() throws Exception
1025 this.setLayout(borderLayout1);
1026 settingsPane.setLayout(borderLayout2);
1027 dasSettingsPane.setLayout(borderLayout3);
1028 bigPanel.setLayout(borderLayout4);
1029 invert.setFont(JvSwingUtils.getLabelFont());
1030 invert.setText(MessageManager.getString("label.invert_selection"));
1031 invert.addActionListener(new ActionListener()
1034 public void actionPerformed(ActionEvent e)
1039 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1040 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1041 optimizeOrder.addActionListener(new ActionListener()
1044 public void actionPerformed(ActionEvent e)
1049 sortByScore.setFont(JvSwingUtils.getLabelFont());
1051 .setText(MessageManager.getString("label.seq_sort_by_score"));
1052 sortByScore.addActionListener(new ActionListener()
1055 public void actionPerformed(ActionEvent e)
1057 af.avc.sortAlignmentByFeatureScore(null);
1060 sortByDens.setFont(JvSwingUtils.getLabelFont());
1061 sortByDens.setText(MessageManager
1062 .getString("label.sequence_sort_by_density"));
1063 sortByDens.addActionListener(new ActionListener()
1066 public void actionPerformed(ActionEvent e)
1068 af.avc.sortAlignmentByFeatureDensity(null);
1071 help.setFont(JvSwingUtils.getLabelFont());
1072 help.setText(MessageManager.getString("action.help"));
1073 help.addActionListener(new ActionListener()
1076 public void actionPerformed(ActionEvent e)
1080 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1081 } catch (HelpSetException e1)
1083 e1.printStackTrace();
1087 help.setFont(JvSwingUtils.getLabelFont());
1088 help.setText(MessageManager.getString("action.help"));
1089 help.addActionListener(new ActionListener()
1092 public void actionPerformed(ActionEvent e)
1096 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1097 } catch (HelpSetException e1)
1099 e1.printStackTrace();
1103 cancel.setFont(JvSwingUtils.getLabelFont());
1104 cancel.setText(MessageManager.getString("action.cancel"));
1105 cancel.addActionListener(new ActionListener()
1108 public void actionPerformed(ActionEvent e)
1110 fr.setTransparency(originalTransparency);
1111 updateFeatureRenderer(originalData);
1115 ok.setFont(JvSwingUtils.getLabelFont());
1116 ok.setText(MessageManager.getString("action.ok"));
1117 ok.addActionListener(new ActionListener()
1120 public void actionPerformed(ActionEvent e)
1125 loadColours.setFont(JvSwingUtils.getLabelFont());
1126 loadColours.setText(MessageManager.getString("label.load_colours"));
1127 loadColours.addActionListener(new ActionListener()
1130 public void actionPerformed(ActionEvent e)
1135 saveColours.setFont(JvSwingUtils.getLabelFont());
1136 saveColours.setText(MessageManager.getString("label.save_colours"));
1137 saveColours.addActionListener(new ActionListener()
1140 public void actionPerformed(ActionEvent e)
1145 transparency.addChangeListener(new ChangeListener()
1148 public void stateChanged(ChangeEvent evt)
1150 fr.setTransparency((100 - transparency.getValue()) / 100f);
1151 af.alignPanel.paintAlignment(true);
1155 transparency.setMaximum(70);
1156 transparency.setToolTipText(MessageManager
1157 .getString("label.transparency_tip"));
1158 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1159 fetchDAS.addActionListener(new ActionListener()
1162 public void actionPerformed(ActionEvent e)
1164 fetchDAS_actionPerformed(e);
1167 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1168 saveDAS.addActionListener(new ActionListener()
1171 public void actionPerformed(ActionEvent e)
1173 saveDAS_actionPerformed(e);
1176 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1177 dasSettingsPane.setBorder(null);
1178 cancelDAS.setEnabled(false);
1179 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1180 cancelDAS.addActionListener(new ActionListener()
1183 public void actionPerformed(ActionEvent e)
1185 cancelDAS_actionPerformed(e);
1188 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1189 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1191 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1193 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1194 transbuttons.add(optimizeOrder);
1195 transbuttons.add(invert);
1196 transbuttons.add(sortByScore);
1197 transbuttons.add(sortByDens);
1198 transbuttons.add(help);
1199 JPanel sliderPanel = new JPanel();
1200 sliderPanel.add(transparency);
1201 transPanel.add(transparency);
1202 transPanel.add(transbuttons);
1203 buttonPanel.add(ok);
1204 buttonPanel.add(cancel);
1205 buttonPanel.add(loadColours);
1206 buttonPanel.add(saveColours);
1207 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1208 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1209 dasButtonPanel.add(fetchDAS);
1210 dasButtonPanel.add(cancelDAS);
1211 dasButtonPanel.add(saveDAS);
1212 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1213 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1216 public void fetchDAS_actionPerformed(ActionEvent e)
1218 fetchDAS.setEnabled(false);
1219 cancelDAS.setEnabled(true);
1220 dassourceBrowser.setGuiEnabled(false);
1221 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1222 .getSelectedSources();
1223 doDasFeatureFetch(selectedSources, true, true);
1227 * get the features from selectedSources for all or the current selection
1229 * @param selectedSources
1230 * @param checkDbRefs
1231 * @param promptFetchDbRefs
1233 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1234 boolean checkDbRefs, boolean promptFetchDbRefs)
1236 SequenceI[] dataset, seqs;
1238 AlignmentViewport vp = af.getViewport();
1239 if (vp.getSelectionGroup() != null
1240 && vp.getSelectionGroup().getSize() > 0)
1242 iSize = vp.getSelectionGroup().getSize();
1243 dataset = new SequenceI[iSize];
1244 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1248 iSize = vp.getAlignment().getHeight();
1249 seqs = vp.getAlignment().getSequencesArray();
1252 dataset = new SequenceI[iSize];
1253 for (int i = 0; i < iSize; i++)
1255 dataset[i] = seqs[i].getDatasetSequence();
1258 cancelDAS.setEnabled(true);
1259 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1260 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1261 af.getViewport().setShowSequenceFeatures(true);
1262 af.showSeqFeatures.setSelected(true);
1266 * blocking call to initialise the das source browser
1268 public void initDasSources()
1270 dassourceBrowser.initDasSources();
1274 * examine the current list of das sources and return any matching the given
1275 * nicknames in sources
1278 * Vector of Strings to resolve to DAS source nicknames.
1279 * @return sources that are present in source list.
1281 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1283 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1287 * get currently selected das sources. ensure you have called initDasSources
1288 * before calling this.
1290 * @return vector of selected das source nicknames
1292 public Vector<jalviewSourceI> getSelectedSources()
1294 return dassourceBrowser.getSelectedSources();
1298 * properly initialise DAS fetcher and then initiate a new thread to fetch
1299 * features from the named sources (rather than any turned on by default)
1303 * if true then runs in same thread, otherwise passes to the Swing
1306 public void fetchDasFeatures(Vector<String> sources, boolean block)
1309 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1310 .resolveSourceNicknames(sources);
1311 if (resolved.size() == 0)
1313 resolved = dassourceBrowser.getSelectedSources();
1315 if (resolved.size() > 0)
1317 final List<jalviewSourceI> dassources = resolved;
1318 fetchDAS.setEnabled(false);
1319 // cancelDAS.setEnabled(true); doDasFetch does this.
1320 Runnable fetcher = new Runnable()
1326 doDasFeatureFetch(dassources, true, false);
1336 SwingUtilities.invokeLater(fetcher);
1341 public void saveDAS_actionPerformed(ActionEvent e)
1344 .saveProperties(jalview.bin.Cache.applicationProperties);
1347 public void complete()
1349 fetchDAS.setEnabled(true);
1350 cancelDAS.setEnabled(false);
1351 dassourceBrowser.setGuiEnabled(true);
1355 public void cancelDAS_actionPerformed(ActionEvent e)
1357 if (dasFeatureFetcher != null)
1359 dasFeatureFetcher.cancel();
1364 public void noDasSourceActive()
1368 .showInternalConfirmDialog(
1371 .getString("label.no_das_sources_selected_warn"),
1373 .getString("label.no_das_sources_selected_title"),
1374 JOptionPane.DEFAULT_OPTION,
1375 JOptionPane.INFORMATION_MESSAGE);
1378 // ///////////////////////////////////////////////////////////////////////
1379 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1380 // ///////////////////////////////////////////////////////////////////////
1381 class FeatureTableModel extends AbstractTableModel
1383 FeatureTableModel(Object[][] data)
1388 private String[] columnNames = {
1389 MessageManager.getString("label.feature_type"),
1390 MessageManager.getString("action.colour"),
1391 MessageManager.getString("label.display") };
1393 private Object[][] data;
1395 public Object[][] getData()
1400 public void setData(Object[][] data)
1406 public int getColumnCount()
1408 return columnNames.length;
1411 public Object[] getRow(int row)
1417 public int getRowCount()
1423 public String getColumnName(int col)
1425 return columnNames[col];
1429 public Object getValueAt(int row, int col)
1431 return data[row][col];
1435 public Class getColumnClass(int c)
1437 return getValueAt(0, c).getClass();
1441 public boolean isCellEditable(int row, int col)
1443 return col == 0 ? false : true;
1447 public void setValueAt(Object value, int row, int col)
1449 data[row][col] = value;
1450 fireTableCellUpdated(row, col);
1451 updateFeatureRenderer(data);
1456 class ColorRenderer extends JLabel implements TableCellRenderer
1458 javax.swing.border.Border unselectedBorder = null;
1460 javax.swing.border.Border selectedBorder = null;
1462 final String baseTT = "Click to edit, right/apple click for menu.";
1464 public ColorRenderer()
1466 setOpaque(true); // MUST do this for background to show up.
1467 setHorizontalTextPosition(SwingConstants.CENTER);
1468 setVerticalTextPosition(SwingConstants.CENTER);
1472 public Component getTableCellRendererComponent(JTable tbl,
1473 Object color, boolean isSelected, boolean hasFocus, int row,
1476 FeatureColourI cellColour = (FeatureColourI) color;
1477 // JLabel comp = new JLabel();
1481 // setBounds(getBounds());
1483 setToolTipText(baseTT);
1484 setBackground(tbl.getBackground());
1485 if (!cellColour.isSimpleColour())
1487 Rectangle cr = tbl.getCellRect(row, column, false);
1488 FeatureSettings.renderGraduatedColor(this, cellColour,
1489 (int) cr.getWidth(), (int) cr.getHeight());
1496 newColor = cellColour.getColour();
1497 setBackground(newColor);
1501 if (selectedBorder == null)
1503 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1504 tbl.getSelectionBackground());
1506 setBorder(selectedBorder);
1510 if (unselectedBorder == null)
1512 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1513 tbl.getBackground());
1515 setBorder(unselectedBorder);
1523 * update comp using rendering settings from gcol
1528 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1530 int w = comp.getWidth(), h = comp.getHeight();
1533 w = (int) comp.getPreferredSize().getWidth();
1534 h = (int) comp.getPreferredSize().getHeight();
1541 renderGraduatedColor(comp, gcol, w, h);
1544 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1547 boolean thr = false;
1550 if (gcol.isAboveThreshold())
1554 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1556 if (gcol.isBelowThreshold())
1560 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1562 if (gcol.isColourByLabel())
1564 tt = "Coloured by label text. " + tt;
1574 Color newColor = gcol.getMaxColour();
1575 comp.setBackground(newColor);
1576 // System.err.println("Width is " + w / 2);
1577 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1578 comp.setIcon(ficon);
1579 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1580 // + newColor.getGreen() + ", " + newColor.getBlue()
1581 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1582 // + ", " + minCol.getBlue() + ")");
1584 comp.setHorizontalAlignment(SwingConstants.CENTER);
1586 if (tt.length() > 0)
1588 if (comp.getToolTipText() == null)
1590 comp.setToolTipText(tt);
1594 comp.setToolTipText(tt + " " + comp.getToolTipText());
1600 class FeatureIcon implements Icon
1602 FeatureColourI gcol;
1606 boolean midspace = false;
1608 int width = 50, height = 20;
1610 int s1, e1; // start and end of midpoint band for thresholded symbol
1612 Color mpcolour = Color.white;
1614 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1634 public int getIconWidth()
1640 public int getIconHeight()
1646 public void paintIcon(Component c, Graphics g, int x, int y)
1649 if (gcol.isColourByLabel())
1652 g.fillRect(0, 0, width, height);
1653 // need an icon here.
1654 g.setColor(gcol.getMaxColour());
1656 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1658 // g.setFont(g.getFont().deriveFont(
1659 // AffineTransform.getScaleInstance(
1660 // width/g.getFontMetrics().stringWidth("Label"),
1661 // height/g.getFontMetrics().getHeight())));
1663 g.drawString(MessageManager.getString("label.label"), 0, 0);
1668 Color minCol = gcol.getMinColour();
1670 g.fillRect(0, 0, s1, height);
1673 g.setColor(Color.white);
1674 g.fillRect(s1, 0, e1 - s1, height);
1676 g.setColor(gcol.getMaxColour());
1677 g.fillRect(0, e1, width - e1, height);
1682 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1687 FeatureColourI currentColor;
1689 FeatureColourChooser chooser;
1695 JColorChooser colorChooser;
1699 protected static final String EDIT = "edit";
1701 int selectedRow = 0;
1703 public ColorEditor(FeatureSettings me)
1706 // Set up the editor (from the table's point of view),
1707 // which is a button.
1708 // This button brings up the color chooser dialog,
1709 // which is the editor from the user's point of view.
1710 button = new JButton();
1711 button.setActionCommand(EDIT);
1712 button.addActionListener(this);
1713 button.setBorderPainted(false);
1714 // Set up the dialog that the button brings up.
1715 colorChooser = new JColorChooser();
1716 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1717 colorChooser, this, // OK button handler
1718 null); // no CANCEL button handler
1722 * Handles events from the editor button and from the dialog's OK button.
1725 public void actionPerformed(ActionEvent e)
1728 if (EDIT.equals(e.getActionCommand()))
1730 // The user has clicked the cell, so
1731 // bring up the dialog.
1732 if (currentColor.isSimpleColour())
1734 // bring up simple color chooser
1735 button.setBackground(currentColor.getColour());
1736 colorChooser.setColor(currentColor.getColour());
1737 dialog.setVisible(true);
1741 // bring up graduated chooser.
1742 chooser = new FeatureColourChooser(me.fr, type);
1743 chooser.setRequestFocusEnabled(true);
1744 chooser.requestFocus();
1745 chooser.addActionListener(this);
1747 // Make the renderer reappear.
1748 fireEditingStopped();
1752 { // User pressed dialog's "OK" button.
1753 if (currentColor.isSimpleColour())
1755 currentColor = new FeatureColour(colorChooser.getColor());
1759 currentColor = chooser.getLastColour();
1761 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1762 fireEditingStopped();
1763 me.table.validate();
1767 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1769 public Object getCellEditorValue()
1771 return currentColor;
1774 // Implement the one method defined by TableCellEditor.
1776 public Component getTableCellEditorComponent(JTable table, Object value,
1777 boolean isSelected, int row, int column)
1779 currentColor = (FeatureColourI) value;
1780 this.selectedRow = row;
1781 type = me.table.getValueAt(row, 0).toString();
1782 button.setOpaque(true);
1783 button.setBackground(me.getBackground());
1784 if (!currentColor.isSimpleColour())
1786 JLabel btn = new JLabel();
1787 btn.setSize(button.getSize());
1788 FeatureSettings.renderGraduatedColor(btn, currentColor);
1789 button.setBackground(btn.getBackground());
1790 button.setIcon(btn.getIcon());
1791 button.setText(btn.getText());
1796 button.setIcon(null);
1797 button.setBackground(currentColor.getColour());