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 boolean ctrlDown = Platform.isControlDown(evt);
178 if (SwingUtilities.isRightMouseButton(evt) && !ctrlDown)
180 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
181 table.getValueAt(selectedRow, 1), fr.getMinMax(),
182 evt.getX(), evt.getY());
184 else if (evt.getClickCount() == 2)
186 boolean invertSelection = evt.isAltDown();
187 boolean toggleSelection = ctrlDown;
188 boolean extendSelection = evt.isShiftDown();
189 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
190 invertSelection, extendSelection, toggleSelection,
191 (String) table.getValueAt(selectedRow, 0));
195 // isPopupTrigger fires on mouseReleased on Mac
197 public void mouseReleased(MouseEvent evt)
199 selectedRow = table.rowAtPoint(evt.getPoint());
200 if (evt.isPopupTrigger())
202 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
203 table.getValueAt(selectedRow, 1), fr.getMinMax(),
204 evt.getX(), evt.getY());
209 table.addMouseMotionListener(new MouseMotionAdapter()
212 public void mouseDragged(MouseEvent evt)
214 int newRow = table.rowAtPoint(evt.getPoint());
215 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
218 * reposition 'selectedRow' to 'newRow' (the dragged to location)
219 * this could be more than one row away for a very fast drag action
220 * so just swap it with adjacent rows until we get it there
222 Object[][] data = ((FeatureTableModel) table.getModel())
224 int direction = newRow < selectedRow ? -1 : 1;
225 for (int i = selectedRow; i != newRow; i += direction)
227 Object[] temp = data[i];
228 data[i] = data[i + direction];
229 data[i + direction] = temp;
231 updateFeatureRenderer(data);
233 selectedRow = newRow;
237 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
238 // MessageManager.getString("label.feature_settings_click_drag")));
239 scrollPane.setViewportView(table);
241 dassourceBrowser = new DasSourceBrowser(this);
242 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
244 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
246 fr.findAllFeatures(true); // display everything!
249 discoverAllFeatureData();
250 final PropertyChangeListener change;
251 final FeatureSettings fs = this;
252 fr.addPropertyChangeListener(change = new PropertyChangeListener()
255 public void propertyChange(PropertyChangeEvent evt)
257 if (!fs.resettingTable && !fs.handlingUpdate)
259 fs.handlingUpdate = true;
260 fs.resetTable(null); // new groups may be added with new seuqence
261 // feature types only
262 fs.handlingUpdate = false;
268 frame = new JInternalFrame();
269 frame.setContentPane(this);
270 if (Platform.isAMac())
272 Desktop.addInternalFrame(frame,
273 MessageManager.getString("label.sequence_feature_settings"),
278 Desktop.addInternalFrame(frame,
279 MessageManager.getString("label.sequence_feature_settings"),
283 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
286 public void internalFrameClosed(
287 javax.swing.event.InternalFrameEvent evt)
289 fr.removePropertyChangeListener(change);
290 dassourceBrowser.fs = null;
293 frame.setLayer(JLayeredPane.PALETTE_LAYER);
296 protected void popupSort(final int selectedRow, final String type,
297 final Object typeCol, final Map<String, float[][]> minmax, int x,
300 final FeatureColourI featureColour = (FeatureColourI) typeCol;
302 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
303 "label.settings_for_param", new String[] { type }));
304 JMenuItem scr = new JMenuItem(
305 MessageManager.getString("label.sort_by_score"));
307 final FeatureSettings me = this;
308 scr.addActionListener(new ActionListener()
312 public void actionPerformed(ActionEvent e)
314 me.af.avc.sortAlignmentByFeatureScore(Arrays
315 .asList(new String[] { type }));
319 JMenuItem dens = new JMenuItem(
320 MessageManager.getString("label.sort_by_density"));
321 dens.addActionListener(new ActionListener()
325 public void actionPerformed(ActionEvent e)
327 me.af.avc.sortAlignmentByFeatureDensity(Arrays
328 .asList(new String[] { type }));
335 final float[][] typeMinMax = minmax.get(type);
337 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
338 * this is broken at the moment and isn't that useful anyway!
339 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
342 * public void actionPerformed(ActionEvent e) {
343 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
344 * null); } else { minmax.put(type, typeMinMax); } }
350 if (typeMinMax != null && typeMinMax[0] != null)
352 // if (table.getValueAt(row, column));
353 // graduated colourschemes for those where minmax exists for the
354 // positional features
355 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
357 mxcol.setSelected(!featureColour.isSimpleColour());
359 mxcol.addActionListener(new ActionListener()
361 JColorChooser colorChooser;
364 public void actionPerformed(ActionEvent e)
366 if (e.getSource() == mxcol)
368 if (featureColour.isSimpleColour())
370 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
372 fc.addActionListener(this);
376 // bring up simple color chooser
377 colorChooser = new JColorChooser();
378 JDialog dialog = JColorChooser.createDialog(me,
379 "Select new Colour", true, // modal
380 colorChooser, this, // OK button handler
381 null); // no CANCEL button handler
382 colorChooser.setColor(featureColour.getMaxColour());
383 dialog.setVisible(true);
388 if (e.getSource() instanceof FeatureColourChooser)
390 FeatureColourChooser fc = (FeatureColourChooser) e
392 table.setValueAt(fc.getLastColour(), selectedRow, 1);
397 // probably the color chooser!
399 new FeatureColour(colorChooser.getColor()),
402 me.updateFeatureRenderer(
403 ((FeatureTableModel) table.getModel()).getData(),
412 JMenuItem selCols = new JMenuItem(
413 MessageManager.getString("label.select_columns_containing"));
414 selCols.addActionListener(new ActionListener()
417 public void actionPerformed(ActionEvent arg0)
419 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
423 JMenuItem clearCols = new JMenuItem(
424 MessageManager.getString("label.select_columns_not_containing"));
425 clearCols.addActionListener(new ActionListener()
428 public void actionPerformed(ActionEvent arg0)
430 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
434 JMenuItem hideCols = new JMenuItem(
435 MessageManager.getString("label.hide_columns_containing"));
436 hideCols.addActionListener(new ActionListener()
439 public void actionPerformed(ActionEvent arg0)
441 fr.ap.alignFrame.hideFeatureColumns(type, true);
444 JMenuItem hideOtherCols = new JMenuItem(
445 MessageManager.getString("label.hide_columns_not_containing"));
446 hideOtherCols.addActionListener(new ActionListener()
449 public void actionPerformed(ActionEvent arg0)
451 fr.ap.alignFrame.hideFeatureColumns(type, false);
457 men.add(hideOtherCols);
458 men.show(table, x, y);
462 * true when Feature Settings are updating from feature renderer
464 private boolean handlingUpdate = false;
467 * contains a float[3] for each feature type string. created by setTableData
469 Map<String, float[]> typeWidth = null;
472 synchronized public void discoverAllFeatureData()
474 Vector<String> allFeatures = new Vector<String>();
475 Vector<String> allGroups = new Vector<String>();
476 SequenceFeature[] tmpfeatures;
478 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
480 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
481 .getSequenceFeatures();
482 if (tmpfeatures == null)
488 while (index < tmpfeatures.length)
490 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
496 if (tmpfeatures[index].getFeatureGroup() != null)
498 group = tmpfeatures[index].featureGroup;
499 if (!allGroups.contains(group))
501 allGroups.addElement(group);
502 checkGroupState(group);
506 if (!allFeatures.contains(tmpfeatures[index].getType()))
508 allFeatures.addElement(tmpfeatures[index].getType());
520 * Synchronise gui group list and check visibility of group
523 * @return true if group is visible
525 private boolean checkGroupState(String group)
527 boolean visible = fr.checkGroupVisibility(group, true);
529 if (groupPanel == null)
531 groupPanel = new JPanel();
534 boolean alreadyAdded = false;
535 for (int g = 0; g < groupPanel.getComponentCount(); g++)
537 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
540 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
550 final String grp = group;
551 final JCheckBox check = new JCheckBox(group, visible);
552 check.setFont(new Font("Serif", Font.BOLD, 12));
553 check.addItemListener(new ItemListener()
556 public void itemStateChanged(ItemEvent evt)
558 fr.setGroupVisibility(check.getText(), check.isSelected());
559 af.alignPanel.getSeqPanel().seqCanvas.repaint();
560 if (af.alignPanel.overviewPanel != null)
562 af.alignPanel.overviewPanel.updateOverviewImage();
565 resetTable(new String[] { grp });
568 groupPanel.add(check);
572 boolean resettingTable = false;
574 synchronized void resetTable(String[] groupChanged)
576 if (resettingTable == true)
580 resettingTable = true;
581 typeWidth = new Hashtable<String, float[]>();
582 // TODO: change avWidth calculation to 'per-sequence' average and use long
584 float[] avWidth = null;
585 SequenceFeature[] tmpfeatures;
586 String group = null, type;
587 Vector<String> visibleChecks = new Vector<String>();
589 // Find out which features should be visible depending on which groups
590 // are selected / deselected
591 // and recompute average width ordering
592 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
595 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
596 .getSequenceFeatures();
597 if (tmpfeatures == null)
603 while (index < tmpfeatures.length)
605 group = tmpfeatures[index].featureGroup;
607 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
613 if (group == null || checkGroupState(group))
615 type = tmpfeatures[index].getType();
616 if (!visibleChecks.contains(type))
618 visibleChecks.addElement(type);
621 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
623 typeWidth.put(tmpfeatures[index].getType(),
624 avWidth = new float[3]);
628 avWidth = typeWidth.get(tmpfeatures[index].getType());
631 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
633 avWidth[1] += 1 + tmpfeatures[index].getBegin()
634 - tmpfeatures[index].getEnd();
638 avWidth[1] += 1 + tmpfeatures[index].getEnd()
639 - tmpfeatures[index].getBegin();
645 int fSize = visibleChecks.size();
646 Object[][] data = new Object[fSize][3];
649 if (fr.hasRenderOrder())
653 fr.findAllFeatures(groupChanged != null); // prod to update
654 // colourschemes. but don't
656 // First add the checks in the previous render order,
657 // in case the window has been closed and reopened
659 List<String> frl = fr.getRenderOrder();
660 for (int ro = frl.size() - 1; ro > -1; ro--)
664 if (!visibleChecks.contains(type))
669 data[dataIndex][0] = type;
670 data[dataIndex][1] = fr.getFeatureStyle(type);
671 data[dataIndex][2] = new Boolean(af.getViewport()
672 .getFeaturesDisplayed().isVisible(type));
674 visibleChecks.removeElement(type);
678 fSize = visibleChecks.size();
679 for (int i = 0; i < fSize; i++)
681 // These must be extra features belonging to the group
682 // which was just selected
683 type = visibleChecks.elementAt(i).toString();
684 data[dataIndex][0] = type;
686 data[dataIndex][1] = fr.getFeatureStyle(type);
687 if (data[dataIndex][1] == null)
689 // "Colour has been updated in another view!!"
690 fr.clearRenderOrder();
694 data[dataIndex][2] = new Boolean(true);
698 if (originalData == null)
700 originalData = new Object[data.length][3];
701 for (int i = 0; i < data.length; i++)
703 System.arraycopy(data[i], 0, originalData[i], 0, 3);
707 table.setModel(new FeatureTableModel(data));
708 table.getColumnModel().getColumn(0).setPreferredWidth(200);
710 if (groupPanel != null)
712 groupPanel.setLayout(new GridLayout(
713 fr.getFeatureGroupsSize() / 4 + 1, 4));
715 groupPanel.validate();
716 bigPanel.add(groupPanel, BorderLayout.NORTH);
719 updateFeatureRenderer(data, groupChanged != null);
720 resettingTable = false;
724 * reorder data based on the featureRenderers global priority list.
728 private void ensureOrder(Object[][] data)
730 boolean sort = false;
731 float[] order = new float[data.length];
732 for (int i = 0; i < order.length; i++)
734 order[i] = fr.getOrder(data[i][0].toString());
737 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
741 sort = sort || order[i - 1] > order[i];
746 jalview.util.QuickSort.sort(order, data);
752 JalviewFileChooser chooser = new JalviewFileChooser(
753 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
754 new String[] { "fc" },
755 new String[] { "Sequence Feature Colours" },
756 "Sequence Feature Colours");
757 chooser.setFileView(new jalview.io.JalviewFileView());
758 chooser.setDialogTitle(MessageManager
759 .getString("label.load_feature_colours"));
760 chooser.setToolTipText(MessageManager.getString("action.load"));
762 int value = chooser.showOpenDialog(this);
764 if (value == JalviewFileChooser.APPROVE_OPTION)
766 File file = chooser.getSelectedFile();
770 InputStreamReader in = new InputStreamReader(new FileInputStream(
773 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
775 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
778 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
781 Color mincol = null, maxcol = null;
784 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
785 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
787 } catch (Exception e)
789 Cache.log.warn("Couldn't parse out graduated feature color.",
792 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
793 newcol.getMin(), newcol.getMax());
794 if (newcol.hasAutoScale())
796 gcol.setAutoScaled(newcol.getAutoScale());
798 if (newcol.hasColourByLabel())
800 gcol.setColourByLabel(newcol.getColourByLabel());
802 if (newcol.hasThreshold())
804 gcol.setThreshold(newcol.getThreshold());
806 if (newcol.getThreshType().length() > 0)
808 String ttyp = newcol.getThreshType();
809 if (ttyp.equalsIgnoreCase("ABOVE"))
811 gcol.setAboveThreshold(true);
813 if (ttyp.equalsIgnoreCase("BELOW"))
815 gcol.setBelowThreshold(true);
818 fr.setColour(name = newcol.getName(), gcol);
822 Color color = new Color(
823 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
824 fr.setColour(name = jucs.getColour(i).getName(),
825 new FeatureColour(color));
827 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
832 Object[][] data = ((FeatureTableModel) table.getModel())
835 updateFeatureRenderer(data, false);
838 } catch (Exception ex)
840 System.out.println("Error loading User Colour File\n" + ex);
847 JalviewFileChooser chooser = new JalviewFileChooser(
848 Cache.getProperty("LAST_DIRECTORY"),
849 new String[] { "fc" },
850 new String[] { "Sequence Feature Colours" },
851 "Sequence Feature Colours");
852 chooser.setFileView(new jalview.io.JalviewFileView());
853 chooser.setDialogTitle(MessageManager
854 .getString("label.save_feature_colours"));
855 chooser.setToolTipText(MessageManager.getString("action.save"));
857 int value = chooser.showSaveDialog(this);
859 if (value == JalviewFileChooser.APPROVE_OPTION)
861 String choice = chooser.getSelectedFile().getPath();
862 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
863 ucs.setSchemeName("Sequence Features");
866 PrintWriter out = new PrintWriter(new OutputStreamWriter(
867 new FileOutputStream(choice), "UTF-8"));
869 Set<String> fr_colours = fr.getAllFeatureColours();
870 Iterator<String> e = fr_colours.iterator();
871 float[] sortOrder = new float[fr_colours.size()];
872 String[] sortTypes = new String[fr_colours.size()];
876 sortTypes[i] = e.next();
877 sortOrder[i] = fr.getOrder(sortTypes[i]);
880 QuickSort.sort(sortOrder, sortTypes);
882 for (i = 0; i < sortTypes.length; i++)
884 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
885 col.setName(sortTypes[i]);
886 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
887 if (fcol.isSimpleColour())
889 col.setRGB(Format.getHexString(fcol.getColour()));
893 col.setRGB(Format.getHexString(fcol.getMaxColour()));
894 col.setMin(fcol.getMin());
895 col.setMax(fcol.getMax());
896 col.setMinRGB(jalview.util.Format.getHexString(fcol
898 col.setAutoScale(fcol.isAutoScaled());
899 col.setThreshold(fcol.getThreshold());
900 col.setColourByLabel(fcol.isColourByLabel());
901 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
902 .isBelowThreshold() ? "BELOW" : "NONE"));
908 } catch (Exception ex)
910 ex.printStackTrace();
915 public void invertSelection()
917 for (int i = 0; i < table.getRowCount(); i++)
919 Boolean value = (Boolean) table.getValueAt(i, 2);
921 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
925 public void orderByAvWidth()
927 if (table == null || table.getModel() == null)
931 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
932 float[] width = new float[data.length];
936 for (int i = 0; i < data.length; i++)
938 awidth = typeWidth.get(data[i][0]);
941 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
942 // weight - but have to make per
943 // sequence, too (awidth[2])
944 // if (width[i]==1) // hack to distinguish single width sequences.
956 boolean sort = false;
957 for (int i = 0; i < width.length; i++)
959 // awidth = (float[]) typeWidth.get(data[i][0]);
962 width[i] = fr.getOrder(data[i][0].toString());
965 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
970 width[i] /= max; // normalize
971 fr.setOrder(data[i][0].toString(), width[i]); // store for later
975 sort = sort || width[i - 1] > width[i];
980 jalview.util.QuickSort.sort(width, data);
981 // update global priority order
984 updateFeatureRenderer(data, false);
992 frame.setClosed(true);
993 } catch (Exception exe)
999 public void updateFeatureRenderer(Object[][] data)
1001 updateFeatureRenderer(data, true);
1005 * Update the priority order of features; only repaint if this changed the
1006 * order of visible features
1011 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1013 if (fr.setFeaturePriority(data, visibleNew))
1015 af.alignPanel.paintAlignment(true);
1019 int selectedRow = -1;
1021 JTabbedPane tabbedPane = new JTabbedPane();
1023 BorderLayout borderLayout1 = new BorderLayout();
1025 BorderLayout borderLayout2 = new BorderLayout();
1027 BorderLayout borderLayout3 = new BorderLayout();
1029 JPanel bigPanel = new JPanel();
1031 BorderLayout borderLayout4 = new BorderLayout();
1033 JButton invert = new JButton();
1035 JPanel buttonPanel = new JPanel();
1037 JButton cancel = new JButton();
1039 JButton ok = new JButton();
1041 JButton loadColours = new JButton();
1043 JButton saveColours = new JButton();
1045 JPanel dasButtonPanel = new JPanel();
1047 JButton fetchDAS = new JButton();
1049 JButton saveDAS = new JButton();
1051 JButton cancelDAS = new JButton();
1053 JButton optimizeOrder = new JButton();
1055 JButton sortByScore = new JButton();
1057 JButton sortByDens = new JButton();
1059 JButton help = new JButton();
1061 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1063 private void jbInit() throws Exception
1065 this.setLayout(borderLayout1);
1066 settingsPane.setLayout(borderLayout2);
1067 dasSettingsPane.setLayout(borderLayout3);
1068 bigPanel.setLayout(borderLayout4);
1069 invert.setFont(JvSwingUtils.getLabelFont());
1070 invert.setText(MessageManager.getString("label.invert_selection"));
1071 invert.addActionListener(new ActionListener()
1074 public void actionPerformed(ActionEvent e)
1079 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1080 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1081 optimizeOrder.addActionListener(new ActionListener()
1084 public void actionPerformed(ActionEvent e)
1089 sortByScore.setFont(JvSwingUtils.getLabelFont());
1091 .setText(MessageManager.getString("label.seq_sort_by_score"));
1092 sortByScore.addActionListener(new ActionListener()
1095 public void actionPerformed(ActionEvent e)
1097 af.avc.sortAlignmentByFeatureScore(null);
1100 sortByDens.setFont(JvSwingUtils.getLabelFont());
1101 sortByDens.setText(MessageManager
1102 .getString("label.sequence_sort_by_density"));
1103 sortByDens.addActionListener(new ActionListener()
1106 public void actionPerformed(ActionEvent e)
1108 af.avc.sortAlignmentByFeatureDensity(null);
1111 help.setFont(JvSwingUtils.getLabelFont());
1112 help.setText(MessageManager.getString("action.help"));
1113 help.addActionListener(new ActionListener()
1116 public void actionPerformed(ActionEvent e)
1120 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1121 } catch (HelpSetException e1)
1123 e1.printStackTrace();
1127 help.setFont(JvSwingUtils.getLabelFont());
1128 help.setText(MessageManager.getString("action.help"));
1129 help.addActionListener(new ActionListener()
1132 public void actionPerformed(ActionEvent e)
1136 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1137 } catch (HelpSetException e1)
1139 e1.printStackTrace();
1143 cancel.setFont(JvSwingUtils.getLabelFont());
1144 cancel.setText(MessageManager.getString("action.cancel"));
1145 cancel.addActionListener(new ActionListener()
1148 public void actionPerformed(ActionEvent e)
1150 fr.setTransparency(originalTransparency);
1151 updateFeatureRenderer(originalData);
1155 ok.setFont(JvSwingUtils.getLabelFont());
1156 ok.setText(MessageManager.getString("action.ok"));
1157 ok.addActionListener(new ActionListener()
1160 public void actionPerformed(ActionEvent e)
1165 loadColours.setFont(JvSwingUtils.getLabelFont());
1166 loadColours.setText(MessageManager.getString("label.load_colours"));
1167 loadColours.addActionListener(new ActionListener()
1170 public void actionPerformed(ActionEvent e)
1175 saveColours.setFont(JvSwingUtils.getLabelFont());
1176 saveColours.setText(MessageManager.getString("label.save_colours"));
1177 saveColours.addActionListener(new ActionListener()
1180 public void actionPerformed(ActionEvent e)
1185 transparency.addChangeListener(new ChangeListener()
1188 public void stateChanged(ChangeEvent evt)
1190 fr.setTransparency((100 - transparency.getValue()) / 100f);
1191 af.alignPanel.paintAlignment(true);
1195 transparency.setMaximum(70);
1196 transparency.setToolTipText(MessageManager
1197 .getString("label.transparency_tip"));
1198 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1199 fetchDAS.addActionListener(new ActionListener()
1202 public void actionPerformed(ActionEvent e)
1204 fetchDAS_actionPerformed(e);
1207 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1208 saveDAS.addActionListener(new ActionListener()
1211 public void actionPerformed(ActionEvent e)
1213 saveDAS_actionPerformed(e);
1216 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1217 dasSettingsPane.setBorder(null);
1218 cancelDAS.setEnabled(false);
1219 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1220 cancelDAS.addActionListener(new ActionListener()
1223 public void actionPerformed(ActionEvent e)
1225 cancelDAS_actionPerformed(e);
1228 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1229 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1231 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1233 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1234 transbuttons.add(optimizeOrder);
1235 transbuttons.add(invert);
1236 transbuttons.add(sortByScore);
1237 transbuttons.add(sortByDens);
1238 transbuttons.add(help);
1239 JPanel sliderPanel = new JPanel();
1240 sliderPanel.add(transparency);
1241 transPanel.add(transparency);
1242 transPanel.add(transbuttons);
1243 buttonPanel.add(ok);
1244 buttonPanel.add(cancel);
1245 buttonPanel.add(loadColours);
1246 buttonPanel.add(saveColours);
1247 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1248 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1249 dasButtonPanel.add(fetchDAS);
1250 dasButtonPanel.add(cancelDAS);
1251 dasButtonPanel.add(saveDAS);
1252 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1253 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1256 public void fetchDAS_actionPerformed(ActionEvent e)
1258 fetchDAS.setEnabled(false);
1259 cancelDAS.setEnabled(true);
1260 dassourceBrowser.setGuiEnabled(false);
1261 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1262 .getSelectedSources();
1263 doDasFeatureFetch(selectedSources, true, true);
1267 * get the features from selectedSources for all or the current selection
1269 * @param selectedSources
1270 * @param checkDbRefs
1271 * @param promptFetchDbRefs
1273 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1274 boolean checkDbRefs, boolean promptFetchDbRefs)
1276 SequenceI[] dataset, seqs;
1278 AlignmentViewport vp = af.getViewport();
1279 if (vp.getSelectionGroup() != null
1280 && vp.getSelectionGroup().getSize() > 0)
1282 iSize = vp.getSelectionGroup().getSize();
1283 dataset = new SequenceI[iSize];
1284 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1288 iSize = vp.getAlignment().getHeight();
1289 seqs = vp.getAlignment().getSequencesArray();
1292 dataset = new SequenceI[iSize];
1293 for (int i = 0; i < iSize; i++)
1295 dataset[i] = seqs[i].getDatasetSequence();
1298 cancelDAS.setEnabled(true);
1299 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1300 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1301 af.getViewport().setShowSequenceFeatures(true);
1302 af.showSeqFeatures.setSelected(true);
1306 * blocking call to initialise the das source browser
1308 public void initDasSources()
1310 dassourceBrowser.initDasSources();
1314 * examine the current list of das sources and return any matching the given
1315 * nicknames in sources
1318 * Vector of Strings to resolve to DAS source nicknames.
1319 * @return sources that are present in source list.
1321 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1323 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1327 * get currently selected das sources. ensure you have called initDasSources
1328 * before calling this.
1330 * @return vector of selected das source nicknames
1332 public Vector<jalviewSourceI> getSelectedSources()
1334 return dassourceBrowser.getSelectedSources();
1338 * properly initialise DAS fetcher and then initiate a new thread to fetch
1339 * features from the named sources (rather than any turned on by default)
1343 * if true then runs in same thread, otherwise passes to the Swing
1346 public void fetchDasFeatures(Vector<String> sources, boolean block)
1349 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1350 .resolveSourceNicknames(sources);
1351 if (resolved.size() == 0)
1353 resolved = dassourceBrowser.getSelectedSources();
1355 if (resolved.size() > 0)
1357 final List<jalviewSourceI> dassources = resolved;
1358 fetchDAS.setEnabled(false);
1359 // cancelDAS.setEnabled(true); doDasFetch does this.
1360 Runnable fetcher = new Runnable()
1366 doDasFeatureFetch(dassources, true, false);
1376 SwingUtilities.invokeLater(fetcher);
1381 public void saveDAS_actionPerformed(ActionEvent e)
1384 .saveProperties(jalview.bin.Cache.applicationProperties);
1387 public void complete()
1389 fetchDAS.setEnabled(true);
1390 cancelDAS.setEnabled(false);
1391 dassourceBrowser.setGuiEnabled(true);
1395 public void cancelDAS_actionPerformed(ActionEvent e)
1397 if (dasFeatureFetcher != null)
1399 dasFeatureFetcher.cancel();
1404 public void noDasSourceActive()
1408 .showInternalConfirmDialog(
1411 .getString("label.no_das_sources_selected_warn"),
1413 .getString("label.no_das_sources_selected_title"),
1414 JOptionPane.DEFAULT_OPTION,
1415 JOptionPane.INFORMATION_MESSAGE);
1418 // ///////////////////////////////////////////////////////////////////////
1419 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1420 // ///////////////////////////////////////////////////////////////////////
1421 class FeatureTableModel extends AbstractTableModel
1423 FeatureTableModel(Object[][] data)
1428 private String[] columnNames = {
1429 MessageManager.getString("label.feature_type"),
1430 MessageManager.getString("action.colour"),
1431 MessageManager.getString("label.display") };
1433 private Object[][] data;
1435 public Object[][] getData()
1440 public void setData(Object[][] data)
1446 public int getColumnCount()
1448 return columnNames.length;
1451 public Object[] getRow(int row)
1457 public int getRowCount()
1463 public String getColumnName(int col)
1465 return columnNames[col];
1469 public Object getValueAt(int row, int col)
1471 return data[row][col];
1475 public Class getColumnClass(int c)
1477 return getValueAt(0, c).getClass();
1481 public boolean isCellEditable(int row, int col)
1483 return col == 0 ? false : true;
1487 public void setValueAt(Object value, int row, int col)
1489 data[row][col] = value;
1490 fireTableCellUpdated(row, col);
1491 updateFeatureRenderer(data);
1496 class ColorRenderer extends JLabel implements TableCellRenderer
1498 javax.swing.border.Border unselectedBorder = null;
1500 javax.swing.border.Border selectedBorder = null;
1502 final String baseTT = "Click to edit, right/apple click for menu.";
1504 public ColorRenderer()
1506 setOpaque(true); // MUST do this for background to show up.
1507 setHorizontalTextPosition(SwingConstants.CENTER);
1508 setVerticalTextPosition(SwingConstants.CENTER);
1512 public Component getTableCellRendererComponent(JTable tbl,
1513 Object color, boolean isSelected, boolean hasFocus, int row,
1516 FeatureColourI cellColour = (FeatureColourI) color;
1517 // JLabel comp = new JLabel();
1521 // setBounds(getBounds());
1523 setToolTipText(baseTT);
1524 setBackground(tbl.getBackground());
1525 if (!cellColour.isSimpleColour())
1527 Rectangle cr = tbl.getCellRect(row, column, false);
1528 FeatureSettings.renderGraduatedColor(this, cellColour,
1529 (int) cr.getWidth(), (int) cr.getHeight());
1536 newColor = cellColour.getColour();
1537 setBackground(newColor);
1541 if (selectedBorder == null)
1543 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1544 tbl.getSelectionBackground());
1546 setBorder(selectedBorder);
1550 if (unselectedBorder == null)
1552 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1553 tbl.getBackground());
1555 setBorder(unselectedBorder);
1563 * update comp using rendering settings from gcol
1568 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1570 int w = comp.getWidth(), h = comp.getHeight();
1573 w = (int) comp.getPreferredSize().getWidth();
1574 h = (int) comp.getPreferredSize().getHeight();
1581 renderGraduatedColor(comp, gcol, w, h);
1584 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1587 boolean thr = false;
1590 if (gcol.isAboveThreshold())
1594 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1596 if (gcol.isBelowThreshold())
1600 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1602 if (gcol.isColourByLabel())
1604 tt = "Coloured by label text. " + tt;
1614 Color newColor = gcol.getMaxColour();
1615 comp.setBackground(newColor);
1616 // System.err.println("Width is " + w / 2);
1617 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1618 comp.setIcon(ficon);
1619 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1620 // + newColor.getGreen() + ", " + newColor.getBlue()
1621 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1622 // + ", " + minCol.getBlue() + ")");
1624 comp.setHorizontalAlignment(SwingConstants.CENTER);
1626 if (tt.length() > 0)
1628 if (comp.getToolTipText() == null)
1630 comp.setToolTipText(tt);
1634 comp.setToolTipText(tt + " " + comp.getToolTipText());
1640 class FeatureIcon implements Icon
1642 FeatureColourI gcol;
1646 boolean midspace = false;
1648 int width = 50, height = 20;
1650 int s1, e1; // start and end of midpoint band for thresholded symbol
1652 Color mpcolour = Color.white;
1654 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1674 public int getIconWidth()
1680 public int getIconHeight()
1686 public void paintIcon(Component c, Graphics g, int x, int y)
1689 if (gcol.isColourByLabel())
1692 g.fillRect(0, 0, width, height);
1693 // need an icon here.
1694 g.setColor(gcol.getMaxColour());
1696 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1698 // g.setFont(g.getFont().deriveFont(
1699 // AffineTransform.getScaleInstance(
1700 // width/g.getFontMetrics().stringWidth("Label"),
1701 // height/g.getFontMetrics().getHeight())));
1703 g.drawString(MessageManager.getString("label.label"), 0, 0);
1708 Color minCol = gcol.getMinColour();
1710 g.fillRect(0, 0, s1, height);
1713 g.setColor(Color.white);
1714 g.fillRect(s1, 0, e1 - s1, height);
1716 g.setColor(gcol.getMaxColour());
1717 g.fillRect(0, e1, width - e1, height);
1722 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1727 FeatureColourI currentColor;
1729 FeatureColourChooser chooser;
1735 JColorChooser colorChooser;
1739 protected static final String EDIT = "edit";
1741 int selectedRow = 0;
1743 public ColorEditor(FeatureSettings me)
1746 // Set up the editor (from the table's point of view),
1747 // which is a button.
1748 // This button brings up the color chooser dialog,
1749 // which is the editor from the user's point of view.
1750 button = new JButton();
1751 button.setActionCommand(EDIT);
1752 button.addActionListener(this);
1753 button.setBorderPainted(false);
1754 // Set up the dialog that the button brings up.
1755 colorChooser = new JColorChooser();
1756 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1757 colorChooser, this, // OK button handler
1758 null); // no CANCEL button handler
1762 * Handles events from the editor button and from the dialog's OK button.
1765 public void actionPerformed(ActionEvent e)
1768 if (EDIT.equals(e.getActionCommand()))
1770 // The user has clicked the cell, so
1771 // bring up the dialog.
1772 if (currentColor.isSimpleColour())
1774 // bring up simple color chooser
1775 button.setBackground(currentColor.getColour());
1776 colorChooser.setColor(currentColor.getColour());
1777 dialog.setVisible(true);
1781 // bring up graduated chooser.
1782 chooser = new FeatureColourChooser(me.fr, type);
1783 chooser.setRequestFocusEnabled(true);
1784 chooser.requestFocus();
1785 chooser.addActionListener(this);
1787 // Make the renderer reappear.
1788 fireEditingStopped();
1792 { // User pressed dialog's "OK" button.
1793 if (currentColor.isSimpleColour())
1795 currentColor = new FeatureColour(colorChooser.getColor());
1799 currentColor = chooser.getLastColour();
1801 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1802 fireEditingStopped();
1803 me.table.validate();
1807 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1809 public Object getCellEditorValue()
1811 return currentColor;
1814 // Implement the one method defined by TableCellEditor.
1816 public Component getTableCellEditorComponent(JTable table, Object value,
1817 boolean isSelected, int row, int column)
1819 currentColor = (FeatureColourI) value;
1820 this.selectedRow = row;
1821 type = me.table.getValueAt(row, 0).toString();
1822 button.setOpaque(true);
1823 button.setBackground(me.getBackground());
1824 if (!currentColor.isSimpleColour())
1826 JLabel btn = new JLabel();
1827 btn.setSize(button.getSize());
1828 FeatureSettings.renderGraduatedColor(btn, currentColor);
1829 button.setBackground(btn.getBackground());
1830 button.setIcon(btn.getIcon());
1831 button.setText(btn.getText());
1836 button.setIcon(null);
1837 button.setBackground(currentColor.getColour());