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.Format;
32 import jalview.util.MessageManager;
33 import jalview.util.QuickSort;
34 import jalview.viewmodel.AlignmentViewport;
35 import jalview.ws.dbsources.das.api.jalviewSourceI;
37 import java.awt.BorderLayout;
38 import java.awt.Color;
39 import java.awt.Component;
41 import java.awt.Graphics;
42 import java.awt.GridLayout;
43 import java.awt.Rectangle;
44 import java.awt.event.ActionEvent;
45 import java.awt.event.ActionListener;
46 import java.awt.event.ItemEvent;
47 import java.awt.event.ItemListener;
48 import java.awt.event.MouseAdapter;
49 import java.awt.event.MouseEvent;
50 import java.awt.event.MouseMotionAdapter;
51 import java.beans.PropertyChangeEvent;
52 import java.beans.PropertyChangeListener;
54 import java.io.FileInputStream;
55 import java.io.FileOutputStream;
56 import java.io.InputStreamReader;
57 import java.io.OutputStreamWriter;
58 import java.io.PrintWriter;
59 import java.util.Arrays;
60 import java.util.Hashtable;
61 import java.util.Iterator;
62 import java.util.List;
65 import java.util.Vector;
67 import javax.help.HelpSetException;
68 import javax.swing.AbstractCellEditor;
69 import javax.swing.BorderFactory;
70 import javax.swing.Icon;
71 import javax.swing.JButton;
72 import javax.swing.JCheckBox;
73 import javax.swing.JCheckBoxMenuItem;
74 import javax.swing.JColorChooser;
75 import javax.swing.JDialog;
76 import javax.swing.JInternalFrame;
77 import javax.swing.JLabel;
78 import javax.swing.JLayeredPane;
79 import javax.swing.JMenuItem;
80 import javax.swing.JOptionPane;
81 import javax.swing.JPanel;
82 import javax.swing.JPopupMenu;
83 import javax.swing.JScrollPane;
84 import javax.swing.JSlider;
85 import javax.swing.JTabbedPane;
86 import javax.swing.JTable;
87 import javax.swing.ListSelectionModel;
88 import javax.swing.SwingConstants;
89 import javax.swing.SwingUtilities;
90 import javax.swing.event.ChangeEvent;
91 import javax.swing.event.ChangeListener;
92 import javax.swing.table.AbstractTableModel;
93 import javax.swing.table.TableCellEditor;
94 import javax.swing.table.TableCellRenderer;
96 public class FeatureSettings extends JPanel implements
97 FeatureSettingsControllerI
99 DasSourceBrowser dassourceBrowser;
101 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
103 JPanel settingsPane = new JPanel();
105 JPanel dasSettingsPane = new JPanel();
107 final FeatureRenderer fr;
109 public final AlignFrame af;
111 Object[][] originalData;
113 private float originalTransparency;
115 final JInternalFrame frame;
117 JScrollPane scrollPane = new JScrollPane();
123 JSlider transparency = new JSlider();
125 JPanel transPanel = new JPanel(new GridLayout(1, 2));
127 public FeatureSettings(AlignFrame af)
130 fr = af.getFeatureRenderer();
131 // allow transparency to be recovered
132 transparency.setMaximum(100 - (int) ((originalTransparency = fr
133 .getTransparency()) * 100));
138 } catch (Exception ex)
140 ex.printStackTrace();
146 public String getToolTipText(MouseEvent e)
148 if (table.columnAtPoint(e.getPoint()) == 0)
151 * Tooltip for feature name only
153 return JvSwingUtils.wrapTooltip(true, MessageManager
154 .getString("label.feature_settings_click_drag"));
159 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
160 table.setFont(new Font("Verdana", Font.PLAIN, 12));
161 table.setDefaultRenderer(Color.class, new ColorRenderer());
163 table.setDefaultEditor(Color.class, new ColorEditor(this));
165 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
166 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
167 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
169 table.addMouseListener(new MouseAdapter()
172 public void mousePressed(MouseEvent evt)
174 selectedRow = table.rowAtPoint(evt.getPoint());
175 if (evt.isPopupTrigger())
177 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
178 table.getValueAt(selectedRow, 1), fr.getMinMax(),
179 evt.getX(), evt.getY());
181 else if (evt.getClickCount() == 2)
183 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
184 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
186 (String) table.getValueAt(selectedRow, 0));
190 // isPopupTrigger fires on mouseReleased on Mac
192 public void mouseReleased(MouseEvent evt)
194 selectedRow = table.rowAtPoint(evt.getPoint());
195 if (evt.isPopupTrigger())
197 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
198 table.getValueAt(selectedRow, 1), fr.getMinMax(),
199 evt.getX(), evt.getY());
204 table.addMouseMotionListener(new MouseMotionAdapter()
207 public void mouseDragged(MouseEvent evt)
209 int newRow = table.rowAtPoint(evt.getPoint());
210 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
212 Object[][] data = ((FeatureTableModel) table.getModel())
214 Object[] temp = data[selectedRow];
215 data[selectedRow] = data[newRow];
217 updateFeatureRenderer(data);
219 selectedRow = newRow;
223 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
224 // MessageManager.getString("label.feature_settings_click_drag")));
225 scrollPane.setViewportView(table);
227 dassourceBrowser = new DasSourceBrowser(this);
228 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
230 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
232 fr.findAllFeatures(true); // display everything!
235 discoverAllFeatureData();
236 final PropertyChangeListener change;
237 final FeatureSettings fs = this;
238 fr.addPropertyChangeListener(change = new PropertyChangeListener()
241 public void propertyChange(PropertyChangeEvent evt)
243 if (!fs.resettingTable && !fs.handlingUpdate)
245 fs.handlingUpdate = true;
246 fs.resetTable(null); // new groups may be added with new seuqence
247 // feature types only
248 fs.handlingUpdate = false;
254 frame = new JInternalFrame();
255 frame.setContentPane(this);
256 if (new jalview.util.Platform().isAMac())
258 Desktop.addInternalFrame(frame,
259 MessageManager.getString("label.sequence_feature_settings"),
264 Desktop.addInternalFrame(frame,
265 MessageManager.getString("label.sequence_feature_settings"),
269 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 Map<String, float[][]> minmax, int x,
286 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
287 "label.settings_for_param", new String[] { type }));
288 JMenuItem scr = new JMenuItem(
289 MessageManager.getString("label.sort_by_score"));
291 final FeatureSettings me = this;
292 scr.addActionListener(new ActionListener()
296 public void actionPerformed(ActionEvent e)
298 me.af.avc.sortAlignmentByFeatureScore(Arrays
299 .asList(new String[] { type }));
303 JMenuItem dens = new JMenuItem(
304 MessageManager.getString("label.sort_by_density"));
305 dens.addActionListener(new ActionListener()
309 public void actionPerformed(ActionEvent e)
311 me.af.avc.sortAlignmentByFeatureDensity(Arrays
312 .asList(new String[] { type }));
319 final float[][] typeMinMax = minmax.get(type);
321 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
322 * this is broken at the moment and isn't that useful anyway!
323 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
326 * public void actionPerformed(ActionEvent e) {
327 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
328 * null); } else { minmax.put(type, typeMinMax); } }
334 if (typeMinMax != null && typeMinMax[0] != null)
336 // if (table.getValueAt(row, column));
337 // graduated colourschemes for those where minmax exists for the
338 // positional features
339 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
341 mxcol.setSelected(!(typeCol instanceof Color));
343 mxcol.addActionListener(new ActionListener()
345 JColorChooser colorChooser;
348 public void actionPerformed(ActionEvent e)
350 if (e.getSource() == mxcol)
352 if (typeCol instanceof Color)
354 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
356 fc.addActionListener(this);
360 // bring up simple color chooser
361 colorChooser = new JColorChooser();
362 JDialog dialog = JColorChooser.createDialog(me,
363 "Select new Colour", true, // modal
364 colorChooser, this, // OK button handler
365 null); // no CANCEL button handler
366 colorChooser.setColor(((GraduatedColor) typeCol)
368 dialog.setVisible(true);
373 if (e.getSource() instanceof FeatureColourChooser)
375 FeatureColourChooser fc = (FeatureColourChooser) e
377 table.setValueAt(fc.getLastColour(), selectedRow, 1);
382 // probably the color chooser!
383 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
385 me.updateFeatureRenderer(
386 ((FeatureTableModel) table.getModel()).getData(),
395 JMenuItem selCols = new JMenuItem(
396 MessageManager.getString("label.select_columns_containing"));
397 selCols.addActionListener(new ActionListener()
400 public void actionPerformed(ActionEvent arg0)
402 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
406 JMenuItem clearCols = new JMenuItem(
407 MessageManager.getString("label.select_columns_not_containing"));
408 clearCols.addActionListener(new ActionListener()
411 public void actionPerformed(ActionEvent arg0)
413 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
417 JMenuItem hideCols = new JMenuItem(
418 MessageManager.getString("label.hide_columns_containing"));
419 hideCols.addActionListener(new ActionListener()
422 public void actionPerformed(ActionEvent arg0)
424 fr.ap.alignFrame.hideFeatureColumns(type, true);
427 JMenuItem hideOtherCols = new JMenuItem(
428 MessageManager.getString("label.hide_columns_not_containing"));
429 hideOtherCols.addActionListener(new ActionListener()
432 public void actionPerformed(ActionEvent arg0)
434 fr.ap.alignFrame.hideFeatureColumns(type, false);
440 men.add(hideOtherCols);
441 men.show(table, x, y);
445 * true when Feature Settings are updating from feature renderer
447 private boolean handlingUpdate = false;
450 * contains a float[3] for each feature type string. created by setTableData
452 Hashtable typeWidth = null;
455 synchronized public void discoverAllFeatureData()
457 Vector allFeatures = new Vector();
458 Vector allGroups = new Vector();
459 SequenceFeature[] tmpfeatures;
461 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
463 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
464 .getSequenceFeatures();
465 if (tmpfeatures == null)
471 while (index < tmpfeatures.length)
473 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
479 if (tmpfeatures[index].getFeatureGroup() != null)
481 group = tmpfeatures[index].featureGroup;
482 if (!allGroups.contains(group))
484 allGroups.addElement(group);
485 checkGroupState(group);
489 if (!allFeatures.contains(tmpfeatures[index].getType()))
491 allFeatures.addElement(tmpfeatures[index].getType());
503 * Synchronise gui group list and check visibility of group
506 * @return true if group is visible
508 private boolean checkGroupState(String group)
510 boolean visible = fr.checkGroupVisibility(group, true);
512 if (groupPanel == null)
514 groupPanel = new JPanel();
517 boolean alreadyAdded = false;
518 for (int g = 0; g < groupPanel.getComponentCount(); g++)
520 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
523 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
533 final String grp = group;
534 final JCheckBox check = new JCheckBox(group, visible);
535 check.setFont(new Font("Serif", Font.BOLD, 12));
536 check.addItemListener(new ItemListener()
539 public void itemStateChanged(ItemEvent evt)
541 fr.setGroupVisibility(check.getText(), check.isSelected());
542 af.alignPanel.getSeqPanel().seqCanvas.repaint();
543 if (af.alignPanel.overviewPanel != null)
545 af.alignPanel.overviewPanel.updateOverviewImage();
548 resetTable(new String[] { grp });
551 groupPanel.add(check);
555 boolean resettingTable = false;
557 synchronized void resetTable(String[] groupChanged)
559 if (resettingTable == true)
563 resettingTable = true;
564 typeWidth = new Hashtable();
565 // TODO: change avWidth calculation to 'per-sequence' average and use long
567 float[] avWidth = null;
568 SequenceFeature[] tmpfeatures;
569 String group = null, type;
570 Vector visibleChecks = new Vector();
572 // Find out which features should be visible depending on which groups
573 // are selected / deselected
574 // and recompute average width ordering
575 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
578 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
579 .getSequenceFeatures();
580 if (tmpfeatures == null)
586 while (index < tmpfeatures.length)
588 group = tmpfeatures[index].featureGroup;
590 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
596 if (group == null || checkGroupState(group))
598 type = tmpfeatures[index].getType();
599 if (!visibleChecks.contains(type))
601 visibleChecks.addElement(type);
604 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
606 typeWidth.put(tmpfeatures[index].getType(),
607 avWidth = new float[3]);
611 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
614 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
616 avWidth[1] += 1 + tmpfeatures[index].getBegin()
617 - tmpfeatures[index].getEnd();
621 avWidth[1] += 1 + tmpfeatures[index].getEnd()
622 - tmpfeatures[index].getBegin();
628 int fSize = visibleChecks.size();
629 Object[][] data = new Object[fSize][3];
632 if (fr.hasRenderOrder())
636 fr.findAllFeatures(groupChanged != null); // prod to update
637 // colourschemes. but don't
639 // First add the checks in the previous render order,
640 // in case the window has been closed and reopened
642 List<String> frl = fr.getRenderOrder();
643 for (int ro = frl.size() - 1; ro > -1; ro--)
647 if (!visibleChecks.contains(type))
652 data[dataIndex][0] = type;
653 data[dataIndex][1] = fr.getFeatureStyle(type);
654 data[dataIndex][2] = new Boolean(af.getViewport()
655 .getFeaturesDisplayed().isVisible(type));
657 visibleChecks.removeElement(type);
661 fSize = visibleChecks.size();
662 for (int i = 0; i < fSize; i++)
664 // These must be extra features belonging to the group
665 // which was just selected
666 type = visibleChecks.elementAt(i).toString();
667 data[dataIndex][0] = type;
669 data[dataIndex][1] = fr.getFeatureStyle(type);
670 if (data[dataIndex][1] == null)
672 // "Colour has been updated in another view!!"
673 fr.clearRenderOrder();
677 data[dataIndex][2] = new Boolean(true);
681 if (originalData == null)
683 originalData = new Object[data.length][3];
684 for (int i = 0; i < data.length; i++)
686 System.arraycopy(data[i], 0, originalData[i], 0, 3);
690 table.setModel(new FeatureTableModel(data));
691 table.getColumnModel().getColumn(0).setPreferredWidth(200);
693 if (groupPanel != null)
695 groupPanel.setLayout(new GridLayout(
696 fr.getFeatureGroupsSize() / 4 + 1, 4));
698 groupPanel.validate();
699 bigPanel.add(groupPanel, BorderLayout.NORTH);
702 updateFeatureRenderer(data, groupChanged != null);
703 resettingTable = false;
707 * reorder data based on the featureRenderers global priority list.
711 private void ensureOrder(Object[][] data)
713 boolean sort = false;
714 float[] order = new float[data.length];
715 for (int i = 0; i < order.length; i++)
717 order[i] = fr.getOrder(data[i][0].toString());
720 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
724 sort = sort || order[i - 1] > order[i];
729 jalview.util.QuickSort.sort(order, data);
735 JalviewFileChooser chooser = new JalviewFileChooser(
736 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
737 new String[] { "fc" },
738 new String[] { "Sequence Feature Colours" },
739 "Sequence Feature Colours");
740 chooser.setFileView(new jalview.io.JalviewFileView());
741 chooser.setDialogTitle(MessageManager
742 .getString("label.load_feature_colours"));
743 chooser.setToolTipText(MessageManager.getString("action.load"));
745 int value = chooser.showOpenDialog(this);
747 if (value == JalviewFileChooser.APPROVE_OPTION)
749 File file = chooser.getSelectedFile();
753 InputStreamReader in = new InputStreamReader(new FileInputStream(
756 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
757 jucs = jucs.unmarshal(in);
759 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
762 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
765 Color mincol = null, maxcol = null;
768 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
769 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
771 } catch (Exception e)
773 Cache.log.warn("Couldn't parse out graduated feature color.",
776 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
777 newcol.getMin(), newcol.getMax());
778 if (newcol.hasAutoScale())
780 gcol.setAutoScaled(newcol.getAutoScale());
782 if (newcol.hasColourByLabel())
784 gcol.setColourByLabel(newcol.getColourByLabel());
786 if (newcol.hasThreshold())
788 gcol.setThresh(newcol.getThreshold());
789 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
791 if (newcol.getThreshType().length() > 0)
793 String ttyp = newcol.getThreshType();
794 if (ttyp.equalsIgnoreCase("NONE"))
796 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
798 if (ttyp.equalsIgnoreCase("ABOVE"))
800 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
802 if (ttyp.equalsIgnoreCase("BELOW"))
804 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
807 fr.setColour(name = newcol.getName(), gcol);
811 fr.setColour(name = jucs.getColour(i).getName(), new Color(
812 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
814 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
819 Object[][] data = ((FeatureTableModel) table.getModel())
822 updateFeatureRenderer(data, false);
825 } catch (Exception ex)
827 System.out.println("Error loading User Colour File\n" + ex);
834 JalviewFileChooser chooser = new JalviewFileChooser(
835 Cache.getProperty("LAST_DIRECTORY"),
836 new String[] { "fc" },
837 new String[] { "Sequence Feature Colours" },
838 "Sequence Feature Colours");
839 chooser.setFileView(new jalview.io.JalviewFileView());
840 chooser.setDialogTitle(MessageManager
841 .getString("label.save_feature_colours"));
842 chooser.setToolTipText(MessageManager.getString("action.save"));
844 int value = chooser.showSaveDialog(this);
846 if (value == JalviewFileChooser.APPROVE_OPTION)
848 String choice = chooser.getSelectedFile().getPath();
849 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
850 ucs.setSchemeName("Sequence Features");
853 PrintWriter out = new PrintWriter(new OutputStreamWriter(
854 new FileOutputStream(choice), "UTF-8"));
856 Set<String> fr_colours = fr.getAllFeatureColours();
857 Iterator<String> e = fr_colours.iterator();
858 float[] sortOrder = new float[fr_colours.size()];
859 String[] sortTypes = new String[fr_colours.size()];
863 sortTypes[i] = e.next();
864 sortOrder[i] = fr.getOrder(sortTypes[i]);
867 QuickSort.sort(sortOrder, sortTypes);
871 for (String featureType : sortTypes)
873 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
874 col.setName(featureType);
875 fcol = fr.getFeatureStyle(featureType);
876 Color colour = fcol instanceof Color ? (Color) fcol
877 : ((GraduatedColor) fcol).getMaxColor();
878 col.setRGB(Format.getHexString(colour));
879 if (fcol instanceof GraduatedColor)
881 gcol = (GraduatedColor) fcol;
882 col.setMin(gcol.getMin());
883 col.setMax(gcol.getMax());
884 col.setMinRGB(Format.getHexString(gcol
886 col.setAutoScale(gcol.isAutoScale());
887 col.setThreshold(gcol.getThresh());
888 col.setColourByLabel(gcol.isColourByLabel());
889 switch (gcol.getThreshType())
891 case AnnotationColourGradient.NO_THRESHOLD:
892 col.setThreshType("NONE");
894 case AnnotationColourGradient.ABOVE_THRESHOLD:
895 col.setThreshType("ABOVE");
897 case AnnotationColourGradient.BELOW_THRESHOLD:
898 col.setThreshType("BELOW");
906 } catch (Exception ex)
908 ex.printStackTrace();
913 public void invertSelection()
915 for (int i = 0; i < table.getRowCount(); i++)
917 Boolean value = (Boolean) table.getValueAt(i, 2);
919 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
923 public void orderByAvWidth()
925 if (table == null || table.getModel() == null)
929 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
930 float[] width = new float[data.length];
934 for (int i = 0; i < data.length; i++)
936 awidth = (float[]) typeWidth.get(data[i][0]);
939 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
940 // weight - but have to make per
941 // sequence, too (awidth[2])
942 // if (width[i]==1) // hack to distinguish single width sequences.
954 boolean sort = false;
955 for (int i = 0; i < width.length; i++)
957 // awidth = (float[]) typeWidth.get(data[i][0]);
960 width[i] = fr.getOrder(data[i][0].toString());
963 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
968 width[i] /= max; // normalize
969 fr.setOrder(data[i][0].toString(), width[i]); // store for later
973 sort = sort || width[i - 1] > width[i];
978 jalview.util.QuickSort.sort(width, data);
979 // update global priority order
982 updateFeatureRenderer(data, false);
990 frame.setClosed(true);
991 } catch (Exception exe)
997 public void updateFeatureRenderer(Object[][] data)
999 updateFeatureRenderer(data, true);
1003 * Update the priority order of features; only repaint if this changed the
1004 * order of visible features
1009 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1011 if (fr.setFeaturePriority(data, visibleNew))
1013 af.alignPanel.paintAlignment(true);
1017 int selectedRow = -1;
1019 JTabbedPane tabbedPane = new JTabbedPane();
1021 BorderLayout borderLayout1 = new BorderLayout();
1023 BorderLayout borderLayout2 = new BorderLayout();
1025 BorderLayout borderLayout3 = new BorderLayout();
1027 JPanel bigPanel = new JPanel();
1029 BorderLayout borderLayout4 = new BorderLayout();
1031 JButton invert = new JButton();
1033 JPanel buttonPanel = new JPanel();
1035 JButton cancel = new JButton();
1037 JButton ok = new JButton();
1039 JButton loadColours = new JButton();
1041 JButton saveColours = new JButton();
1043 JPanel dasButtonPanel = new JPanel();
1045 JButton fetchDAS = new JButton();
1047 JButton saveDAS = new JButton();
1049 JButton cancelDAS = new JButton();
1051 JButton optimizeOrder = new JButton();
1053 JButton sortByScore = new JButton();
1055 JButton sortByDens = new JButton();
1057 JButton help = new JButton();
1059 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1061 private void jbInit() throws Exception
1063 this.setLayout(borderLayout1);
1064 settingsPane.setLayout(borderLayout2);
1065 dasSettingsPane.setLayout(borderLayout3);
1066 bigPanel.setLayout(borderLayout4);
1067 invert.setFont(JvSwingUtils.getLabelFont());
1068 invert.setText(MessageManager.getString("label.invert_selection"));
1069 invert.addActionListener(new ActionListener()
1072 public void actionPerformed(ActionEvent e)
1077 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1078 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1079 optimizeOrder.addActionListener(new ActionListener()
1082 public void actionPerformed(ActionEvent e)
1087 sortByScore.setFont(JvSwingUtils.getLabelFont());
1089 .setText(MessageManager.getString("label.seq_sort_by_score"));
1090 sortByScore.addActionListener(new ActionListener()
1093 public void actionPerformed(ActionEvent e)
1095 af.avc.sortAlignmentByFeatureScore(null);
1098 sortByDens.setFont(JvSwingUtils.getLabelFont());
1099 sortByDens.setText(MessageManager
1100 .getString("label.sequence_sort_by_density"));
1101 sortByDens.addActionListener(new ActionListener()
1104 public void actionPerformed(ActionEvent e)
1106 af.avc.sortAlignmentByFeatureDensity(null);
1109 help.setFont(JvSwingUtils.getLabelFont());
1110 help.setText(MessageManager.getString("action.help"));
1111 help.addActionListener(new ActionListener()
1114 public void actionPerformed(ActionEvent e)
1118 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1119 } catch (HelpSetException e1)
1121 e1.printStackTrace();
1125 help.setFont(JvSwingUtils.getLabelFont());
1126 help.setText(MessageManager.getString("action.help"));
1127 help.addActionListener(new ActionListener()
1130 public void actionPerformed(ActionEvent e)
1134 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1135 } catch (HelpSetException e1)
1137 e1.printStackTrace();
1141 cancel.setFont(JvSwingUtils.getLabelFont());
1142 cancel.setText(MessageManager.getString("action.cancel"));
1143 cancel.addActionListener(new ActionListener()
1146 public void actionPerformed(ActionEvent e)
1148 fr.setTransparency(originalTransparency);
1149 updateFeatureRenderer(originalData);
1153 ok.setFont(JvSwingUtils.getLabelFont());
1154 ok.setText(MessageManager.getString("action.ok"));
1155 ok.addActionListener(new ActionListener()
1158 public void actionPerformed(ActionEvent e)
1163 loadColours.setFont(JvSwingUtils.getLabelFont());
1164 loadColours.setText(MessageManager.getString("label.load_colours"));
1165 loadColours.addActionListener(new ActionListener()
1168 public void actionPerformed(ActionEvent e)
1173 saveColours.setFont(JvSwingUtils.getLabelFont());
1174 saveColours.setText(MessageManager.getString("label.save_colours"));
1175 saveColours.addActionListener(new ActionListener()
1178 public void actionPerformed(ActionEvent e)
1183 transparency.addChangeListener(new ChangeListener()
1186 public void stateChanged(ChangeEvent evt)
1188 fr.setTransparency((100 - transparency.getValue()) / 100f);
1189 af.alignPanel.paintAlignment(true);
1193 transparency.setMaximum(70);
1194 transparency.setToolTipText(MessageManager
1195 .getString("label.transparency_tip"));
1196 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1197 fetchDAS.addActionListener(new ActionListener()
1200 public void actionPerformed(ActionEvent e)
1202 fetchDAS_actionPerformed(e);
1205 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1206 saveDAS.addActionListener(new ActionListener()
1209 public void actionPerformed(ActionEvent e)
1211 saveDAS_actionPerformed(e);
1214 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1215 dasSettingsPane.setBorder(null);
1216 cancelDAS.setEnabled(false);
1217 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1218 cancelDAS.addActionListener(new ActionListener()
1221 public void actionPerformed(ActionEvent e)
1223 cancelDAS_actionPerformed(e);
1226 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1227 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1229 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1231 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1232 transbuttons.add(optimizeOrder);
1233 transbuttons.add(invert);
1234 transbuttons.add(sortByScore);
1235 transbuttons.add(sortByDens);
1236 transbuttons.add(help);
1237 JPanel sliderPanel = new JPanel();
1238 sliderPanel.add(transparency);
1239 transPanel.add(transparency);
1240 transPanel.add(transbuttons);
1241 buttonPanel.add(ok);
1242 buttonPanel.add(cancel);
1243 buttonPanel.add(loadColours);
1244 buttonPanel.add(saveColours);
1245 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1246 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1247 dasButtonPanel.add(fetchDAS);
1248 dasButtonPanel.add(cancelDAS);
1249 dasButtonPanel.add(saveDAS);
1250 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1251 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1254 public void fetchDAS_actionPerformed(ActionEvent e)
1256 fetchDAS.setEnabled(false);
1257 cancelDAS.setEnabled(true);
1258 dassourceBrowser.setGuiEnabled(false);
1259 Vector selectedSources = dassourceBrowser.getSelectedSources();
1260 doDasFeatureFetch(selectedSources, true, true);
1264 * get the features from selectedSources for all or the current selection
1266 * @param selectedSources
1267 * @param checkDbRefs
1268 * @param promptFetchDbRefs
1270 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1271 boolean checkDbRefs, boolean promptFetchDbRefs)
1273 SequenceI[] dataset, seqs;
1275 AlignmentViewport vp = af.getViewport();
1276 if (vp.getSelectionGroup() != null
1277 && vp.getSelectionGroup().getSize() > 0)
1279 iSize = vp.getSelectionGroup().getSize();
1280 dataset = new SequenceI[iSize];
1281 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1285 iSize = vp.getAlignment().getHeight();
1286 seqs = vp.getAlignment().getSequencesArray();
1289 dataset = new SequenceI[iSize];
1290 for (int i = 0; i < iSize; i++)
1292 dataset[i] = seqs[i].getDatasetSequence();
1295 cancelDAS.setEnabled(true);
1296 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1297 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1298 af.getViewport().setShowSequenceFeatures(true);
1299 af.showSeqFeatures.setSelected(true);
1303 * blocking call to initialise the das source browser
1305 public void initDasSources()
1307 dassourceBrowser.initDasSources();
1311 * examine the current list of das sources and return any matching the given
1312 * nicknames in sources
1315 * Vector of Strings to resolve to DAS source nicknames.
1316 * @return sources that are present in source list.
1318 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1320 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1324 * get currently selected das sources. ensure you have called initDasSources
1325 * before calling this.
1327 * @return vector of selected das source nicknames
1329 public Vector<jalviewSourceI> getSelectedSources()
1331 return dassourceBrowser.getSelectedSources();
1335 * properly initialise DAS fetcher and then initiate a new thread to fetch
1336 * features from the named sources (rather than any turned on by default)
1340 * if true then runs in same thread, otherwise passes to the Swing
1343 public void fetchDasFeatures(Vector sources, boolean block)
1346 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1347 .resolveSourceNicknames(sources);
1348 if (resolved.size() == 0)
1350 resolved = dassourceBrowser.getSelectedSources();
1352 if (resolved.size() > 0)
1354 final List<jalviewSourceI> dassources = resolved;
1355 fetchDAS.setEnabled(false);
1356 // cancelDAS.setEnabled(true); doDasFetch does this.
1357 Runnable fetcher = new Runnable()
1363 doDasFeatureFetch(dassources, true, false);
1373 SwingUtilities.invokeLater(fetcher);
1378 public void saveDAS_actionPerformed(ActionEvent e)
1381 .saveProperties(jalview.bin.Cache.applicationProperties);
1384 public void complete()
1386 fetchDAS.setEnabled(true);
1387 cancelDAS.setEnabled(false);
1388 dassourceBrowser.setGuiEnabled(true);
1392 public void cancelDAS_actionPerformed(ActionEvent e)
1394 if (dasFeatureFetcher != null)
1396 dasFeatureFetcher.cancel();
1401 public void noDasSourceActive()
1405 .showInternalConfirmDialog(
1408 .getString("label.no_das_sources_selected_warn"),
1410 .getString("label.no_das_sources_selected_title"),
1411 JOptionPane.DEFAULT_OPTION,
1412 JOptionPane.INFORMATION_MESSAGE);
1415 // ///////////////////////////////////////////////////////////////////////
1416 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1417 // ///////////////////////////////////////////////////////////////////////
1418 class FeatureTableModel extends AbstractTableModel
1420 FeatureTableModel(Object[][] data)
1425 private String[] columnNames = {
1426 MessageManager.getString("label.feature_type"),
1427 MessageManager.getString("action.colour"),
1428 MessageManager.getString("label.display") };
1430 private Object[][] data;
1432 public Object[][] getData()
1437 public void setData(Object[][] data)
1443 public int getColumnCount()
1445 return columnNames.length;
1448 public Object[] getRow(int row)
1454 public int getRowCount()
1460 public String getColumnName(int col)
1462 return columnNames[col];
1466 public Object getValueAt(int row, int col)
1468 return data[row][col];
1472 public Class getColumnClass(int c)
1474 return getValueAt(0, c).getClass();
1478 public boolean isCellEditable(int row, int col)
1480 return col == 0 ? false : true;
1484 public void setValueAt(Object value, int row, int col)
1486 data[row][col] = value;
1487 fireTableCellUpdated(row, col);
1488 updateFeatureRenderer(data);
1493 class ColorRenderer extends JLabel implements TableCellRenderer
1495 javax.swing.border.Border unselectedBorder = null;
1497 javax.swing.border.Border selectedBorder = null;
1499 final String baseTT = "Click to edit, right/apple click for menu.";
1501 public ColorRenderer()
1503 setOpaque(true); // MUST do this for background to show up.
1504 setHorizontalTextPosition(SwingConstants.CENTER);
1505 setVerticalTextPosition(SwingConstants.CENTER);
1509 public Component getTableCellRendererComponent(JTable table,
1510 Object color, boolean isSelected, boolean hasFocus, int row,
1513 // JLabel comp = new JLabel();
1517 // setBounds(getBounds());
1519 setToolTipText(baseTT);
1520 setBackground(table.getBackground());
1521 if (color instanceof GraduatedColor)
1523 Rectangle cr = table.getCellRect(row, column, false);
1524 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1525 (int) cr.getWidth(), (int) cr.getHeight());
1532 newColor = (Color) color;
1534 setBackground(newColor);
1535 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1536 // + newColor.getGreen() + ", " + newColor.getBlue());
1540 if (selectedBorder == null)
1542 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1543 table.getSelectionBackground());
1546 setBorder(selectedBorder);
1550 if (unselectedBorder == null)
1552 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1553 table.getBackground());
1556 setBorder(unselectedBorder);
1564 * update comp using rendering settings from gcol
1569 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1571 int w = comp.getWidth(), h = comp.getHeight();
1574 w = (int) comp.getPreferredSize().getWidth();
1575 h = (int) comp.getPreferredSize().getHeight();
1582 renderGraduatedColor(comp, gcol, w, h);
1585 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1588 boolean thr = false;
1591 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1595 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1597 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1601 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1603 if (gcol.isColourByLabel())
1605 tt = "Coloured by label text. " + tt;
1615 Color newColor = gcol.getMaxColor();
1616 comp.setBackground(newColor);
1617 // System.err.println("Width is " + w / 2);
1618 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1619 comp.setIcon(ficon);
1620 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1621 // + newColor.getGreen() + ", " + newColor.getBlue()
1622 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1623 // + ", " + minCol.getBlue() + ")");
1625 comp.setHorizontalAlignment(SwingConstants.CENTER);
1627 if (tt.length() > 0)
1629 if (comp.getToolTipText() == null)
1631 comp.setToolTipText(tt);
1635 comp.setToolTipText(tt + " " + comp.getToolTipText());
1641 class FeatureIcon implements Icon
1643 GraduatedColor gcol;
1647 boolean midspace = false;
1649 int width = 50, height = 20;
1651 int s1, e1; // start and end of midpoint band for thresholded symbol
1653 Color mpcolour = Color.white;
1655 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1675 public int getIconWidth()
1681 public int getIconHeight()
1687 public void paintIcon(Component c, Graphics g, int x, int y)
1690 if (gcol.isColourByLabel())
1693 g.fillRect(0, 0, width, height);
1694 // need an icon here.
1695 g.setColor(gcol.getMaxColor());
1697 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1699 // g.setFont(g.getFont().deriveFont(
1700 // AffineTransform.getScaleInstance(
1701 // width/g.getFontMetrics().stringWidth("Label"),
1702 // height/g.getFontMetrics().getHeight())));
1704 g.drawString(MessageManager.getString("label.label"), 0, 0);
1709 Color minCol = gcol.getMinColor();
1711 g.fillRect(0, 0, s1, height);
1714 g.setColor(Color.white);
1715 g.fillRect(s1, 0, e1 - s1, height);
1717 g.setColor(gcol.getMaxColor());
1718 g.fillRect(0, e1, width - e1, height);
1723 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1728 GraduatedColor currentGColor;
1730 FeatureColourChooser chooser;
1738 JColorChooser colorChooser;
1742 protected static final String EDIT = "edit";
1744 int selectedRow = 0;
1746 public ColorEditor(FeatureSettings me)
1749 // Set up the editor (from the table's point of view),
1750 // which is a button.
1751 // This button brings up the color chooser dialog,
1752 // which is the editor from the user's point of view.
1753 button = new JButton();
1754 button.setActionCommand(EDIT);
1755 button.addActionListener(this);
1756 button.setBorderPainted(false);
1757 // Set up the dialog that the button brings up.
1758 colorChooser = new JColorChooser();
1759 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1760 colorChooser, this, // OK button handler
1761 null); // no CANCEL button handler
1765 * Handles events from the editor button and from the dialog's OK button.
1768 public void actionPerformed(ActionEvent e)
1771 if (EDIT.equals(e.getActionCommand()))
1773 // The user has clicked the cell, so
1774 // bring up the dialog.
1775 if (currentColor != null)
1777 // bring up simple color chooser
1778 button.setBackground(currentColor);
1779 colorChooser.setColor(currentColor);
1780 dialog.setVisible(true);
1784 // bring up graduated chooser.
1785 chooser = new FeatureColourChooser(me.fr, type);
1786 chooser.setRequestFocusEnabled(true);
1787 chooser.requestFocus();
1788 chooser.addActionListener(this);
1790 // Make the renderer reappear.
1791 fireEditingStopped();
1795 { // User pressed dialog's "OK" button.
1796 if (currentColor != null)
1798 currentColor = colorChooser.getColor();
1802 // class cast exceptions may be raised if the chooser created on a
1803 // non-graduated color
1804 currentGColor = (GraduatedColor) chooser.getLastColour();
1806 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1807 fireEditingStopped();
1808 me.table.validate();
1812 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1814 public Object getCellEditorValue()
1816 if (currentColor == null)
1818 return currentGColor;
1820 return currentColor;
1823 // Implement the one method defined by TableCellEditor.
1825 public Component getTableCellEditorComponent(JTable table, Object value,
1826 boolean isSelected, int row, int column)
1828 currentGColor = null;
1829 currentColor = null;
1830 this.selectedRow = row;
1831 type = me.table.getValueAt(row, 0).toString();
1832 button.setOpaque(true);
1833 button.setBackground(me.getBackground());
1834 if (value instanceof GraduatedColor)
1836 currentGColor = (GraduatedColor) value;
1837 JLabel btn = new JLabel();
1838 btn.setSize(button.getSize());
1839 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1840 button.setBackground(btn.getBackground());
1841 button.setIcon(btn.getIcon());
1842 button.setText(btn.getText());
1847 button.setIcon(null);
1848 currentColor = (Color) value;
1849 button.setBackground(currentColor);