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;
63 import java.util.Vector;
65 import javax.help.HelpSetException;
66 import javax.swing.AbstractCellEditor;
67 import javax.swing.BorderFactory;
68 import javax.swing.Icon;
69 import javax.swing.JButton;
70 import javax.swing.JCheckBox;
71 import javax.swing.JCheckBoxMenuItem;
72 import javax.swing.JColorChooser;
73 import javax.swing.JDialog;
74 import javax.swing.JInternalFrame;
75 import javax.swing.JLabel;
76 import javax.swing.JLayeredPane;
77 import javax.swing.JMenuItem;
78 import javax.swing.JOptionPane;
79 import javax.swing.JPanel;
80 import javax.swing.JPopupMenu;
81 import javax.swing.JScrollPane;
82 import javax.swing.JSlider;
83 import javax.swing.JTabbedPane;
84 import javax.swing.JTable;
85 import javax.swing.ListSelectionModel;
86 import javax.swing.SwingConstants;
87 import javax.swing.SwingUtilities;
88 import javax.swing.event.ChangeEvent;
89 import javax.swing.event.ChangeListener;
90 import javax.swing.table.AbstractTableModel;
91 import javax.swing.table.TableCellEditor;
92 import javax.swing.table.TableCellRenderer;
94 public class FeatureSettings extends JPanel implements
95 FeatureSettingsControllerI
97 DasSourceBrowser dassourceBrowser;
99 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
101 JPanel settingsPane = new JPanel();
103 JPanel dasSettingsPane = new JPanel();
105 final FeatureRenderer fr;
107 public final AlignFrame af;
109 Object[][] originalData;
111 private float originalTransparency;
113 final JInternalFrame frame;
115 JScrollPane scrollPane = new JScrollPane();
121 JSlider transparency = new JSlider();
123 JPanel transPanel = new JPanel(new GridLayout(1, 2));
125 public FeatureSettings(AlignFrame af)
128 fr = af.getFeatureRenderer();
129 // allow transparency to be recovered
130 transparency.setMaximum(100 - (int) ((originalTransparency = fr
131 .getTransparency()) * 100));
136 } catch (Exception ex)
138 ex.printStackTrace();
144 public String getToolTipText(MouseEvent e)
146 if (table.columnAtPoint(e.getPoint()) == 0)
149 * Tooltip for feature name only
151 return JvSwingUtils.wrapTooltip(true, MessageManager
152 .getString("label.feature_settings_click_drag"));
157 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
158 table.setFont(new Font("Verdana", Font.PLAIN, 12));
159 table.setDefaultRenderer(Color.class, new ColorRenderer());
161 table.setDefaultEditor(Color.class, new ColorEditor(this));
163 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
164 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
165 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
167 table.addMouseListener(new MouseAdapter()
170 public void mousePressed(MouseEvent evt)
172 selectedRow = table.rowAtPoint(evt.getPoint());
173 if (evt.isPopupTrigger())
175 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
176 table.getValueAt(selectedRow, 1), fr.getMinMax(),
177 evt.getX(), evt.getY());
179 else if (evt.getClickCount() == 2)
181 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
182 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
184 (String) table.getValueAt(selectedRow, 0));
188 // isPopupTrigger fires on mouseReleased on Mac
190 public void mouseReleased(MouseEvent evt)
192 selectedRow = table.rowAtPoint(evt.getPoint());
193 if (evt.isPopupTrigger())
195 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
196 table.getValueAt(selectedRow, 1), fr.getMinMax(),
197 evt.getX(), evt.getY());
202 table.addMouseMotionListener(new MouseMotionAdapter()
205 public void mouseDragged(MouseEvent evt)
207 int newRow = table.rowAtPoint(evt.getPoint());
208 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
210 Object[][] data = ((FeatureTableModel) table.getModel())
212 Object[] temp = data[selectedRow];
213 data[selectedRow] = data[newRow];
215 updateFeatureRenderer(data);
217 selectedRow = newRow;
221 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
222 // MessageManager.getString("label.feature_settings_click_drag")));
223 scrollPane.setViewportView(table);
225 dassourceBrowser = new DasSourceBrowser(this);
226 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
228 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
230 fr.findAllFeatures(true); // display everything!
233 discoverAllFeatureData();
234 final PropertyChangeListener change;
235 final FeatureSettings fs = this;
236 fr.addPropertyChangeListener(change = new PropertyChangeListener()
239 public void propertyChange(PropertyChangeEvent evt)
241 if (!fs.resettingTable && !fs.handlingUpdate)
243 fs.handlingUpdate = true;
244 fs.resetTable(null); // new groups may be added with new seuqence
245 // feature types only
246 fs.handlingUpdate = false;
252 frame = new JInternalFrame();
253 frame.setContentPane(this);
254 if (new jalview.util.Platform().isAMac())
256 Desktop.addInternalFrame(frame,
257 MessageManager.getString("label.sequence_feature_settings"),
262 Desktop.addInternalFrame(frame,
263 MessageManager.getString("label.sequence_feature_settings"),
267 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
270 public void internalFrameClosed(
271 javax.swing.event.InternalFrameEvent evt)
273 fr.removePropertyChangeListener(change);
274 dassourceBrowser.fs = null;
277 frame.setLayer(JLayeredPane.PALETTE_LAYER);
280 protected void popupSort(final int selectedRow, final String type,
281 final Object typeCol, final Map<String, float[][]> minmax, int x,
284 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
285 "label.settings_for_param", new String[] { type }));
286 JMenuItem scr = new JMenuItem(
287 MessageManager.getString("label.sort_by_score"));
289 final FeatureSettings me = this;
290 scr.addActionListener(new ActionListener()
294 public void actionPerformed(ActionEvent e)
296 me.af.avc.sortAlignmentByFeatureScore(Arrays
297 .asList(new String[] { type }));
301 JMenuItem dens = new JMenuItem(
302 MessageManager.getString("label.sort_by_density"));
303 dens.addActionListener(new ActionListener()
307 public void actionPerformed(ActionEvent e)
309 me.af.avc.sortAlignmentByFeatureDensity(Arrays
310 .asList(new String[] { type }));
317 final float[][] 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 && 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;
346 public void actionPerformed(ActionEvent e)
348 if (e.getSource() == mxcol)
350 if (typeCol instanceof Color)
352 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
354 fc.addActionListener(this);
358 // bring up simple color chooser
359 colorChooser = new JColorChooser();
360 JDialog dialog = JColorChooser.createDialog(me,
361 "Select new Colour", true, // modal
362 colorChooser, this, // OK button handler
363 null); // no CANCEL button handler
364 colorChooser.setColor(((GraduatedColor) typeCol)
366 dialog.setVisible(true);
371 if (e.getSource() instanceof FeatureColourChooser)
373 FeatureColourChooser fc = (FeatureColourChooser) e
375 table.setValueAt(fc.getLastColour(), selectedRow, 1);
380 // probably the color chooser!
381 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
383 me.updateFeatureRenderer(
384 ((FeatureTableModel) table.getModel()).getData(),
393 JMenuItem selCols = new JMenuItem(
394 MessageManager.getString("label.select_columns_containing"));
395 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()
409 public void actionPerformed(ActionEvent arg0)
411 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
415 JMenuItem hideCols = new JMenuItem(
416 MessageManager.getString("label.hide_columns_containing"));
417 hideCols.addActionListener(new ActionListener()
420 public void actionPerformed(ActionEvent arg0)
422 fr.ap.alignFrame.hideFeatureColumns(type, true);
425 JMenuItem hideOtherCols = new JMenuItem(
426 MessageManager.getString("label.hide_columns_not_containing"));
427 hideOtherCols.addActionListener(new ActionListener()
430 public void actionPerformed(ActionEvent arg0)
432 fr.ap.alignFrame.hideFeatureColumns(type, false);
438 men.add(hideOtherCols);
439 men.show(table, x, y);
443 * true when Feature Settings are updating from feature renderer
445 private boolean handlingUpdate = false;
448 * contains a float[3] for each feature type string. created by setTableData
450 Hashtable typeWidth = null;
453 synchronized public void discoverAllFeatureData()
455 Vector allFeatures = new Vector();
456 Vector allGroups = new Vector();
457 SequenceFeature[] tmpfeatures;
459 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
461 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
462 .getSequenceFeatures();
463 if (tmpfeatures == null)
469 while (index < tmpfeatures.length)
471 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
477 if (tmpfeatures[index].getFeatureGroup() != null)
479 group = tmpfeatures[index].featureGroup;
480 if (!allGroups.contains(group))
482 allGroups.addElement(group);
483 checkGroupState(group);
487 if (!allFeatures.contains(tmpfeatures[index].getType()))
489 allFeatures.addElement(tmpfeatures[index].getType());
501 * Synchronise gui group list and check visibility of group
504 * @return true if group is visible
506 private boolean checkGroupState(String group)
508 boolean visible = fr.checkGroupVisibility(group, true);
510 if (groupPanel == null)
512 groupPanel = new JPanel();
515 boolean alreadyAdded = false;
516 for (int g = 0; g < groupPanel.getComponentCount(); g++)
518 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
521 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
531 final String grp = group;
532 final JCheckBox check = new JCheckBox(group, visible);
533 check.setFont(new Font("Serif", Font.BOLD, 12));
534 check.addItemListener(new ItemListener()
537 public void itemStateChanged(ItemEvent evt)
539 fr.setGroupVisibility(check.getText(), check.isSelected());
540 af.alignPanel.getSeqPanel().seqCanvas.repaint();
541 if (af.alignPanel.overviewPanel != null)
543 af.alignPanel.overviewPanel.updateOverviewImage();
546 resetTable(new String[] { grp });
549 groupPanel.add(check);
553 boolean resettingTable = false;
555 synchronized void resetTable(String[] groupChanged)
557 if (resettingTable == true)
561 resettingTable = true;
562 typeWidth = new Hashtable();
563 // TODO: change avWidth calculation to 'per-sequence' average and use long
565 float[] avWidth = null;
566 SequenceFeature[] tmpfeatures;
567 String group = null, type;
568 Vector visibleChecks = new Vector();
570 // Find out which features should be visible depending on which groups
571 // are selected / deselected
572 // and recompute average width ordering
573 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
576 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
577 .getSequenceFeatures();
578 if (tmpfeatures == null)
584 while (index < tmpfeatures.length)
586 group = tmpfeatures[index].featureGroup;
588 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
594 if (group == null || checkGroupState(group))
596 type = tmpfeatures[index].getType();
597 if (!visibleChecks.contains(type))
599 visibleChecks.addElement(type);
602 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
604 typeWidth.put(tmpfeatures[index].getType(),
605 avWidth = new float[3]);
609 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
612 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
614 avWidth[1] += 1 + tmpfeatures[index].getBegin()
615 - tmpfeatures[index].getEnd();
619 avWidth[1] += 1 + tmpfeatures[index].getEnd()
620 - tmpfeatures[index].getBegin();
626 int fSize = visibleChecks.size();
627 Object[][] data = new Object[fSize][3];
630 if (fr.hasRenderOrder())
634 fr.findAllFeatures(groupChanged != null); // prod to update
635 // colourschemes. but don't
637 // First add the checks in the previous render order,
638 // in case the window has been closed and reopened
640 List<String> frl = fr.getRenderOrder();
641 for (int ro = frl.size() - 1; ro > -1; ro--)
645 if (!visibleChecks.contains(type))
650 data[dataIndex][0] = type;
651 data[dataIndex][1] = fr.getFeatureStyle(type);
652 data[dataIndex][2] = new Boolean(af.getViewport()
653 .getFeaturesDisplayed().isVisible(type));
655 visibleChecks.removeElement(type);
659 fSize = visibleChecks.size();
660 for (int i = 0; i < fSize; i++)
662 // These must be extra features belonging to the group
663 // which was just selected
664 type = visibleChecks.elementAt(i).toString();
665 data[dataIndex][0] = type;
667 data[dataIndex][1] = fr.getFeatureStyle(type);
668 if (data[dataIndex][1] == null)
670 // "Colour has been updated in another view!!"
671 fr.clearRenderOrder();
675 data[dataIndex][2] = new Boolean(true);
679 if (originalData == null)
681 originalData = new Object[data.length][3];
682 for (int i = 0; i < data.length; i++)
684 System.arraycopy(data[i], 0, originalData[i], 0, 3);
688 table.setModel(new FeatureTableModel(data));
689 table.getColumnModel().getColumn(0).setPreferredWidth(200);
691 if (groupPanel != null)
693 groupPanel.setLayout(new GridLayout(
694 fr.getFeatureGroupsSize() / 4 + 1, 4));
696 groupPanel.validate();
697 bigPanel.add(groupPanel, BorderLayout.NORTH);
700 updateFeatureRenderer(data, groupChanged != null);
701 resettingTable = false;
705 * reorder data based on the featureRenderers global priority list.
709 private void ensureOrder(Object[][] data)
711 boolean sort = false;
712 float[] order = new float[data.length];
713 for (int i = 0; i < order.length; i++)
715 order[i] = fr.getOrder(data[i][0].toString());
718 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
722 sort = sort || order[i - 1] > order[i];
727 jalview.util.QuickSort.sort(order, data);
733 JalviewFileChooser chooser = new JalviewFileChooser(
734 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
735 new String[] { "fc" },
736 new String[] { "Sequence Feature Colours" },
737 "Sequence Feature Colours");
738 chooser.setFileView(new jalview.io.JalviewFileView());
739 chooser.setDialogTitle(MessageManager
740 .getString("label.load_feature_colours"));
741 chooser.setToolTipText(MessageManager.getString("action.load"));
743 int value = chooser.showOpenDialog(this);
745 if (value == JalviewFileChooser.APPROVE_OPTION)
747 File file = chooser.getSelectedFile();
751 InputStreamReader in = new InputStreamReader(new FileInputStream(
754 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
755 jucs = jucs.unmarshal(in);
757 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
760 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
763 Color mincol = null, maxcol = null;
766 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
767 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
769 } catch (Exception e)
771 Cache.log.warn("Couldn't parse out graduated feature color.",
774 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
775 newcol.getMin(), newcol.getMax());
776 if (newcol.hasAutoScale())
778 gcol.setAutoScaled(newcol.getAutoScale());
780 if (newcol.hasColourByLabel())
782 gcol.setColourByLabel(newcol.getColourByLabel());
784 if (newcol.hasThreshold())
786 gcol.setThresh(newcol.getThreshold());
787 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
789 if (newcol.getThreshType().length() > 0)
791 String ttyp = newcol.getThreshType();
792 if (ttyp.equalsIgnoreCase("NONE"))
794 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
796 if (ttyp.equalsIgnoreCase("ABOVE"))
798 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
800 if (ttyp.equalsIgnoreCase("BELOW"))
802 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
805 fr.setColour(name = newcol.getName(), gcol);
809 fr.setColour(name = jucs.getColour(i).getName(), new Color(
810 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
812 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
817 Object[][] data = ((FeatureTableModel) table.getModel())
820 updateFeatureRenderer(data, false);
823 } catch (Exception ex)
825 System.out.println("Error loading User Colour File\n" + ex);
832 JalviewFileChooser chooser = new JalviewFileChooser(
833 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
834 new String[] { "fc" },
835 new String[] { "Sequence Feature Colours" },
836 "Sequence Feature Colours");
837 chooser.setFileView(new jalview.io.JalviewFileView());
838 chooser.setDialogTitle(MessageManager
839 .getString("label.save_feature_colours"));
840 chooser.setToolTipText(MessageManager.getString("action.save"));
842 int value = chooser.showSaveDialog(this);
844 if (value == JalviewFileChooser.APPROVE_OPTION)
846 String choice = chooser.getSelectedFile().getPath();
847 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
848 ucs.setSchemeName("Sequence Features");
851 PrintWriter out = new PrintWriter(new OutputStreamWriter(
852 new FileOutputStream(choice), "UTF-8"));
854 Set fr_colours = fr.getAllFeatureColours();
855 Iterator e = fr_colours.iterator();
856 float[] sortOrder = new float[fr_colours.size()];
857 String[] sortTypes = new String[fr_colours.size()];
861 sortTypes[i] = e.next().toString();
862 sortOrder[i] = fr.getOrder(sortTypes[i]);
865 jalview.util.QuickSort.sort(sortOrder, sortTypes);
869 for (i = 0; i < sortTypes.length; i++)
871 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
872 col.setName(sortTypes[i]);
873 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
875 fcol = fr.getFeatureStyle(sortTypes[i]);
876 if (fcol instanceof GraduatedColor)
878 gcol = (GraduatedColor) fcol;
879 col.setMin(gcol.getMin());
880 col.setMax(gcol.getMax());
881 col.setMinRGB(jalview.util.Format.getHexString(gcol
883 col.setAutoScale(gcol.isAutoScale());
884 col.setThreshold(gcol.getThresh());
885 col.setColourByLabel(gcol.isColourByLabel());
886 switch (gcol.getThreshType())
888 case AnnotationColourGradient.NO_THRESHOLD:
889 col.setThreshType("NONE");
891 case AnnotationColourGradient.ABOVE_THRESHOLD:
892 col.setThreshType("ABOVE");
894 case AnnotationColourGradient.BELOW_THRESHOLD:
895 col.setThreshType("BELOW");
903 } catch (Exception ex)
905 ex.printStackTrace();
910 public void invertSelection()
912 for (int i = 0; i < table.getRowCount(); i++)
914 Boolean value = (Boolean) table.getValueAt(i, 2);
916 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
920 public void orderByAvWidth()
922 if (table == null || table.getModel() == null)
926 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
927 float[] width = new float[data.length];
931 for (int i = 0; i < data.length; i++)
933 awidth = (float[]) typeWidth.get(data[i][0]);
936 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
937 // weight - but have to make per
938 // sequence, too (awidth[2])
939 // if (width[i]==1) // hack to distinguish single width sequences.
951 boolean sort = false;
952 for (int i = 0; i < width.length; i++)
954 // awidth = (float[]) typeWidth.get(data[i][0]);
957 width[i] = fr.getOrder(data[i][0].toString());
960 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
965 width[i] /= max; // normalize
966 fr.setOrder(data[i][0].toString(), width[i]); // store for later
970 sort = sort || width[i - 1] > width[i];
975 jalview.util.QuickSort.sort(width, data);
976 // update global priority order
979 updateFeatureRenderer(data, false);
987 frame.setClosed(true);
988 } catch (Exception exe)
994 public void updateFeatureRenderer(Object[][] data)
996 updateFeatureRenderer(data, true);
1000 * Update the priority order of features; only repaint if this changed the
1001 * order of visible features
1006 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1008 if (fr.setFeaturePriority(data, visibleNew))
1010 af.alignPanel.paintAlignment(true);
1014 int selectedRow = -1;
1016 JTabbedPane tabbedPane = new JTabbedPane();
1018 BorderLayout borderLayout1 = new BorderLayout();
1020 BorderLayout borderLayout2 = new BorderLayout();
1022 BorderLayout borderLayout3 = new BorderLayout();
1024 JPanel bigPanel = new JPanel();
1026 BorderLayout borderLayout4 = new BorderLayout();
1028 JButton invert = new JButton();
1030 JPanel buttonPanel = new JPanel();
1032 JButton cancel = new JButton();
1034 JButton ok = new JButton();
1036 JButton loadColours = new JButton();
1038 JButton saveColours = new JButton();
1040 JPanel dasButtonPanel = new JPanel();
1042 JButton fetchDAS = new JButton();
1044 JButton saveDAS = new JButton();
1046 JButton cancelDAS = new JButton();
1048 JButton optimizeOrder = new JButton();
1050 JButton sortByScore = new JButton();
1052 JButton sortByDens = new JButton();
1054 JButton help = new JButton();
1056 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1058 private void jbInit() throws Exception
1060 this.setLayout(borderLayout1);
1061 settingsPane.setLayout(borderLayout2);
1062 dasSettingsPane.setLayout(borderLayout3);
1063 bigPanel.setLayout(borderLayout4);
1064 invert.setFont(JvSwingUtils.getLabelFont());
1065 invert.setText(MessageManager.getString("label.invert_selection"));
1066 invert.addActionListener(new ActionListener()
1069 public void actionPerformed(ActionEvent e)
1074 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1075 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1076 optimizeOrder.addActionListener(new ActionListener()
1079 public void actionPerformed(ActionEvent e)
1084 sortByScore.setFont(JvSwingUtils.getLabelFont());
1086 .setText(MessageManager.getString("label.seq_sort_by_score"));
1087 sortByScore.addActionListener(new ActionListener()
1090 public void actionPerformed(ActionEvent e)
1092 af.avc.sortAlignmentByFeatureScore(null);
1095 sortByDens.setFont(JvSwingUtils.getLabelFont());
1096 sortByDens.setText(MessageManager
1097 .getString("label.sequence_sort_by_density"));
1098 sortByDens.addActionListener(new ActionListener()
1101 public void actionPerformed(ActionEvent e)
1103 af.avc.sortAlignmentByFeatureDensity(null);
1106 help.setFont(JvSwingUtils.getLabelFont());
1107 help.setText(MessageManager.getString("action.help"));
1108 help.addActionListener(new ActionListener()
1111 public void actionPerformed(ActionEvent e)
1115 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1116 } catch (HelpSetException e1)
1118 e1.printStackTrace();
1122 help.setFont(JvSwingUtils.getLabelFont());
1123 help.setText(MessageManager.getString("action.help"));
1124 help.addActionListener(new ActionListener()
1127 public void actionPerformed(ActionEvent e)
1131 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1132 } catch (HelpSetException e1)
1134 e1.printStackTrace();
1138 cancel.setFont(JvSwingUtils.getLabelFont());
1139 cancel.setText(MessageManager.getString("action.cancel"));
1140 cancel.addActionListener(new ActionListener()
1143 public void actionPerformed(ActionEvent e)
1145 fr.setTransparency(originalTransparency);
1146 updateFeatureRenderer(originalData);
1150 ok.setFont(JvSwingUtils.getLabelFont());
1151 ok.setText(MessageManager.getString("action.ok"));
1152 ok.addActionListener(new ActionListener()
1155 public void actionPerformed(ActionEvent e)
1160 loadColours.setFont(JvSwingUtils.getLabelFont());
1161 loadColours.setText(MessageManager.getString("label.load_colours"));
1162 loadColours.addActionListener(new ActionListener()
1165 public void actionPerformed(ActionEvent e)
1170 saveColours.setFont(JvSwingUtils.getLabelFont());
1171 saveColours.setText(MessageManager.getString("label.save_colours"));
1172 saveColours.addActionListener(new ActionListener()
1175 public void actionPerformed(ActionEvent e)
1180 transparency.addChangeListener(new ChangeListener()
1183 public void stateChanged(ChangeEvent evt)
1185 fr.setTransparency((100 - transparency.getValue()) / 100f);
1186 af.alignPanel.paintAlignment(true);
1190 transparency.setMaximum(70);
1191 transparency.setToolTipText(MessageManager
1192 .getString("label.transparency_tip"));
1193 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1194 fetchDAS.addActionListener(new ActionListener()
1197 public void actionPerformed(ActionEvent e)
1199 fetchDAS_actionPerformed(e);
1202 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1203 saveDAS.addActionListener(new ActionListener()
1206 public void actionPerformed(ActionEvent e)
1208 saveDAS_actionPerformed(e);
1211 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1212 dasSettingsPane.setBorder(null);
1213 cancelDAS.setEnabled(false);
1214 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1215 cancelDAS.addActionListener(new ActionListener()
1218 public void actionPerformed(ActionEvent e)
1220 cancelDAS_actionPerformed(e);
1223 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1224 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1226 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1228 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1229 transbuttons.add(optimizeOrder);
1230 transbuttons.add(invert);
1231 transbuttons.add(sortByScore);
1232 transbuttons.add(sortByDens);
1233 transbuttons.add(help);
1234 JPanel sliderPanel = new JPanel();
1235 sliderPanel.add(transparency);
1236 transPanel.add(transparency);
1237 transPanel.add(transbuttons);
1238 buttonPanel.add(ok);
1239 buttonPanel.add(cancel);
1240 buttonPanel.add(loadColours);
1241 buttonPanel.add(saveColours);
1242 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1243 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1244 dasButtonPanel.add(fetchDAS);
1245 dasButtonPanel.add(cancelDAS);
1246 dasButtonPanel.add(saveDAS);
1247 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1248 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1251 public void fetchDAS_actionPerformed(ActionEvent e)
1253 fetchDAS.setEnabled(false);
1254 cancelDAS.setEnabled(true);
1255 dassourceBrowser.setGuiEnabled(false);
1256 Vector selectedSources = dassourceBrowser.getSelectedSources();
1257 doDasFeatureFetch(selectedSources, true, true);
1261 * get the features from selectedSources for all or the current selection
1263 * @param selectedSources
1264 * @param checkDbRefs
1265 * @param promptFetchDbRefs
1267 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1268 boolean checkDbRefs, boolean promptFetchDbRefs)
1270 SequenceI[] dataset, seqs;
1272 AlignmentViewport vp = af.getViewport();
1273 if (vp.getSelectionGroup() != null
1274 && vp.getSelectionGroup().getSize() > 0)
1276 iSize = vp.getSelectionGroup().getSize();
1277 dataset = new SequenceI[iSize];
1278 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1282 iSize = vp.getAlignment().getHeight();
1283 seqs = vp.getAlignment().getSequencesArray();
1286 dataset = new SequenceI[iSize];
1287 for (int i = 0; i < iSize; i++)
1289 dataset[i] = seqs[i].getDatasetSequence();
1292 cancelDAS.setEnabled(true);
1293 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1294 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1295 af.getViewport().setShowSequenceFeatures(true);
1296 af.showSeqFeatures.setSelected(true);
1300 * blocking call to initialise the das source browser
1302 public void initDasSources()
1304 dassourceBrowser.initDasSources();
1308 * examine the current list of das sources and return any matching the given
1309 * nicknames in sources
1312 * Vector of Strings to resolve to DAS source nicknames.
1313 * @return sources that are present in source list.
1315 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1317 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1321 * get currently selected das sources. ensure you have called initDasSources
1322 * before calling this.
1324 * @return vector of selected das source nicknames
1326 public Vector getSelectedSources()
1328 return dassourceBrowser.getSelectedSources();
1332 * properly initialise DAS fetcher and then initiate a new thread to fetch
1333 * features from the named sources (rather than any turned on by default)
1337 * if true then runs in same thread, otherwise passes to the Swing
1340 public void fetchDasFeatures(Vector sources, boolean block)
1343 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1344 .resolveSourceNicknames(sources);
1345 if (resolved.size() == 0)
1347 resolved = dassourceBrowser.getSelectedSources();
1349 if (resolved.size() > 0)
1351 final List<jalviewSourceI> dassources = resolved;
1352 fetchDAS.setEnabled(false);
1353 // cancelDAS.setEnabled(true); doDasFetch does this.
1354 Runnable fetcher = new Runnable()
1360 doDasFeatureFetch(dassources, true, false);
1370 SwingUtilities.invokeLater(fetcher);
1375 public void saveDAS_actionPerformed(ActionEvent e)
1378 .saveProperties(jalview.bin.Cache.applicationProperties);
1381 public void complete()
1383 fetchDAS.setEnabled(true);
1384 cancelDAS.setEnabled(false);
1385 dassourceBrowser.setGuiEnabled(true);
1389 public void cancelDAS_actionPerformed(ActionEvent e)
1391 if (dasFeatureFetcher != null)
1393 dasFeatureFetcher.cancel();
1398 public void noDasSourceActive()
1402 .showInternalConfirmDialog(
1405 .getString("label.no_das_sources_selected_warn"),
1407 .getString("label.no_das_sources_selected_title"),
1408 JOptionPane.DEFAULT_OPTION,
1409 JOptionPane.INFORMATION_MESSAGE);
1412 // ///////////////////////////////////////////////////////////////////////
1413 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1414 // ///////////////////////////////////////////////////////////////////////
1415 class FeatureTableModel extends AbstractTableModel
1417 FeatureTableModel(Object[][] data)
1422 private String[] columnNames = {
1423 MessageManager.getString("label.feature_type"),
1424 MessageManager.getString("action.colour"),
1425 MessageManager.getString("label.display") };
1427 private Object[][] data;
1429 public Object[][] getData()
1434 public void setData(Object[][] data)
1440 public int getColumnCount()
1442 return columnNames.length;
1445 public Object[] getRow(int row)
1451 public int getRowCount()
1457 public String getColumnName(int col)
1459 return columnNames[col];
1463 public Object getValueAt(int row, int col)
1465 return data[row][col];
1469 public Class getColumnClass(int c)
1471 return getValueAt(0, c).getClass();
1475 public boolean isCellEditable(int row, int col)
1477 return col == 0 ? false : true;
1481 public void setValueAt(Object value, int row, int col)
1483 data[row][col] = value;
1484 fireTableCellUpdated(row, col);
1485 updateFeatureRenderer(data);
1490 class ColorRenderer extends JLabel implements TableCellRenderer
1492 javax.swing.border.Border unselectedBorder = null;
1494 javax.swing.border.Border selectedBorder = null;
1496 final String baseTT = "Click to edit, right/apple click for menu.";
1498 public ColorRenderer()
1500 setOpaque(true); // MUST do this for background to show up.
1501 setHorizontalTextPosition(SwingConstants.CENTER);
1502 setVerticalTextPosition(SwingConstants.CENTER);
1506 public Component getTableCellRendererComponent(JTable table,
1507 Object color, boolean isSelected, boolean hasFocus, int row,
1510 // JLabel comp = new JLabel();
1514 // setBounds(getBounds());
1516 setToolTipText(baseTT);
1517 setBackground(table.getBackground());
1518 if (color instanceof GraduatedColor)
1520 Rectangle cr = table.getCellRect(row, column, false);
1521 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1522 (int) cr.getWidth(), (int) cr.getHeight());
1529 newColor = (Color) color;
1531 setBackground(newColor);
1532 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1533 // + newColor.getGreen() + ", " + newColor.getBlue());
1537 if (selectedBorder == null)
1539 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1540 table.getSelectionBackground());
1543 setBorder(selectedBorder);
1547 if (unselectedBorder == null)
1549 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1550 table.getBackground());
1553 setBorder(unselectedBorder);
1561 * update comp using rendering settings from gcol
1566 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1568 int w = comp.getWidth(), h = comp.getHeight();
1571 w = (int) comp.getPreferredSize().getWidth();
1572 h = (int) comp.getPreferredSize().getHeight();
1579 renderGraduatedColor(comp, gcol, w, h);
1582 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1585 boolean thr = false;
1588 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1592 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1594 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1598 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1600 if (gcol.isColourByLabel())
1602 tt = "Coloured by label text. " + tt;
1612 Color newColor = gcol.getMaxColor();
1613 comp.setBackground(newColor);
1614 // System.err.println("Width is " + w / 2);
1615 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1616 comp.setIcon(ficon);
1617 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1618 // + newColor.getGreen() + ", " + newColor.getBlue()
1619 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1620 // + ", " + minCol.getBlue() + ")");
1622 comp.setHorizontalAlignment(SwingConstants.CENTER);
1624 if (tt.length() > 0)
1626 if (comp.getToolTipText() == null)
1628 comp.setToolTipText(tt);
1632 comp.setToolTipText(tt + " " + comp.getToolTipText());
1638 class FeatureIcon implements Icon
1640 GraduatedColor gcol;
1644 boolean midspace = false;
1646 int width = 50, height = 20;
1648 int s1, e1; // start and end of midpoint band for thresholded symbol
1650 Color mpcolour = Color.white;
1652 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1672 public int getIconWidth()
1678 public int getIconHeight()
1684 public void paintIcon(Component c, Graphics g, int x, int y)
1687 if (gcol.isColourByLabel())
1690 g.fillRect(0, 0, width, height);
1691 // need an icon here.
1692 g.setColor(gcol.getMaxColor());
1694 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1696 // g.setFont(g.getFont().deriveFont(
1697 // AffineTransform.getScaleInstance(
1698 // width/g.getFontMetrics().stringWidth("Label"),
1699 // height/g.getFontMetrics().getHeight())));
1701 g.drawString(MessageManager.getString("label.label"), 0, 0);
1706 Color minCol = gcol.getMinColor();
1708 g.fillRect(0, 0, s1, height);
1711 g.setColor(Color.white);
1712 g.fillRect(s1, 0, e1 - s1, height);
1714 g.setColor(gcol.getMaxColor());
1715 g.fillRect(0, e1, width - e1, height);
1720 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1725 GraduatedColor currentGColor;
1727 FeatureColourChooser chooser;
1735 JColorChooser colorChooser;
1739 protected static final String EDIT = "edit";
1741 int selectedRow = 0;
1743 public ColorEditor(FeatureSettings me)
1746 // Set up the editor (from the table's point of view),
1747 // which is a button.
1748 // This button brings up the color chooser dialog,
1749 // which is the editor from the user's point of view.
1750 button = new JButton();
1751 button.setActionCommand(EDIT);
1752 button.addActionListener(this);
1753 button.setBorderPainted(false);
1754 // Set up the dialog that the button brings up.
1755 colorChooser = new JColorChooser();
1756 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1757 colorChooser, this, // OK button handler
1758 null); // no CANCEL button handler
1762 * Handles events from the editor button and from the dialog's OK button.
1765 public void actionPerformed(ActionEvent e)
1768 if (EDIT.equals(e.getActionCommand()))
1770 // The user has clicked the cell, so
1771 // bring up the dialog.
1772 if (currentColor != null)
1774 // bring up simple color chooser
1775 button.setBackground(currentColor);
1776 colorChooser.setColor(currentColor);
1777 dialog.setVisible(true);
1781 // bring up graduated chooser.
1782 chooser = new FeatureColourChooser(me.fr, type);
1783 chooser.setRequestFocusEnabled(true);
1784 chooser.requestFocus();
1785 chooser.addActionListener(this);
1787 // Make the renderer reappear.
1788 fireEditingStopped();
1792 { // User pressed dialog's "OK" button.
1793 if (currentColor != null)
1795 currentColor = colorChooser.getColor();
1799 // class cast exceptions may be raised if the chooser created on a
1800 // non-graduated color
1801 currentGColor = (GraduatedColor) chooser.getLastColour();
1803 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1804 fireEditingStopped();
1805 me.table.validate();
1809 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1811 public Object getCellEditorValue()
1813 if (currentColor == null)
1815 return currentGColor;
1817 return currentColor;
1820 // Implement the one method defined by TableCellEditor.
1822 public Component getTableCellEditorComponent(JTable table, Object value,
1823 boolean isSelected, int row, int column)
1825 currentGColor = null;
1826 currentColor = null;
1827 this.selectedRow = row;
1828 type = me.table.getValueAt(row, 0).toString();
1829 button.setOpaque(true);
1830 button.setBackground(me.getBackground());
1831 if (value instanceof GraduatedColor)
1833 currentGColor = (GraduatedColor) value;
1834 JLabel btn = new JLabel();
1835 btn.setSize(button.getSize());
1836 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1837 button.setBackground(btn.getBackground());
1838 button.setIcon(btn.getIcon());
1839 button.setText(btn.getText());
1844 button.setIcon(null);
1845 currentColor = (Color) value;
1846 button.setBackground(currentColor);