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.Arrays;
62 import java.util.Hashtable;
63 import java.util.Iterator;
64 import java.util.List;
67 import java.util.Vector;
69 import javax.help.HelpSetException;
70 import javax.swing.AbstractCellEditor;
71 import javax.swing.BorderFactory;
72 import javax.swing.Icon;
73 import javax.swing.JButton;
74 import javax.swing.JCheckBox;
75 import javax.swing.JCheckBoxMenuItem;
76 import javax.swing.JColorChooser;
77 import javax.swing.JDialog;
78 import javax.swing.JInternalFrame;
79 import javax.swing.JLabel;
80 import javax.swing.JLayeredPane;
81 import javax.swing.JMenuItem;
82 import javax.swing.JOptionPane;
83 import javax.swing.JPanel;
84 import javax.swing.JPopupMenu;
85 import javax.swing.JScrollPane;
86 import javax.swing.JSlider;
87 import javax.swing.JTabbedPane;
88 import javax.swing.JTable;
89 import javax.swing.ListSelectionModel;
90 import javax.swing.SwingConstants;
91 import javax.swing.SwingUtilities;
92 import javax.swing.event.ChangeEvent;
93 import javax.swing.event.ChangeListener;
94 import javax.swing.table.AbstractTableModel;
95 import javax.swing.table.TableCellEditor;
96 import javax.swing.table.TableCellRenderer;
98 public class FeatureSettings extends JPanel implements
99 FeatureSettingsControllerI
101 DasSourceBrowser dassourceBrowser;
103 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
105 JPanel settingsPane = new JPanel();
107 JPanel dasSettingsPane = new JPanel();
109 final FeatureRenderer fr;
111 public final AlignFrame af;
113 Object[][] originalData;
115 private float originalTransparency;
117 final JInternalFrame frame;
119 JScrollPane scrollPane = new JScrollPane();
125 JSlider transparency = new JSlider();
127 JPanel transPanel = new JPanel(new GridLayout(1, 2));
129 public FeatureSettings(AlignFrame af)
132 fr = af.getFeatureRenderer();
133 // allow transparency to be recovered
134 transparency.setMaximum(100 - (int) ((originalTransparency = fr
135 .getTransparency()) * 100));
140 } catch (Exception ex)
142 ex.printStackTrace();
148 public String getToolTipText(MouseEvent e)
150 if (table.columnAtPoint(e.getPoint()) == 0)
153 * Tooltip for feature name only
155 return JvSwingUtils.wrapTooltip(true, MessageManager
156 .getString("label.feature_settings_click_drag"));
161 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
162 table.setFont(new Font("Verdana", Font.PLAIN, 12));
163 table.setDefaultRenderer(Color.class, new ColorRenderer());
165 table.setDefaultEditor(Color.class, new ColorEditor(this));
167 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
168 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
169 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
171 table.addMouseListener(new MouseAdapter()
174 public void mousePressed(MouseEvent evt)
176 selectedRow = table.rowAtPoint(evt.getPoint());
177 if (SwingUtilities.isRightMouseButton(evt))
179 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
180 table.getValueAt(selectedRow, 1), fr.getMinMax(),
181 evt.getX(), evt.getY());
183 else if (evt.getClickCount() == 2)
185 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
186 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
188 (String) table.getValueAt(selectedRow, 0));
192 // isPopupTrigger fires on mouseReleased on Mac
194 public void mouseReleased(MouseEvent evt)
196 selectedRow = table.rowAtPoint(evt.getPoint());
197 if (evt.isPopupTrigger())
199 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
200 table.getValueAt(selectedRow, 1), fr.getMinMax(),
201 evt.getX(), evt.getY());
206 table.addMouseMotionListener(new MouseMotionAdapter()
209 public void mouseDragged(MouseEvent evt)
211 int newRow = table.rowAtPoint(evt.getPoint());
212 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
214 Object[][] data = ((FeatureTableModel) table.getModel())
216 Object[] temp = data[selectedRow];
217 data[selectedRow] = data[newRow];
219 updateFeatureRenderer(data);
221 selectedRow = newRow;
225 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
226 // MessageManager.getString("label.feature_settings_click_drag")));
227 scrollPane.setViewportView(table);
229 dassourceBrowser = new DasSourceBrowser(this);
230 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
232 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
234 fr.findAllFeatures(true); // display everything!
237 discoverAllFeatureData();
238 final PropertyChangeListener change;
239 final FeatureSettings fs = this;
240 fr.addPropertyChangeListener(change = new PropertyChangeListener()
243 public void propertyChange(PropertyChangeEvent evt)
245 if (!fs.resettingTable && !fs.handlingUpdate)
247 fs.handlingUpdate = true;
248 fs.resetTable(null); // new groups may be added with new seuqence
249 // feature types only
250 fs.handlingUpdate = false;
256 frame = new JInternalFrame();
257 frame.setContentPane(this);
258 if (Platform.isAMac())
260 Desktop.addInternalFrame(frame,
261 MessageManager.getString("label.sequence_feature_settings"),
266 Desktop.addInternalFrame(frame,
267 MessageManager.getString("label.sequence_feature_settings"),
271 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
274 public void internalFrameClosed(
275 javax.swing.event.InternalFrameEvent evt)
277 fr.removePropertyChangeListener(change);
278 dassourceBrowser.fs = null;
281 frame.setLayer(JLayeredPane.PALETTE_LAYER);
284 protected void popupSort(final int selectedRow, final String type,
285 final Object typeCol, final Map<String, float[][]> minmax, int x,
288 final FeatureColourI featureColour = (FeatureColourI) typeCol;
290 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
291 "label.settings_for_param", new String[] { type }));
292 JMenuItem scr = new JMenuItem(
293 MessageManager.getString("label.sort_by_score"));
295 final FeatureSettings me = this;
296 scr.addActionListener(new ActionListener()
300 public void actionPerformed(ActionEvent e)
302 me.af.avc.sortAlignmentByFeatureScore(Arrays
303 .asList(new String[] { type }));
307 JMenuItem dens = new JMenuItem(
308 MessageManager.getString("label.sort_by_density"));
309 dens.addActionListener(new ActionListener()
313 public void actionPerformed(ActionEvent e)
315 me.af.avc.sortAlignmentByFeatureDensity(Arrays
316 .asList(new String[] { type }));
323 final float[][] typeMinMax = minmax.get(type);
325 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
326 * this is broken at the moment and isn't that useful anyway!
327 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
330 * public void actionPerformed(ActionEvent e) {
331 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
332 * null); } else { minmax.put(type, typeMinMax); } }
338 if (typeMinMax != null && typeMinMax[0] != null)
340 // if (table.getValueAt(row, column));
341 // graduated colourschemes for those where minmax exists for the
342 // positional features
343 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
345 mxcol.setSelected(!featureColour.isSimpleColour());
347 mxcol.addActionListener(new ActionListener()
349 JColorChooser colorChooser;
352 public void actionPerformed(ActionEvent e)
354 if (e.getSource() == mxcol)
356 if (featureColour.isSimpleColour())
358 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
360 fc.addActionListener(this);
364 // bring up simple color chooser
365 colorChooser = new JColorChooser();
366 JDialog dialog = JColorChooser.createDialog(me,
367 "Select new Colour", true, // modal
368 colorChooser, this, // OK button handler
369 null); // no CANCEL button handler
370 colorChooser.setColor(featureColour.getMaxColour());
371 dialog.setVisible(true);
376 if (e.getSource() instanceof FeatureColourChooser)
378 FeatureColourChooser fc = (FeatureColourChooser) e
380 table.setValueAt(fc.getLastColour(), selectedRow, 1);
385 // probably the color chooser!
386 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
388 me.updateFeatureRenderer(
389 ((FeatureTableModel) table.getModel()).getData(),
398 JMenuItem selCols = new JMenuItem(
399 MessageManager.getString("label.select_columns_containing"));
400 selCols.addActionListener(new ActionListener()
403 public void actionPerformed(ActionEvent arg0)
405 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
409 JMenuItem clearCols = new JMenuItem(
410 MessageManager.getString("label.select_columns_not_containing"));
411 clearCols.addActionListener(new ActionListener()
414 public void actionPerformed(ActionEvent arg0)
416 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
420 JMenuItem hideCols = new JMenuItem(
421 MessageManager.getString("label.hide_columns_containing"));
422 hideCols.addActionListener(new ActionListener()
425 public void actionPerformed(ActionEvent arg0)
427 fr.ap.alignFrame.hideFeatureColumns(type, true);
430 JMenuItem hideOtherCols = new JMenuItem(
431 MessageManager.getString("label.hide_columns_not_containing"));
432 hideOtherCols.addActionListener(new ActionListener()
435 public void actionPerformed(ActionEvent arg0)
437 fr.ap.alignFrame.hideFeatureColumns(type, false);
443 men.add(hideOtherCols);
444 men.show(table, x, y);
448 * true when Feature Settings are updating from feature renderer
450 private boolean handlingUpdate = false;
453 * contains a float[3] for each feature type string. created by setTableData
455 Map<String, float[]> typeWidth = null;
458 synchronized public void discoverAllFeatureData()
460 Vector<String> allFeatures = new Vector<String>();
461 Vector<String> allGroups = new Vector<String>();
462 SequenceFeature[] tmpfeatures;
464 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
466 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
467 .getSequenceFeatures();
468 if (tmpfeatures == null)
474 while (index < tmpfeatures.length)
476 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
482 if (tmpfeatures[index].getFeatureGroup() != null)
484 group = tmpfeatures[index].featureGroup;
485 if (!allGroups.contains(group))
487 allGroups.addElement(group);
488 checkGroupState(group);
492 if (!allFeatures.contains(tmpfeatures[index].getType()))
494 allFeatures.addElement(tmpfeatures[index].getType());
506 * Synchronise gui group list and check visibility of group
509 * @return true if group is visible
511 private boolean checkGroupState(String group)
513 boolean visible = fr.checkGroupVisibility(group, true);
515 if (groupPanel == null)
517 groupPanel = new JPanel();
520 boolean alreadyAdded = false;
521 for (int g = 0; g < groupPanel.getComponentCount(); g++)
523 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
526 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
536 final String grp = group;
537 final JCheckBox check = new JCheckBox(group, visible);
538 check.setFont(new Font("Serif", Font.BOLD, 12));
539 check.addItemListener(new ItemListener()
542 public void itemStateChanged(ItemEvent evt)
544 fr.setGroupVisibility(check.getText(), check.isSelected());
545 af.alignPanel.getSeqPanel().seqCanvas.repaint();
546 if (af.alignPanel.overviewPanel != null)
548 af.alignPanel.overviewPanel.updateOverviewImage();
551 resetTable(new String[] { grp });
554 groupPanel.add(check);
558 boolean resettingTable = false;
560 synchronized void resetTable(String[] groupChanged)
562 if (resettingTable == true)
566 resettingTable = true;
567 typeWidth = new Hashtable<String, float[]>();
568 // TODO: change avWidth calculation to 'per-sequence' average and use long
570 float[] avWidth = null;
571 SequenceFeature[] tmpfeatures;
572 String group = null, type;
573 Vector<String> visibleChecks = new Vector<String>();
575 // Find out which features should be visible depending on which groups
576 // are selected / deselected
577 // and recompute average width ordering
578 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
581 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
582 .getSequenceFeatures();
583 if (tmpfeatures == null)
589 while (index < tmpfeatures.length)
591 group = tmpfeatures[index].featureGroup;
593 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
599 if (group == null || checkGroupState(group))
601 type = tmpfeatures[index].getType();
602 if (!visibleChecks.contains(type))
604 visibleChecks.addElement(type);
607 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
609 typeWidth.put(tmpfeatures[index].getType(),
610 avWidth = new float[3]);
614 avWidth = typeWidth.get(tmpfeatures[index].getType());
617 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
619 avWidth[1] += 1 + tmpfeatures[index].getBegin()
620 - tmpfeatures[index].getEnd();
624 avWidth[1] += 1 + tmpfeatures[index].getEnd()
625 - tmpfeatures[index].getBegin();
631 int fSize = visibleChecks.size();
632 Object[][] data = new Object[fSize][3];
635 if (fr.hasRenderOrder())
639 fr.findAllFeatures(groupChanged != null); // prod to update
640 // colourschemes. but don't
642 // First add the checks in the previous render order,
643 // in case the window has been closed and reopened
645 List<String> frl = fr.getRenderOrder();
646 for (int ro = frl.size() - 1; ro > -1; ro--)
650 if (!visibleChecks.contains(type))
655 data[dataIndex][0] = type;
656 data[dataIndex][1] = fr.getFeatureStyle(type);
657 data[dataIndex][2] = new Boolean(af.getViewport()
658 .getFeaturesDisplayed().isVisible(type));
660 visibleChecks.removeElement(type);
664 fSize = visibleChecks.size();
665 for (int i = 0; i < fSize; i++)
667 // These must be extra features belonging to the group
668 // which was just selected
669 type = visibleChecks.elementAt(i).toString();
670 data[dataIndex][0] = type;
672 data[dataIndex][1] = fr.getFeatureStyle(type);
673 if (data[dataIndex][1] == null)
675 // "Colour has been updated in another view!!"
676 fr.clearRenderOrder();
680 data[dataIndex][2] = new Boolean(true);
684 if (originalData == null)
686 originalData = new Object[data.length][3];
687 for (int i = 0; i < data.length; i++)
689 System.arraycopy(data[i], 0, originalData[i], 0, 3);
693 table.setModel(new FeatureTableModel(data));
694 table.getColumnModel().getColumn(0).setPreferredWidth(200);
696 if (groupPanel != null)
698 groupPanel.setLayout(new GridLayout(
699 fr.getFeatureGroupsSize() / 4 + 1, 4));
701 groupPanel.validate();
702 bigPanel.add(groupPanel, BorderLayout.NORTH);
705 updateFeatureRenderer(data, groupChanged != null);
706 resettingTable = false;
710 * reorder data based on the featureRenderers global priority list.
714 private void ensureOrder(Object[][] data)
716 boolean sort = false;
717 float[] order = new float[data.length];
718 for (int i = 0; i < order.length; i++)
720 order[i] = fr.getOrder(data[i][0].toString());
723 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
727 sort = sort || order[i - 1] > order[i];
732 jalview.util.QuickSort.sort(order, data);
738 JalviewFileChooser chooser = new JalviewFileChooser(
739 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
740 new String[] { "fc" },
741 new String[] { "Sequence Feature Colours" },
742 "Sequence Feature Colours");
743 chooser.setFileView(new jalview.io.JalviewFileView());
744 chooser.setDialogTitle(MessageManager
745 .getString("label.load_feature_colours"));
746 chooser.setToolTipText(MessageManager.getString("action.load"));
748 int value = chooser.showOpenDialog(this);
750 if (value == JalviewFileChooser.APPROVE_OPTION)
752 File file = chooser.getSelectedFile();
756 InputStreamReader in = new InputStreamReader(new FileInputStream(
759 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
761 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
764 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
767 Color mincol = null, maxcol = null;
770 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
771 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
773 } catch (Exception e)
775 Cache.log.warn("Couldn't parse out graduated feature color.",
778 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
779 newcol.getMin(), newcol.getMax());
780 if (newcol.hasAutoScale())
782 gcol.setAutoScaled(newcol.getAutoScale());
784 if (newcol.hasColourByLabel())
786 gcol.setColourByLabel(newcol.getColourByLabel());
788 if (newcol.hasThreshold())
790 gcol.setThreshold(newcol.getThreshold());
792 if (newcol.getThreshType().length() > 0)
794 String ttyp = newcol.getThreshType();
795 if (ttyp.equalsIgnoreCase("ABOVE"))
797 gcol.setAboveThreshold(true);
799 if (ttyp.equalsIgnoreCase("BELOW"))
801 gcol.setBelowThreshold(true);
804 fr.setColour(name = newcol.getName(), gcol);
808 Color color = new Color(
809 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
810 fr.setColour(name = jucs.getColour(i).getName(),
811 new FeatureColour(color));
813 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
818 Object[][] data = ((FeatureTableModel) table.getModel())
821 updateFeatureRenderer(data, false);
824 } catch (Exception ex)
826 System.out.println("Error loading User Colour File\n" + ex);
833 JalviewFileChooser chooser = new JalviewFileChooser(
834 Cache.getProperty("LAST_DIRECTORY"),
835 new String[] { "fc" },
836 new String[] { "Sequence Feature Colours" },
837 "Sequence Feature Colours");
838 chooser.setFileView(new jalview.io.JalviewFileView());
839 chooser.setDialogTitle(MessageManager
840 .getString("label.save_feature_colours"));
841 chooser.setToolTipText(MessageManager.getString("action.save"));
843 int value = chooser.showSaveDialog(this);
845 if (value == JalviewFileChooser.APPROVE_OPTION)
847 String choice = chooser.getSelectedFile().getPath();
848 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
849 ucs.setSchemeName("Sequence Features");
852 PrintWriter out = new PrintWriter(new OutputStreamWriter(
853 new FileOutputStream(choice), "UTF-8"));
855 Set<String> fr_colours = fr.getAllFeatureColours();
856 Iterator<String> e = fr_colours.iterator();
857 float[] sortOrder = new float[fr_colours.size()];
858 String[] sortTypes = new String[fr_colours.size()];
862 sortTypes[i] = e.next();
863 sortOrder[i] = fr.getOrder(sortTypes[i]);
866 QuickSort.sort(sortOrder, sortTypes);
868 for (i = 0; i < sortTypes.length; i++)
870 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
871 col.setName(sortTypes[i]);
872 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
873 if (fcol.isSimpleColour())
875 col.setRGB(Format.getHexString(fcol.getColour()));
879 col.setRGB(Format.getHexString(fcol.getMaxColour()));
880 col.setMin(fcol.getMin());
881 col.setMax(fcol.getMax());
882 col.setMinRGB(jalview.util.Format.getHexString(fcol
884 col.setAutoScale(fcol.isAutoScaled());
885 col.setThreshold(fcol.getThreshold());
886 col.setColourByLabel(fcol.isColourByLabel());
887 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
888 .isBelowThreshold() ? "BELOW" : "NONE"));
894 } catch (Exception ex)
896 ex.printStackTrace();
901 public void invertSelection()
903 for (int i = 0; i < table.getRowCount(); i++)
905 Boolean value = (Boolean) table.getValueAt(i, 2);
907 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
911 public void orderByAvWidth()
913 if (table == null || table.getModel() == null)
917 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
918 float[] width = new float[data.length];
922 for (int i = 0; i < data.length; i++)
924 awidth = typeWidth.get(data[i][0]);
927 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
928 // weight - but have to make per
929 // sequence, too (awidth[2])
930 // if (width[i]==1) // hack to distinguish single width sequences.
942 boolean sort = false;
943 for (int i = 0; i < width.length; i++)
945 // awidth = (float[]) typeWidth.get(data[i][0]);
948 width[i] = fr.getOrder(data[i][0].toString());
951 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
956 width[i] /= max; // normalize
957 fr.setOrder(data[i][0].toString(), width[i]); // store for later
961 sort = sort || width[i - 1] > width[i];
966 jalview.util.QuickSort.sort(width, data);
967 // update global priority order
970 updateFeatureRenderer(data, false);
978 frame.setClosed(true);
979 } catch (Exception exe)
985 public void updateFeatureRenderer(Object[][] data)
987 updateFeatureRenderer(data, true);
991 * Update the priority order of features; only repaint if this changed the
992 * order of visible features
997 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
999 if (fr.setFeaturePriority(data, visibleNew))
1001 af.alignPanel.paintAlignment(true);
1005 int selectedRow = -1;
1007 JTabbedPane tabbedPane = new JTabbedPane();
1009 BorderLayout borderLayout1 = new BorderLayout();
1011 BorderLayout borderLayout2 = new BorderLayout();
1013 BorderLayout borderLayout3 = new BorderLayout();
1015 JPanel bigPanel = new JPanel();
1017 BorderLayout borderLayout4 = new BorderLayout();
1019 JButton invert = new JButton();
1021 JPanel buttonPanel = new JPanel();
1023 JButton cancel = new JButton();
1025 JButton ok = new JButton();
1027 JButton loadColours = new JButton();
1029 JButton saveColours = new JButton();
1031 JPanel dasButtonPanel = new JPanel();
1033 JButton fetchDAS = new JButton();
1035 JButton saveDAS = new JButton();
1037 JButton cancelDAS = new JButton();
1039 JButton optimizeOrder = new JButton();
1041 JButton sortByScore = new JButton();
1043 JButton sortByDens = new JButton();
1045 JButton help = new JButton();
1047 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1049 private void jbInit() throws Exception
1051 this.setLayout(borderLayout1);
1052 settingsPane.setLayout(borderLayout2);
1053 dasSettingsPane.setLayout(borderLayout3);
1054 bigPanel.setLayout(borderLayout4);
1055 invert.setFont(JvSwingUtils.getLabelFont());
1056 invert.setText(MessageManager.getString("label.invert_selection"));
1057 invert.addActionListener(new ActionListener()
1060 public void actionPerformed(ActionEvent e)
1065 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1066 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1067 optimizeOrder.addActionListener(new ActionListener()
1070 public void actionPerformed(ActionEvent e)
1075 sortByScore.setFont(JvSwingUtils.getLabelFont());
1077 .setText(MessageManager.getString("label.seq_sort_by_score"));
1078 sortByScore.addActionListener(new ActionListener()
1081 public void actionPerformed(ActionEvent e)
1083 af.avc.sortAlignmentByFeatureScore(null);
1086 sortByDens.setFont(JvSwingUtils.getLabelFont());
1087 sortByDens.setText(MessageManager
1088 .getString("label.sequence_sort_by_density"));
1089 sortByDens.addActionListener(new ActionListener()
1092 public void actionPerformed(ActionEvent e)
1094 af.avc.sortAlignmentByFeatureDensity(null);
1097 help.setFont(JvSwingUtils.getLabelFont());
1098 help.setText(MessageManager.getString("action.help"));
1099 help.addActionListener(new ActionListener()
1102 public void actionPerformed(ActionEvent e)
1106 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1107 } catch (HelpSetException e1)
1109 e1.printStackTrace();
1113 help.setFont(JvSwingUtils.getLabelFont());
1114 help.setText(MessageManager.getString("action.help"));
1115 help.addActionListener(new ActionListener()
1118 public void actionPerformed(ActionEvent e)
1122 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1123 } catch (HelpSetException e1)
1125 e1.printStackTrace();
1129 cancel.setFont(JvSwingUtils.getLabelFont());
1130 cancel.setText(MessageManager.getString("action.cancel"));
1131 cancel.addActionListener(new ActionListener()
1134 public void actionPerformed(ActionEvent e)
1136 fr.setTransparency(originalTransparency);
1137 updateFeatureRenderer(originalData);
1141 ok.setFont(JvSwingUtils.getLabelFont());
1142 ok.setText(MessageManager.getString("action.ok"));
1143 ok.addActionListener(new ActionListener()
1146 public void actionPerformed(ActionEvent e)
1151 loadColours.setFont(JvSwingUtils.getLabelFont());
1152 loadColours.setText(MessageManager.getString("label.load_colours"));
1153 loadColours.addActionListener(new ActionListener()
1156 public void actionPerformed(ActionEvent e)
1161 saveColours.setFont(JvSwingUtils.getLabelFont());
1162 saveColours.setText(MessageManager.getString("label.save_colours"));
1163 saveColours.addActionListener(new ActionListener()
1166 public void actionPerformed(ActionEvent e)
1171 transparency.addChangeListener(new ChangeListener()
1174 public void stateChanged(ChangeEvent evt)
1176 fr.setTransparency((100 - transparency.getValue()) / 100f);
1177 af.alignPanel.paintAlignment(true);
1181 transparency.setMaximum(70);
1182 transparency.setToolTipText(MessageManager
1183 .getString("label.transparency_tip"));
1184 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1185 fetchDAS.addActionListener(new ActionListener()
1188 public void actionPerformed(ActionEvent e)
1190 fetchDAS_actionPerformed(e);
1193 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1194 saveDAS.addActionListener(new ActionListener()
1197 public void actionPerformed(ActionEvent e)
1199 saveDAS_actionPerformed(e);
1202 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1203 dasSettingsPane.setBorder(null);
1204 cancelDAS.setEnabled(false);
1205 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1206 cancelDAS.addActionListener(new ActionListener()
1209 public void actionPerformed(ActionEvent e)
1211 cancelDAS_actionPerformed(e);
1214 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1215 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1217 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1219 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1220 transbuttons.add(optimizeOrder);
1221 transbuttons.add(invert);
1222 transbuttons.add(sortByScore);
1223 transbuttons.add(sortByDens);
1224 transbuttons.add(help);
1225 JPanel sliderPanel = new JPanel();
1226 sliderPanel.add(transparency);
1227 transPanel.add(transparency);
1228 transPanel.add(transbuttons);
1229 buttonPanel.add(ok);
1230 buttonPanel.add(cancel);
1231 buttonPanel.add(loadColours);
1232 buttonPanel.add(saveColours);
1233 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1234 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1235 dasButtonPanel.add(fetchDAS);
1236 dasButtonPanel.add(cancelDAS);
1237 dasButtonPanel.add(saveDAS);
1238 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1239 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1242 public void fetchDAS_actionPerformed(ActionEvent e)
1244 fetchDAS.setEnabled(false);
1245 cancelDAS.setEnabled(true);
1246 dassourceBrowser.setGuiEnabled(false);
1247 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1248 .getSelectedSources();
1249 doDasFeatureFetch(selectedSources, true, true);
1253 * get the features from selectedSources for all or the current selection
1255 * @param selectedSources
1256 * @param checkDbRefs
1257 * @param promptFetchDbRefs
1259 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1260 boolean checkDbRefs, boolean promptFetchDbRefs)
1262 SequenceI[] dataset, seqs;
1264 AlignmentViewport vp = af.getViewport();
1265 if (vp.getSelectionGroup() != null
1266 && vp.getSelectionGroup().getSize() > 0)
1268 iSize = vp.getSelectionGroup().getSize();
1269 dataset = new SequenceI[iSize];
1270 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1274 iSize = vp.getAlignment().getHeight();
1275 seqs = vp.getAlignment().getSequencesArray();
1278 dataset = new SequenceI[iSize];
1279 for (int i = 0; i < iSize; i++)
1281 dataset[i] = seqs[i].getDatasetSequence();
1284 cancelDAS.setEnabled(true);
1285 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1286 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1287 af.getViewport().setShowSequenceFeatures(true);
1288 af.showSeqFeatures.setSelected(true);
1292 * blocking call to initialise the das source browser
1294 public void initDasSources()
1296 dassourceBrowser.initDasSources();
1300 * examine the current list of das sources and return any matching the given
1301 * nicknames in sources
1304 * Vector of Strings to resolve to DAS source nicknames.
1305 * @return sources that are present in source list.
1307 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1309 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1313 * get currently selected das sources. ensure you have called initDasSources
1314 * before calling this.
1316 * @return vector of selected das source nicknames
1318 public Vector<jalviewSourceI> getSelectedSources()
1320 return dassourceBrowser.getSelectedSources();
1324 * properly initialise DAS fetcher and then initiate a new thread to fetch
1325 * features from the named sources (rather than any turned on by default)
1329 * if true then runs in same thread, otherwise passes to the Swing
1332 public void fetchDasFeatures(Vector<String> sources, boolean block)
1335 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1336 .resolveSourceNicknames(sources);
1337 if (resolved.size() == 0)
1339 resolved = dassourceBrowser.getSelectedSources();
1341 if (resolved.size() > 0)
1343 final List<jalviewSourceI> dassources = resolved;
1344 fetchDAS.setEnabled(false);
1345 // cancelDAS.setEnabled(true); doDasFetch does this.
1346 Runnable fetcher = new Runnable()
1352 doDasFeatureFetch(dassources, true, false);
1362 SwingUtilities.invokeLater(fetcher);
1367 public void saveDAS_actionPerformed(ActionEvent e)
1370 .saveProperties(jalview.bin.Cache.applicationProperties);
1373 public void complete()
1375 fetchDAS.setEnabled(true);
1376 cancelDAS.setEnabled(false);
1377 dassourceBrowser.setGuiEnabled(true);
1381 public void cancelDAS_actionPerformed(ActionEvent e)
1383 if (dasFeatureFetcher != null)
1385 dasFeatureFetcher.cancel();
1390 public void noDasSourceActive()
1394 .showInternalConfirmDialog(
1397 .getString("label.no_das_sources_selected_warn"),
1399 .getString("label.no_das_sources_selected_title"),
1400 JOptionPane.DEFAULT_OPTION,
1401 JOptionPane.INFORMATION_MESSAGE);
1404 // ///////////////////////////////////////////////////////////////////////
1405 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1406 // ///////////////////////////////////////////////////////////////////////
1407 class FeatureTableModel extends AbstractTableModel
1409 FeatureTableModel(Object[][] data)
1414 private String[] columnNames = {
1415 MessageManager.getString("label.feature_type"),
1416 MessageManager.getString("action.colour"),
1417 MessageManager.getString("label.display") };
1419 private Object[][] data;
1421 public Object[][] getData()
1426 public void setData(Object[][] data)
1432 public int getColumnCount()
1434 return columnNames.length;
1437 public Object[] getRow(int row)
1443 public int getRowCount()
1449 public String getColumnName(int col)
1451 return columnNames[col];
1455 public Object getValueAt(int row, int col)
1457 return data[row][col];
1461 public Class getColumnClass(int c)
1463 return getValueAt(0, c).getClass();
1467 public boolean isCellEditable(int row, int col)
1469 return col == 0 ? false : true;
1473 public void setValueAt(Object value, int row, int col)
1475 data[row][col] = value;
1476 fireTableCellUpdated(row, col);
1477 updateFeatureRenderer(data);
1482 class ColorRenderer extends JLabel implements TableCellRenderer
1484 javax.swing.border.Border unselectedBorder = null;
1486 javax.swing.border.Border selectedBorder = null;
1488 final String baseTT = "Click to edit, right/apple click for menu.";
1490 public ColorRenderer()
1492 setOpaque(true); // MUST do this for background to show up.
1493 setHorizontalTextPosition(SwingConstants.CENTER);
1494 setVerticalTextPosition(SwingConstants.CENTER);
1498 public Component getTableCellRendererComponent(JTable tbl,
1499 Object color, boolean isSelected, boolean hasFocus, int row,
1502 FeatureColourI cellColour = (FeatureColourI) color;
1503 // JLabel comp = new JLabel();
1507 // setBounds(getBounds());
1509 setToolTipText(baseTT);
1510 setBackground(tbl.getBackground());
1511 if (!cellColour.isSimpleColour())
1513 Rectangle cr = tbl.getCellRect(row, column, false);
1514 FeatureSettings.renderGraduatedColor(this, cellColour,
1515 (int) cr.getWidth(), (int) cr.getHeight());
1522 newColor = cellColour.getColour();
1523 setBackground(newColor);
1527 if (selectedBorder == null)
1529 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1530 tbl.getSelectionBackground());
1532 setBorder(selectedBorder);
1536 if (unselectedBorder == null)
1538 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1539 tbl.getBackground());
1541 setBorder(unselectedBorder);
1549 * update comp using rendering settings from gcol
1554 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1556 int w = comp.getWidth(), h = comp.getHeight();
1559 w = (int) comp.getPreferredSize().getWidth();
1560 h = (int) comp.getPreferredSize().getHeight();
1567 renderGraduatedColor(comp, gcol, w, h);
1570 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1573 boolean thr = false;
1576 if (gcol.isAboveThreshold())
1580 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1582 if (gcol.isBelowThreshold())
1586 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1588 if (gcol.isColourByLabel())
1590 tt = "Coloured by label text. " + tt;
1600 Color newColor = gcol.getMaxColour();
1601 comp.setBackground(newColor);
1602 // System.err.println("Width is " + w / 2);
1603 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1604 comp.setIcon(ficon);
1605 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1606 // + newColor.getGreen() + ", " + newColor.getBlue()
1607 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1608 // + ", " + minCol.getBlue() + ")");
1610 comp.setHorizontalAlignment(SwingConstants.CENTER);
1612 if (tt.length() > 0)
1614 if (comp.getToolTipText() == null)
1616 comp.setToolTipText(tt);
1620 comp.setToolTipText(tt + " " + comp.getToolTipText());
1626 class FeatureIcon implements Icon
1628 FeatureColourI gcol;
1632 boolean midspace = false;
1634 int width = 50, height = 20;
1636 int s1, e1; // start and end of midpoint band for thresholded symbol
1638 Color mpcolour = Color.white;
1640 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1660 public int getIconWidth()
1666 public int getIconHeight()
1672 public void paintIcon(Component c, Graphics g, int x, int y)
1675 if (gcol.isColourByLabel())
1678 g.fillRect(0, 0, width, height);
1679 // need an icon here.
1680 g.setColor(gcol.getMaxColour());
1682 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1684 // g.setFont(g.getFont().deriveFont(
1685 // AffineTransform.getScaleInstance(
1686 // width/g.getFontMetrics().stringWidth("Label"),
1687 // height/g.getFontMetrics().getHeight())));
1689 g.drawString(MessageManager.getString("label.label"), 0, 0);
1694 Color minCol = gcol.getMinColour();
1696 g.fillRect(0, 0, s1, height);
1699 g.setColor(Color.white);
1700 g.fillRect(s1, 0, e1 - s1, height);
1702 g.setColor(gcol.getMaxColour());
1703 g.fillRect(0, e1, width - e1, height);
1708 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1713 FeatureColourI currentColor;
1715 FeatureColourChooser chooser;
1721 JColorChooser colorChooser;
1725 protected static final String EDIT = "edit";
1727 int selectedRow = 0;
1729 public ColorEditor(FeatureSettings me)
1732 // Set up the editor (from the table's point of view),
1733 // which is a button.
1734 // This button brings up the color chooser dialog,
1735 // which is the editor from the user's point of view.
1736 button = new JButton();
1737 button.setActionCommand(EDIT);
1738 button.addActionListener(this);
1739 button.setBorderPainted(false);
1740 // Set up the dialog that the button brings up.
1741 colorChooser = new JColorChooser();
1742 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1743 colorChooser, this, // OK button handler
1744 null); // no CANCEL button handler
1748 * Handles events from the editor button and from the dialog's OK button.
1751 public void actionPerformed(ActionEvent e)
1754 if (EDIT.equals(e.getActionCommand()))
1756 // The user has clicked the cell, so
1757 // bring up the dialog.
1758 if (currentColor.isSimpleColour())
1760 // bring up simple color chooser
1761 button.setBackground(currentColor.getColour());
1762 colorChooser.setColor(currentColor.getColour());
1763 dialog.setVisible(true);
1767 // bring up graduated chooser.
1768 chooser = new FeatureColourChooser(me.fr, type);
1769 chooser.setRequestFocusEnabled(true);
1770 chooser.requestFocus();
1771 chooser.addActionListener(this);
1773 // Make the renderer reappear.
1774 fireEditingStopped();
1778 { // User pressed dialog's "OK" button.
1779 if (currentColor.isSimpleColour())
1781 currentColor = new FeatureColour(colorChooser.getColor());
1785 currentColor = chooser.getLastColour();
1787 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1788 fireEditingStopped();
1789 me.table.validate();
1793 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1795 public Object getCellEditorValue()
1797 return currentColor;
1800 // Implement the one method defined by TableCellEditor.
1802 public Component getTableCellEditorComponent(JTable table, Object value,
1803 boolean isSelected, int row, int column)
1805 currentColor = (FeatureColourI) value;
1806 this.selectedRow = row;
1807 type = me.table.getValueAt(row, 0).toString();
1808 button.setOpaque(true);
1809 button.setBackground(me.getBackground());
1810 if (!currentColor.isSimpleColour())
1812 JLabel btn = new JLabel();
1813 btn.setSize(button.getSize());
1814 FeatureSettings.renderGraduatedColor(btn, currentColor);
1815 button.setBackground(btn.getBackground());
1816 button.setIcon(btn.getIcon());
1817 button.setText(btn.getText());
1822 button.setIcon(null);
1823 button.setBackground(currentColor.getColour());