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 Cache.getProperty("LAST_DIRECTORY"), "fc",
754 "Sequence Feature Colours", "Sequence Feature Colours");
755 chooser.setFileView(new jalview.io.JalviewFileView());
756 chooser.setDialogTitle(MessageManager
757 .getString("label.load_feature_colours"));
758 chooser.setToolTipText(MessageManager.getString("action.load"));
760 int value = chooser.showOpenDialog(this);
762 if (value == JalviewFileChooser.APPROVE_OPTION)
764 File file = chooser.getSelectedFile();
768 InputStreamReader in = new InputStreamReader(new FileInputStream(
771 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
773 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
776 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
779 Color mincol = null, maxcol = null;
782 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
783 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
785 } catch (Exception e)
787 Cache.log.warn("Couldn't parse out graduated feature color.",
790 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
791 newcol.getMin(), newcol.getMax());
792 if (newcol.hasAutoScale())
794 gcol.setAutoScaled(newcol.getAutoScale());
796 if (newcol.hasColourByLabel())
798 gcol.setColourByLabel(newcol.getColourByLabel());
800 if (newcol.hasThreshold())
802 gcol.setThreshold(newcol.getThreshold());
804 if (newcol.getThreshType().length() > 0)
806 String ttyp = newcol.getThreshType();
807 if (ttyp.equalsIgnoreCase("ABOVE"))
809 gcol.setAboveThreshold(true);
811 if (ttyp.equalsIgnoreCase("BELOW"))
813 gcol.setBelowThreshold(true);
816 fr.setColour(name = newcol.getName(), gcol);
820 Color color = new Color(
821 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
822 fr.setColour(name = jucs.getColour(i).getName(),
823 new FeatureColour(color));
825 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
830 Object[][] data = ((FeatureTableModel) table.getModel())
833 updateFeatureRenderer(data, false);
836 } catch (Exception ex)
838 System.out.println("Error loading User Colour File\n" + ex);
845 JalviewFileChooser chooser = new JalviewFileChooser(
846 Cache.getProperty("LAST_DIRECTORY"), "fc",
847 "Sequence Feature Colours", "Sequence Feature Colours");
848 chooser.setFileView(new jalview.io.JalviewFileView());
849 chooser.setDialogTitle(MessageManager
850 .getString("label.save_feature_colours"));
851 chooser.setToolTipText(MessageManager.getString("action.save"));
853 int value = chooser.showSaveDialog(this);
855 if (value == JalviewFileChooser.APPROVE_OPTION)
857 String choice = chooser.getSelectedFile().getPath();
858 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
859 ucs.setSchemeName("Sequence Features");
862 PrintWriter out = new PrintWriter(new OutputStreamWriter(
863 new FileOutputStream(choice), "UTF-8"));
865 Set<String> fr_colours = fr.getAllFeatureColours();
866 Iterator<String> e = fr_colours.iterator();
867 float[] sortOrder = new float[fr_colours.size()];
868 String[] sortTypes = new String[fr_colours.size()];
872 sortTypes[i] = e.next();
873 sortOrder[i] = fr.getOrder(sortTypes[i]);
876 QuickSort.sort(sortOrder, sortTypes);
878 for (i = 0; i < sortTypes.length; i++)
880 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
881 col.setName(sortTypes[i]);
882 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
883 if (fcol.isSimpleColour())
885 col.setRGB(Format.getHexString(fcol.getColour()));
889 col.setRGB(Format.getHexString(fcol.getMaxColour()));
890 col.setMin(fcol.getMin());
891 col.setMax(fcol.getMax());
892 col.setMinRGB(jalview.util.Format.getHexString(fcol
894 col.setAutoScale(fcol.isAutoScaled());
895 col.setThreshold(fcol.getThreshold());
896 col.setColourByLabel(fcol.isColourByLabel());
897 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
898 .isBelowThreshold() ? "BELOW" : "NONE"));
904 } catch (Exception ex)
906 ex.printStackTrace();
911 public void invertSelection()
913 for (int i = 0; i < table.getRowCount(); i++)
915 Boolean value = (Boolean) table.getValueAt(i, 2);
917 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
921 public void orderByAvWidth()
923 if (table == null || table.getModel() == null)
927 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
928 float[] width = new float[data.length];
932 for (int i = 0; i < data.length; i++)
934 awidth = typeWidth.get(data[i][0]);
937 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
938 // weight - but have to make per
939 // sequence, too (awidth[2])
940 // if (width[i]==1) // hack to distinguish single width sequences.
952 boolean sort = false;
953 for (int i = 0; i < width.length; i++)
955 // awidth = (float[]) typeWidth.get(data[i][0]);
958 width[i] = fr.getOrder(data[i][0].toString());
961 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
966 width[i] /= max; // normalize
967 fr.setOrder(data[i][0].toString(), width[i]); // store for later
971 sort = sort || width[i - 1] > width[i];
976 jalview.util.QuickSort.sort(width, data);
977 // update global priority order
980 updateFeatureRenderer(data, false);
988 frame.setClosed(true);
989 } catch (Exception exe)
995 public void updateFeatureRenderer(Object[][] data)
997 updateFeatureRenderer(data, true);
1001 * Update the priority order of features; only repaint if this changed the
1002 * order of visible features
1007 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1009 if (fr.setFeaturePriority(data, visibleNew))
1011 af.alignPanel.paintAlignment(true);
1015 int selectedRow = -1;
1017 JTabbedPane tabbedPane = new JTabbedPane();
1019 BorderLayout borderLayout1 = new BorderLayout();
1021 BorderLayout borderLayout2 = new BorderLayout();
1023 BorderLayout borderLayout3 = new BorderLayout();
1025 JPanel bigPanel = new JPanel();
1027 BorderLayout borderLayout4 = new BorderLayout();
1029 JButton invert = new JButton();
1031 JPanel buttonPanel = new JPanel();
1033 JButton cancel = new JButton();
1035 JButton ok = new JButton();
1037 JButton loadColours = new JButton();
1039 JButton saveColours = new JButton();
1041 JPanel dasButtonPanel = new JPanel();
1043 JButton fetchDAS = new JButton();
1045 JButton saveDAS = new JButton();
1047 JButton cancelDAS = new JButton();
1049 JButton optimizeOrder = new JButton();
1051 JButton sortByScore = new JButton();
1053 JButton sortByDens = new JButton();
1055 JButton help = new JButton();
1057 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1059 private void jbInit() throws Exception
1061 this.setLayout(borderLayout1);
1062 settingsPane.setLayout(borderLayout2);
1063 dasSettingsPane.setLayout(borderLayout3);
1064 bigPanel.setLayout(borderLayout4);
1065 invert.setFont(JvSwingUtils.getLabelFont());
1066 invert.setText(MessageManager.getString("label.invert_selection"));
1067 invert.addActionListener(new ActionListener()
1070 public void actionPerformed(ActionEvent e)
1075 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1076 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1077 optimizeOrder.addActionListener(new ActionListener()
1080 public void actionPerformed(ActionEvent e)
1085 sortByScore.setFont(JvSwingUtils.getLabelFont());
1087 .setText(MessageManager.getString("label.seq_sort_by_score"));
1088 sortByScore.addActionListener(new ActionListener()
1091 public void actionPerformed(ActionEvent e)
1093 af.avc.sortAlignmentByFeatureScore(null);
1096 sortByDens.setFont(JvSwingUtils.getLabelFont());
1097 sortByDens.setText(MessageManager
1098 .getString("label.sequence_sort_by_density"));
1099 sortByDens.addActionListener(new ActionListener()
1102 public void actionPerformed(ActionEvent e)
1104 af.avc.sortAlignmentByFeatureDensity(null);
1107 help.setFont(JvSwingUtils.getLabelFont());
1108 help.setText(MessageManager.getString("action.help"));
1109 help.addActionListener(new ActionListener()
1112 public void actionPerformed(ActionEvent e)
1116 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1117 } catch (HelpSetException e1)
1119 e1.printStackTrace();
1123 help.setFont(JvSwingUtils.getLabelFont());
1124 help.setText(MessageManager.getString("action.help"));
1125 help.addActionListener(new ActionListener()
1128 public void actionPerformed(ActionEvent e)
1132 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1133 } catch (HelpSetException e1)
1135 e1.printStackTrace();
1139 cancel.setFont(JvSwingUtils.getLabelFont());
1140 cancel.setText(MessageManager.getString("action.cancel"));
1141 cancel.addActionListener(new ActionListener()
1144 public void actionPerformed(ActionEvent e)
1146 fr.setTransparency(originalTransparency);
1147 updateFeatureRenderer(originalData);
1151 ok.setFont(JvSwingUtils.getLabelFont());
1152 ok.setText(MessageManager.getString("action.ok"));
1153 ok.addActionListener(new ActionListener()
1156 public void actionPerformed(ActionEvent e)
1161 loadColours.setFont(JvSwingUtils.getLabelFont());
1162 loadColours.setText(MessageManager.getString("label.load_colours"));
1163 loadColours.addActionListener(new ActionListener()
1166 public void actionPerformed(ActionEvent e)
1171 saveColours.setFont(JvSwingUtils.getLabelFont());
1172 saveColours.setText(MessageManager.getString("label.save_colours"));
1173 saveColours.addActionListener(new ActionListener()
1176 public void actionPerformed(ActionEvent e)
1181 transparency.addChangeListener(new ChangeListener()
1184 public void stateChanged(ChangeEvent evt)
1186 fr.setTransparency((100 - transparency.getValue()) / 100f);
1187 af.alignPanel.paintAlignment(true);
1191 transparency.setMaximum(70);
1192 transparency.setToolTipText(MessageManager
1193 .getString("label.transparency_tip"));
1194 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1195 fetchDAS.addActionListener(new ActionListener()
1198 public void actionPerformed(ActionEvent e)
1200 fetchDAS_actionPerformed(e);
1203 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1204 saveDAS.addActionListener(new ActionListener()
1207 public void actionPerformed(ActionEvent e)
1209 saveDAS_actionPerformed(e);
1212 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1213 dasSettingsPane.setBorder(null);
1214 cancelDAS.setEnabled(false);
1215 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1216 cancelDAS.addActionListener(new ActionListener()
1219 public void actionPerformed(ActionEvent e)
1221 cancelDAS_actionPerformed(e);
1224 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1225 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1227 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1229 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1230 transbuttons.add(optimizeOrder);
1231 transbuttons.add(invert);
1232 transbuttons.add(sortByScore);
1233 transbuttons.add(sortByDens);
1234 transbuttons.add(help);
1235 JPanel sliderPanel = new JPanel();
1236 sliderPanel.add(transparency);
1237 transPanel.add(transparency);
1238 transPanel.add(transbuttons);
1239 buttonPanel.add(ok);
1240 buttonPanel.add(cancel);
1241 buttonPanel.add(loadColours);
1242 buttonPanel.add(saveColours);
1243 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1244 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1245 dasButtonPanel.add(fetchDAS);
1246 dasButtonPanel.add(cancelDAS);
1247 dasButtonPanel.add(saveDAS);
1248 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1249 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1252 public void fetchDAS_actionPerformed(ActionEvent e)
1254 fetchDAS.setEnabled(false);
1255 cancelDAS.setEnabled(true);
1256 dassourceBrowser.setGuiEnabled(false);
1257 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1258 .getSelectedSources();
1259 doDasFeatureFetch(selectedSources, true, true);
1263 * get the features from selectedSources for all or the current selection
1265 * @param selectedSources
1266 * @param checkDbRefs
1267 * @param promptFetchDbRefs
1269 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1270 boolean checkDbRefs, boolean promptFetchDbRefs)
1272 SequenceI[] dataset, seqs;
1274 AlignmentViewport vp = af.getViewport();
1275 if (vp.getSelectionGroup() != null
1276 && vp.getSelectionGroup().getSize() > 0)
1278 iSize = vp.getSelectionGroup().getSize();
1279 dataset = new SequenceI[iSize];
1280 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1284 iSize = vp.getAlignment().getHeight();
1285 seqs = vp.getAlignment().getSequencesArray();
1288 dataset = new SequenceI[iSize];
1289 for (int i = 0; i < iSize; i++)
1291 dataset[i] = seqs[i].getDatasetSequence();
1294 cancelDAS.setEnabled(true);
1295 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1296 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1297 af.getViewport().setShowSequenceFeatures(true);
1298 af.showSeqFeatures.setSelected(true);
1302 * blocking call to initialise the das source browser
1304 public void initDasSources()
1306 dassourceBrowser.initDasSources();
1310 * examine the current list of das sources and return any matching the given
1311 * nicknames in sources
1314 * Vector of Strings to resolve to DAS source nicknames.
1315 * @return sources that are present in source list.
1317 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1319 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1323 * get currently selected das sources. ensure you have called initDasSources
1324 * before calling this.
1326 * @return vector of selected das source nicknames
1328 public Vector<jalviewSourceI> getSelectedSources()
1330 return dassourceBrowser.getSelectedSources();
1334 * properly initialise DAS fetcher and then initiate a new thread to fetch
1335 * features from the named sources (rather than any turned on by default)
1339 * if true then runs in same thread, otherwise passes to the Swing
1342 public void fetchDasFeatures(Vector<String> sources, boolean block)
1345 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1346 .resolveSourceNicknames(sources);
1347 if (resolved.size() == 0)
1349 resolved = dassourceBrowser.getSelectedSources();
1351 if (resolved.size() > 0)
1353 final List<jalviewSourceI> dassources = resolved;
1354 fetchDAS.setEnabled(false);
1355 // cancelDAS.setEnabled(true); doDasFetch does this.
1356 Runnable fetcher = new Runnable()
1362 doDasFeatureFetch(dassources, true, false);
1372 SwingUtilities.invokeLater(fetcher);
1377 public void saveDAS_actionPerformed(ActionEvent e)
1380 .saveProperties(jalview.bin.Cache.applicationProperties);
1383 public void complete()
1385 fetchDAS.setEnabled(true);
1386 cancelDAS.setEnabled(false);
1387 dassourceBrowser.setGuiEnabled(true);
1391 public void cancelDAS_actionPerformed(ActionEvent e)
1393 if (dasFeatureFetcher != null)
1395 dasFeatureFetcher.cancel();
1400 public void noDasSourceActive()
1404 .showInternalConfirmDialog(
1407 .getString("label.no_das_sources_selected_warn"),
1409 .getString("label.no_das_sources_selected_title"),
1410 JOptionPane.DEFAULT_OPTION,
1411 JOptionPane.INFORMATION_MESSAGE);
1414 // ///////////////////////////////////////////////////////////////////////
1415 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1416 // ///////////////////////////////////////////////////////////////////////
1417 class FeatureTableModel extends AbstractTableModel
1419 FeatureTableModel(Object[][] data)
1424 private String[] columnNames = {
1425 MessageManager.getString("label.feature_type"),
1426 MessageManager.getString("action.colour"),
1427 MessageManager.getString("label.display") };
1429 private Object[][] data;
1431 public Object[][] getData()
1436 public void setData(Object[][] data)
1442 public int getColumnCount()
1444 return columnNames.length;
1447 public Object[] getRow(int row)
1453 public int getRowCount()
1459 public String getColumnName(int col)
1461 return columnNames[col];
1465 public Object getValueAt(int row, int col)
1467 return data[row][col];
1471 public Class getColumnClass(int c)
1473 return getValueAt(0, c).getClass();
1477 public boolean isCellEditable(int row, int col)
1479 return col == 0 ? false : true;
1483 public void setValueAt(Object value, int row, int col)
1485 data[row][col] = value;
1486 fireTableCellUpdated(row, col);
1487 updateFeatureRenderer(data);
1492 class ColorRenderer extends JLabel implements TableCellRenderer
1494 javax.swing.border.Border unselectedBorder = null;
1496 javax.swing.border.Border selectedBorder = null;
1498 final String baseTT = "Click to edit, right/apple click for menu.";
1500 public ColorRenderer()
1502 setOpaque(true); // MUST do this for background to show up.
1503 setHorizontalTextPosition(SwingConstants.CENTER);
1504 setVerticalTextPosition(SwingConstants.CENTER);
1508 public Component getTableCellRendererComponent(JTable tbl,
1509 Object color, boolean isSelected, boolean hasFocus, int row,
1512 FeatureColourI cellColour = (FeatureColourI) color;
1513 // JLabel comp = new JLabel();
1517 // setBounds(getBounds());
1519 setToolTipText(baseTT);
1520 setBackground(tbl.getBackground());
1521 if (!cellColour.isSimpleColour())
1523 Rectangle cr = tbl.getCellRect(row, column, false);
1524 FeatureSettings.renderGraduatedColor(this, cellColour,
1525 (int) cr.getWidth(), (int) cr.getHeight());
1532 newColor = cellColour.getColour();
1533 setBackground(newColor);
1537 if (selectedBorder == null)
1539 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1540 tbl.getSelectionBackground());
1542 setBorder(selectedBorder);
1546 if (unselectedBorder == null)
1548 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1549 tbl.getBackground());
1551 setBorder(unselectedBorder);
1559 * update comp using rendering settings from gcol
1564 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1566 int w = comp.getWidth(), h = comp.getHeight();
1569 w = (int) comp.getPreferredSize().getWidth();
1570 h = (int) comp.getPreferredSize().getHeight();
1577 renderGraduatedColor(comp, gcol, w, h);
1580 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1583 boolean thr = false;
1586 if (gcol.isAboveThreshold())
1590 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1592 if (gcol.isBelowThreshold())
1596 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1598 if (gcol.isColourByLabel())
1600 tt = "Coloured by label text. " + tt;
1610 Color newColor = gcol.getMaxColour();
1611 comp.setBackground(newColor);
1612 // System.err.println("Width is " + w / 2);
1613 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1614 comp.setIcon(ficon);
1615 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1616 // + newColor.getGreen() + ", " + newColor.getBlue()
1617 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1618 // + ", " + minCol.getBlue() + ")");
1620 comp.setHorizontalAlignment(SwingConstants.CENTER);
1622 if (tt.length() > 0)
1624 if (comp.getToolTipText() == null)
1626 comp.setToolTipText(tt);
1630 comp.setToolTipText(tt + " " + comp.getToolTipText());
1636 class FeatureIcon implements Icon
1638 FeatureColourI gcol;
1642 boolean midspace = false;
1644 int width = 50, height = 20;
1646 int s1, e1; // start and end of midpoint band for thresholded symbol
1648 Color mpcolour = Color.white;
1650 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1670 public int getIconWidth()
1676 public int getIconHeight()
1682 public void paintIcon(Component c, Graphics g, int x, int y)
1685 if (gcol.isColourByLabel())
1688 g.fillRect(0, 0, width, height);
1689 // need an icon here.
1690 g.setColor(gcol.getMaxColour());
1692 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1694 // g.setFont(g.getFont().deriveFont(
1695 // AffineTransform.getScaleInstance(
1696 // width/g.getFontMetrics().stringWidth("Label"),
1697 // height/g.getFontMetrics().getHeight())));
1699 g.drawString(MessageManager.getString("label.label"), 0, 0);
1704 Color minCol = gcol.getMinColour();
1706 g.fillRect(0, 0, s1, height);
1709 g.setColor(Color.white);
1710 g.fillRect(s1, 0, e1 - s1, height);
1712 g.setColor(gcol.getMaxColour());
1713 g.fillRect(0, e1, width - e1, height);
1718 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1723 FeatureColourI currentColor;
1725 FeatureColourChooser chooser;
1731 JColorChooser colorChooser;
1735 protected static final String EDIT = "edit";
1737 int selectedRow = 0;
1739 public ColorEditor(FeatureSettings me)
1742 // Set up the editor (from the table's point of view),
1743 // which is a button.
1744 // This button brings up the color chooser dialog,
1745 // which is the editor from the user's point of view.
1746 button = new JButton();
1747 button.setActionCommand(EDIT);
1748 button.addActionListener(this);
1749 button.setBorderPainted(false);
1750 // Set up the dialog that the button brings up.
1751 colorChooser = new JColorChooser();
1752 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1753 colorChooser, this, // OK button handler
1754 null); // no CANCEL button handler
1758 * Handles events from the editor button and from the dialog's OK button.
1761 public void actionPerformed(ActionEvent e)
1764 if (EDIT.equals(e.getActionCommand()))
1766 // The user has clicked the cell, so
1767 // bring up the dialog.
1768 if (currentColor.isSimpleColour())
1770 // bring up simple color chooser
1771 button.setBackground(currentColor.getColour());
1772 colorChooser.setColor(currentColor.getColour());
1773 dialog.setVisible(true);
1777 // bring up graduated chooser.
1778 chooser = new FeatureColourChooser(me.fr, type);
1779 chooser.setRequestFocusEnabled(true);
1780 chooser.requestFocus();
1781 chooser.addActionListener(this);
1783 // Make the renderer reappear.
1784 fireEditingStopped();
1788 { // User pressed dialog's "OK" button.
1789 if (currentColor.isSimpleColour())
1791 currentColor = new FeatureColour(colorChooser.getColor());
1795 currentColor = chooser.getLastColour();
1797 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1798 fireEditingStopped();
1799 me.table.validate();
1803 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1805 public Object getCellEditorValue()
1807 return currentColor;
1810 // Implement the one method defined by TableCellEditor.
1812 public Component getTableCellEditorComponent(JTable table, Object value,
1813 boolean isSelected, int row, int column)
1815 currentColor = (FeatureColourI) value;
1816 this.selectedRow = row;
1817 type = me.table.getValueAt(row, 0).toString();
1818 button.setOpaque(true);
1819 button.setBackground(me.getBackground());
1820 if (!currentColor.isSimpleColour())
1822 JLabel btn = new JLabel();
1823 btn.setSize(button.getSize());
1824 FeatureSettings.renderGraduatedColor(btn, currentColor);
1825 button.setBackground(btn.getBackground());
1826 button.setIcon(btn.getIcon());
1827 button.setText(btn.getText());
1832 button.setIcon(null);
1833 button.setBackground(currentColor.getColour());