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.Colour;
32 import jalview.schemes.FeatureColour;
33 import jalview.util.ColorUtils;
34 import jalview.util.Format;
35 import jalview.util.MessageManager;
36 import jalview.util.Platform;
37 import jalview.util.QuickSort;
38 import jalview.viewmodel.AlignmentViewport;
39 import jalview.ws.dbsources.das.api.jalviewSourceI;
41 import java.awt.BorderLayout;
42 import java.awt.Color;
43 import java.awt.Component;
45 import java.awt.Graphics;
46 import java.awt.GridLayout;
47 import java.awt.Rectangle;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ActionListener;
50 import java.awt.event.ItemEvent;
51 import java.awt.event.ItemListener;
52 import java.awt.event.MouseAdapter;
53 import java.awt.event.MouseEvent;
54 import java.awt.event.MouseMotionAdapter;
55 import java.beans.PropertyChangeEvent;
56 import java.beans.PropertyChangeListener;
58 import java.io.FileInputStream;
59 import java.io.FileOutputStream;
60 import java.io.InputStreamReader;
61 import java.io.OutputStreamWriter;
62 import java.io.PrintWriter;
63 import java.util.Arrays;
64 import java.util.Hashtable;
65 import java.util.Iterator;
66 import java.util.List;
69 import java.util.Vector;
71 import javax.help.HelpSetException;
72 import javax.swing.AbstractCellEditor;
73 import javax.swing.BorderFactory;
74 import javax.swing.Icon;
75 import javax.swing.JButton;
76 import javax.swing.JCheckBox;
77 import javax.swing.JCheckBoxMenuItem;
78 import javax.swing.JColorChooser;
79 import javax.swing.JDialog;
80 import javax.swing.JInternalFrame;
81 import javax.swing.JLabel;
82 import javax.swing.JLayeredPane;
83 import javax.swing.JMenuItem;
84 import javax.swing.JOptionPane;
85 import javax.swing.JPanel;
86 import javax.swing.JPopupMenu;
87 import javax.swing.JScrollPane;
88 import javax.swing.JSlider;
89 import javax.swing.JTabbedPane;
90 import javax.swing.JTable;
91 import javax.swing.ListSelectionModel;
92 import javax.swing.SwingConstants;
93 import javax.swing.SwingUtilities;
94 import javax.swing.event.ChangeEvent;
95 import javax.swing.event.ChangeListener;
96 import javax.swing.table.AbstractTableModel;
97 import javax.swing.table.TableCellEditor;
98 import javax.swing.table.TableCellRenderer;
100 public class FeatureSettings extends JPanel implements
101 FeatureSettingsControllerI
103 DasSourceBrowser dassourceBrowser;
105 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
107 JPanel settingsPane = new JPanel();
109 JPanel dasSettingsPane = new JPanel();
111 final FeatureRenderer fr;
113 public final AlignFrame af;
115 Object[][] originalData;
117 private float originalTransparency;
119 final JInternalFrame frame;
121 JScrollPane scrollPane = new JScrollPane();
127 JSlider transparency = new JSlider();
129 JPanel transPanel = new JPanel(new GridLayout(1, 2));
131 public FeatureSettings(AlignFrame af)
134 fr = af.getFeatureRenderer();
135 // allow transparency to be recovered
136 transparency.setMaximum(100 - (int) ((originalTransparency = fr
137 .getTransparency()) * 100));
142 } catch (Exception ex)
144 ex.printStackTrace();
150 public String getToolTipText(MouseEvent e)
152 if (table.columnAtPoint(e.getPoint()) == 0)
155 * Tooltip for feature name only
157 return JvSwingUtils.wrapTooltip(true, MessageManager
158 .getString("label.feature_settings_click_drag"));
163 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
164 table.setFont(new Font("Verdana", Font.PLAIN, 12));
165 table.setDefaultRenderer(Color.class, new ColorRenderer());
167 table.setDefaultEditor(Color.class, new ColorEditor(this));
169 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
170 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
171 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
173 table.addMouseListener(new MouseAdapter()
176 public void mousePressed(MouseEvent evt)
178 selectedRow = table.rowAtPoint(evt.getPoint());
179 if (evt.isPopupTrigger())
181 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
182 table.getValueAt(selectedRow, 1), fr.getMinMax(),
183 evt.getX(), evt.getY());
185 else if (evt.getClickCount() == 2)
187 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
188 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
190 (String) table.getValueAt(selectedRow, 0));
194 // isPopupTrigger fires on mouseReleased on Mac
196 public void mouseReleased(MouseEvent evt)
198 selectedRow = table.rowAtPoint(evt.getPoint());
199 if (evt.isPopupTrigger())
201 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
202 table.getValueAt(selectedRow, 1), fr.getMinMax(),
203 evt.getX(), evt.getY());
208 table.addMouseMotionListener(new MouseMotionAdapter()
211 public void mouseDragged(MouseEvent evt)
213 int newRow = table.rowAtPoint(evt.getPoint());
214 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
216 Object[][] data = ((FeatureTableModel) table.getModel())
218 Object[] temp = data[selectedRow];
219 data[selectedRow] = data[newRow];
221 updateFeatureRenderer(data);
223 selectedRow = newRow;
227 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
228 // MessageManager.getString("label.feature_settings_click_drag")));
229 scrollPane.setViewportView(table);
231 dassourceBrowser = new DasSourceBrowser(this);
232 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
234 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
236 fr.findAllFeatures(true); // display everything!
239 discoverAllFeatureData();
240 final PropertyChangeListener change;
241 final FeatureSettings fs = this;
242 fr.addPropertyChangeListener(change = new PropertyChangeListener()
245 public void propertyChange(PropertyChangeEvent evt)
247 if (!fs.resettingTable && !fs.handlingUpdate)
249 fs.handlingUpdate = true;
250 fs.resetTable(null); // new groups may be added with new seuqence
251 // feature types only
252 fs.handlingUpdate = false;
258 frame = new JInternalFrame();
259 frame.setContentPane(this);
260 if (Platform.isAMac())
262 Desktop.addInternalFrame(frame,
263 MessageManager.getString("label.sequence_feature_settings"),
268 Desktop.addInternalFrame(frame,
269 MessageManager.getString("label.sequence_feature_settings"),
273 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
276 public void internalFrameClosed(
277 javax.swing.event.InternalFrameEvent evt)
279 fr.removePropertyChangeListener(change);
280 dassourceBrowser.fs = null;
283 frame.setLayer(JLayeredPane.PALETTE_LAYER);
286 protected void popupSort(final int selectedRow, final String type,
287 final Object typeCol, final Map<String, float[][]> minmax, int x,
290 final FeatureColourI featureColour = (FeatureColourI) typeCol;
292 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
293 "label.settings_for_param", new String[] { type }));
294 JMenuItem scr = new JMenuItem(
295 MessageManager.getString("label.sort_by_score"));
297 final FeatureSettings me = this;
298 scr.addActionListener(new ActionListener()
302 public void actionPerformed(ActionEvent e)
304 me.af.avc.sortAlignmentByFeatureScore(Arrays
305 .asList(new String[] { type }));
309 JMenuItem dens = new JMenuItem(
310 MessageManager.getString("label.sort_by_density"));
311 dens.addActionListener(new ActionListener()
315 public void actionPerformed(ActionEvent e)
317 me.af.avc.sortAlignmentByFeatureDensity(Arrays
318 .asList(new String[] { type }));
325 final float[][] typeMinMax = minmax.get(type);
327 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
328 * this is broken at the moment and isn't that useful anyway!
329 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
332 * public void actionPerformed(ActionEvent e) {
333 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
334 * null); } else { minmax.put(type, typeMinMax); } }
340 if (typeMinMax != null && typeMinMax[0] != null)
342 // if (table.getValueAt(row, column));
343 // graduated colourschemes for those where minmax exists for the
344 // positional features
345 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
347 mxcol.setSelected(!featureColour.isSimpleColour());
349 mxcol.addActionListener(new ActionListener()
351 JColorChooser colorChooser;
354 public void actionPerformed(ActionEvent e)
356 if (e.getSource() == mxcol)
358 if (featureColour.isSimpleColour())
360 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
362 fc.addActionListener(this);
366 // bring up simple color chooser
367 colorChooser = new JColorChooser();
368 JDialog dialog = JColorChooser.createDialog(me,
369 "Select new Colour", true, // modal
370 colorChooser, this, // OK button handler
371 null); // no CANCEL button handler
372 colorChooser.setColor(ColorUtils.getColor(featureColour
374 dialog.setVisible(true);
379 if (e.getSource() instanceof FeatureColourChooser)
381 FeatureColourChooser fc = (FeatureColourChooser) e
383 table.setValueAt(fc.getLastColour(), selectedRow, 1);
388 // probably the color chooser!
389 table.setValueAt(colorChooser.getColor(), selectedRow, 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()
406 public void actionPerformed(ActionEvent arg0)
408 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
412 JMenuItem clearCols = new JMenuItem(
413 MessageManager.getString("label.select_columns_not_containing"));
414 clearCols.addActionListener(new ActionListener()
417 public void actionPerformed(ActionEvent arg0)
419 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
423 JMenuItem hideCols = new JMenuItem(
424 MessageManager.getString("label.hide_columns_containing"));
425 hideCols.addActionListener(new ActionListener()
428 public void actionPerformed(ActionEvent arg0)
430 fr.ap.alignFrame.hideFeatureColumns(type, true);
433 JMenuItem hideOtherCols = new JMenuItem(
434 MessageManager.getString("label.hide_columns_not_containing"));
435 hideOtherCols.addActionListener(new ActionListener()
438 public void actionPerformed(ActionEvent arg0)
440 fr.ap.alignFrame.hideFeatureColumns(type, false);
446 men.add(hideOtherCols);
447 men.show(table, x, y);
451 * true when Feature Settings are updating from feature renderer
453 private boolean handlingUpdate = false;
456 * contains a float[3] for each feature type string. created by setTableData
458 Map<String, float[]> typeWidth = null;
461 synchronized public void discoverAllFeatureData()
463 Vector<String> allFeatures = new Vector<String>();
464 Vector<String> allGroups = new Vector<String>();
465 SequenceFeature[] tmpfeatures;
467 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
469 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
470 .getSequenceFeatures();
471 if (tmpfeatures == null)
477 while (index < tmpfeatures.length)
479 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
485 if (tmpfeatures[index].getFeatureGroup() != null)
487 group = tmpfeatures[index].featureGroup;
488 if (!allGroups.contains(group))
490 allGroups.addElement(group);
491 checkGroupState(group);
495 if (!allFeatures.contains(tmpfeatures[index].getType()))
497 allFeatures.addElement(tmpfeatures[index].getType());
509 * Synchronise gui group list and check visibility of group
512 * @return true if group is visible
514 private boolean checkGroupState(String group)
516 boolean visible = fr.checkGroupVisibility(group, true);
518 if (groupPanel == null)
520 groupPanel = new JPanel();
523 boolean alreadyAdded = false;
524 for (int g = 0; g < groupPanel.getComponentCount(); g++)
526 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
529 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
539 final String grp = group;
540 final JCheckBox check = new JCheckBox(group, visible);
541 check.setFont(new Font("Serif", Font.BOLD, 12));
542 check.addItemListener(new ItemListener()
545 public void itemStateChanged(ItemEvent evt)
547 fr.setGroupVisibility(check.getText(), check.isSelected());
548 af.alignPanel.getSeqPanel().seqCanvas.repaint();
549 if (af.alignPanel.overviewPanel != null)
551 af.alignPanel.overviewPanel.updateOverviewImage();
554 resetTable(new String[] { grp });
557 groupPanel.add(check);
561 boolean resettingTable = false;
563 synchronized void resetTable(String[] groupChanged)
565 if (resettingTable == true)
569 resettingTable = true;
570 typeWidth = new Hashtable<String, float[]>();
571 // TODO: change avWidth calculation to 'per-sequence' average and use long
573 float[] avWidth = null;
574 SequenceFeature[] tmpfeatures;
575 String group = null, type;
576 Vector<String> visibleChecks = new Vector<String>();
578 // Find out which features should be visible depending on which groups
579 // are selected / deselected
580 // and recompute average width ordering
581 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
584 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
585 .getSequenceFeatures();
586 if (tmpfeatures == null)
592 while (index < tmpfeatures.length)
594 group = tmpfeatures[index].featureGroup;
596 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
602 if (group == null || checkGroupState(group))
604 type = tmpfeatures[index].getType();
605 if (!visibleChecks.contains(type))
607 visibleChecks.addElement(type);
610 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
612 typeWidth.put(tmpfeatures[index].getType(),
613 avWidth = new float[3]);
617 avWidth = typeWidth.get(tmpfeatures[index].getType());
620 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
622 avWidth[1] += 1 + tmpfeatures[index].getBegin()
623 - tmpfeatures[index].getEnd();
627 avWidth[1] += 1 + tmpfeatures[index].getEnd()
628 - tmpfeatures[index].getBegin();
634 int fSize = visibleChecks.size();
635 Object[][] data = new Object[fSize][3];
638 if (fr.hasRenderOrder())
642 fr.findAllFeatures(groupChanged != null); // prod to update
643 // colourschemes. but don't
645 // First add the checks in the previous render order,
646 // in case the window has been closed and reopened
648 List<String> frl = fr.getRenderOrder();
649 for (int ro = frl.size() - 1; ro > -1; ro--)
653 if (!visibleChecks.contains(type))
658 data[dataIndex][0] = type;
659 data[dataIndex][1] = fr.getFeatureStyle(type);
660 data[dataIndex][2] = new Boolean(af.getViewport()
661 .getFeaturesDisplayed().isVisible(type));
663 visibleChecks.removeElement(type);
667 fSize = visibleChecks.size();
668 for (int i = 0; i < fSize; i++)
670 // These must be extra features belonging to the group
671 // which was just selected
672 type = visibleChecks.elementAt(i).toString();
673 data[dataIndex][0] = type;
675 data[dataIndex][1] = fr.getFeatureStyle(type);
676 if (data[dataIndex][1] == null)
678 // "Colour has been updated in another view!!"
679 fr.clearRenderOrder();
683 data[dataIndex][2] = new Boolean(true);
687 if (originalData == null)
689 originalData = new Object[data.length][3];
690 for (int i = 0; i < data.length; i++)
692 System.arraycopy(data[i], 0, originalData[i], 0, 3);
696 table.setModel(new FeatureTableModel(data));
697 table.getColumnModel().getColumn(0).setPreferredWidth(200);
699 if (groupPanel != null)
701 groupPanel.setLayout(new GridLayout(
702 fr.getFeatureGroupsSize() / 4 + 1, 4));
704 groupPanel.validate();
705 bigPanel.add(groupPanel, BorderLayout.NORTH);
708 updateFeatureRenderer(data, groupChanged != null);
709 resettingTable = false;
713 * reorder data based on the featureRenderers global priority list.
717 private void ensureOrder(Object[][] data)
719 boolean sort = false;
720 float[] order = new float[data.length];
721 for (int i = 0; i < order.length; i++)
723 order[i] = fr.getOrder(data[i][0].toString());
726 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
730 sort = sort || order[i - 1] > order[i];
735 jalview.util.QuickSort.sort(order, data);
741 JalviewFileChooser chooser = new JalviewFileChooser(
742 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
743 new String[] { "fc" },
744 new String[] { "Sequence Feature Colours" },
745 "Sequence Feature Colours");
746 chooser.setFileView(new jalview.io.JalviewFileView());
747 chooser.setDialogTitle(MessageManager
748 .getString("label.load_feature_colours"));
749 chooser.setToolTipText(MessageManager.getString("action.load"));
751 int value = chooser.showOpenDialog(this);
753 if (value == JalviewFileChooser.APPROVE_OPTION)
755 File file = chooser.getSelectedFile();
759 InputStreamReader in = new InputStreamReader(new FileInputStream(
762 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
764 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
767 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
770 Color mincol = null, maxcol = null;
773 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
774 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
776 } catch (Exception e)
778 Cache.log.warn("Couldn't parse out graduated feature color.",
781 FeatureColourI gcol = new FeatureColour(new Colour(mincol),
783 newcol.getMin(), newcol.getMax());
784 if (newcol.hasAutoScale())
786 gcol.setAutoScaled(newcol.getAutoScale());
788 if (newcol.hasColourByLabel())
790 gcol.setColourByLabel(newcol.getColourByLabel());
792 if (newcol.hasThreshold())
794 gcol.setThreshold(newcol.getThreshold());
796 if (newcol.getThreshType().length() > 0)
798 String ttyp = newcol.getThreshType();
799 if (ttyp.equalsIgnoreCase("ABOVE"))
801 gcol.setAboveThreshold(true);
803 if (ttyp.equalsIgnoreCase("BELOW"))
805 gcol.setBelowThreshold(true);
808 fr.setColour(name = newcol.getName(), gcol);
812 Color color = new Color(
813 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
814 fr.setColour(name = jucs.getColour(i).getName(),
815 new FeatureColour(new Colour(color)));
817 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
822 Object[][] data = ((FeatureTableModel) table.getModel())
825 updateFeatureRenderer(data, false);
828 } catch (Exception ex)
830 System.out.println("Error loading User Colour File\n" + ex);
837 JalviewFileChooser chooser = new JalviewFileChooser(
838 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
839 new String[] { "fc" },
840 new String[] { "Sequence Feature Colours" },
841 "Sequence Feature Colours");
842 chooser.setFileView(new jalview.io.JalviewFileView());
843 chooser.setDialogTitle(MessageManager
844 .getString("label.save_feature_colours"));
845 chooser.setToolTipText(MessageManager.getString("action.save"));
847 int value = chooser.showSaveDialog(this);
849 if (value == JalviewFileChooser.APPROVE_OPTION)
851 String choice = chooser.getSelectedFile().getPath();
852 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
853 ucs.setSchemeName("Sequence Features");
856 PrintWriter out = new PrintWriter(new OutputStreamWriter(
857 new FileOutputStream(choice), "UTF-8"));
859 Set<String> fr_colours = fr.getAllFeatureColours();
860 Iterator<String> e = fr_colours.iterator();
861 float[] sortOrder = new float[fr_colours.size()];
862 String[] sortTypes = new String[fr_colours.size()];
866 sortTypes[i] = e.next();
867 sortOrder[i] = fr.getOrder(sortTypes[i]);
870 QuickSort.sort(sortOrder, sortTypes);
872 for (i = 0; i < sortTypes.length; i++)
874 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
875 col.setName(sortTypes[i]);
876 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
877 if (fcol.isSimpleColour())
879 col.setRGB(Format.getHexString(fcol.getColour()));
883 col.setRGB(Format.getHexString(fcol.getMaxColour()));
884 col.setMin(fcol.getMin());
885 col.setMax(fcol.getMax());
886 col.setMinRGB(jalview.util.Format.getHexString(fcol
888 col.setAutoScale(fcol.isAutoScaled());
889 col.setThreshold(fcol.getThreshold());
890 col.setColourByLabel(fcol.isColourByLabel());
891 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
892 .isBelowThreshold() ? "BELOW" : "NONE"));
898 } catch (Exception ex)
900 ex.printStackTrace();
905 public void invertSelection()
907 for (int i = 0; i < table.getRowCount(); i++)
909 Boolean value = (Boolean) table.getValueAt(i, 2);
911 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
915 public void orderByAvWidth()
917 if (table == null || table.getModel() == null)
921 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
922 float[] width = new float[data.length];
926 for (int i = 0; i < data.length; i++)
928 awidth = typeWidth.get(data[i][0]);
931 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
932 // weight - but have to make per
933 // sequence, too (awidth[2])
934 // if (width[i]==1) // hack to distinguish single width sequences.
946 boolean sort = false;
947 for (int i = 0; i < width.length; i++)
949 // awidth = (float[]) typeWidth.get(data[i][0]);
952 width[i] = fr.getOrder(data[i][0].toString());
955 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
960 width[i] /= max; // normalize
961 fr.setOrder(data[i][0].toString(), width[i]); // store for later
965 sort = sort || width[i - 1] > width[i];
970 jalview.util.QuickSort.sort(width, data);
971 // update global priority order
974 updateFeatureRenderer(data, false);
982 frame.setClosed(true);
983 } catch (Exception exe)
989 public void updateFeatureRenderer(Object[][] data)
991 updateFeatureRenderer(data, true);
995 * Update the priority order of features; only repaint if this changed the
996 * order of visible features
1001 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1003 if (fr.setFeaturePriority(data, visibleNew))
1005 af.alignPanel.paintAlignment(true);
1009 int selectedRow = -1;
1011 JTabbedPane tabbedPane = new JTabbedPane();
1013 BorderLayout borderLayout1 = new BorderLayout();
1015 BorderLayout borderLayout2 = new BorderLayout();
1017 BorderLayout borderLayout3 = new BorderLayout();
1019 JPanel bigPanel = new JPanel();
1021 BorderLayout borderLayout4 = new BorderLayout();
1023 JButton invert = new JButton();
1025 JPanel buttonPanel = new JPanel();
1027 JButton cancel = new JButton();
1029 JButton ok = new JButton();
1031 JButton loadColours = new JButton();
1033 JButton saveColours = new JButton();
1035 JPanel dasButtonPanel = new JPanel();
1037 JButton fetchDAS = new JButton();
1039 JButton saveDAS = new JButton();
1041 JButton cancelDAS = new JButton();
1043 JButton optimizeOrder = new JButton();
1045 JButton sortByScore = new JButton();
1047 JButton sortByDens = new JButton();
1049 JButton help = new JButton();
1051 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1053 private void jbInit() throws Exception
1055 this.setLayout(borderLayout1);
1056 settingsPane.setLayout(borderLayout2);
1057 dasSettingsPane.setLayout(borderLayout3);
1058 bigPanel.setLayout(borderLayout4);
1059 invert.setFont(JvSwingUtils.getLabelFont());
1060 invert.setText(MessageManager.getString("label.invert_selection"));
1061 invert.addActionListener(new ActionListener()
1064 public void actionPerformed(ActionEvent e)
1069 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1070 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1071 optimizeOrder.addActionListener(new ActionListener()
1074 public void actionPerformed(ActionEvent e)
1079 sortByScore.setFont(JvSwingUtils.getLabelFont());
1081 .setText(MessageManager.getString("label.seq_sort_by_score"));
1082 sortByScore.addActionListener(new ActionListener()
1085 public void actionPerformed(ActionEvent e)
1087 af.avc.sortAlignmentByFeatureScore(null);
1090 sortByDens.setFont(JvSwingUtils.getLabelFont());
1091 sortByDens.setText(MessageManager
1092 .getString("label.sequence_sort_by_density"));
1093 sortByDens.addActionListener(new ActionListener()
1096 public void actionPerformed(ActionEvent e)
1098 af.avc.sortAlignmentByFeatureDensity(null);
1101 help.setFont(JvSwingUtils.getLabelFont());
1102 help.setText(MessageManager.getString("action.help"));
1103 help.addActionListener(new ActionListener()
1106 public void actionPerformed(ActionEvent e)
1110 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1111 } catch (HelpSetException e1)
1113 e1.printStackTrace();
1117 help.setFont(JvSwingUtils.getLabelFont());
1118 help.setText(MessageManager.getString("action.help"));
1119 help.addActionListener(new ActionListener()
1122 public void actionPerformed(ActionEvent e)
1126 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1127 } catch (HelpSetException e1)
1129 e1.printStackTrace();
1133 cancel.setFont(JvSwingUtils.getLabelFont());
1134 cancel.setText(MessageManager.getString("action.cancel"));
1135 cancel.addActionListener(new ActionListener()
1138 public void actionPerformed(ActionEvent e)
1140 fr.setTransparency(originalTransparency);
1141 updateFeatureRenderer(originalData);
1145 ok.setFont(JvSwingUtils.getLabelFont());
1146 ok.setText(MessageManager.getString("action.ok"));
1147 ok.addActionListener(new ActionListener()
1150 public void actionPerformed(ActionEvent e)
1155 loadColours.setFont(JvSwingUtils.getLabelFont());
1156 loadColours.setText(MessageManager.getString("label.load_colours"));
1157 loadColours.addActionListener(new ActionListener()
1160 public void actionPerformed(ActionEvent e)
1165 saveColours.setFont(JvSwingUtils.getLabelFont());
1166 saveColours.setText(MessageManager.getString("label.save_colours"));
1167 saveColours.addActionListener(new ActionListener()
1170 public void actionPerformed(ActionEvent e)
1175 transparency.addChangeListener(new ChangeListener()
1178 public void stateChanged(ChangeEvent evt)
1180 fr.setTransparency((100 - transparency.getValue()) / 100f);
1181 af.alignPanel.paintAlignment(true);
1185 transparency.setMaximum(70);
1186 transparency.setToolTipText(MessageManager
1187 .getString("label.transparency_tip"));
1188 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1189 fetchDAS.addActionListener(new ActionListener()
1192 public void actionPerformed(ActionEvent e)
1194 fetchDAS_actionPerformed(e);
1197 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1198 saveDAS.addActionListener(new ActionListener()
1201 public void actionPerformed(ActionEvent e)
1203 saveDAS_actionPerformed(e);
1206 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1207 dasSettingsPane.setBorder(null);
1208 cancelDAS.setEnabled(false);
1209 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1210 cancelDAS.addActionListener(new ActionListener()
1213 public void actionPerformed(ActionEvent e)
1215 cancelDAS_actionPerformed(e);
1218 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1219 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1221 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1223 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1224 transbuttons.add(optimizeOrder);
1225 transbuttons.add(invert);
1226 transbuttons.add(sortByScore);
1227 transbuttons.add(sortByDens);
1228 transbuttons.add(help);
1229 JPanel sliderPanel = new JPanel();
1230 sliderPanel.add(transparency);
1231 transPanel.add(transparency);
1232 transPanel.add(transbuttons);
1233 buttonPanel.add(ok);
1234 buttonPanel.add(cancel);
1235 buttonPanel.add(loadColours);
1236 buttonPanel.add(saveColours);
1237 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1238 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1239 dasButtonPanel.add(fetchDAS);
1240 dasButtonPanel.add(cancelDAS);
1241 dasButtonPanel.add(saveDAS);
1242 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1243 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1246 public void fetchDAS_actionPerformed(ActionEvent e)
1248 fetchDAS.setEnabled(false);
1249 cancelDAS.setEnabled(true);
1250 dassourceBrowser.setGuiEnabled(false);
1251 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1252 .getSelectedSources();
1253 doDasFeatureFetch(selectedSources, true, true);
1257 * get the features from selectedSources for all or the current selection
1259 * @param selectedSources
1260 * @param checkDbRefs
1261 * @param promptFetchDbRefs
1263 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1264 boolean checkDbRefs, boolean promptFetchDbRefs)
1266 SequenceI[] dataset, seqs;
1268 AlignmentViewport vp = af.getViewport();
1269 if (vp.getSelectionGroup() != null
1270 && vp.getSelectionGroup().getSize() > 0)
1272 iSize = vp.getSelectionGroup().getSize();
1273 dataset = new SequenceI[iSize];
1274 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1278 iSize = vp.getAlignment().getHeight();
1279 seqs = vp.getAlignment().getSequencesArray();
1282 dataset = new SequenceI[iSize];
1283 for (int i = 0; i < iSize; i++)
1285 dataset[i] = seqs[i].getDatasetSequence();
1288 cancelDAS.setEnabled(true);
1289 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1290 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1291 af.getViewport().setShowSequenceFeatures(true);
1292 af.showSeqFeatures.setSelected(true);
1296 * blocking call to initialise the das source browser
1298 public void initDasSources()
1300 dassourceBrowser.initDasSources();
1304 * examine the current list of das sources and return any matching the given
1305 * nicknames in sources
1308 * Vector of Strings to resolve to DAS source nicknames.
1309 * @return sources that are present in source list.
1311 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1313 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1317 * get currently selected das sources. ensure you have called initDasSources
1318 * before calling this.
1320 * @return vector of selected das source nicknames
1322 public Vector<jalviewSourceI> getSelectedSources()
1324 return dassourceBrowser.getSelectedSources();
1328 * properly initialise DAS fetcher and then initiate a new thread to fetch
1329 * features from the named sources (rather than any turned on by default)
1333 * if true then runs in same thread, otherwise passes to the Swing
1336 public void fetchDasFeatures(Vector<String> sources, boolean block)
1339 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1340 .resolveSourceNicknames(sources);
1341 if (resolved.size() == 0)
1343 resolved = dassourceBrowser.getSelectedSources();
1345 if (resolved.size() > 0)
1347 final List<jalviewSourceI> dassources = resolved;
1348 fetchDAS.setEnabled(false);
1349 // cancelDAS.setEnabled(true); doDasFetch does this.
1350 Runnable fetcher = new Runnable()
1356 doDasFeatureFetch(dassources, true, false);
1366 SwingUtilities.invokeLater(fetcher);
1371 public void saveDAS_actionPerformed(ActionEvent e)
1374 .saveProperties(jalview.bin.Cache.applicationProperties);
1377 public void complete()
1379 fetchDAS.setEnabled(true);
1380 cancelDAS.setEnabled(false);
1381 dassourceBrowser.setGuiEnabled(true);
1385 public void cancelDAS_actionPerformed(ActionEvent e)
1387 if (dasFeatureFetcher != null)
1389 dasFeatureFetcher.cancel();
1394 public void noDasSourceActive()
1398 .showInternalConfirmDialog(
1401 .getString("label.no_das_sources_selected_warn"),
1403 .getString("label.no_das_sources_selected_title"),
1404 JOptionPane.DEFAULT_OPTION,
1405 JOptionPane.INFORMATION_MESSAGE);
1408 // ///////////////////////////////////////////////////////////////////////
1409 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1410 // ///////////////////////////////////////////////////////////////////////
1411 class FeatureTableModel extends AbstractTableModel
1413 FeatureTableModel(Object[][] data)
1418 private String[] columnNames = {
1419 MessageManager.getString("label.feature_type"),
1420 MessageManager.getString("action.colour"),
1421 MessageManager.getString("label.display") };
1423 private Object[][] data;
1425 public Object[][] getData()
1430 public void setData(Object[][] data)
1436 public int getColumnCount()
1438 return columnNames.length;
1441 public Object[] getRow(int row)
1447 public int getRowCount()
1453 public String getColumnName(int col)
1455 return columnNames[col];
1459 public Object getValueAt(int row, int col)
1461 return data[row][col];
1465 public Class getColumnClass(int c)
1467 return getValueAt(0, c).getClass();
1471 public boolean isCellEditable(int row, int col)
1473 return col == 0 ? false : true;
1477 public void setValueAt(Object value, int row, int col)
1479 data[row][col] = value;
1480 fireTableCellUpdated(row, col);
1481 updateFeatureRenderer(data);
1486 class ColorRenderer extends JLabel implements TableCellRenderer
1488 javax.swing.border.Border unselectedBorder = null;
1490 javax.swing.border.Border selectedBorder = null;
1492 final String baseTT = "Click to edit, right/apple click for menu.";
1494 public ColorRenderer()
1496 setOpaque(true); // MUST do this for background to show up.
1497 setHorizontalTextPosition(SwingConstants.CENTER);
1498 setVerticalTextPosition(SwingConstants.CENTER);
1502 public Component getTableCellRendererComponent(JTable tbl,
1503 Object color, boolean isSelected, boolean hasFocus, int row,
1506 FeatureColourI cellColour = (FeatureColourI) color;
1507 // JLabel comp = new JLabel();
1511 // setBounds(getBounds());
1513 setToolTipText(baseTT);
1514 setBackground(tbl.getBackground());
1515 if (!cellColour.isSimpleColour())
1517 Rectangle cr = tbl.getCellRect(row, column, false);
1518 FeatureSettings.renderGraduatedColor(this, cellColour,
1519 (int) cr.getWidth(), (int) cr.getHeight());
1526 newColor = ColorUtils.getColor(cellColour.getColour());
1527 setBackground(newColor);
1528 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1529 // + newColor.getGreen() + ", " + newColor.getBlue());
1533 if (selectedBorder == null)
1535 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1536 tbl.getSelectionBackground());
1538 setBorder(selectedBorder);
1542 if (unselectedBorder == null)
1544 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1545 tbl.getBackground());
1547 setBorder(unselectedBorder);
1555 * update comp using rendering settings from gcol
1560 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1562 int w = comp.getWidth(), h = comp.getHeight();
1565 w = (int) comp.getPreferredSize().getWidth();
1566 h = (int) comp.getPreferredSize().getHeight();
1573 renderGraduatedColor(comp, gcol, w, h);
1576 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1579 boolean thr = false;
1582 if (gcol.isAboveThreshold())
1586 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1588 if (gcol.isBelowThreshold())
1592 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1594 if (gcol.isColourByLabel())
1596 tt = "Coloured by label text. " + tt;
1606 Color newColor = ColorUtils.getColor(gcol.getMaxColour());
1607 comp.setBackground(newColor);
1608 // System.err.println("Width is " + w / 2);
1609 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1610 comp.setIcon(ficon);
1611 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1612 // + newColor.getGreen() + ", " + newColor.getBlue()
1613 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1614 // + ", " + minCol.getBlue() + ")");
1616 comp.setHorizontalAlignment(SwingConstants.CENTER);
1618 if (tt.length() > 0)
1620 if (comp.getToolTipText() == null)
1622 comp.setToolTipText(tt);
1626 comp.setToolTipText(tt + " " + comp.getToolTipText());
1632 class FeatureIcon implements Icon
1634 FeatureColourI gcol;
1638 boolean midspace = false;
1640 int width = 50, height = 20;
1642 int s1, e1; // start and end of midpoint band for thresholded symbol
1644 Color mpcolour = Color.white;
1646 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1666 public int getIconWidth()
1672 public int getIconHeight()
1678 public void paintIcon(Component c, Graphics g, int x, int y)
1681 if (gcol.isColourByLabel())
1684 g.fillRect(0, 0, width, height);
1685 // need an icon here.
1686 g.setColor(ColorUtils.getColor(gcol.getMaxColour()));
1688 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1690 // g.setFont(g.getFont().deriveFont(
1691 // AffineTransform.getScaleInstance(
1692 // width/g.getFontMetrics().stringWidth("Label"),
1693 // height/g.getFontMetrics().getHeight())));
1695 g.drawString(MessageManager.getString("label.label"), 0, 0);
1700 Color minCol = ColorUtils.getColor(gcol.getMinColour());
1702 g.fillRect(0, 0, s1, height);
1705 g.setColor(Color.white);
1706 g.fillRect(s1, 0, e1 - s1, height);
1708 g.setColor(ColorUtils.getColor(gcol.getMaxColour()));
1709 g.fillRect(0, e1, width - e1, height);
1714 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1719 FeatureColourI currentColor;
1721 FeatureColourChooser chooser;
1727 JColorChooser colorChooser;
1731 protected static final String EDIT = "edit";
1733 int selectedRow = 0;
1735 public ColorEditor(FeatureSettings me)
1738 // Set up the editor (from the table's point of view),
1739 // which is a button.
1740 // This button brings up the color chooser dialog,
1741 // which is the editor from the user's point of view.
1742 button = new JButton();
1743 button.setActionCommand(EDIT);
1744 button.addActionListener(this);
1745 button.setBorderPainted(false);
1746 // Set up the dialog that the button brings up.
1747 colorChooser = new JColorChooser();
1748 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1749 colorChooser, this, // OK button handler
1750 null); // no CANCEL button handler
1754 * Handles events from the editor button and from the dialog's OK button.
1757 public void actionPerformed(ActionEvent e)
1760 if (EDIT.equals(e.getActionCommand()))
1762 // The user has clicked the cell, so
1763 // bring up the dialog.
1764 if (currentColor.isSimpleColour())
1766 // bring up simple color chooser
1767 button.setBackground(ColorUtils.getColor(currentColor.getColour()));
1769 .setColor(ColorUtils.getColor(currentColor.getColour()));
1770 dialog.setVisible(true);
1774 // bring up graduated chooser.
1775 chooser = new FeatureColourChooser(me.fr, type);
1776 chooser.setRequestFocusEnabled(true);
1777 chooser.requestFocus();
1778 chooser.addActionListener(this);
1780 // Make the renderer reappear.
1781 fireEditingStopped();
1785 { // User pressed dialog's "OK" button.
1786 if (currentColor.isSimpleColour())
1788 currentColor = new FeatureColour(
1789 new Colour(colorChooser.getColor()));
1793 currentColor = chooser.getLastColour();
1795 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1796 fireEditingStopped();
1797 me.table.validate();
1801 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1803 public Object getCellEditorValue()
1805 return currentColor;
1808 // Implement the one method defined by TableCellEditor.
1810 public Component getTableCellEditorComponent(JTable table, Object value,
1811 boolean isSelected, int row, int column)
1813 currentColor = (FeatureColourI) value;
1814 this.selectedRow = row;
1815 type = me.table.getValueAt(row, 0).toString();
1816 button.setOpaque(true);
1817 button.setBackground(me.getBackground());
1818 if (!currentColor.isSimpleColour())
1820 JLabel btn = new JLabel();
1821 btn.setSize(button.getSize());
1822 FeatureSettings.renderGraduatedColor(btn, currentColor);
1823 button.setBackground(btn.getBackground());
1824 button.setIcon(btn.getIcon());
1825 button.setText(btn.getText());
1830 button.setIcon(null);
1831 button.setBackground(ColorUtils.getColor(currentColor.getColour()));