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 (evt.isPopupTrigger())
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 boolean invertSelection = evt.isAltDown();
186 boolean toggleSelection = Platform.isControlDown(evt);
187 boolean extendSelection = evt.isShiftDown();
188 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
189 invertSelection, extendSelection, toggleSelection,
190 (String) table.getValueAt(selectedRow, 0));
194 // isPopupTrigger fires on mouseReleased on Windows
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)
217 * reposition 'selectedRow' to 'newRow' (the dragged to location)
218 * this could be more than one row away for a very fast drag action
219 * so just swap it with adjacent rows until we get it there
221 Object[][] data = ((FeatureTableModel) table.getModel())
223 int direction = newRow < selectedRow ? -1 : 1;
224 for (int i = selectedRow; i != newRow; i += direction)
226 Object[] temp = data[i];
227 data[i] = data[i + direction];
228 data[i + direction] = temp;
230 updateFeatureRenderer(data);
232 selectedRow = newRow;
236 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
237 // MessageManager.getString("label.feature_settings_click_drag")));
238 scrollPane.setViewportView(table);
240 dassourceBrowser = new DasSourceBrowser(this);
241 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
243 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
245 fr.findAllFeatures(true); // display everything!
248 discoverAllFeatureData();
249 final PropertyChangeListener change;
250 final FeatureSettings fs = this;
251 fr.addPropertyChangeListener(change = new PropertyChangeListener()
254 public void propertyChange(PropertyChangeEvent evt)
256 if (!fs.resettingTable && !fs.handlingUpdate)
258 fs.handlingUpdate = true;
259 fs.resetTable(null); // new groups may be added with new seuqence
260 // feature types only
261 fs.handlingUpdate = false;
267 frame = new JInternalFrame();
268 frame.setContentPane(this);
269 if (Platform.isAMac())
271 Desktop.addInternalFrame(frame,
272 MessageManager.getString("label.sequence_feature_settings"),
277 Desktop.addInternalFrame(frame,
278 MessageManager.getString("label.sequence_feature_settings"),
282 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
285 public void internalFrameClosed(
286 javax.swing.event.InternalFrameEvent evt)
288 fr.removePropertyChangeListener(change);
289 dassourceBrowser.fs = null;
292 frame.setLayer(JLayeredPane.PALETTE_LAYER);
295 protected void popupSort(final int selectedRow, final String type,
296 final Object typeCol, final Map<String, float[][]> minmax, int x,
299 final FeatureColourI featureColour = (FeatureColourI) typeCol;
301 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
302 "label.settings_for_param", new String[] { type }));
303 JMenuItem scr = new JMenuItem(
304 MessageManager.getString("label.sort_by_score"));
306 final FeatureSettings me = this;
307 scr.addActionListener(new ActionListener()
311 public void actionPerformed(ActionEvent e)
313 me.af.avc.sortAlignmentByFeatureScore(Arrays
314 .asList(new String[] { type }));
318 JMenuItem dens = new JMenuItem(
319 MessageManager.getString("label.sort_by_density"));
320 dens.addActionListener(new ActionListener()
324 public void actionPerformed(ActionEvent e)
326 me.af.avc.sortAlignmentByFeatureDensity(Arrays
327 .asList(new String[] { type }));
334 final float[][] typeMinMax = minmax.get(type);
336 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
337 * this is broken at the moment and isn't that useful anyway!
338 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
341 * public void actionPerformed(ActionEvent e) {
342 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
343 * null); } else { minmax.put(type, typeMinMax); } }
349 if (typeMinMax != null && typeMinMax[0] != null)
351 // if (table.getValueAt(row, column));
352 // graduated colourschemes for those where minmax exists for the
353 // positional features
354 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
356 mxcol.setSelected(!featureColour.isSimpleColour());
358 mxcol.addActionListener(new ActionListener()
360 JColorChooser colorChooser;
363 public void actionPerformed(ActionEvent e)
365 if (e.getSource() == mxcol)
367 if (featureColour.isSimpleColour())
369 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
371 fc.addActionListener(this);
375 // bring up simple color chooser
376 colorChooser = new JColorChooser();
377 JDialog dialog = JColorChooser.createDialog(me,
378 "Select new Colour", true, // modal
379 colorChooser, this, // OK button handler
380 null); // no CANCEL button handler
381 colorChooser.setColor(featureColour.getMaxColour());
382 dialog.setVisible(true);
387 if (e.getSource() instanceof FeatureColourChooser)
389 FeatureColourChooser fc = (FeatureColourChooser) e
391 table.setValueAt(fc.getLastColour(), selectedRow, 1);
396 // probably the color chooser!
398 new FeatureColour(colorChooser.getColor()),
401 me.updateFeatureRenderer(
402 ((FeatureTableModel) table.getModel()).getData(),
411 JMenuItem selCols = new JMenuItem(
412 MessageManager.getString("label.select_columns_containing"));
413 selCols.addActionListener(new ActionListener()
416 public void actionPerformed(ActionEvent arg0)
418 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
422 JMenuItem clearCols = new JMenuItem(
423 MessageManager.getString("label.select_columns_not_containing"));
424 clearCols.addActionListener(new ActionListener()
427 public void actionPerformed(ActionEvent arg0)
429 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
433 JMenuItem hideCols = new JMenuItem(
434 MessageManager.getString("label.hide_columns_containing"));
435 hideCols.addActionListener(new ActionListener()
438 public void actionPerformed(ActionEvent arg0)
440 fr.ap.alignFrame.hideFeatureColumns(type, true);
443 JMenuItem hideOtherCols = new JMenuItem(
444 MessageManager.getString("label.hide_columns_not_containing"));
445 hideOtherCols.addActionListener(new ActionListener()
448 public void actionPerformed(ActionEvent arg0)
450 fr.ap.alignFrame.hideFeatureColumns(type, false);
456 men.add(hideOtherCols);
457 men.show(table, x, y);
461 * true when Feature Settings are updating from feature renderer
463 private boolean handlingUpdate = false;
466 * contains a float[3] for each feature type string. created by setTableData
468 Map<String, float[]> typeWidth = null;
471 synchronized public void discoverAllFeatureData()
473 Vector<String> allFeatures = new Vector<String>();
474 Vector<String> allGroups = new Vector<String>();
475 SequenceFeature[] tmpfeatures;
477 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
479 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
480 .getSequenceFeatures();
481 if (tmpfeatures == null)
487 while (index < tmpfeatures.length)
489 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
495 if (tmpfeatures[index].getFeatureGroup() != null)
497 group = tmpfeatures[index].featureGroup;
498 if (!allGroups.contains(group))
500 allGroups.addElement(group);
501 checkGroupState(group);
505 if (!allFeatures.contains(tmpfeatures[index].getType()))
507 allFeatures.addElement(tmpfeatures[index].getType());
519 * Synchronise gui group list and check visibility of group
522 * @return true if group is visible
524 private boolean checkGroupState(String group)
526 boolean visible = fr.checkGroupVisibility(group, true);
528 if (groupPanel == null)
530 groupPanel = new JPanel();
533 boolean alreadyAdded = false;
534 for (int g = 0; g < groupPanel.getComponentCount(); g++)
536 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
539 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
549 final String grp = group;
550 final JCheckBox check = new JCheckBox(group, visible);
551 check.setFont(new Font("Serif", Font.BOLD, 12));
552 check.addItemListener(new ItemListener()
555 public void itemStateChanged(ItemEvent evt)
557 fr.setGroupVisibility(check.getText(), check.isSelected());
558 af.alignPanel.getSeqPanel().seqCanvas.repaint();
559 if (af.alignPanel.overviewPanel != null)
561 af.alignPanel.overviewPanel.updateOverviewImage();
564 resetTable(new String[] { grp });
567 groupPanel.add(check);
571 boolean resettingTable = false;
573 synchronized void resetTable(String[] groupChanged)
575 if (resettingTable == true)
579 resettingTable = true;
580 typeWidth = new Hashtable<String, float[]>();
581 // TODO: change avWidth calculation to 'per-sequence' average and use long
583 float[] avWidth = null;
584 SequenceFeature[] tmpfeatures;
585 String group = null, type;
586 Vector<String> visibleChecks = new Vector<String>();
588 // Find out which features should be visible depending on which groups
589 // are selected / deselected
590 // and recompute average width ordering
591 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
594 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
595 .getSequenceFeatures();
596 if (tmpfeatures == null)
602 while (index < tmpfeatures.length)
604 group = tmpfeatures[index].featureGroup;
606 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
612 if (group == null || checkGroupState(group))
614 type = tmpfeatures[index].getType();
615 if (!visibleChecks.contains(type))
617 visibleChecks.addElement(type);
620 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
622 typeWidth.put(tmpfeatures[index].getType(),
623 avWidth = new float[3]);
627 avWidth = typeWidth.get(tmpfeatures[index].getType());
630 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
632 avWidth[1] += 1 + tmpfeatures[index].getBegin()
633 - tmpfeatures[index].getEnd();
637 avWidth[1] += 1 + tmpfeatures[index].getEnd()
638 - tmpfeatures[index].getBegin();
644 int fSize = visibleChecks.size();
645 Object[][] data = new Object[fSize][3];
648 if (fr.hasRenderOrder())
652 fr.findAllFeatures(groupChanged != null); // prod to update
653 // colourschemes. but don't
655 // First add the checks in the previous render order,
656 // in case the window has been closed and reopened
658 List<String> frl = fr.getRenderOrder();
659 for (int ro = frl.size() - 1; ro > -1; ro--)
663 if (!visibleChecks.contains(type))
668 data[dataIndex][0] = type;
669 data[dataIndex][1] = fr.getFeatureStyle(type);
670 data[dataIndex][2] = new Boolean(af.getViewport()
671 .getFeaturesDisplayed().isVisible(type));
673 visibleChecks.removeElement(type);
677 fSize = visibleChecks.size();
678 for (int i = 0; i < fSize; i++)
680 // These must be extra features belonging to the group
681 // which was just selected
682 type = visibleChecks.elementAt(i).toString();
683 data[dataIndex][0] = type;
685 data[dataIndex][1] = fr.getFeatureStyle(type);
686 if (data[dataIndex][1] == null)
688 // "Colour has been updated in another view!!"
689 fr.clearRenderOrder();
693 data[dataIndex][2] = new Boolean(true);
697 if (originalData == null)
699 originalData = new Object[data.length][3];
700 for (int i = 0; i < data.length; i++)
702 System.arraycopy(data[i], 0, originalData[i], 0, 3);
706 table.setModel(new FeatureTableModel(data));
707 table.getColumnModel().getColumn(0).setPreferredWidth(200);
709 if (groupPanel != null)
711 groupPanel.setLayout(new GridLayout(
712 fr.getFeatureGroupsSize() / 4 + 1, 4));
714 groupPanel.validate();
715 bigPanel.add(groupPanel, BorderLayout.NORTH);
718 updateFeatureRenderer(data, groupChanged != null);
719 resettingTable = false;
723 * reorder data based on the featureRenderers global priority list.
727 private void ensureOrder(Object[][] data)
729 boolean sort = false;
730 float[] order = new float[data.length];
731 for (int i = 0; i < order.length; i++)
733 order[i] = fr.getOrder(data[i][0].toString());
736 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
740 sort = sort || order[i - 1] > order[i];
745 jalview.util.QuickSort.sort(order, data);
751 JalviewFileChooser chooser = new JalviewFileChooser(
752 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
753 new String[] { "fc" },
754 new String[] { "Sequence Feature Colours" },
755 "Sequence Feature Colours");
756 chooser.setFileView(new jalview.io.JalviewFileView());
757 chooser.setDialogTitle(MessageManager
758 .getString("label.load_feature_colours"));
759 chooser.setToolTipText(MessageManager.getString("action.load"));
761 int value = chooser.showOpenDialog(this);
763 if (value == JalviewFileChooser.APPROVE_OPTION)
765 File file = chooser.getSelectedFile();
769 InputStreamReader in = new InputStreamReader(new FileInputStream(
772 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
774 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
777 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
780 Color mincol = null, maxcol = null;
783 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
784 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
786 } catch (Exception e)
788 Cache.log.warn("Couldn't parse out graduated feature color.",
791 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
792 newcol.getMin(), newcol.getMax());
793 if (newcol.hasAutoScale())
795 gcol.setAutoScaled(newcol.getAutoScale());
797 if (newcol.hasColourByLabel())
799 gcol.setColourByLabel(newcol.getColourByLabel());
801 if (newcol.hasThreshold())
803 gcol.setThreshold(newcol.getThreshold());
805 if (newcol.getThreshType().length() > 0)
807 String ttyp = newcol.getThreshType();
808 if (ttyp.equalsIgnoreCase("ABOVE"))
810 gcol.setAboveThreshold(true);
812 if (ttyp.equalsIgnoreCase("BELOW"))
814 gcol.setBelowThreshold(true);
817 fr.setColour(name = newcol.getName(), gcol);
821 Color color = new Color(Integer.parseInt(jucs.getColour(i)
823 fr.setColour(name = jucs.getColour(i).getName(),
824 new FeatureColour(color));
826 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
831 Object[][] data = ((FeatureTableModel) table.getModel())
834 updateFeatureRenderer(data, false);
837 } catch (Exception ex)
839 System.out.println("Error loading User Colour File\n" + ex);
846 JalviewFileChooser chooser = new JalviewFileChooser(
847 Cache.getProperty("LAST_DIRECTORY"), new String[] { "fc" },
848 new String[] { "Sequence Feature Colours" },
849 "Sequence Feature Colours");
850 chooser.setFileView(new jalview.io.JalviewFileView());
851 chooser.setDialogTitle(MessageManager
852 .getString("label.save_feature_colours"));
853 chooser.setToolTipText(MessageManager.getString("action.save"));
855 int value = chooser.showSaveDialog(this);
857 if (value == JalviewFileChooser.APPROVE_OPTION)
859 String choice = chooser.getSelectedFile().getPath();
860 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
861 ucs.setSchemeName("Sequence Features");
864 PrintWriter out = new PrintWriter(new OutputStreamWriter(
865 new FileOutputStream(choice), "UTF-8"));
867 Set<String> fr_colours = fr.getAllFeatureColours();
868 Iterator<String> e = fr_colours.iterator();
869 float[] sortOrder = new float[fr_colours.size()];
870 String[] sortTypes = new String[fr_colours.size()];
874 sortTypes[i] = e.next();
875 sortOrder[i] = fr.getOrder(sortTypes[i]);
878 QuickSort.sort(sortOrder, sortTypes);
880 for (i = 0; i < sortTypes.length; i++)
882 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
883 col.setName(sortTypes[i]);
884 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
885 if (fcol.isSimpleColour())
887 col.setRGB(Format.getHexString(fcol.getColour()));
891 col.setRGB(Format.getHexString(fcol.getMaxColour()));
892 col.setMin(fcol.getMin());
893 col.setMax(fcol.getMax());
894 col.setMinRGB(jalview.util.Format.getHexString(fcol
896 col.setAutoScale(fcol.isAutoScaled());
897 col.setThreshold(fcol.getThreshold());
898 col.setColourByLabel(fcol.isColourByLabel());
899 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
900 .isBelowThreshold() ? "BELOW" : "NONE"));
906 } catch (Exception ex)
908 ex.printStackTrace();
913 public void invertSelection()
915 for (int i = 0; i < table.getRowCount(); i++)
917 Boolean value = (Boolean) table.getValueAt(i, 2);
919 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
923 public void orderByAvWidth()
925 if (table == null || table.getModel() == null)
929 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
930 float[] width = new float[data.length];
934 for (int i = 0; i < data.length; i++)
936 awidth = typeWidth.get(data[i][0]);
939 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
940 // weight - but have to make per
941 // sequence, too (awidth[2])
942 // if (width[i]==1) // hack to distinguish single width sequences.
954 boolean sort = false;
955 for (int i = 0; i < width.length; i++)
957 // awidth = (float[]) typeWidth.get(data[i][0]);
960 width[i] = fr.getOrder(data[i][0].toString());
963 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
968 width[i] /= max; // normalize
969 fr.setOrder(data[i][0].toString(), width[i]); // store for later
973 sort = sort || width[i - 1] > width[i];
978 jalview.util.QuickSort.sort(width, data);
979 // update global priority order
982 updateFeatureRenderer(data, false);
990 frame.setClosed(true);
991 } catch (Exception exe)
997 public void updateFeatureRenderer(Object[][] data)
999 updateFeatureRenderer(data, true);
1003 * Update the priority order of features; only repaint if this changed the
1004 * order of visible features
1009 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1011 if (fr.setFeaturePriority(data, visibleNew))
1013 af.alignPanel.paintAlignment(true);
1017 int selectedRow = -1;
1019 JTabbedPane tabbedPane = new JTabbedPane();
1021 BorderLayout borderLayout1 = new BorderLayout();
1023 BorderLayout borderLayout2 = new BorderLayout();
1025 BorderLayout borderLayout3 = new BorderLayout();
1027 JPanel bigPanel = new JPanel();
1029 BorderLayout borderLayout4 = new BorderLayout();
1031 JButton invert = new JButton();
1033 JPanel buttonPanel = new JPanel();
1035 JButton cancel = new JButton();
1037 JButton ok = new JButton();
1039 JButton loadColours = new JButton();
1041 JButton saveColours = new JButton();
1043 JPanel dasButtonPanel = new JPanel();
1045 JButton fetchDAS = new JButton();
1047 JButton saveDAS = new JButton();
1049 JButton cancelDAS = new JButton();
1051 JButton optimizeOrder = new JButton();
1053 JButton sortByScore = new JButton();
1055 JButton sortByDens = new JButton();
1057 JButton help = new JButton();
1059 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1061 private void jbInit() throws Exception
1063 this.setLayout(borderLayout1);
1064 settingsPane.setLayout(borderLayout2);
1065 dasSettingsPane.setLayout(borderLayout3);
1066 bigPanel.setLayout(borderLayout4);
1067 invert.setFont(JvSwingUtils.getLabelFont());
1068 invert.setText(MessageManager.getString("label.invert_selection"));
1069 invert.addActionListener(new ActionListener()
1072 public void actionPerformed(ActionEvent e)
1077 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1078 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1079 optimizeOrder.addActionListener(new ActionListener()
1082 public void actionPerformed(ActionEvent e)
1087 sortByScore.setFont(JvSwingUtils.getLabelFont());
1089 .setText(MessageManager.getString("label.seq_sort_by_score"));
1090 sortByScore.addActionListener(new ActionListener()
1093 public void actionPerformed(ActionEvent e)
1095 af.avc.sortAlignmentByFeatureScore(null);
1098 sortByDens.setFont(JvSwingUtils.getLabelFont());
1099 sortByDens.setText(MessageManager
1100 .getString("label.sequence_sort_by_density"));
1101 sortByDens.addActionListener(new ActionListener()
1104 public void actionPerformed(ActionEvent e)
1106 af.avc.sortAlignmentByFeatureDensity(null);
1109 help.setFont(JvSwingUtils.getLabelFont());
1110 help.setText(MessageManager.getString("action.help"));
1111 help.addActionListener(new ActionListener()
1114 public void actionPerformed(ActionEvent e)
1118 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1119 } catch (HelpSetException e1)
1121 e1.printStackTrace();
1125 help.setFont(JvSwingUtils.getLabelFont());
1126 help.setText(MessageManager.getString("action.help"));
1127 help.addActionListener(new ActionListener()
1130 public void actionPerformed(ActionEvent e)
1134 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1135 } catch (HelpSetException e1)
1137 e1.printStackTrace();
1141 cancel.setFont(JvSwingUtils.getLabelFont());
1142 cancel.setText(MessageManager.getString("action.cancel"));
1143 cancel.addActionListener(new ActionListener()
1146 public void actionPerformed(ActionEvent e)
1148 fr.setTransparency(originalTransparency);
1149 updateFeatureRenderer(originalData);
1153 ok.setFont(JvSwingUtils.getLabelFont());
1154 ok.setText(MessageManager.getString("action.ok"));
1155 ok.addActionListener(new ActionListener()
1158 public void actionPerformed(ActionEvent e)
1163 loadColours.setFont(JvSwingUtils.getLabelFont());
1164 loadColours.setText(MessageManager.getString("label.load_colours"));
1165 loadColours.addActionListener(new ActionListener()
1168 public void actionPerformed(ActionEvent e)
1173 saveColours.setFont(JvSwingUtils.getLabelFont());
1174 saveColours.setText(MessageManager.getString("label.save_colours"));
1175 saveColours.addActionListener(new ActionListener()
1178 public void actionPerformed(ActionEvent e)
1183 transparency.addChangeListener(new ChangeListener()
1186 public void stateChanged(ChangeEvent evt)
1188 fr.setTransparency((100 - transparency.getValue()) / 100f);
1189 af.alignPanel.paintAlignment(true);
1193 transparency.setMaximum(70);
1194 transparency.setToolTipText(MessageManager
1195 .getString("label.transparency_tip"));
1196 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1197 fetchDAS.addActionListener(new ActionListener()
1200 public void actionPerformed(ActionEvent e)
1202 fetchDAS_actionPerformed(e);
1205 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1206 saveDAS.addActionListener(new ActionListener()
1209 public void actionPerformed(ActionEvent e)
1211 saveDAS_actionPerformed(e);
1214 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1215 dasSettingsPane.setBorder(null);
1216 cancelDAS.setEnabled(false);
1217 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1218 cancelDAS.addActionListener(new ActionListener()
1221 public void actionPerformed(ActionEvent e)
1223 cancelDAS_actionPerformed(e);
1226 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1227 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1229 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1231 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1232 transbuttons.add(optimizeOrder);
1233 transbuttons.add(invert);
1234 transbuttons.add(sortByScore);
1235 transbuttons.add(sortByDens);
1236 transbuttons.add(help);
1237 JPanel sliderPanel = new JPanel();
1238 sliderPanel.add(transparency);
1239 transPanel.add(transparency);
1240 transPanel.add(transbuttons);
1241 buttonPanel.add(ok);
1242 buttonPanel.add(cancel);
1243 buttonPanel.add(loadColours);
1244 buttonPanel.add(saveColours);
1245 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1246 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1247 dasButtonPanel.add(fetchDAS);
1248 dasButtonPanel.add(cancelDAS);
1249 dasButtonPanel.add(saveDAS);
1250 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1251 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1254 public void fetchDAS_actionPerformed(ActionEvent e)
1256 fetchDAS.setEnabled(false);
1257 cancelDAS.setEnabled(true);
1258 dassourceBrowser.setGuiEnabled(false);
1259 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1260 .getSelectedSources();
1261 doDasFeatureFetch(selectedSources, true, true);
1265 * get the features from selectedSources for all or the current selection
1267 * @param selectedSources
1268 * @param checkDbRefs
1269 * @param promptFetchDbRefs
1271 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1272 boolean checkDbRefs, boolean promptFetchDbRefs)
1274 SequenceI[] dataset, seqs;
1276 AlignmentViewport vp = af.getViewport();
1277 if (vp.getSelectionGroup() != null
1278 && vp.getSelectionGroup().getSize() > 0)
1280 iSize = vp.getSelectionGroup().getSize();
1281 dataset = new SequenceI[iSize];
1282 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1286 iSize = vp.getAlignment().getHeight();
1287 seqs = vp.getAlignment().getSequencesArray();
1290 dataset = new SequenceI[iSize];
1291 for (int i = 0; i < iSize; i++)
1293 dataset[i] = seqs[i].getDatasetSequence();
1296 cancelDAS.setEnabled(true);
1297 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1298 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1299 af.getViewport().setShowSequenceFeatures(true);
1300 af.showSeqFeatures.setSelected(true);
1304 * blocking call to initialise the das source browser
1306 public void initDasSources()
1308 dassourceBrowser.initDasSources();
1312 * examine the current list of das sources and return any matching the given
1313 * nicknames in sources
1316 * Vector of Strings to resolve to DAS source nicknames.
1317 * @return sources that are present in source list.
1319 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1321 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1325 * get currently selected das sources. ensure you have called initDasSources
1326 * before calling this.
1328 * @return vector of selected das source nicknames
1330 public Vector<jalviewSourceI> getSelectedSources()
1332 return dassourceBrowser.getSelectedSources();
1336 * properly initialise DAS fetcher and then initiate a new thread to fetch
1337 * features from the named sources (rather than any turned on by default)
1341 * if true then runs in same thread, otherwise passes to the Swing
1344 public void fetchDasFeatures(Vector<String> sources, boolean block)
1347 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1348 .resolveSourceNicknames(sources);
1349 if (resolved.size() == 0)
1351 resolved = dassourceBrowser.getSelectedSources();
1353 if (resolved.size() > 0)
1355 final List<jalviewSourceI> dassources = resolved;
1356 fetchDAS.setEnabled(false);
1357 // cancelDAS.setEnabled(true); doDasFetch does this.
1358 Runnable fetcher = new Runnable()
1364 doDasFeatureFetch(dassources, true, false);
1374 SwingUtilities.invokeLater(fetcher);
1379 public void saveDAS_actionPerformed(ActionEvent e)
1382 .saveProperties(jalview.bin.Cache.applicationProperties);
1385 public void complete()
1387 fetchDAS.setEnabled(true);
1388 cancelDAS.setEnabled(false);
1389 dassourceBrowser.setGuiEnabled(true);
1393 public void cancelDAS_actionPerformed(ActionEvent e)
1395 if (dasFeatureFetcher != null)
1397 dasFeatureFetcher.cancel();
1402 public void noDasSourceActive()
1406 .showInternalConfirmDialog(
1409 .getString("label.no_das_sources_selected_warn"),
1411 .getString("label.no_das_sources_selected_title"),
1412 JOptionPane.DEFAULT_OPTION,
1413 JOptionPane.INFORMATION_MESSAGE);
1416 // ///////////////////////////////////////////////////////////////////////
1417 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1418 // ///////////////////////////////////////////////////////////////////////
1419 class FeatureTableModel extends AbstractTableModel
1421 FeatureTableModel(Object[][] data)
1426 private String[] columnNames = {
1427 MessageManager.getString("label.feature_type"),
1428 MessageManager.getString("action.colour"),
1429 MessageManager.getString("label.display") };
1431 private Object[][] data;
1433 public Object[][] getData()
1438 public void setData(Object[][] data)
1444 public int getColumnCount()
1446 return columnNames.length;
1449 public Object[] getRow(int row)
1455 public int getRowCount()
1461 public String getColumnName(int col)
1463 return columnNames[col];
1467 public Object getValueAt(int row, int col)
1469 return data[row][col];
1473 public Class getColumnClass(int c)
1475 return getValueAt(0, c).getClass();
1479 public boolean isCellEditable(int row, int col)
1481 return col == 0 ? false : true;
1485 public void setValueAt(Object value, int row, int col)
1487 data[row][col] = value;
1488 fireTableCellUpdated(row, col);
1489 updateFeatureRenderer(data);
1494 class ColorRenderer extends JLabel implements TableCellRenderer
1496 javax.swing.border.Border unselectedBorder = null;
1498 javax.swing.border.Border selectedBorder = null;
1500 final String baseTT = "Click to edit, right/apple click for menu.";
1502 public ColorRenderer()
1504 setOpaque(true); // MUST do this for background to show up.
1505 setHorizontalTextPosition(SwingConstants.CENTER);
1506 setVerticalTextPosition(SwingConstants.CENTER);
1510 public Component getTableCellRendererComponent(JTable tbl,
1511 Object color, boolean isSelected, boolean hasFocus, int row,
1514 FeatureColourI cellColour = (FeatureColourI) color;
1515 // JLabel comp = new JLabel();
1519 // setBounds(getBounds());
1521 setToolTipText(baseTT);
1522 setBackground(tbl.getBackground());
1523 if (!cellColour.isSimpleColour())
1525 Rectangle cr = tbl.getCellRect(row, column, false);
1526 FeatureSettings.renderGraduatedColor(this, cellColour,
1527 (int) cr.getWidth(), (int) cr.getHeight());
1534 newColor = cellColour.getColour();
1535 setBackground(newColor);
1539 if (selectedBorder == null)
1541 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1542 tbl.getSelectionBackground());
1544 setBorder(selectedBorder);
1548 if (unselectedBorder == null)
1550 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1551 tbl.getBackground());
1553 setBorder(unselectedBorder);
1561 * update comp using rendering settings from gcol
1566 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1568 int w = comp.getWidth(), h = comp.getHeight();
1571 w = (int) comp.getPreferredSize().getWidth();
1572 h = (int) comp.getPreferredSize().getHeight();
1579 renderGraduatedColor(comp, gcol, w, h);
1582 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1585 boolean thr = false;
1588 if (gcol.isAboveThreshold())
1592 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1594 if (gcol.isBelowThreshold())
1598 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1600 if (gcol.isColourByLabel())
1602 tt = "Coloured by label text. " + tt;
1612 Color newColor = gcol.getMaxColour();
1613 comp.setBackground(newColor);
1614 // System.err.println("Width is " + w / 2);
1615 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1616 comp.setIcon(ficon);
1617 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1618 // + newColor.getGreen() + ", " + newColor.getBlue()
1619 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1620 // + ", " + minCol.getBlue() + ")");
1622 comp.setHorizontalAlignment(SwingConstants.CENTER);
1624 if (tt.length() > 0)
1626 if (comp.getToolTipText() == null)
1628 comp.setToolTipText(tt);
1632 comp.setToolTipText(tt + " " + comp.getToolTipText());
1638 class FeatureIcon implements Icon
1640 FeatureColourI gcol;
1644 boolean midspace = false;
1646 int width = 50, height = 20;
1648 int s1, e1; // start and end of midpoint band for thresholded symbol
1650 Color mpcolour = Color.white;
1652 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1672 public int getIconWidth()
1678 public int getIconHeight()
1684 public void paintIcon(Component c, Graphics g, int x, int y)
1687 if (gcol.isColourByLabel())
1690 g.fillRect(0, 0, width, height);
1691 // need an icon here.
1692 g.setColor(gcol.getMaxColour());
1694 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1696 // g.setFont(g.getFont().deriveFont(
1697 // AffineTransform.getScaleInstance(
1698 // width/g.getFontMetrics().stringWidth("Label"),
1699 // height/g.getFontMetrics().getHeight())));
1701 g.drawString(MessageManager.getString("label.label"), 0, 0);
1706 Color minCol = gcol.getMinColour();
1708 g.fillRect(0, 0, s1, height);
1711 g.setColor(Color.white);
1712 g.fillRect(s1, 0, e1 - s1, height);
1714 g.setColor(gcol.getMaxColour());
1715 g.fillRect(0, e1, width - e1, height);
1720 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1725 FeatureColourI currentColor;
1727 FeatureColourChooser chooser;
1733 JColorChooser colorChooser;
1737 protected static final String EDIT = "edit";
1739 int selectedRow = 0;
1741 public ColorEditor(FeatureSettings me)
1744 // Set up the editor (from the table's point of view),
1745 // which is a button.
1746 // This button brings up the color chooser dialog,
1747 // which is the editor from the user's point of view.
1748 button = new JButton();
1749 button.setActionCommand(EDIT);
1750 button.addActionListener(this);
1751 button.setBorderPainted(false);
1752 // Set up the dialog that the button brings up.
1753 colorChooser = new JColorChooser();
1754 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1755 colorChooser, this, // OK button handler
1756 null); // no CANCEL button handler
1760 * Handles events from the editor button and from the dialog's OK button.
1763 public void actionPerformed(ActionEvent e)
1766 if (EDIT.equals(e.getActionCommand()))
1768 // The user has clicked the cell, so
1769 // bring up the dialog.
1770 if (currentColor.isSimpleColour())
1772 // bring up simple color chooser
1773 button.setBackground(currentColor.getColour());
1774 colorChooser.setColor(currentColor.getColour());
1775 dialog.setVisible(true);
1779 // bring up graduated chooser.
1780 chooser = new FeatureColourChooser(me.fr, type);
1781 chooser.setRequestFocusEnabled(true);
1782 chooser.requestFocus();
1783 chooser.addActionListener(this);
1785 // Make the renderer reappear.
1786 fireEditingStopped();
1790 { // User pressed dialog's "OK" button.
1791 if (currentColor.isSimpleColour())
1793 currentColor = new FeatureColour(colorChooser.getColor());
1797 currentColor = chooser.getLastColour();
1799 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1800 fireEditingStopped();
1801 me.table.validate();
1805 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1807 public Object getCellEditorValue()
1809 return currentColor;
1812 // Implement the one method defined by TableCellEditor.
1814 public Component getTableCellEditorComponent(JTable table, Object value,
1815 boolean isSelected, int row, int column)
1817 currentColor = (FeatureColourI) value;
1818 this.selectedRow = row;
1819 type = me.table.getValueAt(row, 0).toString();
1820 button.setOpaque(true);
1821 button.setBackground(me.getBackground());
1822 if (!currentColor.isSimpleColour())
1824 JLabel btn = new JLabel();
1825 btn.setSize(button.getSize());
1826 FeatureSettings.renderGraduatedColor(btn, currentColor);
1827 button.setBackground(btn.getBackground());
1828 button.setIcon(btn.getIcon());
1829 button.setText(btn.getText());
1834 button.setIcon(null);
1835 button.setBackground(currentColor.getColour());