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.schemes.AnnotationColourGradient;
30 import jalview.schemes.GraduatedColor;
31 import jalview.util.MessageManager;
32 import jalview.viewmodel.AlignmentViewport;
33 import jalview.ws.dbsources.das.api.jalviewSourceI;
35 import java.awt.BorderLayout;
36 import java.awt.Color;
37 import java.awt.Component;
39 import java.awt.Graphics;
40 import java.awt.GridLayout;
41 import java.awt.Rectangle;
42 import java.awt.event.ActionEvent;
43 import java.awt.event.ActionListener;
44 import java.awt.event.ItemEvent;
45 import java.awt.event.ItemListener;
46 import java.awt.event.MouseAdapter;
47 import java.awt.event.MouseEvent;
48 import java.awt.event.MouseMotionAdapter;
49 import java.beans.PropertyChangeEvent;
50 import java.beans.PropertyChangeListener;
52 import java.io.FileInputStream;
53 import java.io.FileOutputStream;
54 import java.io.InputStreamReader;
55 import java.io.OutputStreamWriter;
56 import java.io.PrintWriter;
57 import java.util.Arrays;
58 import java.util.Hashtable;
59 import java.util.Iterator;
60 import java.util.List;
62 import java.util.Vector;
64 import javax.help.HelpSetException;
65 import javax.swing.AbstractCellEditor;
66 import javax.swing.BorderFactory;
67 import javax.swing.Icon;
68 import javax.swing.JButton;
69 import javax.swing.JCheckBox;
70 import javax.swing.JCheckBoxMenuItem;
71 import javax.swing.JColorChooser;
72 import javax.swing.JDialog;
73 import javax.swing.JInternalFrame;
74 import javax.swing.JLabel;
75 import javax.swing.JLayeredPane;
76 import javax.swing.JMenuItem;
77 import javax.swing.JOptionPane;
78 import javax.swing.JPanel;
79 import javax.swing.JPopupMenu;
80 import javax.swing.JScrollPane;
81 import javax.swing.JSlider;
82 import javax.swing.JTabbedPane;
83 import javax.swing.JTable;
84 import javax.swing.ListSelectionModel;
85 import javax.swing.SwingConstants;
86 import javax.swing.SwingUtilities;
87 import javax.swing.event.ChangeEvent;
88 import javax.swing.event.ChangeListener;
89 import javax.swing.table.AbstractTableModel;
90 import javax.swing.table.TableCellEditor;
91 import javax.swing.table.TableCellRenderer;
93 public class FeatureSettings extends JPanel implements
94 FeatureSettingsControllerI
96 DasSourceBrowser dassourceBrowser;
98 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
100 JPanel settingsPane = new JPanel();
102 JPanel dasSettingsPane = new JPanel();
104 final FeatureRenderer fr;
106 public final AlignFrame af;
108 Object[][] originalData;
110 private float originalTransparency;
112 final JInternalFrame frame;
114 JScrollPane scrollPane = new JScrollPane();
120 JSlider transparency = new JSlider();
122 JPanel transPanel = new JPanel(new GridLayout(1, 2));
124 public FeatureSettings(AlignFrame af)
127 fr = af.getFeatureRenderer();
128 // allow transparency to be recovered
129 transparency.setMaximum(100 - (int) ((originalTransparency = fr
130 .getTransparency()) * 100));
135 } catch (Exception ex)
137 ex.printStackTrace();
143 public String getToolTipText(MouseEvent e)
145 if (table.columnAtPoint(e.getPoint()) == 0)
148 * Tooltip for feature name only
150 return JvSwingUtils.wrapTooltip(true, MessageManager
151 .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()
169 public void mousePressed(MouseEvent evt)
171 selectedRow = table.rowAtPoint(evt.getPoint());
172 if (SwingUtilities.isRightMouseButton(evt))
174 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
175 table.getValueAt(selectedRow, 1), fr.getMinMax(),
176 evt.getX(), evt.getY());
178 else if (evt.getClickCount() == 2)
180 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
181 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
183 (String) table.getValueAt(selectedRow, 0));
187 // isPopupTrigger fires on mouseReleased on Mac
189 public void mouseReleased(MouseEvent evt)
191 selectedRow = table.rowAtPoint(evt.getPoint());
192 if (evt.isPopupTrigger())
194 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
195 table.getValueAt(selectedRow, 1), fr.getMinMax(),
196 evt.getX(), evt.getY());
201 table.addMouseMotionListener(new MouseMotionAdapter()
204 public void mouseDragged(MouseEvent evt)
206 int newRow = table.rowAtPoint(evt.getPoint());
207 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
209 Object[][] data = ((FeatureTableModel) table.getModel())
211 Object[] temp = data[selectedRow];
212 data[selectedRow] = data[newRow];
214 updateFeatureRenderer(data);
216 selectedRow = newRow;
220 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
221 // MessageManager.getString("label.feature_settings_click_drag")));
222 scrollPane.setViewportView(table);
224 dassourceBrowser = new DasSourceBrowser(this);
225 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
227 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
229 fr.findAllFeatures(true); // display everything!
232 discoverAllFeatureData();
233 final PropertyChangeListener change;
234 final FeatureSettings fs = this;
235 fr.addPropertyChangeListener(change = new PropertyChangeListener()
238 public void propertyChange(PropertyChangeEvent evt)
240 if (!fs.resettingTable && !fs.handlingUpdate)
242 fs.handlingUpdate = true;
243 fs.resetTable(null); // new groups may be added with new seuqence
244 // feature types only
245 fs.handlingUpdate = false;
251 frame = new JInternalFrame();
252 frame.setContentPane(this);
253 if (new jalview.util.Platform().isAMac())
255 Desktop.addInternalFrame(frame,
256 MessageManager.getString("label.sequence_feature_settings"),
261 Desktop.addInternalFrame(frame,
262 MessageManager.getString("label.sequence_feature_settings"),
266 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
269 public void internalFrameClosed(
270 javax.swing.event.InternalFrameEvent evt)
272 fr.removePropertyChangeListener(change);
273 dassourceBrowser.fs = null;
276 frame.setLayer(JLayeredPane.PALETTE_LAYER);
279 protected void popupSort(final int selectedRow, final String type,
280 final Object typeCol, final Hashtable minmax, int x, int y)
282 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
283 "label.settings_for_param", new String[] { type }));
284 JMenuItem scr = new JMenuItem(
285 MessageManager.getString("label.sort_by_score"));
287 final FeatureSettings me = this;
288 scr.addActionListener(new ActionListener()
292 public void actionPerformed(ActionEvent e)
294 me.af.avc.sortAlignmentByFeatureScore(Arrays
295 .asList(new String[] { type }));
299 JMenuItem dens = new JMenuItem(
300 MessageManager.getString("label.sort_by_density"));
301 dens.addActionListener(new ActionListener()
305 public void actionPerformed(ActionEvent e)
307 me.af.avc.sortAlignmentByFeatureDensity(Arrays
308 .asList(new String[] { type }));
315 final Object typeMinMax = minmax.get(type);
317 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
318 * this is broken at the moment and isn't that useful anyway!
319 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
322 * public void actionPerformed(ActionEvent e) {
323 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
324 * null); } else { minmax.put(type, typeMinMax); } }
330 if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
332 // if (table.getValueAt(row, column));
333 // graduated colourschemes for those where minmax exists for the
334 // positional features
335 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
337 mxcol.setSelected(!(typeCol instanceof Color));
339 mxcol.addActionListener(new ActionListener()
341 JColorChooser colorChooser;
344 public void actionPerformed(ActionEvent e)
346 if (e.getSource() == mxcol)
348 if (typeCol instanceof Color)
350 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
352 fc.addActionListener(this);
356 // bring up simple color chooser
357 colorChooser = new JColorChooser();
358 JDialog dialog = JColorChooser.createDialog(me,
359 "Select new Colour", true, // modal
360 colorChooser, this, // OK button handler
361 null); // no CANCEL button handler
362 colorChooser.setColor(((GraduatedColor) typeCol)
364 dialog.setVisible(true);
369 if (e.getSource() instanceof FeatureColourChooser)
371 FeatureColourChooser fc = (FeatureColourChooser) e
373 table.setValueAt(fc.getLastColour(), selectedRow, 1);
378 // probably the color chooser!
379 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
381 me.updateFeatureRenderer(
382 ((FeatureTableModel) table.getModel()).getData(),
391 JMenuItem selCols = new JMenuItem(
392 MessageManager.getString("label.select_columns_containing"));
393 selCols.addActionListener(new ActionListener()
397 public void actionPerformed(ActionEvent arg0)
399 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
403 JMenuItem clearCols = new JMenuItem(
404 MessageManager.getString("label.select_columns_not_containing"));
405 clearCols.addActionListener(new ActionListener()
409 public void actionPerformed(ActionEvent arg0)
411 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
417 men.show(table, x, y);
421 * true when Feature Settings are updating from feature renderer
423 private boolean handlingUpdate = false;
426 * contains a float[3] for each feature type string. created by setTableData
428 Hashtable typeWidth = null;
431 synchronized public void discoverAllFeatureData()
433 Vector allFeatures = new Vector();
434 Vector allGroups = new Vector();
435 SequenceFeature[] tmpfeatures;
437 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
439 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
440 .getSequenceFeatures();
441 if (tmpfeatures == null)
447 while (index < tmpfeatures.length)
449 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
455 if (tmpfeatures[index].getFeatureGroup() != null)
457 group = tmpfeatures[index].featureGroup;
458 if (!allGroups.contains(group))
460 allGroups.addElement(group);
461 checkGroupState(group);
465 if (!allFeatures.contains(tmpfeatures[index].getType()))
467 allFeatures.addElement(tmpfeatures[index].getType());
479 * Synchronise gui group list and check visibility of group
482 * @return true if group is visible
484 private boolean checkGroupState(String group)
486 boolean visible = fr.checkGroupVisibility(group, true);
488 if (groupPanel == null)
490 groupPanel = new JPanel();
493 boolean alreadyAdded = false;
494 for (int g = 0; g < groupPanel.getComponentCount(); g++)
496 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
499 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
509 final String grp = group;
510 final JCheckBox check = new JCheckBox(group, visible);
511 check.setFont(new Font("Serif", Font.BOLD, 12));
512 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[] { grp });
527 groupPanel.add(check);
531 boolean resettingTable = false;
533 synchronized void resetTable(String[] groupChanged)
535 if (resettingTable == true)
539 resettingTable = true;
540 typeWidth = new Hashtable();
541 // TODO: change avWidth calculation to 'per-sequence' average and use long
543 float[] avWidth = null;
544 SequenceFeature[] tmpfeatures;
545 String group = null, type;
546 Vector visibleChecks = new Vector();
548 // Find out which features should be visible depending on which groups
549 // are selected / deselected
550 // and recompute average width ordering
551 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
554 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
555 .getSequenceFeatures();
556 if (tmpfeatures == null)
562 while (index < tmpfeatures.length)
564 group = tmpfeatures[index].featureGroup;
566 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
572 if (group == null || checkGroupState(group))
574 type = tmpfeatures[index].getType();
575 if (!visibleChecks.contains(type))
577 visibleChecks.addElement(type);
580 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
582 typeWidth.put(tmpfeatures[index].getType(),
583 avWidth = new float[3]);
587 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
590 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
592 avWidth[1] += 1 + tmpfeatures[index].getBegin()
593 - tmpfeatures[index].getEnd();
597 avWidth[1] += 1 + tmpfeatures[index].getEnd()
598 - tmpfeatures[index].getBegin();
604 int fSize = visibleChecks.size();
605 Object[][] data = new Object[fSize][3];
608 if (fr.hasRenderOrder())
612 fr.findAllFeatures(groupChanged != null); // prod to update
613 // colourschemes. but don't
615 // First add the checks in the previous render order,
616 // in case the window has been closed and reopened
618 List<String> frl = fr.getRenderOrder();
619 for (int ro = frl.size() - 1; ro > -1; ro--)
623 if (!visibleChecks.contains(type))
628 data[dataIndex][0] = type;
629 data[dataIndex][1] = fr.getFeatureStyle(type);
630 data[dataIndex][2] = new Boolean(af.getViewport()
631 .getFeaturesDisplayed().isVisible(type));
633 visibleChecks.removeElement(type);
637 fSize = visibleChecks.size();
638 for (int i = 0; i < fSize; i++)
640 // These must be extra features belonging to the group
641 // which was just selected
642 type = visibleChecks.elementAt(i).toString();
643 data[dataIndex][0] = type;
645 data[dataIndex][1] = fr.getFeatureStyle(type);
646 if (data[dataIndex][1] == null)
648 // "Colour has been updated in another view!!"
649 fr.clearRenderOrder();
653 data[dataIndex][2] = new Boolean(true);
657 if (originalData == null)
659 originalData = new Object[data.length][3];
660 for (int i = 0; i < data.length; i++)
662 System.arraycopy(data[i], 0, originalData[i], 0, 3);
666 table.setModel(new FeatureTableModel(data));
667 table.getColumnModel().getColumn(0).setPreferredWidth(200);
669 if (groupPanel != null)
671 groupPanel.setLayout(new GridLayout(
672 fr.getFeatureGroupsSize() / 4 + 1, 4));
674 groupPanel.validate();
675 bigPanel.add(groupPanel, BorderLayout.NORTH);
678 updateFeatureRenderer(data, groupChanged != null);
679 resettingTable = false;
683 * reorder data based on the featureRenderers global priority list.
687 private void ensureOrder(Object[][] data)
689 boolean sort = false;
690 float[] order = new float[data.length];
691 for (int i = 0; i < order.length; i++)
693 order[i] = fr.getOrder(data[i][0].toString());
696 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
700 sort = sort || order[i - 1] > order[i];
705 jalview.util.QuickSort.sort(order, data);
711 JalviewFileChooser chooser = new JalviewFileChooser(
712 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
713 new String[] { "fc" },
714 new String[] { "Sequence Feature Colours" },
715 "Sequence Feature Colours");
716 chooser.setFileView(new jalview.io.JalviewFileView());
717 chooser.setDialogTitle(MessageManager
718 .getString("label.load_feature_colours"));
719 chooser.setToolTipText(MessageManager.getString("action.load"));
721 int value = chooser.showOpenDialog(this);
723 if (value == JalviewFileChooser.APPROVE_OPTION)
725 File file = chooser.getSelectedFile();
729 InputStreamReader in = new InputStreamReader(new FileInputStream(
732 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
733 jucs = jucs.unmarshal(in);
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 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
812 new String[] { "fc" },
813 new String[] { "Sequence Feature Colours" },
814 "Sequence Feature Colours");
815 chooser.setFileView(new jalview.io.JalviewFileView());
816 chooser.setDialogTitle(MessageManager
817 .getString("label.save_feature_colours"));
818 chooser.setToolTipText(MessageManager.getString("action.save"));
820 int value = chooser.showSaveDialog(this);
822 if (value == JalviewFileChooser.APPROVE_OPTION)
824 String choice = chooser.getSelectedFile().getPath();
825 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
826 ucs.setSchemeName("Sequence Features");
829 PrintWriter out = new PrintWriter(new OutputStreamWriter(
830 new FileOutputStream(choice), "UTF-8"));
832 Set fr_colours = fr.getAllFeatureColours();
833 Iterator e = fr_colours.iterator();
834 float[] sortOrder = new float[fr_colours.size()];
835 String[] sortTypes = new String[fr_colours.size()];
839 sortTypes[i] = e.next().toString();
840 sortOrder[i] = fr.getOrder(sortTypes[i]);
843 jalview.util.QuickSort.sort(sortOrder, sortTypes);
847 for (i = 0; i < sortTypes.length; i++)
849 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
850 col.setName(sortTypes[i]);
851 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
853 fcol = fr.getFeatureStyle(sortTypes[i]);
854 if (fcol instanceof GraduatedColor)
856 gcol = (GraduatedColor) fcol;
857 col.setMin(gcol.getMin());
858 col.setMax(gcol.getMax());
859 col.setMinRGB(jalview.util.Format.getHexString(gcol
861 col.setAutoScale(gcol.isAutoScale());
862 col.setThreshold(gcol.getThresh());
863 col.setColourByLabel(gcol.isColourByLabel());
864 switch (gcol.getThreshType())
866 case AnnotationColourGradient.NO_THRESHOLD:
867 col.setThreshType("NONE");
869 case AnnotationColourGradient.ABOVE_THRESHOLD:
870 col.setThreshType("ABOVE");
872 case AnnotationColourGradient.BELOW_THRESHOLD:
873 col.setThreshType("BELOW");
881 } catch (Exception ex)
883 ex.printStackTrace();
888 public void invertSelection()
890 for (int i = 0; i < table.getRowCount(); i++)
892 Boolean value = (Boolean) table.getValueAt(i, 2);
894 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
898 public void orderByAvWidth()
900 if (table == null || table.getModel() == null)
904 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
905 float[] width = new float[data.length];
909 for (int i = 0; i < data.length; i++)
911 awidth = (float[]) typeWidth.get(data[i][0]);
914 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
915 // weight - but have to make per
916 // sequence, too (awidth[2])
917 // if (width[i]==1) // hack to distinguish single width sequences.
929 boolean sort = false;
930 for (int i = 0; i < width.length; i++)
932 // awidth = (float[]) typeWidth.get(data[i][0]);
935 width[i] = fr.getOrder(data[i][0].toString());
938 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
943 width[i] /= max; // normalize
944 fr.setOrder(data[i][0].toString(), width[i]); // store for later
948 sort = sort || width[i - 1] > width[i];
953 jalview.util.QuickSort.sort(width, data);
954 // update global priority order
957 updateFeatureRenderer(data, false);
965 frame.setClosed(true);
966 } catch (Exception exe)
972 public void updateFeatureRenderer(Object[][] data)
974 updateFeatureRenderer(data, true);
978 * Update the priority order of features; only repaint if this changed the
979 * order of visible features
984 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
986 if (fr.setFeaturePriority(data, visibleNew))
988 af.alignPanel.paintAlignment(true);
992 int selectedRow = -1;
994 JTabbedPane tabbedPane = new JTabbedPane();
996 BorderLayout borderLayout1 = new BorderLayout();
998 BorderLayout borderLayout2 = new BorderLayout();
1000 BorderLayout borderLayout3 = new BorderLayout();
1002 JPanel bigPanel = new JPanel();
1004 BorderLayout borderLayout4 = new BorderLayout();
1006 JButton invert = new JButton();
1008 JPanel buttonPanel = new JPanel();
1010 JButton cancel = new JButton();
1012 JButton ok = new JButton();
1014 JButton loadColours = new JButton();
1016 JButton saveColours = new JButton();
1018 JPanel dasButtonPanel = new JPanel();
1020 JButton fetchDAS = new JButton();
1022 JButton saveDAS = new JButton();
1024 JButton cancelDAS = new JButton();
1026 JButton optimizeOrder = new JButton();
1028 JButton sortByScore = new JButton();
1030 JButton sortByDens = new JButton();
1032 JButton help = new JButton();
1034 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1036 private void jbInit() throws Exception
1038 this.setLayout(borderLayout1);
1039 settingsPane.setLayout(borderLayout2);
1040 dasSettingsPane.setLayout(borderLayout3);
1041 bigPanel.setLayout(borderLayout4);
1042 invert.setFont(JvSwingUtils.getLabelFont());
1043 invert.setText(MessageManager.getString("label.invert_selection"));
1044 invert.addActionListener(new ActionListener()
1047 public void actionPerformed(ActionEvent e)
1052 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1053 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1054 optimizeOrder.addActionListener(new ActionListener()
1057 public void actionPerformed(ActionEvent e)
1062 sortByScore.setFont(JvSwingUtils.getLabelFont());
1064 .setText(MessageManager.getString("label.seq_sort_by_score"));
1065 sortByScore.addActionListener(new ActionListener()
1068 public void actionPerformed(ActionEvent e)
1070 af.avc.sortAlignmentByFeatureScore(null);
1073 sortByDens.setFont(JvSwingUtils.getLabelFont());
1074 sortByDens.setText(MessageManager
1075 .getString("label.sequence_sort_by_density"));
1076 sortByDens.addActionListener(new ActionListener()
1079 public void actionPerformed(ActionEvent e)
1081 af.avc.sortAlignmentByFeatureDensity(null);
1084 help.setFont(JvSwingUtils.getLabelFont());
1085 help.setText(MessageManager.getString("action.help"));
1086 help.addActionListener(new ActionListener()
1089 public void actionPerformed(ActionEvent e)
1093 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1094 } catch (HelpSetException e1)
1096 e1.printStackTrace();
1100 help.setFont(JvSwingUtils.getLabelFont());
1101 help.setText(MessageManager.getString("action.help"));
1102 help.addActionListener(new ActionListener()
1105 public void actionPerformed(ActionEvent e)
1109 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1110 } catch (HelpSetException e1)
1112 e1.printStackTrace();
1116 cancel.setFont(JvSwingUtils.getLabelFont());
1117 cancel.setText(MessageManager.getString("action.cancel"));
1118 cancel.addActionListener(new ActionListener()
1121 public void actionPerformed(ActionEvent e)
1123 fr.setTransparency(originalTransparency);
1124 updateFeatureRenderer(originalData);
1128 ok.setFont(JvSwingUtils.getLabelFont());
1129 ok.setText(MessageManager.getString("action.ok"));
1130 ok.addActionListener(new ActionListener()
1133 public void actionPerformed(ActionEvent e)
1138 loadColours.setFont(JvSwingUtils.getLabelFont());
1139 loadColours.setText(MessageManager.getString("label.load_colours"));
1140 loadColours.addActionListener(new ActionListener()
1143 public void actionPerformed(ActionEvent e)
1148 saveColours.setFont(JvSwingUtils.getLabelFont());
1149 saveColours.setText(MessageManager.getString("label.save_colours"));
1150 saveColours.addActionListener(new ActionListener()
1153 public void actionPerformed(ActionEvent e)
1158 transparency.addChangeListener(new ChangeListener()
1161 public void stateChanged(ChangeEvent evt)
1163 fr.setTransparency((100 - transparency.getValue()) / 100f);
1164 af.alignPanel.paintAlignment(true);
1168 transparency.setMaximum(70);
1169 transparency.setToolTipText(MessageManager
1170 .getString("label.transparency_tip"));
1171 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1172 fetchDAS.addActionListener(new ActionListener()
1175 public void actionPerformed(ActionEvent e)
1177 fetchDAS_actionPerformed(e);
1180 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1181 saveDAS.addActionListener(new ActionListener()
1184 public void actionPerformed(ActionEvent e)
1186 saveDAS_actionPerformed(e);
1189 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1190 dasSettingsPane.setBorder(null);
1191 cancelDAS.setEnabled(false);
1192 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1193 cancelDAS.addActionListener(new ActionListener()
1196 public void actionPerformed(ActionEvent e)
1198 cancelDAS_actionPerformed(e);
1201 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1202 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1204 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1206 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1207 transbuttons.add(optimizeOrder);
1208 transbuttons.add(invert);
1209 transbuttons.add(sortByScore);
1210 transbuttons.add(sortByDens);
1211 transbuttons.add(help);
1212 JPanel sliderPanel = new JPanel();
1213 sliderPanel.add(transparency);
1214 transPanel.add(transparency);
1215 transPanel.add(transbuttons);
1216 buttonPanel.add(ok);
1217 buttonPanel.add(cancel);
1218 buttonPanel.add(loadColours);
1219 buttonPanel.add(saveColours);
1220 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1221 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1222 dasButtonPanel.add(fetchDAS);
1223 dasButtonPanel.add(cancelDAS);
1224 dasButtonPanel.add(saveDAS);
1225 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1226 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1229 public void fetchDAS_actionPerformed(ActionEvent e)
1231 fetchDAS.setEnabled(false);
1232 cancelDAS.setEnabled(true);
1233 dassourceBrowser.setGuiEnabled(false);
1234 Vector selectedSources = dassourceBrowser.getSelectedSources();
1235 doDasFeatureFetch(selectedSources, true, true);
1239 * get the features from selectedSources for all or the current selection
1241 * @param selectedSources
1242 * @param checkDbRefs
1243 * @param promptFetchDbRefs
1245 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1246 boolean checkDbRefs, boolean promptFetchDbRefs)
1248 SequenceI[] dataset, seqs;
1250 AlignmentViewport vp = af.getViewport();
1251 if (vp.getSelectionGroup() != null
1252 && vp.getSelectionGroup().getSize() > 0)
1254 iSize = vp.getSelectionGroup().getSize();
1255 dataset = new SequenceI[iSize];
1256 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1260 iSize = vp.getAlignment().getHeight();
1261 seqs = vp.getAlignment().getSequencesArray();
1264 dataset = new SequenceI[iSize];
1265 for (int i = 0; i < iSize; i++)
1267 dataset[i] = seqs[i].getDatasetSequence();
1270 cancelDAS.setEnabled(true);
1271 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1272 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1273 af.getViewport().setShowSequenceFeatures(true);
1274 af.showSeqFeatures.setSelected(true);
1278 * blocking call to initialise the das source browser
1280 public void initDasSources()
1282 dassourceBrowser.initDasSources();
1286 * examine the current list of das sources and return any matching the given
1287 * nicknames in sources
1290 * Vector of Strings to resolve to DAS source nicknames.
1291 * @return sources that are present in source list.
1293 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1295 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1299 * get currently selected das sources. ensure you have called initDasSources
1300 * before calling this.
1302 * @return vector of selected das source nicknames
1304 public Vector getSelectedSources()
1306 return dassourceBrowser.getSelectedSources();
1310 * properly initialise DAS fetcher and then initiate a new thread to fetch
1311 * features from the named sources (rather than any turned on by default)
1315 * if true then runs in same thread, otherwise passes to the Swing
1318 public void fetchDasFeatures(Vector sources, boolean block)
1321 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1322 .resolveSourceNicknames(sources);
1323 if (resolved.size() == 0)
1325 resolved = dassourceBrowser.getSelectedSources();
1327 if (resolved.size() > 0)
1329 final List<jalviewSourceI> dassources = resolved;
1330 fetchDAS.setEnabled(false);
1331 // cancelDAS.setEnabled(true); doDasFetch does this.
1332 Runnable fetcher = new Runnable()
1338 doDasFeatureFetch(dassources, true, false);
1348 SwingUtilities.invokeLater(fetcher);
1353 public void saveDAS_actionPerformed(ActionEvent e)
1356 .saveProperties(jalview.bin.Cache.applicationProperties);
1359 public void complete()
1361 fetchDAS.setEnabled(true);
1362 cancelDAS.setEnabled(false);
1363 dassourceBrowser.setGuiEnabled(true);
1367 public void cancelDAS_actionPerformed(ActionEvent e)
1369 if (dasFeatureFetcher != null)
1371 dasFeatureFetcher.cancel();
1376 public void noDasSourceActive()
1380 .showInternalConfirmDialog(
1383 .getString("label.no_das_sources_selected_warn"),
1385 .getString("label.no_das_sources_selected_title"),
1386 JOptionPane.DEFAULT_OPTION,
1387 JOptionPane.INFORMATION_MESSAGE);
1390 // ///////////////////////////////////////////////////////////////////////
1391 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1392 // ///////////////////////////////////////////////////////////////////////
1393 class FeatureTableModel extends AbstractTableModel
1395 FeatureTableModel(Object[][] data)
1400 private String[] columnNames = {
1401 MessageManager.getString("label.feature_type"),
1402 MessageManager.getString("action.colour"),
1403 MessageManager.getString("label.display") };
1405 private Object[][] data;
1407 public Object[][] getData()
1412 public void setData(Object[][] data)
1418 public int getColumnCount()
1420 return columnNames.length;
1423 public Object[] getRow(int row)
1429 public int getRowCount()
1435 public String getColumnName(int col)
1437 return columnNames[col];
1441 public Object getValueAt(int row, int col)
1443 return data[row][col];
1447 public Class getColumnClass(int c)
1449 return getValueAt(0, c).getClass();
1453 public boolean isCellEditable(int row, int col)
1455 return col == 0 ? false : true;
1459 public void setValueAt(Object value, int row, int col)
1461 data[row][col] = value;
1462 fireTableCellUpdated(row, col);
1463 updateFeatureRenderer(data);
1468 class ColorRenderer extends JLabel implements TableCellRenderer
1470 javax.swing.border.Border unselectedBorder = null;
1472 javax.swing.border.Border selectedBorder = null;
1474 final String baseTT = "Click to edit, right/apple click for menu.";
1476 public ColorRenderer()
1478 setOpaque(true); // MUST do this for background to show up.
1479 setHorizontalTextPosition(SwingConstants.CENTER);
1480 setVerticalTextPosition(SwingConstants.CENTER);
1484 public Component getTableCellRendererComponent(JTable table,
1485 Object color, boolean isSelected, boolean hasFocus, int row,
1488 // JLabel comp = new JLabel();
1492 // setBounds(getBounds());
1494 setToolTipText(baseTT);
1495 setBackground(table.getBackground());
1496 if (color instanceof GraduatedColor)
1498 Rectangle cr = table.getCellRect(row, column, false);
1499 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1500 (int) cr.getWidth(), (int) cr.getHeight());
1507 newColor = (Color) color;
1509 setBackground(newColor);
1510 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1511 // + newColor.getGreen() + ", " + newColor.getBlue());
1515 if (selectedBorder == null)
1517 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1518 table.getSelectionBackground());
1521 setBorder(selectedBorder);
1525 if (unselectedBorder == null)
1527 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1528 table.getBackground());
1531 setBorder(unselectedBorder);
1539 * update comp using rendering settings from gcol
1544 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1546 int w = comp.getWidth(), h = comp.getHeight();
1549 w = (int) comp.getPreferredSize().getWidth();
1550 h = (int) comp.getPreferredSize().getHeight();
1557 renderGraduatedColor(comp, gcol, w, h);
1560 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1563 boolean thr = false;
1566 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1570 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1572 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1576 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1578 if (gcol.isColourByLabel())
1580 tt = "Coloured by label text. " + tt;
1590 Color newColor = gcol.getMaxColor();
1591 comp.setBackground(newColor);
1592 // System.err.println("Width is " + w / 2);
1593 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1594 comp.setIcon(ficon);
1595 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1596 // + newColor.getGreen() + ", " + newColor.getBlue()
1597 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1598 // + ", " + minCol.getBlue() + ")");
1600 comp.setHorizontalAlignment(SwingConstants.CENTER);
1602 if (tt.length() > 0)
1604 if (comp.getToolTipText() == null)
1606 comp.setToolTipText(tt);
1610 comp.setToolTipText(tt + " " + comp.getToolTipText());
1616 class FeatureIcon implements Icon
1618 GraduatedColor gcol;
1622 boolean midspace = false;
1624 int width = 50, height = 20;
1626 int s1, e1; // start and end of midpoint band for thresholded symbol
1628 Color mpcolour = Color.white;
1630 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1650 public int getIconWidth()
1656 public int getIconHeight()
1662 public void paintIcon(Component c, Graphics g, int x, int y)
1665 if (gcol.isColourByLabel())
1668 g.fillRect(0, 0, width, height);
1669 // need an icon here.
1670 g.setColor(gcol.getMaxColor());
1672 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1674 // g.setFont(g.getFont().deriveFont(
1675 // AffineTransform.getScaleInstance(
1676 // width/g.getFontMetrics().stringWidth("Label"),
1677 // height/g.getFontMetrics().getHeight())));
1679 g.drawString(MessageManager.getString("label.label"), 0, 0);
1684 Color minCol = gcol.getMinColor();
1686 g.fillRect(0, 0, s1, height);
1689 g.setColor(Color.white);
1690 g.fillRect(s1, 0, e1 - s1, height);
1692 g.setColor(gcol.getMaxColor());
1693 g.fillRect(0, e1, width - e1, height);
1698 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1703 GraduatedColor currentGColor;
1705 FeatureColourChooser chooser;
1713 JColorChooser colorChooser;
1717 protected static final String EDIT = "edit";
1719 int selectedRow = 0;
1721 public ColorEditor(FeatureSettings me)
1724 // Set up the editor (from the table's point of view),
1725 // which is a button.
1726 // This button brings up the color chooser dialog,
1727 // which is the editor from the user's point of view.
1728 button = new JButton();
1729 button.setActionCommand(EDIT);
1730 button.addActionListener(this);
1731 button.setBorderPainted(false);
1732 // Set up the dialog that the button brings up.
1733 colorChooser = new JColorChooser();
1734 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1735 colorChooser, this, // OK button handler
1736 null); // no CANCEL button handler
1740 * Handles events from the editor button and from the dialog's OK button.
1743 public void actionPerformed(ActionEvent e)
1746 if (EDIT.equals(e.getActionCommand()))
1748 // The user has clicked the cell, so
1749 // bring up the dialog.
1750 if (currentColor != null)
1752 // bring up simple color chooser
1753 button.setBackground(currentColor);
1754 colorChooser.setColor(currentColor);
1755 dialog.setVisible(true);
1759 // bring up graduated chooser.
1760 chooser = new FeatureColourChooser(me.fr, type);
1761 chooser.setRequestFocusEnabled(true);
1762 chooser.requestFocus();
1763 chooser.addActionListener(this);
1765 // Make the renderer reappear.
1766 fireEditingStopped();
1770 { // User pressed dialog's "OK" button.
1771 if (currentColor != null)
1773 currentColor = colorChooser.getColor();
1777 // class cast exceptions may be raised if the chooser created on a
1778 // non-graduated color
1779 currentGColor = (GraduatedColor) chooser.getLastColour();
1781 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1782 fireEditingStopped();
1783 me.table.validate();
1787 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1789 public Object getCellEditorValue()
1791 if (currentColor == null)
1793 return currentGColor;
1795 return currentColor;
1798 // Implement the one method defined by TableCellEditor.
1800 public Component getTableCellEditorComponent(JTable table, Object value,
1801 boolean isSelected, int row, int column)
1803 currentGColor = null;
1804 currentColor = null;
1805 this.selectedRow = row;
1806 type = me.table.getValueAt(row, 0).toString();
1807 button.setOpaque(true);
1808 button.setBackground(me.getBackground());
1809 if (value instanceof GraduatedColor)
1811 currentGColor = (GraduatedColor) value;
1812 JLabel btn = new JLabel();
1813 btn.setSize(button.getSize());
1814 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1815 button.setBackground(btn.getBackground());
1816 button.setIcon(btn.getIcon());
1817 button.setText(btn.getText());
1822 button.setIcon(null);
1823 currentColor = (Color) value;
1824 button.setBackground(currentColor);