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.FeatureSettingsControllerI;
24 import jalview.bin.Cache;
25 import jalview.datamodel.SequenceFeature;
26 import jalview.datamodel.SequenceI;
27 import jalview.gui.Help.HelpId;
28 import jalview.io.JalviewFileChooser;
29 import jalview.io.JalviewFileView;
30 import jalview.schemes.AnnotationColourGradient;
31 import jalview.schemes.GraduatedColor;
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.DasSequenceFeatureFetcher;
38 import jalview.ws.dbsources.das.api.jalviewSourceI;
40 import java.awt.BorderLayout;
41 import java.awt.Color;
42 import java.awt.Component;
44 import java.awt.Graphics;
45 import java.awt.GridLayout;
46 import java.awt.Rectangle;
47 import java.awt.event.ActionEvent;
48 import java.awt.event.ActionListener;
49 import java.awt.event.ItemEvent;
50 import java.awt.event.ItemListener;
51 import java.awt.event.MouseAdapter;
52 import java.awt.event.MouseEvent;
53 import java.awt.event.MouseMotionAdapter;
54 import java.beans.PropertyChangeEvent;
55 import java.beans.PropertyChangeListener;
57 import java.io.FileInputStream;
58 import java.io.FileOutputStream;
59 import java.io.InputStreamReader;
60 import java.io.OutputStreamWriter;
61 import java.io.PrintWriter;
62 import java.util.Hashtable;
63 import java.util.Iterator;
64 import java.util.List;
66 import java.util.Vector;
68 import javax.help.HelpSetException;
69 import javax.swing.AbstractCellEditor;
70 import javax.swing.BorderFactory;
71 import javax.swing.Icon;
72 import javax.swing.JButton;
73 import javax.swing.JCheckBox;
74 import javax.swing.JCheckBoxMenuItem;
75 import javax.swing.JColorChooser;
76 import javax.swing.JDialog;
77 import javax.swing.JInternalFrame;
78 import javax.swing.JLabel;
79 import javax.swing.JLayeredPane;
80 import javax.swing.JMenuItem;
81 import javax.swing.JOptionPane;
82 import javax.swing.JPanel;
83 import javax.swing.JPopupMenu;
84 import javax.swing.JScrollPane;
85 import javax.swing.JSlider;
86 import javax.swing.JTabbedPane;
87 import javax.swing.JTable;
88 import javax.swing.ListSelectionModel;
89 import javax.swing.SwingConstants;
90 import javax.swing.SwingUtilities;
91 import javax.swing.event.ChangeEvent;
92 import javax.swing.event.ChangeListener;
93 import javax.swing.table.AbstractTableModel;
94 import javax.swing.table.TableCellEditor;
95 import javax.swing.table.TableCellRenderer;
97 public class FeatureSettings extends JPanel implements
98 FeatureSettingsControllerI
100 DasSourceBrowser dassourceBrowser;
102 DasSequenceFeatureFetcher dasFeatureFetcher;
104 JPanel settingsPane = new JPanel();
106 JPanel dasSettingsPane = new JPanel();
108 final FeatureRenderer fr;
110 public final AlignFrame af;
112 Object[][] originalData;
114 private float originalTransparency;
116 final JInternalFrame frame;
118 JScrollPane scrollPane = new JScrollPane();
124 JSlider transparency = new JSlider();
126 JPanel transPanel = new JPanel(new GridLayout(1, 2));
128 public FeatureSettings(AlignFrame af)
131 fr = af.getFeatureRenderer();
132 // allow transparency to be recovered
133 transparency.setMaximum(100 - (int) ((originalTransparency=fr.getTransparency()) * 100));
138 } catch (Exception ex)
140 ex.printStackTrace();
143 table = new JTable() {
145 public String getToolTipText(MouseEvent e) {
146 if (table.columnAtPoint(e.getPoint()) == 0) {
148 * Tooltip for feature name only
150 return JvSwingUtils.wrapTooltip(true,
151 MessageManager.getString("label.feature_settings_click_drag"));
156 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
157 table.setFont(new Font("Verdana", Font.PLAIN, 12));
158 table.setDefaultRenderer(Color.class, new ColorRenderer());
160 table.setDefaultEditor(Color.class, new ColorEditor(this));
162 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
163 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
164 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
166 table.addMouseListener(new MouseAdapter()
168 public void mousePressed(MouseEvent evt)
170 selectedRow = table.rowAtPoint(evt.getPoint());
171 if (SwingUtilities.isRightMouseButton(evt))
173 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
174 table.getValueAt(selectedRow, 1), fr.getMinMax(),
175 evt.getX(), evt.getY());
177 else if (evt.getClickCount() == 2)
179 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
180 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
182 (String) table.getValueAt(selectedRow, 0));
186 // isPopupTrigger fires on mouseReleased on Mac
188 public void mouseReleased(MouseEvent evt)
190 selectedRow = table.rowAtPoint(evt.getPoint());
191 if (evt.isPopupTrigger())
193 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
194 table.getValueAt(selectedRow, 1), fr.getMinMax(),
201 table.addMouseMotionListener(new MouseMotionAdapter()
203 public void mouseDragged(MouseEvent evt)
205 int newRow = table.rowAtPoint(evt.getPoint());
206 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
208 Object[] temp = new Object[3];
209 temp[0] = table.getValueAt(selectedRow, 0);
210 temp[1] = table.getValueAt(selectedRow, 1);
211 temp[2] = table.getValueAt(selectedRow, 2);
213 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
214 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
215 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
217 table.setValueAt(temp[0], newRow, 0);
218 table.setValueAt(temp[1], newRow, 1);
219 table.setValueAt(temp[2], newRow, 2);
221 selectedRow = newRow;
225 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
226 // MessageManager.getString("label.feature_settings_click_drag")));
227 scrollPane.setViewportView(table);
229 dassourceBrowser = new DasSourceBrowser(this);
230 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
232 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
234 fr.findAllFeatures(true); // display everything!
237 discoverAllFeatureData();
238 final PropertyChangeListener change;
239 final FeatureSettings fs = this;
240 fr.addPropertyChangeListener(change = new PropertyChangeListener()
242 public void propertyChange(PropertyChangeEvent evt)
244 if (!fs.resettingTable && !fs.handlingUpdate)
246 fs.handlingUpdate = true;
247 fs.resetTable(null); // new groups may be added with new seuqence
248 // feature types only
249 fs.handlingUpdate = false;
255 frame = new JInternalFrame();
256 frame.setContentPane(this);
257 if (Platform.isAMac())
259 Desktop.addInternalFrame(frame,
260 MessageManager.getString("label.sequence_feature_settings"),
265 Desktop.addInternalFrame(frame,
266 MessageManager.getString("label.sequence_feature_settings"),
270 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
272 public void internalFrameClosed(
273 javax.swing.event.InternalFrameEvent evt)
275 fr.removePropertyChangeListener(change);
276 dassourceBrowser.fs = null;
279 frame.setLayer(JLayeredPane.PALETTE_LAYER);
282 protected void popupSort(final int selectedRow, final String type,
283 final Object typeCol, final Hashtable minmax, int x, int y)
285 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
286 "label.settings_for_param", new String[]
288 JMenuItem scr = new JMenuItem(
289 MessageManager.getString("label.sort_by_score"));
291 final FeatureSettings me = this;
292 scr.addActionListener(new ActionListener()
295 public void actionPerformed(ActionEvent e)
297 me.af.avc.sortAlignmentByFeatureScore(new String[]
302 JMenuItem dens = new JMenuItem(
303 MessageManager.getString("label.sort_by_density"));
304 dens.addActionListener(new ActionListener()
307 public void actionPerformed(ActionEvent e)
309 me.af.avc.sortAlignmentByFeatureDensity(new String[]
317 final Object typeMinMax = minmax.get(type);
319 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
320 * this is broken at the moment and isn't that useful anyway!
321 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
324 * public void actionPerformed(ActionEvent e) {
325 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
326 * null); } else { minmax.put(type, typeMinMax); } }
332 if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
334 // if (table.getValueAt(row, column));
335 // graduated colourschemes for those where minmax exists for the
336 // positional features
337 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
339 mxcol.setSelected(!(typeCol instanceof Color));
341 mxcol.addActionListener(new ActionListener()
343 JColorChooser colorChooser;
345 public void actionPerformed(ActionEvent e)
347 if (e.getSource() == mxcol)
349 if (typeCol instanceof Color)
351 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
353 fc.addActionListener(this);
357 // bring up simple color chooser
358 colorChooser = new JColorChooser();
359 JDialog dialog = JColorChooser.createDialog(me,
360 "Select new Colour", true, // modal
361 colorChooser, this, // OK button handler
362 null); // no CANCEL button handler
363 colorChooser.setColor(((GraduatedColor) typeCol)
365 dialog.setVisible(true);
370 if (e.getSource() instanceof FeatureColourChooser)
372 FeatureColourChooser fc = (FeatureColourChooser) e
374 table.setValueAt(fc.getLastColour(), selectedRow, 1);
379 // probably the color chooser!
380 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
382 me.updateFeatureRenderer(
383 ((FeatureTableModel) table.getModel()).getData(),
392 JMenuItem selCols = new JMenuItem(
393 MessageManager.getString("label.select_columns_containing"));
394 selCols.addActionListener(new ActionListener()
398 public void actionPerformed(ActionEvent arg0)
400 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
404 JMenuItem clearCols = new JMenuItem(
405 MessageManager.getString("label.select_columns_not_containing"));
406 clearCols.addActionListener(new ActionListener()
410 public void actionPerformed(ActionEvent arg0)
412 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
418 men.show(table, x, y);
422 * true when Feature Settings are updating from feature renderer
424 private boolean handlingUpdate = false;
427 * contains a float[3] for each feature type string. created by setTableData
429 Hashtable typeWidth = null;
432 synchronized public void discoverAllFeatureData()
434 Vector allFeatures = new Vector();
435 Vector allGroups = new Vector();
436 SequenceFeature[] tmpfeatures;
438 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
440 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
441 .getSequenceFeatures();
442 if (tmpfeatures == null)
448 while (index < tmpfeatures.length)
450 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
456 if (tmpfeatures[index].getFeatureGroup() != null)
458 group = tmpfeatures[index].featureGroup;
459 if (!allGroups.contains(group))
461 allGroups.addElement(group);
462 checkGroupState(group);
466 if (!allFeatures.contains(tmpfeatures[index].getType()))
468 allFeatures.addElement(tmpfeatures[index].getType());
480 * Synchronise gui group list and check visibility of group
483 * @return true if group is visible
485 private boolean checkGroupState(String group)
487 boolean visible = fr.checkGroupVisibility(group, true);
489 if (groupPanel == null)
491 groupPanel = new JPanel();
494 boolean alreadyAdded = false;
495 for (int g = 0; g < groupPanel.getComponentCount(); g++)
497 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
500 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
510 final String grp = group;
511 final JCheckBox check = new JCheckBox(group, visible);
512 check.setFont(new Font("Serif", Font.BOLD, 12));
513 check.addItemListener(new ItemListener()
515 public void itemStateChanged(ItemEvent evt)
517 fr.setGroupVisibility(check.getText(), check.isSelected());
518 af.alignPanel.getSeqPanel().seqCanvas.repaint();
519 if (af.alignPanel.overviewPanel != null)
521 af.alignPanel.overviewPanel.updateOverviewImage();
524 resetTable(new String[]
528 groupPanel.add(check);
532 boolean resettingTable = false;
534 synchronized void resetTable(String[] groupChanged)
536 if (resettingTable == true)
540 resettingTable = true;
541 typeWidth = new Hashtable();
542 // TODO: change avWidth calculation to 'per-sequence' average and use long
544 float[] avWidth = null;
545 SequenceFeature[] tmpfeatures;
546 String group = null, type;
547 Vector visibleChecks = new Vector();
549 // Find out which features should be visible depending on which groups
550 // are selected / deselected
551 // and recompute average width ordering
552 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
555 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
556 .getSequenceFeatures();
557 if (tmpfeatures == null)
563 while (index < tmpfeatures.length)
565 group = tmpfeatures[index].featureGroup;
567 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
573 if (group == null || checkGroupState(group))
575 type = tmpfeatures[index].getType();
576 if (!visibleChecks.contains(type))
578 visibleChecks.addElement(type);
581 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
583 typeWidth.put(tmpfeatures[index].getType(),
584 avWidth = new float[3]);
588 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
591 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
593 avWidth[1] += 1 + tmpfeatures[index].getBegin()
594 - tmpfeatures[index].getEnd();
598 avWidth[1] += 1 + tmpfeatures[index].getEnd()
599 - tmpfeatures[index].getBegin();
605 int fSize = visibleChecks.size();
606 Object[][] data = new Object[fSize][3];
609 if (fr.hasRenderOrder())
613 fr.findAllFeatures(groupChanged != null); // prod to update
614 // colourschemes. but don't
616 // First add the checks in the previous render order,
617 // in case the window has been closed and reopened
619 List<String> frl = fr.getRenderOrder();
620 for (int ro = frl.size() - 1; ro > -1; ro--)
624 if (!visibleChecks.contains(type))
629 data[dataIndex][0] = type;
630 data[dataIndex][1] = fr.getFeatureStyle(type);
631 data[dataIndex][2] = new Boolean(af.getViewport()
632 .getFeaturesDisplayed().isVisible(type));
634 visibleChecks.removeElement(type);
638 fSize = visibleChecks.size();
639 for (int i = 0; i < fSize; i++)
641 // These must be extra features belonging to the group
642 // which was just selected
643 type = visibleChecks.elementAt(i).toString();
644 data[dataIndex][0] = type;
646 data[dataIndex][1] = fr.getFeatureStyle(type);
647 if (data[dataIndex][1] == null)
649 // "Colour has been updated in another view!!"
650 fr.clearRenderOrder();
654 data[dataIndex][2] = new Boolean(true);
658 if (originalData == null)
660 originalData = new Object[data.length][3];
661 for (int i = 0; i < data.length; i++)
663 System.arraycopy(data[i], 0, originalData[i], 0, 3);
667 table.setModel(new FeatureTableModel(data));
668 table.getColumnModel().getColumn(0).setPreferredWidth(200);
670 if (groupPanel != null)
672 groupPanel.setLayout(new GridLayout(
673 fr.getFeatureGroupsSize() / 4 + 1, 4));
675 groupPanel.validate();
676 bigPanel.add(groupPanel, BorderLayout.NORTH);
679 updateFeatureRenderer(data, groupChanged != null);
680 resettingTable = false;
684 * reorder data based on the featureRenderers global priority list.
688 private void ensureOrder(Object[][] data)
690 boolean sort = false;
691 float[] order = new float[data.length];
692 for (int i = 0; i < order.length; i++)
694 order[i] = fr.getOrder(data[i][0].toString());
697 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
701 sort = sort || order[i - 1] > order[i];
706 QuickSort.sortFloat(order, data);
712 JalviewFileChooser chooser = new JalviewFileChooser(
713 Cache.getProperty("LAST_DIRECTORY"), new String[]
714 { "fc" }, new String[]
715 { "Sequence Feature Colours" }, "Sequence Feature Colours");
716 chooser.setFileView(new JalviewFileView());
717 chooser.setDialogTitle(MessageManager.getString("label.load_feature_colours"));
718 chooser.setToolTipText(MessageManager.getString("action.load"));
720 int value = chooser.showOpenDialog(this);
722 if (value == JalviewFileChooser.APPROVE_OPTION)
724 File file = chooser.getSelectedFile();
728 InputStreamReader in = new InputStreamReader(new FileInputStream(
731 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
735 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
738 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
741 Color mincol = null, maxcol = null;
744 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
745 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
747 } catch (Exception e)
749 Cache.log.warn("Couldn't parse out graduated feature color.",
752 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
753 newcol.getMin(), newcol.getMax());
754 if (newcol.hasAutoScale())
756 gcol.setAutoScaled(newcol.getAutoScale());
758 if (newcol.hasColourByLabel())
760 gcol.setColourByLabel(newcol.getColourByLabel());
762 if (newcol.hasThreshold())
764 gcol.setThresh(newcol.getThreshold());
765 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
767 if (newcol.getThreshType().length() > 0)
769 String ttyp = newcol.getThreshType();
770 if (ttyp.equalsIgnoreCase("NONE"))
772 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
774 if (ttyp.equalsIgnoreCase("ABOVE"))
776 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
778 if (ttyp.equalsIgnoreCase("BELOW"))
780 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
783 fr.setColour(name = newcol.getName(), gcol);
787 fr.setColour(name = jucs.getColour(i).getName(), new Color(
788 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
790 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
795 Object[][] data = ((FeatureTableModel) table.getModel())
798 updateFeatureRenderer(data, false);
801 } catch (Exception ex)
803 System.out.println("Error loading User Colour File\n" + ex);
810 JalviewFileChooser chooser = new JalviewFileChooser(
811 Cache.getProperty("LAST_DIRECTORY"), new String[]
812 { "fc" }, new String[]
813 { "Sequence Feature Colours" }, "Sequence Feature Colours");
814 chooser.setFileView(new JalviewFileView());
815 chooser.setDialogTitle(MessageManager.getString("label.save_feature_colours"));
816 chooser.setToolTipText(MessageManager.getString("action.save"));
818 int value = chooser.showSaveDialog(this);
820 if (value == JalviewFileChooser.APPROVE_OPTION)
822 String choice = chooser.getSelectedFile().getPath();
823 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
824 ucs.setSchemeName("Sequence Features");
827 PrintWriter out = new PrintWriter(new OutputStreamWriter(
828 new FileOutputStream(choice), "UTF-8"));
830 Set fr_colours = fr.getAllFeatureColours();
831 Iterator e = fr_colours.iterator();
832 float[] sortOrder = new float[fr_colours.size()];
833 String[] sortTypes = new String[fr_colours.size()];
837 sortTypes[i] = e.next().toString();
838 sortOrder[i] = fr.getOrder(sortTypes[i]);
841 QuickSort.sortFloat(sortOrder, sortTypes);
845 for (i = 0; i < sortTypes.length; i++)
847 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
848 col.setName(sortTypes[i]);
849 col.setRGB(Format.getHexString(fr.getColour(col
851 fcol = fr.getFeatureStyle(sortTypes[i]);
852 if (fcol instanceof GraduatedColor)
854 gcol = (GraduatedColor) fcol;
855 col.setMin(gcol.getMin());
856 col.setMax(gcol.getMax());
857 col.setMinRGB(Format.getHexString(gcol
859 col.setAutoScale(gcol.isAutoScale());
860 col.setThreshold(gcol.getThresh());
861 col.setColourByLabel(gcol.isColourByLabel());
862 switch (gcol.getThreshType())
864 case AnnotationColourGradient.NO_THRESHOLD:
865 col.setThreshType("NONE");
867 case AnnotationColourGradient.ABOVE_THRESHOLD:
868 col.setThreshType("ABOVE");
870 case AnnotationColourGradient.BELOW_THRESHOLD:
871 col.setThreshType("BELOW");
879 } catch (Exception ex)
881 ex.printStackTrace();
886 public void invertSelection()
888 for (int i = 0; i < table.getRowCount(); i++)
890 Boolean value = (Boolean) table.getValueAt(i, 2);
892 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
896 public void orderByAvWidth()
898 if (table == null || table.getModel() == null)
902 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
903 float[] width = new float[data.length];
907 for (int i = 0; i < data.length; i++)
909 awidth = (float[]) typeWidth.get(data[i][0]);
912 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
913 // weight - but have to make per
914 // sequence, too (awidth[2])
915 // if (width[i]==1) // hack to distinguish single width sequences.
927 boolean sort = false;
928 for (int i = 0; i < width.length; i++)
930 // awidth = (float[]) typeWidth.get(data[i][0]);
933 width[i] = fr.getOrder(data[i][0].toString());
936 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
941 width[i] /= max; // normalize
942 fr.setOrder(data[i][0].toString(), width[i]); // store for later
946 sort = sort || width[i - 1] > width[i];
951 QuickSort.sortFloat(width, data);
952 // update global priority order
955 updateFeatureRenderer(data, false);
963 frame.setClosed(true);
964 } catch (Exception exe)
970 public void updateFeatureRenderer(Object[][] data)
972 updateFeatureRenderer(data, true);
975 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
977 fr.setFeaturePriority(data, visibleNew);
978 af.alignPanel.paintAlignment(true);
981 int selectedRow = -1;
983 JTabbedPane tabbedPane = new JTabbedPane();
985 BorderLayout borderLayout1 = new BorderLayout();
987 BorderLayout borderLayout2 = new BorderLayout();
989 BorderLayout borderLayout3 = new BorderLayout();
991 JPanel bigPanel = new JPanel();
993 BorderLayout borderLayout4 = new BorderLayout();
995 JButton invert = new JButton();
997 JPanel buttonPanel = new JPanel();
999 JButton cancel = new JButton();
1001 JButton ok = new JButton();
1003 JButton loadColours = new JButton();
1005 JButton saveColours = new JButton();
1007 JPanel dasButtonPanel = new JPanel();
1009 JButton fetchDAS = new JButton();
1011 JButton saveDAS = new JButton();
1013 JButton cancelDAS = new JButton();
1015 JButton optimizeOrder = new JButton();
1017 JButton sortByScore = new JButton();
1019 JButton sortByDens = new JButton();
1021 JButton help = new JButton();
1023 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1025 private void jbInit() throws Exception
1027 this.setLayout(borderLayout1);
1028 settingsPane.setLayout(borderLayout2);
1029 dasSettingsPane.setLayout(borderLayout3);
1030 bigPanel.setLayout(borderLayout4);
1031 invert.setFont(JvSwingUtils.getLabelFont());
1032 invert.setText(MessageManager.getString("label.invert_selection"));
1033 invert.addActionListener(new ActionListener()
1035 public void actionPerformed(ActionEvent e)
1040 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1041 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1042 optimizeOrder.addActionListener(new ActionListener()
1044 public void actionPerformed(ActionEvent e)
1049 sortByScore.setFont(JvSwingUtils.getLabelFont());
1051 .setText(MessageManager.getString("label.seq_sort_by_score"));
1052 sortByScore.addActionListener(new ActionListener()
1054 public void actionPerformed(ActionEvent e)
1056 af.avc.sortAlignmentByFeatureScore(null);
1059 sortByDens.setFont(JvSwingUtils.getLabelFont());
1060 sortByDens.setText(MessageManager
1061 .getString("label.sequence_sort_by_density"));
1062 sortByDens.addActionListener(new ActionListener()
1064 public void actionPerformed(ActionEvent e)
1066 af.avc.sortAlignmentByFeatureDensity(null);
1069 help.setFont(JvSwingUtils.getLabelFont());
1070 help.setText(MessageManager.getString("action.help"));
1071 help.addActionListener(new ActionListener()
1073 public void actionPerformed(ActionEvent e)
1077 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1078 } catch (HelpSetException e1)
1080 e1.printStackTrace();
1084 help.setFont(JvSwingUtils.getLabelFont());
1085 help.setText(MessageManager.getString("action.help"));
1086 help.addActionListener(new ActionListener()
1088 public void actionPerformed(ActionEvent e)
1092 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1093 } catch (HelpSetException e1)
1095 e1.printStackTrace();
1099 cancel.setFont(JvSwingUtils.getLabelFont());
1100 cancel.setText(MessageManager.getString("action.cancel"));
1101 cancel.addActionListener(new ActionListener()
1103 public void actionPerformed(ActionEvent e)
1105 fr.setTransparency(originalTransparency);
1106 updateFeatureRenderer(originalData);
1110 ok.setFont(JvSwingUtils.getLabelFont());
1111 ok.setText(MessageManager.getString("action.ok"));
1112 ok.addActionListener(new ActionListener()
1114 public void actionPerformed(ActionEvent e)
1119 loadColours.setFont(JvSwingUtils.getLabelFont());
1120 loadColours.setText(MessageManager.getString("label.load_colours"));
1121 loadColours.addActionListener(new ActionListener()
1123 public void actionPerformed(ActionEvent e)
1128 saveColours.setFont(JvSwingUtils.getLabelFont());
1129 saveColours.setText(MessageManager.getString("label.save_colours"));
1130 saveColours.addActionListener(new ActionListener()
1132 public void actionPerformed(ActionEvent e)
1137 transparency.addChangeListener(new ChangeListener()
1139 public void stateChanged(ChangeEvent evt)
1141 fr.setTransparency((100 - transparency.getValue()) / 100f);
1142 af.alignPanel.paintAlignment(true);
1146 transparency.setMaximum(70);
1147 transparency.setToolTipText(MessageManager
1148 .getString("label.transparency_tip"));
1149 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1150 fetchDAS.addActionListener(new ActionListener()
1152 public void actionPerformed(ActionEvent e)
1154 fetchDAS_actionPerformed(e);
1157 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1158 saveDAS.addActionListener(new ActionListener()
1160 public void actionPerformed(ActionEvent e)
1162 saveDAS_actionPerformed(e);
1165 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1166 dasSettingsPane.setBorder(null);
1167 cancelDAS.setEnabled(false);
1168 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1169 cancelDAS.addActionListener(new ActionListener()
1171 public void actionPerformed(ActionEvent e)
1173 cancelDAS_actionPerformed(e);
1176 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1177 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1178 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1179 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1180 transbuttons.add(optimizeOrder);
1181 transbuttons.add(invert);
1182 transbuttons.add(sortByScore);
1183 transbuttons.add(sortByDens);
1184 transbuttons.add(help);
1185 JPanel sliderPanel = new JPanel();
1186 sliderPanel.add(transparency);
1187 transPanel.add(transparency);
1188 transPanel.add(transbuttons);
1189 buttonPanel.add(ok);
1190 buttonPanel.add(cancel);
1191 buttonPanel.add(loadColours);
1192 buttonPanel.add(saveColours);
1193 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1194 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1195 dasButtonPanel.add(fetchDAS);
1196 dasButtonPanel.add(cancelDAS);
1197 dasButtonPanel.add(saveDAS);
1198 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1199 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1202 public void fetchDAS_actionPerformed(ActionEvent e)
1204 fetchDAS.setEnabled(false);
1205 cancelDAS.setEnabled(true);
1206 dassourceBrowser.setGuiEnabled(false);
1207 Vector selectedSources = dassourceBrowser.getSelectedSources();
1208 doDasFeatureFetch(selectedSources, true, true);
1212 * get the features from selectedSources for all or the current selection
1214 * @param selectedSources
1215 * @param checkDbRefs
1216 * @param promptFetchDbRefs
1218 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1219 boolean checkDbRefs, boolean promptFetchDbRefs)
1221 SequenceI[] dataset, seqs;
1223 AlignmentViewport vp = af.getViewport();
1224 if (vp.getSelectionGroup() != null
1225 && vp.getSelectionGroup().getSize() > 0)
1227 iSize = vp.getSelectionGroup().getSize();
1228 dataset = new SequenceI[iSize];
1229 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1233 iSize = vp.getAlignment().getHeight();
1234 seqs = vp.getAlignment().getSequencesArray();
1237 dataset = new SequenceI[iSize];
1238 for (int i = 0; i < iSize; i++)
1240 dataset[i] = seqs[i].getDatasetSequence();
1243 cancelDAS.setEnabled(true);
1244 dasFeatureFetcher = new DasSequenceFeatureFetcher(dataset,
1245 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1246 af.getViewport().setShowSequenceFeatures(true);
1247 af.showSeqFeatures.setSelected(true);
1251 * blocking call to initialise the das source browser
1253 public void initDasSources()
1255 dassourceBrowser.initDasSources();
1259 * examine the current list of das sources and return any matching the given
1260 * nicknames in sources
1263 * Vector of Strings to resolve to DAS source nicknames.
1264 * @return sources that are present in source list.
1266 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1268 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1272 * get currently selected das sources. ensure you have called initDasSources
1273 * before calling this.
1275 * @return vector of selected das source nicknames
1277 public Vector getSelectedSources()
1279 return dassourceBrowser.getSelectedSources();
1283 * properly initialise DAS fetcher and then initiate a new thread to fetch
1284 * features from the named sources (rather than any turned on by default)
1288 * if true then runs in same thread, otherwise passes to the Swing
1291 public void fetchDasFeatures(Vector sources, boolean block)
1294 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1295 .resolveSourceNicknames(sources);
1296 if (resolved.size() == 0)
1298 resolved = dassourceBrowser.getSelectedSources();
1300 if (resolved.size() > 0)
1302 final List<jalviewSourceI> dassources = resolved;
1303 fetchDAS.setEnabled(false);
1304 // cancelDAS.setEnabled(true); doDasFetch does this.
1305 Runnable fetcher = new Runnable()
1310 doDasFeatureFetch(dassources, true, false);
1320 SwingUtilities.invokeLater(fetcher);
1325 public void saveDAS_actionPerformed(ActionEvent e)
1328 .saveProperties(Cache.applicationProperties);
1331 public void complete()
1333 fetchDAS.setEnabled(true);
1334 cancelDAS.setEnabled(false);
1335 dassourceBrowser.setGuiEnabled(true);
1339 public void cancelDAS_actionPerformed(ActionEvent e)
1341 if (dasFeatureFetcher != null)
1343 dasFeatureFetcher.cancel();
1348 public void noDasSourceActive()
1352 .showInternalConfirmDialog(
1355 .getString("label.no_das_sources_selected_warn"),
1357 .getString("label.no_das_sources_selected_title"),
1358 JOptionPane.DEFAULT_OPTION,
1359 JOptionPane.INFORMATION_MESSAGE);
1362 // ///////////////////////////////////////////////////////////////////////
1363 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1364 // ///////////////////////////////////////////////////////////////////////
1365 class FeatureTableModel extends AbstractTableModel
1367 FeatureTableModel(Object[][] data)
1372 private String[] columnNames =
1373 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1375 private Object[][] data;
1377 public Object[][] getData()
1382 public void setData(Object[][] data)
1387 public int getColumnCount()
1389 return columnNames.length;
1392 public Object[] getRow(int row)
1397 public int getRowCount()
1402 public String getColumnName(int col)
1404 return columnNames[col];
1407 public Object getValueAt(int row, int col)
1409 return data[row][col];
1412 public Class getColumnClass(int c)
1414 return getValueAt(0, c).getClass();
1417 public boolean isCellEditable(int row, int col)
1419 return col == 0 ? false : true;
1422 public void setValueAt(Object value, int row, int col)
1424 data[row][col] = value;
1425 fireTableCellUpdated(row, col);
1426 updateFeatureRenderer(data);
1431 class ColorRenderer extends JLabel implements TableCellRenderer
1433 javax.swing.border.Border unselectedBorder = null;
1435 javax.swing.border.Border selectedBorder = null;
1437 final String baseTT = "Click to edit, right/apple click for menu.";
1439 public ColorRenderer()
1441 setOpaque(true); // MUST do this for background to show up.
1442 setHorizontalTextPosition(SwingConstants.CENTER);
1443 setVerticalTextPosition(SwingConstants.CENTER);
1446 public Component getTableCellRendererComponent(JTable table,
1447 Object color, boolean isSelected, boolean hasFocus, int row,
1450 // JLabel comp = new JLabel();
1454 // setBounds(getBounds());
1456 setToolTipText(baseTT);
1457 setBackground(table.getBackground());
1458 if (color instanceof GraduatedColor)
1460 Rectangle cr = table.getCellRect(row, column, false);
1461 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1462 (int) cr.getWidth(), (int) cr.getHeight());
1469 newColor = (Color) color;
1471 setBackground(newColor);
1472 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1473 // + newColor.getGreen() + ", " + newColor.getBlue());
1477 if (selectedBorder == null)
1479 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1480 table.getSelectionBackground());
1483 setBorder(selectedBorder);
1487 if (unselectedBorder == null)
1489 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1490 table.getBackground());
1493 setBorder(unselectedBorder);
1501 * update comp using rendering settings from gcol
1506 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1508 int w = comp.getWidth(), h = comp.getHeight();
1511 w = (int) comp.getPreferredSize().getWidth();
1512 h = (int) comp.getPreferredSize().getHeight();
1519 renderGraduatedColor(comp, gcol, w, h);
1522 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1525 boolean thr = false;
1528 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1532 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1534 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1538 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1540 if (gcol.isColourByLabel())
1542 tt = "Coloured by label text. " + tt;
1552 Color newColor = gcol.getMaxColor();
1553 comp.setBackground(newColor);
1554 // System.err.println("Width is " + w / 2);
1555 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1556 comp.setIcon(ficon);
1557 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1558 // + newColor.getGreen() + ", " + newColor.getBlue()
1559 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1560 // + ", " + minCol.getBlue() + ")");
1562 comp.setHorizontalAlignment(SwingConstants.CENTER);
1564 if (tt.length() > 0)
1566 if (comp.getToolTipText() == null)
1568 comp.setToolTipText(tt);
1572 comp.setToolTipText(tt + " " + comp.getToolTipText());
1578 class FeatureIcon implements Icon
1580 GraduatedColor gcol;
1584 boolean midspace = false;
1586 int width = 50, height = 20;
1588 int s1, e1; // start and end of midpoint band for thresholded symbol
1590 Color mpcolour = Color.white;
1592 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1611 public int getIconWidth()
1616 public int getIconHeight()
1621 public void paintIcon(Component c, Graphics g, int x, int y)
1624 if (gcol.isColourByLabel())
1627 g.fillRect(0, 0, width, height);
1628 // need an icon here.
1629 g.setColor(gcol.getMaxColor());
1631 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1633 // g.setFont(g.getFont().deriveFont(
1634 // AffineTransform.getScaleInstance(
1635 // width/g.getFontMetrics().stringWidth("Label"),
1636 // height/g.getFontMetrics().getHeight())));
1638 g.drawString(MessageManager.getString("label.label"), 0, 0);
1643 Color minCol = gcol.getMinColor();
1645 g.fillRect(0, 0, s1, height);
1648 g.setColor(Color.white);
1649 g.fillRect(s1, 0, e1 - s1, height);
1651 g.setColor(gcol.getMaxColor());
1652 g.fillRect(0, e1, width - e1, height);
1657 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1662 GraduatedColor currentGColor;
1664 FeatureColourChooser chooser;
1672 JColorChooser colorChooser;
1676 protected static final String EDIT = "edit";
1678 int selectedRow = 0;
1680 public ColorEditor(FeatureSettings me)
1683 // Set up the editor (from the table's point of view),
1684 // which is a button.
1685 // This button brings up the color chooser dialog,
1686 // which is the editor from the user's point of view.
1687 button = new JButton();
1688 button.setActionCommand(EDIT);
1689 button.addActionListener(this);
1690 button.setBorderPainted(false);
1691 // Set up the dialog that the button brings up.
1692 colorChooser = new JColorChooser();
1693 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1694 colorChooser, this, // OK button handler
1695 null); // no CANCEL button handler
1699 * Handles events from the editor button and from the dialog's OK button.
1701 public void actionPerformed(ActionEvent e)
1704 if (EDIT.equals(e.getActionCommand()))
1706 // The user has clicked the cell, so
1707 // bring up the dialog.
1708 if (currentColor != null)
1710 // bring up simple color chooser
1711 button.setBackground(currentColor);
1712 colorChooser.setColor(currentColor);
1713 dialog.setVisible(true);
1717 // bring up graduated chooser.
1718 chooser = new FeatureColourChooser(me.fr, type);
1719 chooser.setRequestFocusEnabled(true);
1720 chooser.requestFocus();
1721 chooser.addActionListener(this);
1723 // Make the renderer reappear.
1724 fireEditingStopped();
1728 { // User pressed dialog's "OK" button.
1729 if (currentColor != null)
1731 currentColor = colorChooser.getColor();
1735 // class cast exceptions may be raised if the chooser created on a
1736 // non-graduated color
1737 currentGColor = (GraduatedColor) chooser.getLastColour();
1739 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1740 fireEditingStopped();
1741 me.table.validate();
1745 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1746 public Object getCellEditorValue()
1748 if (currentColor == null)
1750 return currentGColor;
1752 return currentColor;
1755 // Implement the one method defined by TableCellEditor.
1756 public Component getTableCellEditorComponent(JTable table, Object value,
1757 boolean isSelected, int row, int column)
1759 currentGColor = null;
1760 currentColor = null;
1761 this.selectedRow = row;
1762 type = me.table.getValueAt(row, 0).toString();
1763 button.setOpaque(true);
1764 button.setBackground(me.getBackground());
1765 if (value instanceof GraduatedColor)
1767 currentGColor = (GraduatedColor) value;
1768 JLabel btn = new JLabel();
1769 btn.setSize(button.getSize());
1770 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1771 button.setBackground(btn.getBackground());
1772 button.setIcon(btn.getIcon());
1773 button.setText(btn.getText());
1778 button.setIcon(null);
1779 currentColor = (Color) value;
1780 button.setBackground(currentColor);