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!
387 new FeatureColour(colorChooser.getColor()),
390 me.updateFeatureRenderer(
391 ((FeatureTableModel) table.getModel()).getData(),
400 JMenuItem selCols = new JMenuItem(
401 MessageManager.getString("label.select_columns_containing"));
402 selCols.addActionListener(new ActionListener()
405 public void actionPerformed(ActionEvent arg0)
407 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
411 JMenuItem clearCols = new JMenuItem(
412 MessageManager.getString("label.select_columns_not_containing"));
413 clearCols.addActionListener(new ActionListener()
416 public void actionPerformed(ActionEvent arg0)
418 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
422 JMenuItem hideCols = new JMenuItem(
423 MessageManager.getString("label.hide_columns_containing"));
424 hideCols.addActionListener(new ActionListener()
427 public void actionPerformed(ActionEvent arg0)
429 fr.ap.alignFrame.hideFeatureColumns(type, true);
432 JMenuItem hideOtherCols = new JMenuItem(
433 MessageManager.getString("label.hide_columns_not_containing"));
434 hideOtherCols.addActionListener(new ActionListener()
437 public void actionPerformed(ActionEvent arg0)
439 fr.ap.alignFrame.hideFeatureColumns(type, false);
445 men.add(hideOtherCols);
446 men.show(table, x, y);
450 * true when Feature Settings are updating from feature renderer
452 private boolean handlingUpdate = false;
455 * contains a float[3] for each feature type string. created by setTableData
457 Map<String, float[]> typeWidth = null;
460 synchronized public void discoverAllFeatureData()
462 Vector<String> allFeatures = new Vector<String>();
463 Vector<String> allGroups = new Vector<String>();
464 SequenceFeature[] tmpfeatures;
466 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
468 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
469 .getSequenceFeatures();
470 if (tmpfeatures == null)
476 while (index < tmpfeatures.length)
478 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
484 if (tmpfeatures[index].getFeatureGroup() != null)
486 group = tmpfeatures[index].featureGroup;
487 if (!allGroups.contains(group))
489 allGroups.addElement(group);
490 checkGroupState(group);
494 if (!allFeatures.contains(tmpfeatures[index].getType()))
496 allFeatures.addElement(tmpfeatures[index].getType());
508 * Synchronise gui group list and check visibility of group
511 * @return true if group is visible
513 private boolean checkGroupState(String group)
515 boolean visible = fr.checkGroupVisibility(group, true);
517 if (groupPanel == null)
519 groupPanel = new JPanel();
522 boolean alreadyAdded = false;
523 for (int g = 0; g < groupPanel.getComponentCount(); g++)
525 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
528 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
538 final String grp = group;
539 final JCheckBox check = new JCheckBox(group, visible);
540 check.setFont(new Font("Serif", Font.BOLD, 12));
541 check.addItemListener(new ItemListener()
544 public void itemStateChanged(ItemEvent evt)
546 fr.setGroupVisibility(check.getText(), check.isSelected());
547 af.alignPanel.getSeqPanel().seqCanvas.repaint();
548 if (af.alignPanel.overviewPanel != null)
550 af.alignPanel.overviewPanel.updateOverviewImage();
553 resetTable(new String[] { grp });
556 groupPanel.add(check);
560 boolean resettingTable = false;
562 synchronized void resetTable(String[] groupChanged)
564 if (resettingTable == true)
568 resettingTable = true;
569 typeWidth = new Hashtable<String, float[]>();
570 // TODO: change avWidth calculation to 'per-sequence' average and use long
572 float[] avWidth = null;
573 SequenceFeature[] tmpfeatures;
574 String group = null, type;
575 Vector<String> visibleChecks = new Vector<String>();
577 // Find out which features should be visible depending on which groups
578 // are selected / deselected
579 // and recompute average width ordering
580 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
583 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
584 .getSequenceFeatures();
585 if (tmpfeatures == null)
591 while (index < tmpfeatures.length)
593 group = tmpfeatures[index].featureGroup;
595 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
601 if (group == null || checkGroupState(group))
603 type = tmpfeatures[index].getType();
604 if (!visibleChecks.contains(type))
606 visibleChecks.addElement(type);
609 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
611 typeWidth.put(tmpfeatures[index].getType(),
612 avWidth = new float[3]);
616 avWidth = typeWidth.get(tmpfeatures[index].getType());
619 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
621 avWidth[1] += 1 + tmpfeatures[index].getBegin()
622 - tmpfeatures[index].getEnd();
626 avWidth[1] += 1 + tmpfeatures[index].getEnd()
627 - tmpfeatures[index].getBegin();
633 int fSize = visibleChecks.size();
634 Object[][] data = new Object[fSize][3];
637 if (fr.hasRenderOrder())
641 fr.findAllFeatures(groupChanged != null); // prod to update
642 // colourschemes. but don't
644 // First add the checks in the previous render order,
645 // in case the window has been closed and reopened
647 List<String> frl = fr.getRenderOrder();
648 for (int ro = frl.size() - 1; ro > -1; ro--)
652 if (!visibleChecks.contains(type))
657 data[dataIndex][0] = type;
658 data[dataIndex][1] = fr.getFeatureStyle(type);
659 data[dataIndex][2] = new Boolean(af.getViewport()
660 .getFeaturesDisplayed().isVisible(type));
662 visibleChecks.removeElement(type);
666 fSize = visibleChecks.size();
667 for (int i = 0; i < fSize; i++)
669 // These must be extra features belonging to the group
670 // which was just selected
671 type = visibleChecks.elementAt(i).toString();
672 data[dataIndex][0] = type;
674 data[dataIndex][1] = fr.getFeatureStyle(type);
675 if (data[dataIndex][1] == null)
677 // "Colour has been updated in another view!!"
678 fr.clearRenderOrder();
682 data[dataIndex][2] = new Boolean(true);
686 if (originalData == null)
688 originalData = new Object[data.length][3];
689 for (int i = 0; i < data.length; i++)
691 System.arraycopy(data[i], 0, originalData[i], 0, 3);
695 table.setModel(new FeatureTableModel(data));
696 table.getColumnModel().getColumn(0).setPreferredWidth(200);
698 if (groupPanel != null)
700 groupPanel.setLayout(new GridLayout(
701 fr.getFeatureGroupsSize() / 4 + 1, 4));
703 groupPanel.validate();
704 bigPanel.add(groupPanel, BorderLayout.NORTH);
707 updateFeatureRenderer(data, groupChanged != null);
708 resettingTable = false;
712 * reorder data based on the featureRenderers global priority list.
716 private void ensureOrder(Object[][] data)
718 boolean sort = false;
719 float[] order = new float[data.length];
720 for (int i = 0; i < order.length; i++)
722 order[i] = fr.getOrder(data[i][0].toString());
725 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
729 sort = sort || order[i - 1] > order[i];
734 jalview.util.QuickSort.sort(order, data);
740 JalviewFileChooser chooser = new JalviewFileChooser(
741 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
742 new String[] { "fc" },
743 new String[] { "Sequence Feature Colours" },
744 "Sequence Feature Colours");
745 chooser.setFileView(new jalview.io.JalviewFileView());
746 chooser.setDialogTitle(MessageManager
747 .getString("label.load_feature_colours"));
748 chooser.setToolTipText(MessageManager.getString("action.load"));
750 int value = chooser.showOpenDialog(this);
752 if (value == JalviewFileChooser.APPROVE_OPTION)
754 File file = chooser.getSelectedFile();
758 InputStreamReader in = new InputStreamReader(new FileInputStream(
761 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
763 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
766 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
769 Color mincol = null, maxcol = null;
772 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
773 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
775 } catch (Exception e)
777 Cache.log.warn("Couldn't parse out graduated feature color.",
780 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
781 newcol.getMin(), newcol.getMax());
782 if (newcol.hasAutoScale())
784 gcol.setAutoScaled(newcol.getAutoScale());
786 if (newcol.hasColourByLabel())
788 gcol.setColourByLabel(newcol.getColourByLabel());
790 if (newcol.hasThreshold())
792 gcol.setThreshold(newcol.getThreshold());
794 if (newcol.getThreshType().length() > 0)
796 String ttyp = newcol.getThreshType();
797 if (ttyp.equalsIgnoreCase("ABOVE"))
799 gcol.setAboveThreshold(true);
801 if (ttyp.equalsIgnoreCase("BELOW"))
803 gcol.setBelowThreshold(true);
806 fr.setColour(name = newcol.getName(), gcol);
810 Color color = new Color(
811 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
812 fr.setColour(name = jucs.getColour(i).getName(),
813 new FeatureColour(color));
815 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
820 Object[][] data = ((FeatureTableModel) table.getModel())
823 updateFeatureRenderer(data, false);
826 } catch (Exception ex)
828 System.out.println("Error loading User Colour File\n" + ex);
835 JalviewFileChooser chooser = new JalviewFileChooser(
836 Cache.getProperty("LAST_DIRECTORY"),
837 new String[] { "fc" },
838 new String[] { "Sequence Feature Colours" },
839 "Sequence Feature Colours");
840 chooser.setFileView(new jalview.io.JalviewFileView());
841 chooser.setDialogTitle(MessageManager
842 .getString("label.save_feature_colours"));
843 chooser.setToolTipText(MessageManager.getString("action.save"));
845 int value = chooser.showSaveDialog(this);
847 if (value == JalviewFileChooser.APPROVE_OPTION)
849 String choice = chooser.getSelectedFile().getPath();
850 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
851 ucs.setSchemeName("Sequence Features");
854 PrintWriter out = new PrintWriter(new OutputStreamWriter(
855 new FileOutputStream(choice), "UTF-8"));
857 Set<String> fr_colours = fr.getAllFeatureColours();
858 Iterator<String> e = fr_colours.iterator();
859 float[] sortOrder = new float[fr_colours.size()];
860 String[] sortTypes = new String[fr_colours.size()];
864 sortTypes[i] = e.next();
865 sortOrder[i] = fr.getOrder(sortTypes[i]);
868 QuickSort.sort(sortOrder, sortTypes);
870 for (i = 0; i < sortTypes.length; i++)
872 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
873 col.setName(sortTypes[i]);
874 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
875 if (fcol.isSimpleColour())
877 col.setRGB(Format.getHexString(fcol.getColour()));
881 col.setRGB(Format.getHexString(fcol.getMaxColour()));
882 col.setMin(fcol.getMin());
883 col.setMax(fcol.getMax());
884 col.setMinRGB(jalview.util.Format.getHexString(fcol
886 col.setAutoScale(fcol.isAutoScaled());
887 col.setThreshold(fcol.getThreshold());
888 col.setColourByLabel(fcol.isColourByLabel());
889 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
890 .isBelowThreshold() ? "BELOW" : "NONE"));
896 } catch (Exception ex)
898 ex.printStackTrace();
903 public void invertSelection()
905 for (int i = 0; i < table.getRowCount(); i++)
907 Boolean value = (Boolean) table.getValueAt(i, 2);
909 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
913 public void orderByAvWidth()
915 if (table == null || table.getModel() == null)
919 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
920 float[] width = new float[data.length];
924 for (int i = 0; i < data.length; i++)
926 awidth = typeWidth.get(data[i][0]);
929 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
930 // weight - but have to make per
931 // sequence, too (awidth[2])
932 // if (width[i]==1) // hack to distinguish single width sequences.
944 boolean sort = false;
945 for (int i = 0; i < width.length; i++)
947 // awidth = (float[]) typeWidth.get(data[i][0]);
950 width[i] = fr.getOrder(data[i][0].toString());
953 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
958 width[i] /= max; // normalize
959 fr.setOrder(data[i][0].toString(), width[i]); // store for later
963 sort = sort || width[i - 1] > width[i];
968 jalview.util.QuickSort.sort(width, data);
969 // update global priority order
972 updateFeatureRenderer(data, false);
980 frame.setClosed(true);
981 } catch (Exception exe)
987 public void updateFeatureRenderer(Object[][] data)
989 updateFeatureRenderer(data, true);
993 * Update the priority order of features; only repaint if this changed the
994 * order of visible features
999 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1001 if (fr.setFeaturePriority(data, visibleNew))
1003 af.alignPanel.paintAlignment(true);
1007 int selectedRow = -1;
1009 JTabbedPane tabbedPane = new JTabbedPane();
1011 BorderLayout borderLayout1 = new BorderLayout();
1013 BorderLayout borderLayout2 = new BorderLayout();
1015 BorderLayout borderLayout3 = new BorderLayout();
1017 JPanel bigPanel = new JPanel();
1019 BorderLayout borderLayout4 = new BorderLayout();
1021 JButton invert = new JButton();
1023 JPanel buttonPanel = new JPanel();
1025 JButton cancel = new JButton();
1027 JButton ok = new JButton();
1029 JButton loadColours = new JButton();
1031 JButton saveColours = new JButton();
1033 JPanel dasButtonPanel = new JPanel();
1035 JButton fetchDAS = new JButton();
1037 JButton saveDAS = new JButton();
1039 JButton cancelDAS = new JButton();
1041 JButton optimizeOrder = new JButton();
1043 JButton sortByScore = new JButton();
1045 JButton sortByDens = new JButton();
1047 JButton help = new JButton();
1049 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1051 private void jbInit() throws Exception
1053 this.setLayout(borderLayout1);
1054 settingsPane.setLayout(borderLayout2);
1055 dasSettingsPane.setLayout(borderLayout3);
1056 bigPanel.setLayout(borderLayout4);
1057 invert.setFont(JvSwingUtils.getLabelFont());
1058 invert.setText(MessageManager.getString("label.invert_selection"));
1059 invert.addActionListener(new ActionListener()
1062 public void actionPerformed(ActionEvent e)
1067 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1068 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1069 optimizeOrder.addActionListener(new ActionListener()
1072 public void actionPerformed(ActionEvent e)
1077 sortByScore.setFont(JvSwingUtils.getLabelFont());
1079 .setText(MessageManager.getString("label.seq_sort_by_score"));
1080 sortByScore.addActionListener(new ActionListener()
1083 public void actionPerformed(ActionEvent e)
1085 af.avc.sortAlignmentByFeatureScore(null);
1088 sortByDens.setFont(JvSwingUtils.getLabelFont());
1089 sortByDens.setText(MessageManager
1090 .getString("label.sequence_sort_by_density"));
1091 sortByDens.addActionListener(new ActionListener()
1094 public void actionPerformed(ActionEvent e)
1096 af.avc.sortAlignmentByFeatureDensity(null);
1099 help.setFont(JvSwingUtils.getLabelFont());
1100 help.setText(MessageManager.getString("action.help"));
1101 help.addActionListener(new ActionListener()
1104 public void actionPerformed(ActionEvent e)
1108 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1109 } catch (HelpSetException e1)
1111 e1.printStackTrace();
1115 help.setFont(JvSwingUtils.getLabelFont());
1116 help.setText(MessageManager.getString("action.help"));
1117 help.addActionListener(new ActionListener()
1120 public void actionPerformed(ActionEvent e)
1124 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1125 } catch (HelpSetException e1)
1127 e1.printStackTrace();
1131 cancel.setFont(JvSwingUtils.getLabelFont());
1132 cancel.setText(MessageManager.getString("action.cancel"));
1133 cancel.addActionListener(new ActionListener()
1136 public void actionPerformed(ActionEvent e)
1138 fr.setTransparency(originalTransparency);
1139 updateFeatureRenderer(originalData);
1143 ok.setFont(JvSwingUtils.getLabelFont());
1144 ok.setText(MessageManager.getString("action.ok"));
1145 ok.addActionListener(new ActionListener()
1148 public void actionPerformed(ActionEvent e)
1153 loadColours.setFont(JvSwingUtils.getLabelFont());
1154 loadColours.setText(MessageManager.getString("label.load_colours"));
1155 loadColours.addActionListener(new ActionListener()
1158 public void actionPerformed(ActionEvent e)
1163 saveColours.setFont(JvSwingUtils.getLabelFont());
1164 saveColours.setText(MessageManager.getString("label.save_colours"));
1165 saveColours.addActionListener(new ActionListener()
1168 public void actionPerformed(ActionEvent e)
1173 transparency.addChangeListener(new ChangeListener()
1176 public void stateChanged(ChangeEvent evt)
1178 fr.setTransparency((100 - transparency.getValue()) / 100f);
1179 af.alignPanel.paintAlignment(true);
1183 transparency.setMaximum(70);
1184 transparency.setToolTipText(MessageManager
1185 .getString("label.transparency_tip"));
1186 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1187 fetchDAS.addActionListener(new ActionListener()
1190 public void actionPerformed(ActionEvent e)
1192 fetchDAS_actionPerformed(e);
1195 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1196 saveDAS.addActionListener(new ActionListener()
1199 public void actionPerformed(ActionEvent e)
1201 saveDAS_actionPerformed(e);
1204 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1205 dasSettingsPane.setBorder(null);
1206 cancelDAS.setEnabled(false);
1207 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1208 cancelDAS.addActionListener(new ActionListener()
1211 public void actionPerformed(ActionEvent e)
1213 cancelDAS_actionPerformed(e);
1216 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1217 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1219 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1221 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1222 transbuttons.add(optimizeOrder);
1223 transbuttons.add(invert);
1224 transbuttons.add(sortByScore);
1225 transbuttons.add(sortByDens);
1226 transbuttons.add(help);
1227 JPanel sliderPanel = new JPanel();
1228 sliderPanel.add(transparency);
1229 transPanel.add(transparency);
1230 transPanel.add(transbuttons);
1231 buttonPanel.add(ok);
1232 buttonPanel.add(cancel);
1233 buttonPanel.add(loadColours);
1234 buttonPanel.add(saveColours);
1235 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1236 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1237 dasButtonPanel.add(fetchDAS);
1238 dasButtonPanel.add(cancelDAS);
1239 dasButtonPanel.add(saveDAS);
1240 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1241 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1244 public void fetchDAS_actionPerformed(ActionEvent e)
1246 fetchDAS.setEnabled(false);
1247 cancelDAS.setEnabled(true);
1248 dassourceBrowser.setGuiEnabled(false);
1249 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1250 .getSelectedSources();
1251 doDasFeatureFetch(selectedSources, true, true);
1255 * get the features from selectedSources for all or the current selection
1257 * @param selectedSources
1258 * @param checkDbRefs
1259 * @param promptFetchDbRefs
1261 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1262 boolean checkDbRefs, boolean promptFetchDbRefs)
1264 SequenceI[] dataset, seqs;
1266 AlignmentViewport vp = af.getViewport();
1267 if (vp.getSelectionGroup() != null
1268 && vp.getSelectionGroup().getSize() > 0)
1270 iSize = vp.getSelectionGroup().getSize();
1271 dataset = new SequenceI[iSize];
1272 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1276 iSize = vp.getAlignment().getHeight();
1277 seqs = vp.getAlignment().getSequencesArray();
1280 dataset = new SequenceI[iSize];
1281 for (int i = 0; i < iSize; i++)
1283 dataset[i] = seqs[i].getDatasetSequence();
1286 cancelDAS.setEnabled(true);
1287 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1288 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1289 af.getViewport().setShowSequenceFeatures(true);
1290 af.showSeqFeatures.setSelected(true);
1294 * blocking call to initialise the das source browser
1296 public void initDasSources()
1298 dassourceBrowser.initDasSources();
1302 * examine the current list of das sources and return any matching the given
1303 * nicknames in sources
1306 * Vector of Strings to resolve to DAS source nicknames.
1307 * @return sources that are present in source list.
1309 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1311 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1315 * get currently selected das sources. ensure you have called initDasSources
1316 * before calling this.
1318 * @return vector of selected das source nicknames
1320 public Vector<jalviewSourceI> getSelectedSources()
1322 return dassourceBrowser.getSelectedSources();
1326 * properly initialise DAS fetcher and then initiate a new thread to fetch
1327 * features from the named sources (rather than any turned on by default)
1331 * if true then runs in same thread, otherwise passes to the Swing
1334 public void fetchDasFeatures(Vector<String> sources, boolean block)
1337 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1338 .resolveSourceNicknames(sources);
1339 if (resolved.size() == 0)
1341 resolved = dassourceBrowser.getSelectedSources();
1343 if (resolved.size() > 0)
1345 final List<jalviewSourceI> dassources = resolved;
1346 fetchDAS.setEnabled(false);
1347 // cancelDAS.setEnabled(true); doDasFetch does this.
1348 Runnable fetcher = new Runnable()
1354 doDasFeatureFetch(dassources, true, false);
1364 SwingUtilities.invokeLater(fetcher);
1369 public void saveDAS_actionPerformed(ActionEvent e)
1372 .saveProperties(jalview.bin.Cache.applicationProperties);
1375 public void complete()
1377 fetchDAS.setEnabled(true);
1378 cancelDAS.setEnabled(false);
1379 dassourceBrowser.setGuiEnabled(true);
1383 public void cancelDAS_actionPerformed(ActionEvent e)
1385 if (dasFeatureFetcher != null)
1387 dasFeatureFetcher.cancel();
1392 public void noDasSourceActive()
1396 .showInternalConfirmDialog(
1399 .getString("label.no_das_sources_selected_warn"),
1401 .getString("label.no_das_sources_selected_title"),
1402 JOptionPane.DEFAULT_OPTION,
1403 JOptionPane.INFORMATION_MESSAGE);
1406 // ///////////////////////////////////////////////////////////////////////
1407 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1408 // ///////////////////////////////////////////////////////////////////////
1409 class FeatureTableModel extends AbstractTableModel
1411 FeatureTableModel(Object[][] data)
1416 private String[] columnNames = {
1417 MessageManager.getString("label.feature_type"),
1418 MessageManager.getString("action.colour"),
1419 MessageManager.getString("label.display") };
1421 private Object[][] data;
1423 public Object[][] getData()
1428 public void setData(Object[][] data)
1434 public int getColumnCount()
1436 return columnNames.length;
1439 public Object[] getRow(int row)
1445 public int getRowCount()
1451 public String getColumnName(int col)
1453 return columnNames[col];
1457 public Object getValueAt(int row, int col)
1459 return data[row][col];
1463 public Class getColumnClass(int c)
1465 return getValueAt(0, c).getClass();
1469 public boolean isCellEditable(int row, int col)
1471 return col == 0 ? false : true;
1475 public void setValueAt(Object value, int row, int col)
1477 data[row][col] = value;
1478 fireTableCellUpdated(row, col);
1479 updateFeatureRenderer(data);
1484 class ColorRenderer extends JLabel implements TableCellRenderer
1486 javax.swing.border.Border unselectedBorder = null;
1488 javax.swing.border.Border selectedBorder = null;
1490 final String baseTT = "Click to edit, right/apple click for menu.";
1492 public ColorRenderer()
1494 setOpaque(true); // MUST do this for background to show up.
1495 setHorizontalTextPosition(SwingConstants.CENTER);
1496 setVerticalTextPosition(SwingConstants.CENTER);
1500 public Component getTableCellRendererComponent(JTable tbl,
1501 Object color, boolean isSelected, boolean hasFocus, int row,
1504 FeatureColourI cellColour = (FeatureColourI) color;
1505 // JLabel comp = new JLabel();
1509 // setBounds(getBounds());
1511 setToolTipText(baseTT);
1512 setBackground(tbl.getBackground());
1513 if (!cellColour.isSimpleColour())
1515 Rectangle cr = tbl.getCellRect(row, column, false);
1516 FeatureSettings.renderGraduatedColor(this, cellColour,
1517 (int) cr.getWidth(), (int) cr.getHeight());
1524 newColor = cellColour.getColour();
1525 setBackground(newColor);
1529 if (selectedBorder == null)
1531 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1532 tbl.getSelectionBackground());
1534 setBorder(selectedBorder);
1538 if (unselectedBorder == null)
1540 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1541 tbl.getBackground());
1543 setBorder(unselectedBorder);
1551 * update comp using rendering settings from gcol
1556 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1558 int w = comp.getWidth(), h = comp.getHeight();
1561 w = (int) comp.getPreferredSize().getWidth();
1562 h = (int) comp.getPreferredSize().getHeight();
1569 renderGraduatedColor(comp, gcol, w, h);
1572 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1575 boolean thr = false;
1578 if (gcol.isAboveThreshold())
1582 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1584 if (gcol.isBelowThreshold())
1588 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1590 if (gcol.isColourByLabel())
1592 tt = "Coloured by label text. " + tt;
1602 Color newColor = gcol.getMaxColour();
1603 comp.setBackground(newColor);
1604 // System.err.println("Width is " + w / 2);
1605 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1606 comp.setIcon(ficon);
1607 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1608 // + newColor.getGreen() + ", " + newColor.getBlue()
1609 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1610 // + ", " + minCol.getBlue() + ")");
1612 comp.setHorizontalAlignment(SwingConstants.CENTER);
1614 if (tt.length() > 0)
1616 if (comp.getToolTipText() == null)
1618 comp.setToolTipText(tt);
1622 comp.setToolTipText(tt + " " + comp.getToolTipText());
1628 class FeatureIcon implements Icon
1630 FeatureColourI gcol;
1634 boolean midspace = false;
1636 int width = 50, height = 20;
1638 int s1, e1; // start and end of midpoint band for thresholded symbol
1640 Color mpcolour = Color.white;
1642 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1662 public int getIconWidth()
1668 public int getIconHeight()
1674 public void paintIcon(Component c, Graphics g, int x, int y)
1677 if (gcol.isColourByLabel())
1680 g.fillRect(0, 0, width, height);
1681 // need an icon here.
1682 g.setColor(gcol.getMaxColour());
1684 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1686 // g.setFont(g.getFont().deriveFont(
1687 // AffineTransform.getScaleInstance(
1688 // width/g.getFontMetrics().stringWidth("Label"),
1689 // height/g.getFontMetrics().getHeight())));
1691 g.drawString(MessageManager.getString("label.label"), 0, 0);
1696 Color minCol = gcol.getMinColour();
1698 g.fillRect(0, 0, s1, height);
1701 g.setColor(Color.white);
1702 g.fillRect(s1, 0, e1 - s1, height);
1704 g.setColor(gcol.getMaxColour());
1705 g.fillRect(0, e1, width - e1, height);
1710 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1715 FeatureColourI currentColor;
1717 FeatureColourChooser chooser;
1723 JColorChooser colorChooser;
1727 protected static final String EDIT = "edit";
1729 int selectedRow = 0;
1731 public ColorEditor(FeatureSettings me)
1734 // Set up the editor (from the table's point of view),
1735 // which is a button.
1736 // This button brings up the color chooser dialog,
1737 // which is the editor from the user's point of view.
1738 button = new JButton();
1739 button.setActionCommand(EDIT);
1740 button.addActionListener(this);
1741 button.setBorderPainted(false);
1742 // Set up the dialog that the button brings up.
1743 colorChooser = new JColorChooser();
1744 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1745 colorChooser, this, // OK button handler
1746 null); // no CANCEL button handler
1750 * Handles events from the editor button and from the dialog's OK button.
1753 public void actionPerformed(ActionEvent e)
1756 if (EDIT.equals(e.getActionCommand()))
1758 // The user has clicked the cell, so
1759 // bring up the dialog.
1760 if (currentColor.isSimpleColour())
1762 // bring up simple color chooser
1763 button.setBackground(currentColor.getColour());
1764 colorChooser.setColor(currentColor.getColour());
1765 dialog.setVisible(true);
1769 // bring up graduated chooser.
1770 chooser = new FeatureColourChooser(me.fr, type);
1771 chooser.setRequestFocusEnabled(true);
1772 chooser.requestFocus();
1773 chooser.addActionListener(this);
1775 // Make the renderer reappear.
1776 fireEditingStopped();
1780 { // User pressed dialog's "OK" button.
1781 if (currentColor.isSimpleColour())
1783 currentColor = new FeatureColour(colorChooser.getColor());
1787 currentColor = chooser.getLastColour();
1789 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1790 fireEditingStopped();
1791 me.table.validate();
1795 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1797 public Object getCellEditorValue()
1799 return currentColor;
1802 // Implement the one method defined by TableCellEditor.
1804 public Component getTableCellEditorComponent(JTable table, Object value,
1805 boolean isSelected, int row, int column)
1807 currentColor = (FeatureColourI) value;
1808 this.selectedRow = row;
1809 type = me.table.getValueAt(row, 0).toString();
1810 button.setOpaque(true);
1811 button.setBackground(me.getBackground());
1812 if (!currentColor.isSimpleColour())
1814 JLabel btn = new JLabel();
1815 btn.setSize(button.getSize());
1816 FeatureSettings.renderGraduatedColor(btn, currentColor);
1817 button.setBackground(btn.getBackground());
1818 button.setIcon(btn.getIcon());
1819 button.setText(btn.getText());
1824 button.setIcon(null);
1825 button.setBackground(currentColor.getColour());